1
Last minute pullreq for arm related patches; quite large because
1
First arm pullreq of the cycle; this is mostly my softfloat NaN
2
there were several series that only just made it through code review
2
handling series. (Lots more in my to-review queue, but I don't
3
in time.
3
like pullreqs growing too close to a hundred patches at a time :-))
4
4
5
thanks
5
thanks
6
-- PMM
6
-- PMM
7
7
8
The following changes since commit 091e3e3dbc499d84c004e1c50bc9870af37f6e99:
8
The following changes since commit 97f2796a3736ed37a1b85dc1c76a6c45b829dd17:
9
9
10
Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2020-10-26' into staging (2020-10-26 22:36:35 +0000)
10
Open 10.0 development tree (2024-12-10 17:41:17 +0000)
11
11
12
are available in the Git repository at:
12
are available in the Git repository at:
13
13
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20201027-1
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20241211
15
15
16
for you to fetch changes up to 32bd322a0134ed89db00f2b9b3894982db3dedcb:
16
for you to fetch changes up to 1abe28d519239eea5cf9620bb13149423e5665f8:
17
17
18
hw/timer/armv7m_systick: Rewrite to use ptimers (2020-10-27 11:15:31 +0000)
18
MAINTAINERS: Add correct email address for Vikram Garhwal (2024-12-11 15:31:09 +0000)
19
19
20
----------------------------------------------------------------
20
----------------------------------------------------------------
21
target-arm queue:
21
target-arm queue:
22
* raspi: add model of cprman clock manager
22
* hw/net/lan9118: Extract PHY model, reuse with imx_fec, fix bugs
23
* sbsa-ref: add an SBSA generic watchdog device
23
* fpu: Make muladd NaN handling runtime-selected, not compile-time
24
* arm/trace: Fix hex printing
24
* fpu: Make default NaN pattern runtime-selected, not compile-time
25
* raspi: Add models of Pi 3 model A+, Pi Zero and Pi A+
25
* fpu: Minor NaN-related cleanups
26
* hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
26
* MAINTAINERS: email address updates
27
* Nuvoton NPCM7xx: Add USB, RNG, GPIO and watchdog support
28
* hw/arm: fix min_cpus for xlnx-versal-virt platform
29
* hw/arm/highbank: Silence warnings about missing fallthrough statements
30
* linux-user: Support Aarch64 BTI
31
* Armv7M systick: fix corner case bugs by rewriting to use ptimer
32
27
33
----------------------------------------------------------------
28
----------------------------------------------------------------
34
Dr. David Alan Gilbert (1):
29
Bernhard Beschow (5):
35
arm/trace: Fix hex printing
30
hw/net/lan9118: Extract lan9118_phy
31
hw/net/lan9118_phy: Reuse in imx_fec and consolidate implementations
32
hw/net/lan9118_phy: Fix off-by-one error in MII_ANLPAR register
33
hw/net/lan9118_phy: Reuse MII constants
34
hw/net/lan9118_phy: Add missing 100 mbps full duplex advertisement
36
35
37
Hao Wu (1):
36
Leif Lindholm (1):
38
hw/timer: Adding watchdog for NPCM7XX Timer.
37
MAINTAINERS: update email address for Leif Lindholm
39
38
40
Havard Skinnemoen (4):
39
Peter Maydell (54):
41
Move npcm7xx_timer_reached_zero call out of npcm7xx_timer_pause
40
fpu: handle raising Invalid for infzero in pick_nan_muladd
42
hw/misc: Add npcm7xx random number generator
41
fpu: Check for default_nan_mode before calling pickNaNMulAdd
43
hw/arm/npcm7xx: Add EHCI and OHCI controllers
42
softfloat: Allow runtime choice of inf * 0 + NaN result
44
hw/gpio: Add GPIO model for Nuvoton NPCM7xx
43
tests/fp: Explicitly set inf-zero-nan rule
45
44
target/arm: Set FloatInfZeroNaNRule explicitly
46
Luc Michel (14):
45
target/s390: Set FloatInfZeroNaNRule explicitly
47
hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro
46
target/ppc: Set FloatInfZeroNaNRule explicitly
48
hw/core/clock: trace clock values in Hz instead of ns
47
target/mips: Set FloatInfZeroNaNRule explicitly
49
hw/arm/raspi: fix CPRMAN base address
48
target/sparc: Set FloatInfZeroNaNRule explicitly
50
hw/arm/raspi: add a skeleton implementation of the CPRMAN
49
target/xtensa: Set FloatInfZeroNaNRule explicitly
51
hw/misc/bcm2835_cprman: add a PLL skeleton implementation
50
target/x86: Set FloatInfZeroNaNRule explicitly
52
hw/misc/bcm2835_cprman: implement PLLs behaviour
51
target/loongarch: Set FloatInfZeroNaNRule explicitly
53
hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation
52
target/hppa: Set FloatInfZeroNaNRule explicitly
54
hw/misc/bcm2835_cprman: implement PLL channels behaviour
53
softfloat: Pass have_snan to pickNaNMulAdd
55
hw/misc/bcm2835_cprman: add a clock mux skeleton implementation
54
softfloat: Allow runtime choice of NaN propagation for muladd
56
hw/misc/bcm2835_cprman: implement clock mux behaviour
55
tests/fp: Explicitly set 3-NaN propagation rule
57
hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer
56
target/arm: Set Float3NaNPropRule explicitly
58
hw/misc/bcm2835_cprman: add sane reset values to the registers
57
target/loongarch: Set Float3NaNPropRule explicitly
59
hw/char/pl011: add a clock input
58
target/ppc: Set Float3NaNPropRule explicitly
60
hw/arm/bcm2835_peripherals: connect the UART clock
59
target/s390x: Set Float3NaNPropRule explicitly
61
60
target/sparc: Set Float3NaNPropRule explicitly
62
Pavel Dovgalyuk (1):
61
target/mips: Set Float3NaNPropRule explicitly
63
hw/arm: fix min_cpus for xlnx-versal-virt platform
62
target/xtensa: Set Float3NaNPropRule explicitly
64
63
target/i386: Set Float3NaNPropRule explicitly
65
Peter Maydell (2):
64
target/hppa: Set Float3NaNPropRule explicitly
66
hw/core/ptimer: Support ptimer being disabled by timer callback
65
fpu: Remove use_first_nan field from float_status
67
hw/timer/armv7m_systick: Rewrite to use ptimers
66
target/m68k: Don't pass NULL float_status to floatx80_default_nan()
68
67
softfloat: Create floatx80 default NaN from parts64_default_nan
69
Philippe Mathieu-Daudé (10):
68
target/loongarch: Use normal float_status in fclass_s and fclass_d helpers
70
linux-user/elfload: Avoid leaking interp_name using GLib memory API
69
target/m68k: In frem helper, initialize local float_status from env->fp_status
71
hw/arm/bcm2836: Restrict BCM283XInfo declaration to C source
70
target/m68k: Init local float_status from env fp_status in gdb get/set reg
72
hw/arm/bcm2836: QOM'ify more by adding class_init() to each SoC type
71
target/sparc: Initialize local scratch float_status from env->fp_status
73
hw/arm/bcm2836: Introduce BCM283XClass::core_count
72
target/ppc: Use env->fp_status in helper_compute_fprf functions
74
hw/arm/bcm2836: Only provide "enabled-cpus" property to multicore SoCs
73
fpu: Allow runtime choice of default NaN value
75
hw/arm/bcm2836: Split out common realize() code
74
tests/fp: Set default NaN pattern explicitly
76
hw/arm/bcm2836: Introduce the BCM2835 SoC
75
target/microblaze: Set default NaN pattern explicitly
77
hw/arm/raspi: Add the Raspberry Pi A+ machine
76
target/i386: Set default NaN pattern explicitly
78
hw/arm/raspi: Add the Raspberry Pi Zero machine
77
target/hppa: Set default NaN pattern explicitly
79
hw/arm/raspi: Add the Raspberry Pi 3 model A+
78
target/alpha: Set default NaN pattern explicitly
79
target/arm: Set default NaN pattern explicitly
80
target/loongarch: Set default NaN pattern explicitly
81
target/m68k: Set default NaN pattern explicitly
82
target/mips: Set default NaN pattern explicitly
83
target/openrisc: Set default NaN pattern explicitly
84
target/ppc: Set default NaN pattern explicitly
85
target/sh4: Set default NaN pattern explicitly
86
target/rx: Set default NaN pattern explicitly
87
target/s390x: Set default NaN pattern explicitly
88
target/sparc: Set default NaN pattern explicitly
89
target/xtensa: Set default NaN pattern explicitly
90
target/hexagon: Set default NaN pattern explicitly
91
target/riscv: Set default NaN pattern explicitly
92
target/tricore: Set default NaN pattern explicitly
93
fpu: Remove default handling for dnan_pattern
80
94
81
Richard Henderson (11):
95
Richard Henderson (11):
82
linux-user/aarch64: Reset btype for signals
96
target/arm: Copy entire float_status in is_ebf
83
linux-user: Set PAGE_TARGET_1 for TARGET_PROT_BTI
97
softfloat: Inline pickNaNMulAdd
84
include/elf: Add defines related to GNU property notes for AArch64
98
softfloat: Use goto for default nan case in pick_nan_muladd
85
linux-user/elfload: Fix coding style in load_elf_image
99
softfloat: Remove which from parts_pick_nan_muladd
86
linux-user/elfload: Adjust iteration over phdr
100
softfloat: Pad array size in pick_nan_muladd
87
linux-user/elfload: Move PT_INTERP detection to first loop
101
softfloat: Move propagateFloatx80NaN to softfloat.c
88
linux-user/elfload: Use Error for load_elf_image
102
softfloat: Use parts_pick_nan in propagateFloatx80NaN
89
linux-user/elfload: Use Error for load_elf_interp
103
softfloat: Inline pickNaN
90
linux-user/elfload: Parse NT_GNU_PROPERTY_TYPE_0 notes
104
softfloat: Share code between parts_pick_nan cases
91
linux-user/elfload: Parse GNU_PROPERTY_AARCH64_FEATURE_1_AND
105
softfloat: Sink frac_cmp in parts_pick_nan until needed
92
tests/tcg/aarch64: Add bti smoke tests
106
softfloat: Replace WHICH with RET in parts_pick_nan
93
107
94
Shashi Mallela (2):
108
Vikram Garhwal (1):
95
hw/watchdog: Implement SBSA watchdog device
109
MAINTAINERS: Add correct email address for Vikram Garhwal
96
hw/arm/sbsa-ref: add SBSA watchdog device
97
110
98
Thomas Huth (1):
111
MAINTAINERS | 4 +-
99
hw/arm/highbank: Silence warnings about missing fallthrough statements
112
include/fpu/softfloat-helpers.h | 38 +++-
100
113
include/fpu/softfloat-types.h | 89 +++++++-
101
Zenghui Yu (1):
114
include/hw/net/imx_fec.h | 9 +-
102
hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
115
include/hw/net/lan9118_phy.h | 37 ++++
103
116
include/hw/net/mii.h | 6 +
104
docs/system/arm/nuvoton.rst | 6 +-
117
target/mips/fpu_helper.h | 20 ++
105
hw/usb/hcd-ehci.h | 1 +
118
target/sparc/helper.h | 4 +-
106
include/elf.h | 22 +
119
fpu/softfloat.c | 19 ++
107
include/exec/cpu-all.h | 2 +
120
hw/net/imx_fec.c | 146 ++------------
108
include/hw/arm/bcm2835_peripherals.h | 5 +-
121
hw/net/lan9118.c | 137 ++-----------
109
include/hw/arm/bcm2836.h | 9 +-
122
hw/net/lan9118_phy.c | 222 ++++++++++++++++++++
110
include/hw/arm/npcm7xx.h | 8 +
123
linux-user/arm/nwfpe/fpa11.c | 5 +
111
include/hw/arm/raspi_platform.h | 5 +-
124
target/alpha/cpu.c | 2 +
112
include/hw/char/pl011.h | 1 +
125
target/arm/cpu.c | 10 +
113
include/hw/clock.h | 5 +
126
target/arm/tcg/vec_helper.c | 20 +-
114
include/hw/gpio/npcm7xx_gpio.h | 55 ++
127
target/hexagon/cpu.c | 2 +
115
include/hw/misc/bcm2835_cprman.h | 210 ++++++
128
target/hppa/fpu_helper.c | 12 ++
116
include/hw/misc/bcm2835_cprman_internals.h | 1019 ++++++++++++++++++++++++++++
129
target/i386/tcg/fpu_helper.c | 12 ++
117
include/hw/misc/npcm7xx_clk.h | 2 +
130
target/loongarch/tcg/fpu_helper.c | 14 +-
118
include/hw/misc/npcm7xx_rng.h | 34 +
131
target/m68k/cpu.c | 14 +-
119
include/hw/timer/armv7m_systick.h | 3 +-
132
target/m68k/fpu_helper.c | 6 +-
120
include/hw/timer/npcm7xx_timer.h | 48 +-
133
target/m68k/helper.c | 6 +-
121
include/hw/watchdog/sbsa_gwdt.h | 79 +++
134
target/microblaze/cpu.c | 2 +
122
linux-user/qemu.h | 4 +
135
target/mips/msa.c | 10 +
123
linux-user/syscall_defs.h | 4 +
136
target/openrisc/cpu.c | 2 +
124
target/arm/cpu.h | 5 +
137
target/ppc/cpu_init.c | 19 ++
125
hw/arm/bcm2835_peripherals.c | 15 +-
138
target/ppc/fpu_helper.c | 3 +-
126
hw/arm/bcm2836.c | 182 +++--
139
target/riscv/cpu.c | 2 +
127
hw/arm/highbank.c | 2 +
140
target/rx/cpu.c | 2 +
128
hw/arm/npcm7xx.c | 126 +++-
141
target/s390x/cpu.c | 5 +
129
hw/arm/raspi.c | 41 ++
142
target/sh4/cpu.c | 2 +
130
hw/arm/sbsa-ref.c | 23 +
143
target/sparc/cpu.c | 6 +
131
hw/arm/smmuv3.c | 1 +
144
target/sparc/fop_helper.c | 8 +-
132
hw/arm/xlnx-versal-virt.c | 1 +
145
target/sparc/translate.c | 4 +-
133
hw/char/pl011.c | 45 ++
146
target/tricore/helper.c | 2 +
134
hw/core/clock.c | 6 +-
147
target/xtensa/cpu.c | 4 +
135
hw/core/ptimer.c | 4 +
148
target/xtensa/fpu_helper.c | 3 +-
136
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++
149
tests/fp/fp-bench.c | 7 +
137
hw/misc/bcm2835_cprman.c | 808 ++++++++++++++++++++++
150
tests/fp/fp-test-log2.c | 1 +
138
hw/misc/npcm7xx_clk.c | 28 +
151
tests/fp/fp-test.c | 7 +
139
hw/misc/npcm7xx_rng.c | 180 +++++
152
fpu/softfloat-parts.c.inc | 152 +++++++++++---
140
hw/timer/armv7m_systick.c | 124 ++--
153
fpu/softfloat-specialize.c.inc | 412 ++------------------------------------
141
hw/timer/npcm7xx_timer.c | 270 ++++++--
154
.mailmap | 5 +-
142
hw/usb/hcd-ehci-sysbus.c | 19 +
155
hw/net/Kconfig | 5 +
143
hw/watchdog/sbsa_gwdt.c | 293 ++++++++
156
hw/net/meson.build | 1 +
144
linux-user/aarch64/signal.c | 10 +-
157
hw/net/trace-events | 10 +-
145
linux-user/elfload.c | 326 +++++++--
158
47 files changed, 778 insertions(+), 730 deletions(-)
146
linux-user/mmap.c | 16 +
159
create mode 100644 include/hw/net/lan9118_phy.h
147
target/arm/translate-a64.c | 6 +-
160
create mode 100644 hw/net/lan9118_phy.c
148
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++
149
tests/qtest/npcm7xx_rng-test.c | 278 ++++++++
150
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 +++++++++
151
tests/tcg/aarch64/bti-1.c | 62 ++
152
tests/tcg/aarch64/bti-2.c | 116 ++++
153
tests/tcg/aarch64/bti-crt.inc.c | 51 ++
154
MAINTAINERS | 1 +
155
hw/arm/Kconfig | 1 +
156
hw/arm/trace-events | 2 +-
157
hw/char/trace-events | 1 +
158
hw/core/trace-events | 4 +-
159
hw/gpio/meson.build | 1 +
160
hw/gpio/trace-events | 7 +
161
hw/misc/meson.build | 2 +
162
hw/misc/trace-events | 9 +
163
hw/watchdog/Kconfig | 3 +
164
hw/watchdog/meson.build | 1 +
165
tests/qtest/meson.build | 6 +-
166
tests/tcg/aarch64/Makefile.target | 10 +
167
tests/tcg/configure.sh | 4 +
168
64 files changed, 5461 insertions(+), 279 deletions(-)
169
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
170
create mode 100644 include/hw/misc/bcm2835_cprman.h
171
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
172
create mode 100644 include/hw/misc/npcm7xx_rng.h
173
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
174
create mode 100644 hw/gpio/npcm7xx_gpio.c
175
create mode 100644 hw/misc/bcm2835_cprman.c
176
create mode 100644 hw/misc/npcm7xx_rng.c
177
create mode 100644 hw/watchdog/sbsa_gwdt.c
178
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
179
create mode 100644 tests/qtest/npcm7xx_rng-test.c
180
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
181
create mode 100644 tests/tcg/aarch64/bti-1.c
182
create mode 100644 tests/tcg/aarch64/bti-2.c
183
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
184
diff view generated by jsdifflib
1
From: Havard Skinnemoen <hskinnemoen@google.com>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
The RNG module returns a byte of randomness when the Data Valid bit is
3
A very similar implementation of the same device exists in imx_fec. Prepare for
4
set.
4
a common implementation by extracting a device model into its own files.
5
5
6
This implementation ignores the prescaler setting, and loads a new value
6
Some migration state has been moved into the new device model which breaks
7
into RNGD every time RNGCS is read while the RNG is enabled and random
7
migration compatibility for the following machines:
8
data is available.
8
* smdkc210
9
* realview-*
10
* vexpress-*
11
* kzm
12
* mps2-*
9
13
10
A qtest featuring some simple randomness tests is included.
14
While breaking migration ABI, fix the size of the MII registers to be 16 bit,
15
as defined by IEEE 802.3u.
11
16
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
17
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
18
Tested-by: Guenter Roeck <linux@roeck-us.net>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
20
Message-id: 20241102125724.532843-2-shentey@gmail.com
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
22
---
17
docs/system/arm/nuvoton.rst | 2 +-
23
include/hw/net/lan9118_phy.h | 37 ++++++++
18
include/hw/arm/npcm7xx.h | 2 +
24
hw/net/lan9118.c | 137 +++++-----------------------
19
include/hw/misc/npcm7xx_rng.h | 34 ++++
25
hw/net/lan9118_phy.c | 169 +++++++++++++++++++++++++++++++++++
20
hw/arm/npcm7xx.c | 7 +-
26
hw/net/Kconfig | 4 +
21
hw/misc/npcm7xx_rng.c | 180 +++++++++++++++++++++
27
hw/net/meson.build | 1 +
22
tests/qtest/npcm7xx_rng-test.c | 278 +++++++++++++++++++++++++++++++++
28
5 files changed, 233 insertions(+), 115 deletions(-)
23
hw/misc/meson.build | 1 +
29
create mode 100644 include/hw/net/lan9118_phy.h
24
hw/misc/trace-events | 4 +
30
create mode 100644 hw/net/lan9118_phy.c
25
tests/qtest/meson.build | 5 +-
26
9 files changed, 510 insertions(+), 3 deletions(-)
27
create mode 100644 include/hw/misc/npcm7xx_rng.h
28
create mode 100644 hw/misc/npcm7xx_rng.c
29
create mode 100644 tests/qtest/npcm7xx_rng-test.c
30
31
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
32
diff --git a/include/hw/net/lan9118_phy.h b/include/hw/net/lan9118_phy.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/docs/system/arm/nuvoton.rst
34
+++ b/docs/system/arm/nuvoton.rst
35
@@ -XXX,XX +XXX,XX @@ Supported devices
36
* DDR4 memory controller (dummy interface indicating memory training is done)
37
* OTP controllers (no protection features)
38
* Flash Interface Unit (FIU; no protection features)
39
+ * Random Number Generator (RNG)
40
41
Missing devices
42
---------------
43
@@ -XXX,XX +XXX,XX @@ Missing devices
44
* Peripheral SPI controller (PSPI)
45
* Analog to Digital Converter (ADC)
46
* SD/MMC host
47
- * Random Number Generator (RNG)
48
* PECI interface
49
* Pulse Width Modulation (PWM)
50
* Tachometer
51
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/include/hw/arm/npcm7xx.h
54
+++ b/include/hw/arm/npcm7xx.h
55
@@ -XXX,XX +XXX,XX @@
56
#include "hw/mem/npcm7xx_mc.h"
57
#include "hw/misc/npcm7xx_clk.h"
58
#include "hw/misc/npcm7xx_gcr.h"
59
+#include "hw/misc/npcm7xx_rng.h"
60
#include "hw/nvram/npcm7xx_otp.h"
61
#include "hw/timer/npcm7xx_timer.h"
62
#include "hw/ssi/npcm7xx_fiu.h"
63
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
64
NPCM7xxOTPState key_storage;
65
NPCM7xxOTPState fuse_array;
66
NPCM7xxMCState mc;
67
+ NPCM7xxRNGState rng;
68
NPCM7xxFIUState fiu[2];
69
} NPCM7xxState;
70
71
diff --git a/include/hw/misc/npcm7xx_rng.h b/include/hw/misc/npcm7xx_rng.h
72
new file mode 100644
33
new file mode 100644
73
index XXXXXXX..XXXXXXX
34
index XXXXXXX..XXXXXXX
74
--- /dev/null
35
--- /dev/null
75
+++ b/include/hw/misc/npcm7xx_rng.h
36
+++ b/include/hw/net/lan9118_phy.h
76
@@ -XXX,XX +XXX,XX @@
37
@@ -XXX,XX +XXX,XX @@
77
+/*
38
+/*
78
+ * Nuvoton NPCM7xx Random Number Generator.
39
+ * SMSC LAN9118 PHY emulation
79
+ *
40
+ *
80
+ * Copyright 2020 Google LLC
41
+ * Copyright (c) 2009 CodeSourcery, LLC.
42
+ * Written by Paul Brook
81
+ *
43
+ *
82
+ * This program is free software; you can redistribute it and/or modify it
44
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
83
+ * under the terms of the GNU General Public License as published by the
45
+ * See the COPYING file in the top-level directory.
84
+ * Free Software Foundation; either version 2 of the License, or
85
+ * (at your option) any later version.
86
+ *
87
+ * This program is distributed in the hope that it will be useful, but WITHOUT
88
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
89
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
90
+ * for more details.
91
+ */
46
+ */
92
+#ifndef NPCM7XX_RNG_H
47
+
93
+#define NPCM7XX_RNG_H
48
+#ifndef HW_NET_LAN9118_PHY_H
94
+
49
+#define HW_NET_LAN9118_PHY_H
50
+
51
+#include "qom/object.h"
95
+#include "hw/sysbus.h"
52
+#include "hw/sysbus.h"
96
+
53
+
97
+typedef struct NPCM7xxRNGState {
54
+#define TYPE_LAN9118_PHY "lan9118-phy"
98
+ SysBusDevice parent;
55
+OBJECT_DECLARE_SIMPLE_TYPE(Lan9118PhyState, LAN9118_PHY)
99
+
56
+
100
+ MemoryRegion iomem;
57
+typedef struct Lan9118PhyState {
101
+
58
+ SysBusDevice parent_obj;
102
+ uint8_t rngcs;
59
+
103
+ uint8_t rngd;
60
+ uint16_t status;
104
+ uint8_t rngmode;
61
+ uint16_t control;
105
+} NPCM7xxRNGState;
62
+ uint16_t advertise;
106
+
63
+ uint16_t ints;
107
+#define TYPE_NPCM7XX_RNG "npcm7xx-rng"
64
+ uint16_t int_mask;
108
+#define NPCM7XX_RNG(obj) OBJECT_CHECK(NPCM7xxRNGState, (obj), TYPE_NPCM7XX_RNG)
65
+ qemu_irq irq;
109
+
66
+ bool link_down;
110
+#endif /* NPCM7XX_RNG_H */
67
+} Lan9118PhyState;
111
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
68
+
69
+void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down);
70
+void lan9118_phy_reset(Lan9118PhyState *s);
71
+uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg);
72
+void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val);
73
+
74
+#endif
75
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
112
index XXXXXXX..XXXXXXX 100644
76
index XXXXXXX..XXXXXXX 100644
113
--- a/hw/arm/npcm7xx.c
77
--- a/hw/net/lan9118.c
114
+++ b/hw/arm/npcm7xx.c
78
+++ b/hw/net/lan9118.c
115
@@ -XXX,XX +XXX,XX @@
79
@@ -XXX,XX +XXX,XX @@
116
#define NPCM7XX_GCR_BA (0xf0800000)
80
#include "net/net.h"
117
#define NPCM7XX_CLK_BA (0xf0801000)
81
#include "net/eth.h"
118
#define NPCM7XX_MC_BA (0xf0824000)
82
#include "hw/irq.h"
119
+#define NPCM7XX_RNG_BA (0xf000b000)
83
+#include "hw/net/lan9118_phy.h"
120
84
#include "hw/net/lan9118.h"
121
/* Internal AHB SRAM */
85
#include "hw/ptimer.h"
122
#define NPCM7XX_RAM3_BA (0xc0008000)
86
#include "hw/qdev-properties.h"
123
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
87
@@ -XXX,XX +XXX,XX @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
124
object_initialize_child(obj, "otp2", &s->fuse_array,
88
#define MAC_CR_RXEN 0x00000004
125
TYPE_NPCM7XX_FUSE_ARRAY);
89
#define MAC_CR_RESERVED 0x7f404213
126
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
90
127
+ object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
91
-#define PHY_INT_ENERGYON 0x80
128
92
-#define PHY_INT_AUTONEG_COMPLETE 0x40
129
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
93
-#define PHY_INT_FAULT 0x20
130
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
94
-#define PHY_INT_DOWN 0x10
131
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
95
-#define PHY_INT_AUTONEG_LP 0x08
132
serial_hd(i), DEVICE_LITTLE_ENDIAN);
96
-#define PHY_INT_PARFAULT 0x04
97
-#define PHY_INT_AUTONEG_PAGE 0x02
98
-
99
#define GPT_TIMER_EN 0x20000000
100
101
/*
102
@@ -XXX,XX +XXX,XX @@ struct lan9118_state {
103
uint32_t mac_mii_data;
104
uint32_t mac_flow;
105
106
- uint32_t phy_status;
107
- uint32_t phy_control;
108
- uint32_t phy_advertise;
109
- uint32_t phy_int;
110
- uint32_t phy_int_mask;
111
+ Lan9118PhyState mii;
112
+ IRQState mii_irq;
113
114
int32_t eeprom_writable;
115
uint8_t eeprom[128];
116
@@ -XXX,XX +XXX,XX @@ struct lan9118_state {
117
118
static const VMStateDescription vmstate_lan9118 = {
119
.name = "lan9118",
120
- .version_id = 2,
121
- .minimum_version_id = 1,
122
+ .version_id = 3,
123
+ .minimum_version_id = 3,
124
.fields = (const VMStateField[]) {
125
VMSTATE_PTIMER(timer, lan9118_state),
126
VMSTATE_UINT32(irq_cfg, lan9118_state),
127
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_lan9118 = {
128
VMSTATE_UINT32(mac_mii_acc, lan9118_state),
129
VMSTATE_UINT32(mac_mii_data, lan9118_state),
130
VMSTATE_UINT32(mac_flow, lan9118_state),
131
- VMSTATE_UINT32(phy_status, lan9118_state),
132
- VMSTATE_UINT32(phy_control, lan9118_state),
133
- VMSTATE_UINT32(phy_advertise, lan9118_state),
134
- VMSTATE_UINT32(phy_int, lan9118_state),
135
- VMSTATE_UINT32(phy_int_mask, lan9118_state),
136
VMSTATE_INT32(eeprom_writable, lan9118_state),
137
VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
138
VMSTATE_INT32(tx_fifo_size, lan9118_state),
139
@@ -XXX,XX +XXX,XX @@ static void lan9118_reload_eeprom(lan9118_state *s)
140
lan9118_mac_changed(s);
141
}
142
143
-static void phy_update_irq(lan9118_state *s)
144
+static void lan9118_update_irq(void *opaque, int n, int level)
145
{
146
- if (s->phy_int & s->phy_int_mask) {
147
+ lan9118_state *s = opaque;
148
+
149
+ if (level) {
150
s->int_sts |= PHY_INT;
151
} else {
152
s->int_sts &= ~PHY_INT;
153
@@ -XXX,XX +XXX,XX @@ static void phy_update_irq(lan9118_state *s)
154
lan9118_update(s);
155
}
156
157
-static void phy_update_link(lan9118_state *s)
158
-{
159
- /* Autonegotiation status mirrors link status. */
160
- if (qemu_get_queue(s->nic)->link_down) {
161
- s->phy_status &= ~0x0024;
162
- s->phy_int |= PHY_INT_DOWN;
163
- } else {
164
- s->phy_status |= 0x0024;
165
- s->phy_int |= PHY_INT_ENERGYON;
166
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
167
- }
168
- phy_update_irq(s);
169
-}
170
-
171
static void lan9118_set_link(NetClientState *nc)
172
{
173
- phy_update_link(qemu_get_nic_opaque(nc));
174
-}
175
-
176
-static void phy_reset(lan9118_state *s)
177
-{
178
- s->phy_status = 0x7809;
179
- s->phy_control = 0x3000;
180
- s->phy_advertise = 0x01e1;
181
- s->phy_int_mask = 0;
182
- s->phy_int = 0;
183
- phy_update_link(s);
184
+ lan9118_phy_update_link(&LAN9118(qemu_get_nic_opaque(nc))->mii,
185
+ nc->link_down);
186
}
187
188
static void lan9118_reset(DeviceState *d)
189
@@ -XXX,XX +XXX,XX @@ static void lan9118_reset(DeviceState *d)
190
s->read_word_n = 0;
191
s->write_word_n = 0;
192
193
- phy_reset(s);
194
-
195
s->eeprom_writable = 0;
196
lan9118_reload_eeprom(s);
197
}
198
@@ -XXX,XX +XXX,XX @@ static void do_tx_packet(lan9118_state *s)
199
uint32_t status;
200
201
/* FIXME: Honor TX disable, and allow queueing of packets. */
202
- if (s->phy_control & 0x4000) {
203
+ if (s->mii.control & 0x4000) {
204
/* This assumes the receive routine doesn't touch the VLANClient. */
205
qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
206
} else {
207
@@ -XXX,XX +XXX,XX @@ static void tx_fifo_push(lan9118_state *s, uint32_t val)
133
}
208
}
134
209
}
135
+ /* Random Number Generator. Cannot fail. */
210
136
+ sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
211
-static uint32_t do_phy_read(lan9118_state *s, int reg)
137
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
212
-{
138
+
213
- uint32_t val;
139
/*
214
-
140
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
215
- switch (reg) {
141
* specified, but this is a programming error.
216
- case 0: /* Basic Control */
142
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
217
- return s->phy_control;
143
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
218
- case 1: /* Basic Status */
144
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
219
- return s->phy_status;
145
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
220
- case 2: /* ID1 */
146
- create_unimplemented_device("npcm7xx.rng", 0xf000b000, 4 * KiB);
221
- return 0x0007;
147
create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
222
- case 3: /* ID2 */
148
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
223
- return 0xc0d1;
149
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
224
- case 4: /* Auto-neg advertisement */
150
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
225
- return s->phy_advertise;
226
- case 5: /* Auto-neg Link Partner Ability */
227
- return 0x0f71;
228
- case 6: /* Auto-neg Expansion */
229
- return 1;
230
- /* TODO 17, 18, 27, 29, 30, 31 */
231
- case 29: /* Interrupt source. */
232
- val = s->phy_int;
233
- s->phy_int = 0;
234
- phy_update_irq(s);
235
- return val;
236
- case 30: /* Interrupt mask */
237
- return s->phy_int_mask;
238
- default:
239
- qemu_log_mask(LOG_GUEST_ERROR,
240
- "do_phy_read: PHY read reg %d\n", reg);
241
- return 0;
242
- }
243
-}
244
-
245
-static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
246
-{
247
- switch (reg) {
248
- case 0: /* Basic Control */
249
- if (val & 0x8000) {
250
- phy_reset(s);
251
- break;
252
- }
253
- s->phy_control = val & 0x7980;
254
- /* Complete autonegotiation immediately. */
255
- if (val & 0x1000) {
256
- s->phy_status |= 0x0020;
257
- }
258
- break;
259
- case 4: /* Auto-neg advertisement */
260
- s->phy_advertise = (val & 0x2d7f) | 0x80;
261
- break;
262
- /* TODO 17, 18, 27, 31 */
263
- case 30: /* Interrupt mask */
264
- s->phy_int_mask = val & 0xff;
265
- phy_update_irq(s);
266
- break;
267
- default:
268
- qemu_log_mask(LOG_GUEST_ERROR,
269
- "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
270
- }
271
-}
272
-
273
static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
274
{
275
switch (reg) {
276
@@ -XXX,XX +XXX,XX @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
277
if (val & 2) {
278
DPRINTF("PHY write %d = 0x%04x\n",
279
(val >> 6) & 0x1f, s->mac_mii_data);
280
- do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
281
+ lan9118_phy_write(&s->mii, (val >> 6) & 0x1f, s->mac_mii_data);
282
} else {
283
- s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
284
+ s->mac_mii_data = lan9118_phy_read(&s->mii, (val >> 6) & 0x1f);
285
DPRINTF("PHY read %d = 0x%04x\n",
286
(val >> 6) & 0x1f, s->mac_mii_data);
287
}
288
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
289
break;
290
case CSR_PMT_CTRL:
291
if (val & 0x400) {
292
- phy_reset(s);
293
+ lan9118_phy_reset(&s->mii);
294
}
295
s->pmt_ctrl &= ~0x34e;
296
s->pmt_ctrl |= (val & 0x34e);
297
@@ -XXX,XX +XXX,XX @@ static void lan9118_realize(DeviceState *dev, Error **errp)
298
const MemoryRegionOps *mem_ops =
299
s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops;
300
301
+ qemu_init_irq(&s->mii_irq, lan9118_update_irq, s, 0);
302
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
303
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
304
+ return;
305
+ }
306
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
307
+
308
memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s,
309
"lan9118-mmio", 0x100);
310
sysbus_init_mmio(sbd, &s->mmio);
311
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
151
new file mode 100644
312
new file mode 100644
152
index XXXXXXX..XXXXXXX
313
index XXXXXXX..XXXXXXX
153
--- /dev/null
314
--- /dev/null
154
+++ b/hw/misc/npcm7xx_rng.c
315
+++ b/hw/net/lan9118_phy.c
155
@@ -XXX,XX +XXX,XX @@
316
@@ -XXX,XX +XXX,XX @@
156
+/*
317
+/*
157
+ * Nuvoton NPCM7xx Random Number Generator.
318
+ * SMSC LAN9118 PHY emulation
158
+ *
319
+ *
159
+ * Copyright 2020 Google LLC
320
+ * Copyright (c) 2009 CodeSourcery, LLC.
321
+ * Written by Paul Brook
160
+ *
322
+ *
161
+ * This program is free software; you can redistribute it and/or modify it
323
+ * This code is licensed under the GNU GPL v2
162
+ * under the terms of the GNU General Public License as published by the
163
+ * Free Software Foundation; either version 2 of the License, or
164
+ * (at your option) any later version.
165
+ *
324
+ *
166
+ * This program is distributed in the hope that it will be useful, but WITHOUT
325
+ * Contributions after 2012-01-13 are licensed under the terms of the
167
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
326
+ * GNU GPL, version 2 or (at your option) any later version.
168
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
169
+ * for more details.
170
+ */
327
+ */
171
+
328
+
172
+#include "qemu/osdep.h"
329
+#include "qemu/osdep.h"
173
+
330
+#include "hw/net/lan9118_phy.h"
174
+#include "hw/misc/npcm7xx_rng.h"
331
+#include "hw/irq.h"
332
+#include "hw/resettable.h"
175
+#include "migration/vmstate.h"
333
+#include "migration/vmstate.h"
176
+#include "qemu/bitops.h"
177
+#include "qemu/guest-random.h"
178
+#include "qemu/log.h"
334
+#include "qemu/log.h"
179
+#include "qemu/module.h"
335
+
180
+#include "qemu/units.h"
336
+#define PHY_INT_ENERGYON (1 << 7)
181
+
337
+#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
182
+#include "trace.h"
338
+#define PHY_INT_FAULT (1 << 5)
183
+
339
+#define PHY_INT_DOWN (1 << 4)
184
+#define NPCM7XX_RNG_REGS_SIZE (4 * KiB)
340
+#define PHY_INT_AUTONEG_LP (1 << 3)
185
+
341
+#define PHY_INT_PARFAULT (1 << 2)
186
+#define NPCM7XX_RNGCS (0x00)
342
+#define PHY_INT_AUTONEG_PAGE (1 << 1)
187
+#define NPCM7XX_RNGCS_CLKP(rv) extract32(rv, 2, 4)
343
+
188
+#define NPCM7XX_RNGCS_DVALID BIT(1)
344
+static void lan9118_phy_update_irq(Lan9118PhyState *s)
189
+#define NPCM7XX_RNGCS_RNGE BIT(0)
345
+{
190
+
346
+ qemu_set_irq(s->irq, !!(s->ints & s->int_mask));
191
+#define NPCM7XX_RNGD (0x04)
347
+}
192
+#define NPCM7XX_RNGMODE (0x08)
348
+
193
+#define NPCM7XX_RNGMODE_NORMAL (0x02)
349
+uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
194
+
350
+{
195
+static bool npcm7xx_rng_is_enabled(NPCM7xxRNGState *s)
351
+ uint16_t val;
196
+{
352
+
197
+ return (s->rngcs & NPCM7XX_RNGCS_RNGE) &&
353
+ switch (reg) {
198
+ (s->rngmode == NPCM7XX_RNGMODE_NORMAL);
354
+ case 0: /* Basic Control */
199
+}
355
+ return s->control;
200
+
356
+ case 1: /* Basic Status */
201
+static uint64_t npcm7xx_rng_read(void *opaque, hwaddr offset, unsigned size)
357
+ return s->status;
202
+{
358
+ case 2: /* ID1 */
203
+ NPCM7xxRNGState *s = opaque;
359
+ return 0x0007;
204
+ uint64_t value = 0;
360
+ case 3: /* ID2 */
205
+
361
+ return 0xc0d1;
206
+ switch (offset) {
362
+ case 4: /* Auto-neg advertisement */
207
+ case NPCM7XX_RNGCS:
363
+ return s->advertise;
208
+ /*
364
+ case 5: /* Auto-neg Link Partner Ability */
209
+ * If the RNG is enabled, but we don't have any valid random data, try
365
+ return 0x0f71;
210
+ * obtaining some and update the DVALID bit accordingly.
366
+ case 6: /* Auto-neg Expansion */
211
+ */
367
+ return 1;
212
+ if (!npcm7xx_rng_is_enabled(s)) {
368
+ /* TODO 17, 18, 27, 29, 30, 31 */
213
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
369
+ case 29: /* Interrupt source. */
214
+ } else if (!(s->rngcs & NPCM7XX_RNGCS_DVALID)) {
370
+ val = s->ints;
215
+ uint8_t byte = 0;
371
+ s->ints = 0;
216
+
372
+ lan9118_phy_update_irq(s);
217
+ if (qemu_guest_getrandom(&byte, sizeof(byte), NULL) == 0) {
373
+ return val;
218
+ s->rngd = byte;
374
+ case 30: /* Interrupt mask */
219
+ s->rngcs |= NPCM7XX_RNGCS_DVALID;
375
+ return s->int_mask;
220
+ }
376
+ default:
377
+ qemu_log_mask(LOG_GUEST_ERROR,
378
+ "lan9118_phy_read: PHY read reg %d\n", reg);
379
+ return 0;
380
+ }
381
+}
382
+
383
+void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
384
+{
385
+ switch (reg) {
386
+ case 0: /* Basic Control */
387
+ if (val & 0x8000) {
388
+ lan9118_phy_reset(s);
389
+ break;
221
+ }
390
+ }
222
+ value = s->rngcs;
391
+ s->control = val & 0x7980;
223
+ break;
392
+ /* Complete autonegotiation immediately. */
224
+ case NPCM7XX_RNGD:
393
+ if (val & 0x1000) {
225
+ if (npcm7xx_rng_is_enabled(s) && s->rngcs & NPCM7XX_RNGCS_DVALID) {
394
+ s->status |= 0x0020;
226
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
227
+ value = s->rngd;
228
+ s->rngd = 0;
229
+ }
395
+ }
230
+ break;
396
+ break;
231
+ case NPCM7XX_RNGMODE:
397
+ case 4: /* Auto-neg advertisement */
232
+ value = s->rngmode;
398
+ s->advertise = (val & 0x2d7f) | 0x80;
233
+ break;
399
+ break;
234
+
400
+ /* TODO 17, 18, 27, 31 */
235
+ default:
401
+ case 30: /* Interrupt mask */
236
+ qemu_log_mask(LOG_GUEST_ERROR,
402
+ s->int_mask = val & 0xff;
237
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
403
+ lan9118_phy_update_irq(s);
238
+ DEVICE(s)->canonical_path, offset);
239
+ break;
240
+ }
241
+
242
+ trace_npcm7xx_rng_read(offset, value, size);
243
+
244
+ return value;
245
+}
246
+
247
+static void npcm7xx_rng_write(void *opaque, hwaddr offset, uint64_t value,
248
+ unsigned size)
249
+{
250
+ NPCM7xxRNGState *s = opaque;
251
+
252
+ trace_npcm7xx_rng_write(offset, value, size);
253
+
254
+ switch (offset) {
255
+ case NPCM7XX_RNGCS:
256
+ s->rngcs &= NPCM7XX_RNGCS_DVALID;
257
+ s->rngcs |= value & ~NPCM7XX_RNGCS_DVALID;
258
+ break;
259
+ case NPCM7XX_RNGD:
260
+ qemu_log_mask(LOG_GUEST_ERROR,
261
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
262
+ DEVICE(s)->canonical_path, offset);
263
+ break;
264
+ case NPCM7XX_RNGMODE:
265
+ s->rngmode = value;
266
+ break;
404
+ break;
267
+ default:
405
+ default:
268
+ qemu_log_mask(LOG_GUEST_ERROR,
406
+ qemu_log_mask(LOG_GUEST_ERROR,
269
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
407
+ "lan9118_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
270
+ DEVICE(s)->canonical_path, offset);
271
+ break;
272
+ }
408
+ }
273
+}
409
+}
274
+
410
+
275
+static const MemoryRegionOps npcm7xx_rng_ops = {
411
+void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
276
+ .read = npcm7xx_rng_read,
412
+{
277
+ .write = npcm7xx_rng_write,
413
+ s->link_down = link_down;
278
+ .endianness = DEVICE_LITTLE_ENDIAN,
414
+
279
+ .valid = {
415
+ /* Autonegotiation status mirrors link status. */
280
+ .min_access_size = 1,
416
+ if (link_down) {
281
+ .max_access_size = 4,
417
+ s->status &= ~0x0024;
282
+ .unaligned = false,
418
+ s->ints |= PHY_INT_DOWN;
283
+ },
419
+ } else {
420
+ s->status |= 0x0024;
421
+ s->ints |= PHY_INT_ENERGYON;
422
+ s->ints |= PHY_INT_AUTONEG_COMPLETE;
423
+ }
424
+ lan9118_phy_update_irq(s);
425
+}
426
+
427
+void lan9118_phy_reset(Lan9118PhyState *s)
428
+{
429
+ s->control = 0x3000;
430
+ s->status = 0x7809;
431
+ s->advertise = 0x01e1;
432
+ s->int_mask = 0;
433
+ s->ints = 0;
434
+ lan9118_phy_update_link(s, s->link_down);
435
+}
436
+
437
+static void lan9118_phy_reset_hold(Object *obj, ResetType type)
438
+{
439
+ Lan9118PhyState *s = LAN9118_PHY(obj);
440
+
441
+ lan9118_phy_reset(s);
442
+}
443
+
444
+static void lan9118_phy_init(Object *obj)
445
+{
446
+ Lan9118PhyState *s = LAN9118_PHY(obj);
447
+
448
+ qdev_init_gpio_out(DEVICE(s), &s->irq, 1);
449
+}
450
+
451
+static const VMStateDescription vmstate_lan9118_phy = {
452
+ .name = "lan9118-phy",
453
+ .version_id = 1,
454
+ .minimum_version_id = 1,
455
+ .fields = (const VMStateField[]) {
456
+ VMSTATE_UINT16(control, Lan9118PhyState),
457
+ VMSTATE_UINT16(status, Lan9118PhyState),
458
+ VMSTATE_UINT16(advertise, Lan9118PhyState),
459
+ VMSTATE_UINT16(ints, Lan9118PhyState),
460
+ VMSTATE_UINT16(int_mask, Lan9118PhyState),
461
+ VMSTATE_BOOL(link_down, Lan9118PhyState),
462
+ VMSTATE_END_OF_LIST()
463
+ }
284
+};
464
+};
285
+
465
+
286
+static void npcm7xx_rng_enter_reset(Object *obj, ResetType type)
466
+static void lan9118_phy_class_init(ObjectClass *klass, void *data)
287
+{
288
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
289
+
290
+ s->rngcs = 0;
291
+ s->rngd = 0;
292
+ s->rngmode = 0;
293
+}
294
+
295
+static void npcm7xx_rng_init(Object *obj)
296
+{
297
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
298
+
299
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
300
+ NPCM7XX_RNG_REGS_SIZE);
301
+ sysbus_init_mmio(&s->parent, &s->iomem);
302
+}
303
+
304
+static const VMStateDescription vmstate_npcm7xx_rng = {
305
+ .name = "npcm7xx-rng",
306
+ .version_id = 0,
307
+ .minimum_version_id = 0,
308
+ .fields = (VMStateField[]) {
309
+ VMSTATE_UINT8(rngcs, NPCM7xxRNGState),
310
+ VMSTATE_UINT8(rngd, NPCM7xxRNGState),
311
+ VMSTATE_UINT8(rngmode, NPCM7xxRNGState),
312
+ VMSTATE_END_OF_LIST(),
313
+ },
314
+};
315
+
316
+static void npcm7xx_rng_class_init(ObjectClass *klass, void *data)
317
+{
467
+{
318
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
468
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
319
+ DeviceClass *dc = DEVICE_CLASS(klass);
469
+ DeviceClass *dc = DEVICE_CLASS(klass);
320
+
470
+
321
+ dc->desc = "NPCM7xx Random Number Generator";
471
+ rc->phases.hold = lan9118_phy_reset_hold;
322
+ dc->vmsd = &vmstate_npcm7xx_rng;
472
+ dc->vmsd = &vmstate_lan9118_phy;
323
+ rc->phases.enter = npcm7xx_rng_enter_reset;
473
+}
324
+}
474
+
325
+
475
+static const TypeInfo types[] = {
326
+static const TypeInfo npcm7xx_rng_types[] = {
327
+ {
476
+ {
328
+ .name = TYPE_NPCM7XX_RNG,
477
+ .name = TYPE_LAN9118_PHY,
329
+ .parent = TYPE_SYS_BUS_DEVICE,
478
+ .parent = TYPE_SYS_BUS_DEVICE,
330
+ .instance_size = sizeof(NPCM7xxRNGState),
479
+ .instance_size = sizeof(Lan9118PhyState),
331
+ .class_init = npcm7xx_rng_class_init,
480
+ .instance_init = lan9118_phy_init,
332
+ .instance_init = npcm7xx_rng_init,
481
+ .class_init = lan9118_phy_class_init,
333
+ },
482
+ }
334
+};
483
+};
335
+DEFINE_TYPES(npcm7xx_rng_types);
484
+
336
diff --git a/tests/qtest/npcm7xx_rng-test.c b/tests/qtest/npcm7xx_rng-test.c
485
+DEFINE_TYPES(types)
337
new file mode 100644
486
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
338
index XXXXXXX..XXXXXXX
339
--- /dev/null
340
+++ b/tests/qtest/npcm7xx_rng-test.c
341
@@ -XXX,XX +XXX,XX @@
342
+/*
343
+ * QTest testcase for the Nuvoton NPCM7xx Random Number Generator
344
+ *
345
+ * Copyright 2020 Google LLC
346
+ *
347
+ * This program is free software; you can redistribute it and/or modify it
348
+ * under the terms of the GNU General Public License as published by the
349
+ * Free Software Foundation; either version 2 of the License, or
350
+ * (at your option) any later version.
351
+ *
352
+ * This program is distributed in the hope that it will be useful, but WITHOUT
353
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
354
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
355
+ * for more details.
356
+ */
357
+
358
+#include "qemu/osdep.h"
359
+
360
+#include <math.h>
361
+
362
+#include "libqtest-single.h"
363
+#include "qemu/bitops.h"
364
+
365
+#define RNG_BASE_ADDR 0xf000b000
366
+
367
+/* Control and Status Register */
368
+#define RNGCS 0x00
369
+# define DVALID BIT(1) /* Data Valid */
370
+# define RNGE BIT(0) /* RNG Enable */
371
+/* Data Register */
372
+#define RNGD 0x04
373
+/* Mode Register */
374
+#define RNGMODE 0x08
375
+# define ROSEL_NORMAL (2) /* RNG only works in this mode */
376
+
377
+/* Number of bits to collect for randomness tests. */
378
+#define TEST_INPUT_BITS (128)
379
+
380
+static void rng_writeb(unsigned int offset, uint8_t value)
381
+{
382
+ writeb(RNG_BASE_ADDR + offset, value);
383
+}
384
+
385
+static uint8_t rng_readb(unsigned int offset)
386
+{
387
+ return readb(RNG_BASE_ADDR + offset);
388
+}
389
+
390
+/* Disable RNG and set normal ring oscillator mode. */
391
+static void rng_reset(void)
392
+{
393
+ rng_writeb(RNGCS, 0);
394
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
395
+}
396
+
397
+/* Reset RNG and then enable it. */
398
+static void rng_reset_enable(void)
399
+{
400
+ rng_reset();
401
+ rng_writeb(RNGCS, RNGE);
402
+}
403
+
404
+/* Wait until Data Valid bit is set. */
405
+static bool rng_wait_ready(void)
406
+{
407
+ /* qemu_guest_getrandom may fail. Assume it won't fail 10 times in a row. */
408
+ int retries = 10;
409
+
410
+ while (retries-- > 0) {
411
+ if (rng_readb(RNGCS) & DVALID) {
412
+ return true;
413
+ }
414
+ }
415
+
416
+ return false;
417
+}
418
+
419
+/*
420
+ * Perform a frequency (monobit) test, as defined by NIST SP 800-22, on the
421
+ * sequence in buf and return the P-value. This represents the probability of a
422
+ * truly random sequence having the same proportion of zeros and ones as the
423
+ * sequence in buf.
424
+ *
425
+ * An RNG which always returns 0x00 or 0xff, or has some bits stuck at 0 or 1,
426
+ * will fail this test. However, an RNG which always returns 0x55, 0xf0 or some
427
+ * other value with an equal number of zeroes and ones will pass.
428
+ */
429
+static double calc_monobit_p(const uint8_t *buf, unsigned int len)
430
+{
431
+ unsigned int i;
432
+ double s_obs;
433
+ int sn = 0;
434
+
435
+ for (i = 0; i < len; i++) {
436
+ /*
437
+ * Each 1 counts as 1, each 0 counts as -1.
438
+ * s = cp - (8 - cp) = 2 * cp - 8
439
+ */
440
+ sn += 2 * ctpop8(buf[i]) - 8;
441
+ }
442
+
443
+ s_obs = abs(sn) / sqrt(len * BITS_PER_BYTE);
444
+
445
+ return erfc(s_obs / sqrt(2));
446
+}
447
+
448
+/*
449
+ * Perform a runs test, as defined by NIST SP 800-22, and return the P-value.
450
+ * This represents the probability of a truly random sequence having the same
451
+ * number of runs (i.e. uninterrupted sequences of identical bits) as the
452
+ * sequence in buf.
453
+ */
454
+static double calc_runs_p(const unsigned long *buf, unsigned int nr_bits)
455
+{
456
+ unsigned int j;
457
+ unsigned int k;
458
+ int nr_ones = 0;
459
+ int vn_obs = 0;
460
+ double pi;
461
+
462
+ g_assert(nr_bits % BITS_PER_LONG == 0);
463
+
464
+ for (j = 0; j < nr_bits / BITS_PER_LONG; j++) {
465
+ nr_ones += __builtin_popcountl(buf[j]);
466
+ }
467
+ pi = (double)nr_ones / nr_bits;
468
+
469
+ for (k = 0; k < nr_bits - 1; k++) {
470
+ vn_obs += !(test_bit(k, buf) ^ test_bit(k + 1, buf));
471
+ }
472
+ vn_obs += 1;
473
+
474
+ return erfc(fabs(vn_obs - 2 * nr_bits * pi * (1.0 - pi))
475
+ / (2 * sqrt(2 * nr_bits) * pi * (1.0 - pi)));
476
+}
477
+
478
+/*
479
+ * Verifies that DVALID is clear, and RNGD reads zero, when RNGE is cleared,
480
+ * and DVALID eventually becomes set when RNGE is set.
481
+ */
482
+static void test_enable_disable(void)
483
+{
484
+ /* Disable: DVALID should not be set, and RNGD should read zero */
485
+ rng_reset();
486
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
487
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
488
+
489
+ /* Enable: DVALID should be set, but we can't make assumptions about RNGD */
490
+ rng_writeb(RNGCS, RNGE);
491
+ g_assert_true(rng_wait_ready());
492
+ g_assert_cmphex(rng_readb(RNGCS), ==, DVALID | RNGE);
493
+
494
+ /* Disable: DVALID should not be set, and RNGD should read zero */
495
+ rng_writeb(RNGCS, 0);
496
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
497
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
498
+}
499
+
500
+/*
501
+ * Verifies that the RNG only produces data when RNGMODE is set to 'normal'
502
+ * ring oscillator mode.
503
+ */
504
+static void test_rosel(void)
505
+{
506
+ rng_reset_enable();
507
+ g_assert_true(rng_wait_ready());
508
+ rng_writeb(RNGMODE, 0);
509
+ g_assert_false(rng_wait_ready());
510
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
511
+ g_assert_true(rng_wait_ready());
512
+ rng_writeb(RNGMODE, 0);
513
+ g_assert_false(rng_wait_ready());
514
+}
515
+
516
+/*
517
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
518
+ * satisfies a monobit test.
519
+ */
520
+static void test_continuous_monobit(void)
521
+{
522
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
523
+ unsigned int i;
524
+
525
+ rng_reset_enable();
526
+ for (i = 0; i < sizeof(buf); i++) {
527
+ g_assert_true(rng_wait_ready());
528
+ buf[i] = rng_readb(RNGD);
529
+ }
530
+
531
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
532
+}
533
+
534
+/*
535
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
536
+ * satisfies a runs test.
537
+ */
538
+static void test_continuous_runs(void)
539
+{
540
+ union {
541
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
542
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
543
+ } buf;
544
+ unsigned int i;
545
+
546
+ rng_reset_enable();
547
+ for (i = 0; i < sizeof(buf); i++) {
548
+ g_assert_true(rng_wait_ready());
549
+ buf.c[i] = rng_readb(RNGD);
550
+ }
551
+
552
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
553
+}
554
+
555
+/*
556
+ * Verifies that the first data byte collected after enabling the RNG satisfies
557
+ * a monobit test.
558
+ */
559
+static void test_first_byte_monobit(void)
560
+{
561
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
562
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
563
+ unsigned int i;
564
+
565
+ rng_reset();
566
+ for (i = 0; i < sizeof(buf); i++) {
567
+ rng_writeb(RNGCS, RNGE);
568
+ g_assert_true(rng_wait_ready());
569
+ buf[i] = rng_readb(RNGD);
570
+ rng_writeb(RNGCS, 0);
571
+ }
572
+
573
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
574
+}
575
+
576
+/*
577
+ * Verifies that the first data byte collected after enabling the RNG satisfies
578
+ * a runs test.
579
+ */
580
+static void test_first_byte_runs(void)
581
+{
582
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
583
+ union {
584
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
585
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
586
+ } buf;
587
+ unsigned int i;
588
+
589
+ rng_reset();
590
+ for (i = 0; i < sizeof(buf); i++) {
591
+ rng_writeb(RNGCS, RNGE);
592
+ g_assert_true(rng_wait_ready());
593
+ buf.c[i] = rng_readb(RNGD);
594
+ rng_writeb(RNGCS, 0);
595
+ }
596
+
597
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
598
+}
599
+
600
+int main(int argc, char **argv)
601
+{
602
+ int ret;
603
+
604
+ g_test_init(&argc, &argv, NULL);
605
+ g_test_set_nonfatal_assertions();
606
+
607
+ qtest_add_func("npcm7xx_rng/enable_disable", test_enable_disable);
608
+ qtest_add_func("npcm7xx_rng/rosel", test_rosel);
609
+ qtest_add_func("npcm7xx_rng/continuous/monobit", test_continuous_monobit);
610
+ qtest_add_func("npcm7xx_rng/continuous/runs", test_continuous_runs);
611
+ qtest_add_func("npcm7xx_rng/first_byte/monobit", test_first_byte_monobit);
612
+ qtest_add_func("npcm7xx_rng/first_byte/runs", test_first_byte_runs);
613
+
614
+ qtest_start("-machine npcm750-evb");
615
+ ret = g_test_run();
616
+ qtest_end();
617
+
618
+ return ret;
619
+}
620
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
621
index XXXXXXX..XXXXXXX 100644
487
index XXXXXXX..XXXXXXX 100644
622
--- a/hw/misc/meson.build
488
--- a/hw/net/Kconfig
623
+++ b/hw/misc/meson.build
489
+++ b/hw/net/Kconfig
624
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
490
@@ -XXX,XX +XXX,XX @@ config VMXNET3_PCI
625
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
491
config SMC91C111
626
'npcm7xx_clk.c',
492
bool
627
'npcm7xx_gcr.c',
493
628
+ 'npcm7xx_rng.c',
494
+config LAN9118_PHY
629
))
495
+ bool
630
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
496
+
631
'omap_clk.c',
497
config LAN9118
632
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
498
bool
499
+ select LAN9118_PHY
500
select PTIMER
501
502
config NE2000_ISA
503
diff --git a/hw/net/meson.build b/hw/net/meson.build
633
index XXXXXXX..XXXXXXX 100644
504
index XXXXXXX..XXXXXXX 100644
634
--- a/hw/misc/trace-events
505
--- a/hw/net/meson.build
635
+++ b/hw/misc/trace-events
506
+++ b/hw/net/meson.build
636
@@ -XXX,XX +XXX,XX @@ npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
507
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('vmxnet3.c'))
637
npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
508
638
npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
509
system_ss.add(when: 'CONFIG_SMC91C111', if_true: files('smc91c111.c'))
639
510
system_ss.add(when: 'CONFIG_LAN9118', if_true: files('lan9118.c'))
640
+# npcm7xx_rng.c
511
+system_ss.add(when: 'CONFIG_LAN9118_PHY', if_true: files('lan9118_phy.c'))
641
+npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
512
system_ss.add(when: 'CONFIG_NE2000_ISA', if_true: files('ne2000-isa.c'))
642
+npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
513
system_ss.add(when: 'CONFIG_OPENCORES_ETH', if_true: files('opencores_eth.c'))
643
+
514
system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c'))
644
# stm32f4xx_syscfg.c
645
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
646
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
647
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
648
index XXXXXXX..XXXXXXX 100644
649
--- a/tests/qtest/meson.build
650
+++ b/tests/qtest/meson.build
651
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
652
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
653
['prom-env-test', 'boot-serial-test']
654
655
-qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
656
+qtests_npcm7xx = \
657
+ ['npcm7xx_rng-test',
658
+ 'npcm7xx_timer-test',
659
+ 'npcm7xx_watchdog_timer-test']
660
qtests_arm = \
661
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
662
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
663
--
515
--
664
2.20.1
516
2.34.1
665
666
diff view generated by jsdifflib
1
From: Havard Skinnemoen <hskinnemoen@google.com>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
The NPCM7xx chips have multiple GPIO controllers that are mostly
3
imx_fec models the same PHY as lan9118_phy. The code is almost the same with
4
identical except for some minor differences like the reset values of
4
imx_fec having more logging and tracing. Merge these improvements into
5
some registers. Each controller controls up to 32 pins.
5
lan9118_phy and reuse in imx_fec to fix the code duplication.
6
6
7
Each individual pin is modeled as a pair of unnamed GPIOs -- one for
7
Some migration state how resides in the new device model which breaks migration
8
emitting the actual pin state, and one for driving the pin externally.
8
compatibility for the following machines:
9
Like the nRF51 GPIO controller, a gpio level may be negative, which
9
* imx25-pdk
10
means the pin is not driven, or floating.
10
* sabrelite
11
* mcimx7d-sabre
12
* mcimx6ul-evk
11
13
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
14
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
13
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
15
Tested-by: Guenter Roeck <linux@roeck-us.net>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
17
Message-id: 20241102125724.532843-3-shentey@gmail.com
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
19
---
17
docs/system/arm/nuvoton.rst | 2 +-
20
include/hw/net/imx_fec.h | 9 ++-
18
include/hw/arm/npcm7xx.h | 2 +
21
hw/net/imx_fec.c | 146 ++++-----------------------------------
19
include/hw/gpio/npcm7xx_gpio.h | 55 +++++
22
hw/net/lan9118_phy.c | 82 ++++++++++++++++------
20
hw/arm/npcm7xx.c | 80 ++++++
23
hw/net/Kconfig | 1 +
21
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++++++++++++++++++++++
24
hw/net/trace-events | 10 +--
22
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++++++++++++++++++++
25
5 files changed, 85 insertions(+), 163 deletions(-)
23
hw/gpio/meson.build | 1 +
24
hw/gpio/trace-events | 7 +
25
tests/qtest/meson.build | 3 +-
26
9 files changed, 957 insertions(+), 2 deletions(-)
27
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
28
create mode 100644 hw/gpio/npcm7xx_gpio.c
29
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
30
26
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
27
diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h
32
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
33
--- a/docs/system/arm/nuvoton.rst
29
--- a/include/hw/net/imx_fec.h
34
+++ b/docs/system/arm/nuvoton.rst
30
+++ b/include/hw/net/imx_fec.h
35
@@ -XXX,XX +XXX,XX @@ Supported devices
31
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(IMXFECState, IMX_FEC)
36
* Flash Interface Unit (FIU; no protection features)
32
#define TYPE_IMX_ENET "imx.enet"
37
* Random Number Generator (RNG)
33
38
* USB host (USBH)
34
#include "hw/sysbus.h"
39
+ * GPIO controller
35
+#include "hw/net/lan9118_phy.h"
40
36
+#include "hw/irq.h"
41
Missing devices
37
#include "net/net.h"
42
---------------
38
43
39
#define ENET_EIR 1
44
- * GPIO controller
40
@@ -XXX,XX +XXX,XX @@ struct IMXFECState {
45
* LPC/eSPI host-to-BMC interface, including
41
uint32_t tx_descriptor[ENET_TX_RING_NUM];
46
42
uint32_t tx_ring_num;
47
* Keyboard and mouse controller interface (KBCI)
43
48
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
44
- uint32_t phy_status;
45
- uint32_t phy_control;
46
- uint32_t phy_advertise;
47
- uint32_t phy_int;
48
- uint32_t phy_int_mask;
49
+ Lan9118PhyState mii;
50
+ IRQState mii_irq;
51
uint32_t phy_num;
52
bool phy_connected;
53
struct IMXFECState *phy_consumer;
54
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
49
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
50
--- a/include/hw/arm/npcm7xx.h
56
--- a/hw/net/imx_fec.c
51
+++ b/include/hw/arm/npcm7xx.h
57
+++ b/hw/net/imx_fec.c
52
@@ -XXX,XX +XXX,XX @@
58
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_imx_eth_txdescs = {
53
59
54
#include "hw/boards.h"
60
static const VMStateDescription vmstate_imx_eth = {
55
#include "hw/cpu/a9mpcore.h"
61
.name = TYPE_IMX_FEC,
56
+#include "hw/gpio/npcm7xx_gpio.h"
62
- .version_id = 2,
57
#include "hw/mem/npcm7xx_mc.h"
63
- .minimum_version_id = 2,
58
#include "hw/misc/npcm7xx_clk.h"
64
+ .version_id = 3,
59
#include "hw/misc/npcm7xx_gcr.h"
65
+ .minimum_version_id = 3,
60
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
66
.fields = (const VMStateField[]) {
61
NPCM7xxOTPState fuse_array;
67
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
62
NPCM7xxMCState mc;
68
VMSTATE_UINT32(rx_descriptor, IMXFECState),
63
NPCM7xxRNGState rng;
69
VMSTATE_UINT32(tx_descriptor[0], IMXFECState),
64
+ NPCM7xxGPIOState gpio[8];
70
- VMSTATE_UINT32(phy_status, IMXFECState),
65
EHCISysBusState ehci;
71
- VMSTATE_UINT32(phy_control, IMXFECState),
66
OHCISysBusState ohci;
72
- VMSTATE_UINT32(phy_advertise, IMXFECState),
67
NPCM7xxFIUState fiu[2];
73
- VMSTATE_UINT32(phy_int, IMXFECState),
68
diff --git a/include/hw/gpio/npcm7xx_gpio.h b/include/hw/gpio/npcm7xx_gpio.h
74
- VMSTATE_UINT32(phy_int_mask, IMXFECState),
69
new file mode 100644
75
VMSTATE_END_OF_LIST()
70
index XXXXXXX..XXXXXXX
76
},
71
--- /dev/null
77
.subsections = (const VMStateDescription * const []) {
72
+++ b/include/hw/gpio/npcm7xx_gpio.h
78
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_imx_eth = {
73
@@ -XXX,XX +XXX,XX @@
79
},
74
+/*
75
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
76
+ *
77
+ * Copyright 2020 Google LLC
78
+ *
79
+ * This program is free software; you can redistribute it and/or
80
+ * modify it under the terms of the GNU General Public License
81
+ * version 2 as published by the Free Software Foundation.
82
+ *
83
+ * This program is distributed in the hope that it will be useful,
84
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
85
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86
+ * GNU General Public License for more details.
87
+ */
88
+#ifndef NPCM7XX_GPIO_H
89
+#define NPCM7XX_GPIO_H
90
+
91
+#include "exec/memory.h"
92
+#include "hw/sysbus.h"
93
+
94
+/* Number of pins managed by each controller. */
95
+#define NPCM7XX_GPIO_NR_PINS (32)
96
+
97
+/*
98
+ * Number of registers in our device state structure. Don't change this without
99
+ * incrementing the version_id in the vmstate.
100
+ */
101
+#define NPCM7XX_GPIO_NR_REGS (0x80 / sizeof(uint32_t))
102
+
103
+typedef struct NPCM7xxGPIOState {
104
+ SysBusDevice parent;
105
+
106
+ /* Properties to be defined by the SoC */
107
+ uint32_t reset_pu;
108
+ uint32_t reset_pd;
109
+ uint32_t reset_osrc;
110
+ uint32_t reset_odsc;
111
+
112
+ MemoryRegion mmio;
113
+
114
+ qemu_irq irq;
115
+ qemu_irq output[NPCM7XX_GPIO_NR_PINS];
116
+
117
+ uint32_t pin_level;
118
+ uint32_t ext_level;
119
+ uint32_t ext_driven;
120
+
121
+ uint32_t regs[NPCM7XX_GPIO_NR_REGS];
122
+} NPCM7xxGPIOState;
123
+
124
+#define TYPE_NPCM7XX_GPIO "npcm7xx-gpio"
125
+#define NPCM7XX_GPIO(obj) \
126
+ OBJECT_CHECK(NPCM7xxGPIOState, (obj), TYPE_NPCM7XX_GPIO)
127
+
128
+#endif /* NPCM7XX_GPIO_H */
129
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/hw/arm/npcm7xx.c
132
+++ b/hw/arm/npcm7xx.c
133
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
134
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
135
NPCM7XX_EHCI_IRQ = 61,
136
NPCM7XX_OHCI_IRQ = 62,
137
+ NPCM7XX_GPIO0_IRQ = 116,
138
+ NPCM7XX_GPIO1_IRQ,
139
+ NPCM7XX_GPIO2_IRQ,
140
+ NPCM7XX_GPIO3_IRQ,
141
+ NPCM7XX_GPIO4_IRQ,
142
+ NPCM7XX_GPIO5_IRQ,
143
+ NPCM7XX_GPIO6_IRQ,
144
+ NPCM7XX_GPIO7_IRQ,
145
};
80
};
146
81
147
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
82
-#define PHY_INT_ENERGYON (1 << 7)
148
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
83
-#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
149
0xb8000000, /* CS3 */
84
-#define PHY_INT_FAULT (1 << 5)
150
};
85
-#define PHY_INT_DOWN (1 << 4)
151
86
-#define PHY_INT_AUTONEG_LP (1 << 3)
152
+static const struct {
87
-#define PHY_INT_PARFAULT (1 << 2)
153
+ hwaddr regs_addr;
88
-#define PHY_INT_AUTONEG_PAGE (1 << 1)
154
+ uint32_t unconnected_pins;
89
-
155
+ uint32_t reset_pu;
90
static void imx_eth_update(IMXFECState *s);
156
+ uint32_t reset_pd;
91
157
+ uint32_t reset_osrc;
92
/*
158
+ uint32_t reset_odsc;
93
@@ -XXX,XX +XXX,XX @@ static void imx_eth_update(IMXFECState *s);
159
+} npcm7xx_gpio[] = {
94
* For now we don't handle any GPIO/interrupt line, so the OS will
160
+ {
95
* have to poll for the PHY status.
161
+ .regs_addr = 0xf0010000,
96
*/
162
+ .reset_pu = 0xff03ffff,
97
-static void imx_phy_update_irq(IMXFECState *s)
163
+ .reset_pd = 0x00fc0000,
98
+static void imx_phy_update_irq(void *opaque, int n, int level)
164
+ }, {
99
{
165
+ .regs_addr = 0xf0011000,
100
- imx_eth_update(s);
166
+ .unconnected_pins = 0x0000001e,
101
-}
167
+ .reset_pu = 0xfefffe07,
102
-
168
+ .reset_pd = 0x010001e0,
103
-static void imx_phy_update_link(IMXFECState *s)
169
+ }, {
104
-{
170
+ .regs_addr = 0xf0012000,
105
- /* Autonegotiation status mirrors link status. */
171
+ .reset_pu = 0x780fffff,
106
- if (qemu_get_queue(s->nic)->link_down) {
172
+ .reset_pd = 0x07f00000,
107
- trace_imx_phy_update_link("down");
173
+ .reset_odsc = 0x00700000,
108
- s->phy_status &= ~0x0024;
174
+ }, {
109
- s->phy_int |= PHY_INT_DOWN;
175
+ .regs_addr = 0xf0013000,
110
- } else {
176
+ .reset_pu = 0x00fc0000,
111
- trace_imx_phy_update_link("up");
177
+ .reset_pd = 0xff000000,
112
- s->phy_status |= 0x0024;
178
+ }, {
113
- s->phy_int |= PHY_INT_ENERGYON;
179
+ .regs_addr = 0xf0014000,
114
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
180
+ .reset_pu = 0xffffffff,
115
- }
181
+ }, {
116
- imx_phy_update_irq(s);
182
+ .regs_addr = 0xf0015000,
117
+ imx_eth_update(opaque);
183
+ .reset_pu = 0xbf83f801,
118
}
184
+ .reset_pd = 0x007c0000,
119
185
+ .reset_osrc = 0x000000f1,
120
static void imx_eth_set_link(NetClientState *nc)
186
+ .reset_odsc = 0x3f9f80f1,
121
{
187
+ }, {
122
- imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
188
+ .regs_addr = 0xf0016000,
123
-}
189
+ .reset_pu = 0xfc00f801,
124
-
190
+ .reset_pd = 0x000007fe,
125
-static void imx_phy_reset(IMXFECState *s)
191
+ .reset_odsc = 0x00000800,
126
-{
192
+ }, {
127
- trace_imx_phy_reset();
193
+ .regs_addr = 0xf0017000,
128
-
194
+ .unconnected_pins = 0xffffff00,
129
- s->phy_status = 0x7809;
195
+ .reset_pu = 0x0000007f,
130
- s->phy_control = 0x3000;
196
+ .reset_osrc = 0x0000007f,
131
- s->phy_advertise = 0x01e1;
197
+ .reset_odsc = 0x0000007f,
132
- s->phy_int_mask = 0;
198
+ },
133
- s->phy_int = 0;
199
+};
134
- imx_phy_update_link(s);
200
+
135
+ lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii,
201
static const struct {
136
+ nc->link_down);
202
const char *name;
137
}
203
hwaddr regs_addr;
138
204
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
139
static uint32_t imx_phy_read(IMXFECState *s, int reg)
205
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
140
{
206
}
141
- uint32_t val;
207
142
uint32_t phy = reg / 32;
208
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
143
209
+ object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
144
if (!s->phy_connected) {
210
+ }
145
@@ -XXX,XX +XXX,XX @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
211
+
146
212
object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
147
reg %= 32;
213
object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
148
214
149
- switch (reg) {
215
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
150
- case 0: /* Basic Control */
216
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
151
- val = s->phy_control;
217
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
152
- break;
218
153
- case 1: /* Basic Status */
219
+ /* GPIO modules. Cannot fail. */
154
- val = s->phy_status;
220
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gpio) != ARRAY_SIZE(s->gpio));
155
- break;
221
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
156
- case 2: /* ID1 */
222
+ Object *obj = OBJECT(&s->gpio[i]);
157
- val = 0x0007;
223
+
158
- break;
224
+ object_property_set_uint(obj, "reset-pullup",
159
- case 3: /* ID2 */
225
+ npcm7xx_gpio[i].reset_pu, &error_abort);
160
- val = 0xc0d1;
226
+ object_property_set_uint(obj, "reset-pulldown",
161
- break;
227
+ npcm7xx_gpio[i].reset_pd, &error_abort);
162
- case 4: /* Auto-neg advertisement */
228
+ object_property_set_uint(obj, "reset-osrc",
163
- val = s->phy_advertise;
229
+ npcm7xx_gpio[i].reset_osrc, &error_abort);
164
- break;
230
+ object_property_set_uint(obj, "reset-odsc",
165
- case 5: /* Auto-neg Link Partner Ability */
231
+ npcm7xx_gpio[i].reset_odsc, &error_abort);
166
- val = 0x0f71;
232
+ sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
167
- break;
233
+ sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_gpio[i].regs_addr);
168
- case 6: /* Auto-neg Expansion */
234
+ sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
169
- val = 1;
235
+ npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i));
170
- break;
236
+ }
171
- case 29: /* Interrupt source. */
237
+
172
- val = s->phy_int;
238
/* USB Host */
173
- s->phy_int = 0;
239
object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
174
- imx_phy_update_irq(s);
240
&error_abort);
175
- break;
241
diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c
176
- case 30: /* Interrupt mask */
242
new file mode 100644
177
- val = s->phy_int_mask;
243
index XXXXXXX..XXXXXXX
178
- break;
244
--- /dev/null
179
- case 17:
245
+++ b/hw/gpio/npcm7xx_gpio.c
180
- case 18:
246
@@ -XXX,XX +XXX,XX @@
181
- case 27:
247
+/*
182
- case 31:
248
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
183
- qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n",
249
+ *
184
- TYPE_IMX_FEC, __func__, reg);
250
+ * Copyright 2020 Google LLC
185
- val = 0;
251
+ *
186
- break;
252
+ * This program is free software; you can redistribute it and/or
187
- default:
253
+ * modify it under the terms of the GNU General Public License
188
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
254
+ * version 2 as published by the Free Software Foundation.
189
- TYPE_IMX_FEC, __func__, reg);
255
+ *
190
- val = 0;
256
+ * This program is distributed in the hope that it will be useful,
191
- break;
257
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
192
- }
258
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
193
-
259
+ * GNU General Public License for more details.
194
- trace_imx_phy_read(val, phy, reg);
260
+ */
195
-
261
+
196
- return val;
262
+#include "qemu/osdep.h"
197
+ return lan9118_phy_read(&s->mii, reg);
263
+
198
}
264
+#include "hw/gpio/npcm7xx_gpio.h"
199
265
+#include "hw/irq.h"
200
static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
266
+#include "hw/qdev-properties.h"
201
@@ -XXX,XX +XXX,XX @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
267
+#include "migration/vmstate.h"
202
268
+#include "qapi/error.h"
203
reg %= 32;
269
+#include "qemu/log.h"
204
270
+#include "qemu/module.h"
205
- trace_imx_phy_write(val, phy, reg);
271
+#include "qemu/units.h"
206
-
272
+#include "trace.h"
207
- switch (reg) {
273
+
208
- case 0: /* Basic Control */
274
+/* 32-bit register indices. */
209
- if (val & 0x8000) {
275
+enum NPCM7xxGPIORegister {
210
- imx_phy_reset(s);
276
+ NPCM7XX_GPIO_TLOCK1,
211
- } else {
277
+ NPCM7XX_GPIO_DIN,
212
- s->phy_control = val & 0x7980;
278
+ NPCM7XX_GPIO_POL,
213
- /* Complete autonegotiation immediately. */
279
+ NPCM7XX_GPIO_DOUT,
214
- if (val & 0x1000) {
280
+ NPCM7XX_GPIO_OE,
215
- s->phy_status |= 0x0020;
281
+ NPCM7XX_GPIO_OTYP,
216
- }
282
+ NPCM7XX_GPIO_MP,
217
- }
283
+ NPCM7XX_GPIO_PU,
218
- break;
284
+ NPCM7XX_GPIO_PD,
219
- case 4: /* Auto-neg advertisement */
285
+ NPCM7XX_GPIO_DBNC,
220
- s->phy_advertise = (val & 0x2d7f) | 0x80;
286
+ NPCM7XX_GPIO_EVTYP,
221
- break;
287
+ NPCM7XX_GPIO_EVBE,
222
- case 30: /* Interrupt mask */
288
+ NPCM7XX_GPIO_OBL0,
223
- s->phy_int_mask = val & 0xff;
289
+ NPCM7XX_GPIO_OBL1,
224
- imx_phy_update_irq(s);
290
+ NPCM7XX_GPIO_OBL2,
225
- break;
291
+ NPCM7XX_GPIO_OBL3,
226
- case 17:
292
+ NPCM7XX_GPIO_EVEN,
227
- case 18:
293
+ NPCM7XX_GPIO_EVENS,
228
- case 27:
294
+ NPCM7XX_GPIO_EVENC,
229
- case 31:
295
+ NPCM7XX_GPIO_EVST,
230
- qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n",
296
+ NPCM7XX_GPIO_SPLCK,
231
- TYPE_IMX_FEC, __func__, reg);
297
+ NPCM7XX_GPIO_MPLCK,
232
- break;
298
+ NPCM7XX_GPIO_IEM,
233
- default:
299
+ NPCM7XX_GPIO_OSRC,
234
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
300
+ NPCM7XX_GPIO_ODSC,
235
- TYPE_IMX_FEC, __func__, reg);
301
+ NPCM7XX_GPIO_DOS = 0x68 / sizeof(uint32_t),
236
- break;
302
+ NPCM7XX_GPIO_DOC,
237
- }
303
+ NPCM7XX_GPIO_OES,
238
+ lan9118_phy_write(&s->mii, reg, val);
304
+ NPCM7XX_GPIO_OEC,
239
}
305
+ NPCM7XX_GPIO_TLOCK2 = 0x7c / sizeof(uint32_t),
240
306
+ NPCM7XX_GPIO_REGS_END,
241
static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
307
+};
242
@@ -XXX,XX +XXX,XX @@ static void imx_eth_reset(DeviceState *d)
308
+
243
309
+#define NPCM7XX_GPIO_REGS_SIZE (4 * KiB)
244
s->rx_descriptor = 0;
310
+
245
memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
311
+#define NPCM7XX_GPIO_LOCK_MAGIC1 (0xc0defa73)
246
-
312
+#define NPCM7XX_GPIO_LOCK_MAGIC2 (0xc0de1248)
247
- /* We also reset the PHY */
313
+
248
- imx_phy_reset(s);
314
+static void npcm7xx_gpio_update_events(NPCM7xxGPIOState *s, uint32_t din_diff)
249
}
315
+{
250
316
+ uint32_t din_new = s->regs[NPCM7XX_GPIO_DIN];
251
static uint32_t imx_default_read(IMXFECState *s, uint32_t index)
317
+
252
@@ -XXX,XX +XXX,XX @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
318
+ /* Trigger on high level */
253
sysbus_init_irq(sbd, &s->irq[0]);
319
+ s->regs[NPCM7XX_GPIO_EVST] |= din_new & ~s->regs[NPCM7XX_GPIO_EVTYP];
254
sysbus_init_irq(sbd, &s->irq[1]);
320
+ /* Trigger on both edges */
255
321
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & s->regs[NPCM7XX_GPIO_EVTYP]
256
+ qemu_init_irq(&s->mii_irq, imx_phy_update_irq, s, 0);
322
+ & s->regs[NPCM7XX_GPIO_EVBE]);
257
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
323
+ /* Trigger on rising edge */
258
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
324
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & din_new
325
+ & s->regs[NPCM7XX_GPIO_EVTYP]);
326
+
327
+ trace_npcm7xx_gpio_update_events(DEVICE(s)->canonical_path,
328
+ s->regs[NPCM7XX_GPIO_EVST],
329
+ s->regs[NPCM7XX_GPIO_EVEN]);
330
+ qemu_set_irq(s->irq, !!(s->regs[NPCM7XX_GPIO_EVST]
331
+ & s->regs[NPCM7XX_GPIO_EVEN]));
332
+}
333
+
334
+static void npcm7xx_gpio_update_pins(NPCM7xxGPIOState *s, uint32_t diff)
335
+{
336
+ uint32_t drive_en;
337
+ uint32_t drive_lvl;
338
+ uint32_t not_driven;
339
+ uint32_t undefined;
340
+ uint32_t pin_diff;
341
+ uint32_t din_old;
342
+
343
+ /* Calculate level of each pin driven by GPIO controller. */
344
+ drive_lvl = s->regs[NPCM7XX_GPIO_DOUT] ^ s->regs[NPCM7XX_GPIO_POL];
345
+ /* If OTYP=1, only drive low (open drain) */
346
+ drive_en = s->regs[NPCM7XX_GPIO_OE] & ~(s->regs[NPCM7XX_GPIO_OTYP]
347
+ & drive_lvl);
348
+ /*
349
+ * If a pin is driven to opposite levels by the GPIO controller and the
350
+ * external driver, the result is undefined.
351
+ */
352
+ undefined = drive_en & s->ext_driven & (drive_lvl ^ s->ext_level);
353
+ if (undefined) {
354
+ qemu_log_mask(LOG_GUEST_ERROR,
355
+ "%s: pins have multiple drivers: 0x%" PRIx32 "\n",
356
+ DEVICE(s)->canonical_path, undefined);
357
+ }
358
+
359
+ not_driven = ~(drive_en | s->ext_driven);
360
+ pin_diff = s->pin_level;
361
+
362
+ /* Set pins to externally driven level. */
363
+ s->pin_level = s->ext_level & s->ext_driven;
364
+ /* Set internally driven pins, ignoring any conflicts. */
365
+ s->pin_level |= drive_lvl & drive_en;
366
+ /* Pull up undriven pins with internal pull-up enabled. */
367
+ s->pin_level |= not_driven & s->regs[NPCM7XX_GPIO_PU];
368
+ /* Pins not driven, pulled up or pulled down are undefined */
369
+ undefined |= not_driven & ~(s->regs[NPCM7XX_GPIO_PU]
370
+ | s->regs[NPCM7XX_GPIO_PD]);
371
+
372
+ /* If any pins changed state, update the outgoing GPIOs. */
373
+ pin_diff ^= s->pin_level;
374
+ pin_diff |= undefined & diff;
375
+ if (pin_diff) {
376
+ int i;
377
+
378
+ for (i = 0; i < NPCM7XX_GPIO_NR_PINS; i++) {
379
+ uint32_t mask = BIT(i);
380
+ if (pin_diff & mask) {
381
+ int level = (undefined & mask) ? -1 : !!(s->pin_level & mask);
382
+ trace_npcm7xx_gpio_set_output(DEVICE(s)->canonical_path,
383
+ i, level);
384
+ qemu_set_irq(s->output[i], level);
385
+ }
386
+ }
387
+ }
388
+
389
+ /* Calculate new value of DIN after masking and polarity setting. */
390
+ din_old = s->regs[NPCM7XX_GPIO_DIN];
391
+ s->regs[NPCM7XX_GPIO_DIN] = ((s->pin_level & s->regs[NPCM7XX_GPIO_IEM])
392
+ ^ s->regs[NPCM7XX_GPIO_POL]);
393
+
394
+ /* See if any new events triggered because of all this. */
395
+ npcm7xx_gpio_update_events(s, din_old ^ s->regs[NPCM7XX_GPIO_DIN]);
396
+}
397
+
398
+static bool npcm7xx_gpio_is_locked(NPCM7xxGPIOState *s)
399
+{
400
+ return s->regs[NPCM7XX_GPIO_TLOCK1] == 1;
401
+}
402
+
403
+static uint64_t npcm7xx_gpio_regs_read(void *opaque, hwaddr addr,
404
+ unsigned int size)
405
+{
406
+ hwaddr reg = addr / sizeof(uint32_t);
407
+ NPCM7xxGPIOState *s = opaque;
408
+ uint64_t value = 0;
409
+
410
+ switch (reg) {
411
+ case NPCM7XX_GPIO_TLOCK1 ... NPCM7XX_GPIO_EVEN:
412
+ case NPCM7XX_GPIO_EVST ... NPCM7XX_GPIO_ODSC:
413
+ value = s->regs[reg];
414
+ break;
415
+
416
+ case NPCM7XX_GPIO_EVENS ... NPCM7XX_GPIO_EVENC:
417
+ case NPCM7XX_GPIO_DOS ... NPCM7XX_GPIO_TLOCK2:
418
+ qemu_log_mask(LOG_GUEST_ERROR,
419
+ "%s: read from write-only register 0x%" HWADDR_PRIx "\n",
420
+ DEVICE(s)->canonical_path, addr);
421
+ break;
422
+
423
+ default:
424
+ qemu_log_mask(LOG_GUEST_ERROR,
425
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
426
+ DEVICE(s)->canonical_path, addr);
427
+ break;
428
+ }
429
+
430
+ trace_npcm7xx_gpio_read(DEVICE(s)->canonical_path, addr, value);
431
+
432
+ return value;
433
+}
434
+
435
+static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
436
+ unsigned int size)
437
+{
438
+ hwaddr reg = addr / sizeof(uint32_t);
439
+ NPCM7xxGPIOState *s = opaque;
440
+ uint32_t value = v;
441
+ uint32_t diff;
442
+
443
+ trace_npcm7xx_gpio_write(DEVICE(s)->canonical_path, addr, v);
444
+
445
+ if (npcm7xx_gpio_is_locked(s)) {
446
+ switch (reg) {
447
+ case NPCM7XX_GPIO_TLOCK1:
448
+ if (s->regs[NPCM7XX_GPIO_TLOCK2] == NPCM7XX_GPIO_LOCK_MAGIC2 &&
449
+ value == NPCM7XX_GPIO_LOCK_MAGIC1) {
450
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 0;
451
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
452
+ }
453
+ break;
454
+
455
+ case NPCM7XX_GPIO_TLOCK2:
456
+ s->regs[reg] = value;
457
+ break;
458
+
459
+ default:
460
+ qemu_log_mask(LOG_GUEST_ERROR,
461
+ "%s: write to locked register @ 0x%" HWADDR_PRIx "\n",
462
+ DEVICE(s)->canonical_path, addr);
463
+ break;
464
+ }
465
+
466
+ return;
259
+ return;
467
+ }
260
+ }
468
+
261
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
469
+ diff = s->regs[reg] ^ value;
262
+
470
+
263
qemu_macaddr_default_if_unset(&s->conf.macaddr);
471
+ switch (reg) {
264
472
+ case NPCM7XX_GPIO_TLOCK1:
265
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
473
+ case NPCM7XX_GPIO_TLOCK2:
266
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
474
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 1;
267
index XXXXXXX..XXXXXXX 100644
475
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
268
--- a/hw/net/lan9118_phy.c
476
+ break;
269
+++ b/hw/net/lan9118_phy.c
477
+
478
+ case NPCM7XX_GPIO_DIN:
479
+ qemu_log_mask(LOG_GUEST_ERROR,
480
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
481
+ DEVICE(s)->canonical_path, addr);
482
+ break;
483
+
484
+ case NPCM7XX_GPIO_POL:
485
+ case NPCM7XX_GPIO_DOUT:
486
+ case NPCM7XX_GPIO_OE:
487
+ case NPCM7XX_GPIO_OTYP:
488
+ case NPCM7XX_GPIO_PU:
489
+ case NPCM7XX_GPIO_PD:
490
+ case NPCM7XX_GPIO_IEM:
491
+ s->regs[reg] = value;
492
+ npcm7xx_gpio_update_pins(s, diff);
493
+ break;
494
+
495
+ case NPCM7XX_GPIO_DOS:
496
+ s->regs[NPCM7XX_GPIO_DOUT] |= value;
497
+ npcm7xx_gpio_update_pins(s, value);
498
+ break;
499
+ case NPCM7XX_GPIO_DOC:
500
+ s->regs[NPCM7XX_GPIO_DOUT] &= ~value;
501
+ npcm7xx_gpio_update_pins(s, value);
502
+ break;
503
+ case NPCM7XX_GPIO_OES:
504
+ s->regs[NPCM7XX_GPIO_OE] |= value;
505
+ npcm7xx_gpio_update_pins(s, value);
506
+ break;
507
+ case NPCM7XX_GPIO_OEC:
508
+ s->regs[NPCM7XX_GPIO_OE] &= ~value;
509
+ npcm7xx_gpio_update_pins(s, value);
510
+ break;
511
+
512
+ case NPCM7XX_GPIO_EVTYP:
513
+ case NPCM7XX_GPIO_EVBE:
514
+ case NPCM7XX_GPIO_EVEN:
515
+ s->regs[reg] = value;
516
+ npcm7xx_gpio_update_events(s, 0);
517
+ break;
518
+
519
+ case NPCM7XX_GPIO_EVENS:
520
+ s->regs[NPCM7XX_GPIO_EVEN] |= value;
521
+ npcm7xx_gpio_update_events(s, 0);
522
+ break;
523
+ case NPCM7XX_GPIO_EVENC:
524
+ s->regs[NPCM7XX_GPIO_EVEN] &= ~value;
525
+ npcm7xx_gpio_update_events(s, 0);
526
+ break;
527
+
528
+ case NPCM7XX_GPIO_EVST:
529
+ s->regs[reg] &= ~value;
530
+ npcm7xx_gpio_update_events(s, 0);
531
+ break;
532
+
533
+ case NPCM7XX_GPIO_MP:
534
+ case NPCM7XX_GPIO_DBNC:
535
+ case NPCM7XX_GPIO_OSRC:
536
+ case NPCM7XX_GPIO_ODSC:
537
+ /* Nothing to do; just store the value. */
538
+ s->regs[reg] = value;
539
+ break;
540
+
541
+ case NPCM7XX_GPIO_OBL0:
542
+ case NPCM7XX_GPIO_OBL1:
543
+ case NPCM7XX_GPIO_OBL2:
544
+ case NPCM7XX_GPIO_OBL3:
545
+ s->regs[reg] = value;
546
+ qemu_log_mask(LOG_UNIMP, "%s: Blinking is not implemented\n",
547
+ __func__);
548
+ break;
549
+
550
+ case NPCM7XX_GPIO_SPLCK:
551
+ case NPCM7XX_GPIO_MPLCK:
552
+ qemu_log_mask(LOG_UNIMP, "%s: Per-pin lock is not implemented\n",
553
+ __func__);
554
+ break;
555
+
556
+ default:
557
+ qemu_log_mask(LOG_GUEST_ERROR,
558
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
559
+ DEVICE(s)->canonical_path, addr);
560
+ break;
561
+ }
562
+}
563
+
564
+static const MemoryRegionOps npcm7xx_gpio_regs_ops = {
565
+ .read = npcm7xx_gpio_regs_read,
566
+ .write = npcm7xx_gpio_regs_write,
567
+ .endianness = DEVICE_NATIVE_ENDIAN,
568
+ .valid = {
569
+ .min_access_size = 4,
570
+ .max_access_size = 4,
571
+ .unaligned = false,
572
+ },
573
+};
574
+
575
+static void npcm7xx_gpio_set_input(void *opaque, int line, int level)
576
+{
577
+ NPCM7xxGPIOState *s = opaque;
578
+
579
+ trace_npcm7xx_gpio_set_input(DEVICE(s)->canonical_path, line, level);
580
+
581
+ g_assert(line >= 0 && line < NPCM7XX_GPIO_NR_PINS);
582
+
583
+ s->ext_driven = deposit32(s->ext_driven, line, 1, level >= 0);
584
+ s->ext_level = deposit32(s->ext_level, line, 1, level > 0);
585
+
586
+ npcm7xx_gpio_update_pins(s, BIT(line));
587
+}
588
+
589
+static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type)
590
+{
591
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
592
+
593
+ memset(s->regs, 0, sizeof(s->regs));
594
+
595
+ s->regs[NPCM7XX_GPIO_PU] = s->reset_pu;
596
+ s->regs[NPCM7XX_GPIO_PD] = s->reset_pd;
597
+ s->regs[NPCM7XX_GPIO_OSRC] = s->reset_osrc;
598
+ s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc;
599
+}
600
+
601
+static void npcm7xx_gpio_hold_reset(Object *obj)
602
+{
603
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
604
+
605
+ npcm7xx_gpio_update_pins(s, -1);
606
+}
607
+
608
+static void npcm7xx_gpio_init(Object *obj)
609
+{
610
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
611
+ DeviceState *dev = DEVICE(obj);
612
+
613
+ memory_region_init_io(&s->mmio, obj, &npcm7xx_gpio_regs_ops, s,
614
+ "regs", NPCM7XX_GPIO_REGS_SIZE);
615
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
616
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
617
+
618
+ qdev_init_gpio_in(dev, npcm7xx_gpio_set_input, NPCM7XX_GPIO_NR_PINS);
619
+ qdev_init_gpio_out(dev, s->output, NPCM7XX_GPIO_NR_PINS);
620
+}
621
+
622
+static const VMStateDescription vmstate_npcm7xx_gpio = {
623
+ .name = "npcm7xx-gpio",
624
+ .version_id = 0,
625
+ .minimum_version_id = 0,
626
+ .fields = (VMStateField[]) {
627
+ VMSTATE_UINT32(pin_level, NPCM7xxGPIOState),
628
+ VMSTATE_UINT32(ext_level, NPCM7xxGPIOState),
629
+ VMSTATE_UINT32(ext_driven, NPCM7xxGPIOState),
630
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxGPIOState, NPCM7XX_GPIO_NR_REGS),
631
+ VMSTATE_END_OF_LIST(),
632
+ },
633
+};
634
+
635
+static Property npcm7xx_gpio_properties[] = {
636
+ /* Bit n set => pin n has pullup enabled by default. */
637
+ DEFINE_PROP_UINT32("reset-pullup", NPCM7xxGPIOState, reset_pu, 0),
638
+ /* Bit n set => pin n has pulldown enabled by default. */
639
+ DEFINE_PROP_UINT32("reset-pulldown", NPCM7xxGPIOState, reset_pd, 0),
640
+ /* Bit n set => pin n has high slew rate by default. */
641
+ DEFINE_PROP_UINT32("reset-osrc", NPCM7xxGPIOState, reset_osrc, 0),
642
+ /* Bit n set => pin n has high drive strength by default. */
643
+ DEFINE_PROP_UINT32("reset-odsc", NPCM7xxGPIOState, reset_odsc, 0),
644
+ DEFINE_PROP_END_OF_LIST(),
645
+};
646
+
647
+static void npcm7xx_gpio_class_init(ObjectClass *klass, void *data)
648
+{
649
+ ResettableClass *reset = RESETTABLE_CLASS(klass);
650
+ DeviceClass *dc = DEVICE_CLASS(klass);
651
+
652
+ QEMU_BUILD_BUG_ON(NPCM7XX_GPIO_REGS_END > NPCM7XX_GPIO_NR_REGS);
653
+
654
+ dc->desc = "NPCM7xx GPIO Controller";
655
+ dc->vmsd = &vmstate_npcm7xx_gpio;
656
+ reset->phases.enter = npcm7xx_gpio_enter_reset;
657
+ reset->phases.hold = npcm7xx_gpio_hold_reset;
658
+ device_class_set_props(dc, npcm7xx_gpio_properties);
659
+}
660
+
661
+static const TypeInfo npcm7xx_gpio_types[] = {
662
+ {
663
+ .name = TYPE_NPCM7XX_GPIO,
664
+ .parent = TYPE_SYS_BUS_DEVICE,
665
+ .instance_size = sizeof(NPCM7xxGPIOState),
666
+ .class_init = npcm7xx_gpio_class_init,
667
+ .instance_init = npcm7xx_gpio_init,
668
+ },
669
+};
670
+DEFINE_TYPES(npcm7xx_gpio_types);
671
diff --git a/tests/qtest/npcm7xx_gpio-test.c b/tests/qtest/npcm7xx_gpio-test.c
672
new file mode 100644
673
index XXXXXXX..XXXXXXX
674
--- /dev/null
675
+++ b/tests/qtest/npcm7xx_gpio-test.c
676
@@ -XXX,XX +XXX,XX @@
270
@@ -XXX,XX +XXX,XX @@
677
+/*
271
* Copyright (c) 2009 CodeSourcery, LLC.
678
+ * QTest testcase for the Nuvoton NPCM7xx GPIO modules.
272
* Written by Paul Brook
273
*
274
+ * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
679
+ *
275
+ *
680
+ * Copyright 2020 Google LLC
276
* This code is licensed under the GNU GPL v2
681
+ *
277
*
682
+ * This program is free software; you can redistribute it and/or modify it
278
* Contributions after 2012-01-13 are licensed under the terms of the
683
+ * under the terms of the GNU General Public License as published by the
279
@@ -XXX,XX +XXX,XX @@
684
+ * Free Software Foundation; either version 2 of the License, or
280
#include "hw/resettable.h"
685
+ * (at your option) any later version.
281
#include "migration/vmstate.h"
686
+ *
282
#include "qemu/log.h"
687
+ * This program is distributed in the hope that it will be useful, but WITHOUT
283
+#include "trace.h"
688
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
284
689
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
285
#define PHY_INT_ENERGYON (1 << 7)
690
+ * for more details.
286
#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
691
+ */
287
@@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
692
+
288
693
+#include "qemu/osdep.h"
289
switch (reg) {
694
+#include "libqtest-single.h"
290
case 0: /* Basic Control */
695
+
291
- return s->control;
696
+#define NR_GPIO_DEVICES (8)
292
+ val = s->control;
697
+#define GPIO(x) (0xf0010000 + (x) * 0x1000)
293
+ break;
698
+#define GPIO_IRQ(x) (116 + (x))
294
case 1: /* Basic Status */
699
+
295
- return s->status;
700
+/* GPIO registers */
296
+ val = s->status;
701
+#define GP_N_TLOCK1 0x00
297
+ break;
702
+#define GP_N_DIN 0x04 /* Data IN */
298
case 2: /* ID1 */
703
+#define GP_N_POL 0x08 /* Polarity */
299
- return 0x0007;
704
+#define GP_N_DOUT 0x0c /* Data OUT */
300
+ val = 0x0007;
705
+#define GP_N_OE 0x10 /* Output Enable */
301
+ break;
706
+#define GP_N_OTYP 0x14
302
case 3: /* ID2 */
707
+#define GP_N_MP 0x18
303
- return 0xc0d1;
708
+#define GP_N_PU 0x1c /* Pull-up */
304
+ val = 0xc0d1;
709
+#define GP_N_PD 0x20 /* Pull-down */
305
+ break;
710
+#define GP_N_DBNC 0x24 /* Debounce */
306
case 4: /* Auto-neg advertisement */
711
+#define GP_N_EVTYP 0x28 /* Event Type */
307
- return s->advertise;
712
+#define GP_N_EVBE 0x2c /* Event Both Edge */
308
+ val = s->advertise;
713
+#define GP_N_OBL0 0x30
309
+ break;
714
+#define GP_N_OBL1 0x34
310
case 5: /* Auto-neg Link Partner Ability */
715
+#define GP_N_OBL2 0x38
311
- return 0x0f71;
716
+#define GP_N_OBL3 0x3c
312
+ val = 0x0f71;
717
+#define GP_N_EVEN 0x40 /* Event Enable */
313
+ break;
718
+#define GP_N_EVENS 0x44 /* Event Set (enable) */
314
case 6: /* Auto-neg Expansion */
719
+#define GP_N_EVENC 0x48 /* Event Clear (disable) */
315
- return 1;
720
+#define GP_N_EVST 0x4c /* Event Status */
316
- /* TODO 17, 18, 27, 29, 30, 31 */
721
+#define GP_N_SPLCK 0x50
317
+ val = 1;
722
+#define GP_N_MPLCK 0x54
318
+ break;
723
+#define GP_N_IEM 0x58 /* Input Enable */
319
case 29: /* Interrupt source. */
724
+#define GP_N_OSRC 0x5c
320
val = s->ints;
725
+#define GP_N_ODSC 0x60
321
s->ints = 0;
726
+#define GP_N_DOS 0x68 /* Data OUT Set */
322
lan9118_phy_update_irq(s);
727
+#define GP_N_DOC 0x6c /* Data OUT Clear */
323
- return val;
728
+#define GP_N_OES 0x70 /* Output Enable Set */
324
+ break;
729
+#define GP_N_OEC 0x74 /* Output Enable Clear */
325
case 30: /* Interrupt mask */
730
+#define GP_N_TLOCK2 0x7c
326
- return s->int_mask;
731
+
327
+ val = s->int_mask;
732
+static void gpio_unlock(int n)
328
+ break;
733
+{
329
+ case 17:
734
+ if (readl(GPIO(n) + GP_N_TLOCK1) != 0) {
330
+ case 18:
735
+ writel(GPIO(n) + GP_N_TLOCK2, 0xc0de1248);
331
+ case 27:
736
+ writel(GPIO(n) + GP_N_TLOCK1, 0xc0defa73);
332
+ case 31:
737
+ }
333
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
738
+}
334
+ __func__, reg);
739
+
335
+ val = 0;
740
+/* Restore the GPIO controller to a sensible default state. */
336
+ break;
741
+static void gpio_reset(int n)
337
default:
742
+{
338
- qemu_log_mask(LOG_GUEST_ERROR,
743
+ gpio_unlock(0);
339
- "lan9118_phy_read: PHY read reg %d\n", reg);
744
+
340
- return 0;
745
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
341
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
746
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
342
+ __func__, reg);
747
+ writel(GPIO(n) + GP_N_POL, 0x00000000);
343
+ val = 0;
748
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
344
+ break;
749
+ writel(GPIO(n) + GP_N_OE, 0x00000000);
345
}
750
+ writel(GPIO(n) + GP_N_OTYP, 0x00000000);
346
+
751
+ writel(GPIO(n) + GP_N_PU, 0xffffffff);
347
+ trace_lan9118_phy_read(val, reg);
752
+ writel(GPIO(n) + GP_N_PD, 0x00000000);
348
+
753
+ writel(GPIO(n) + GP_N_IEM, 0xffffffff);
349
+ return val;
754
+}
350
}
755
+
351
756
+static void test_dout_to_din(void)
352
void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
757
+{
353
{
758
+ gpio_reset(0);
354
+ trace_lan9118_phy_write(val, reg);
759
+
355
+
760
+ /* When output is enabled, DOUT should be reflected on DIN. */
356
switch (reg) {
761
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
357
case 0: /* Basic Control */
762
+ /* PU and PD shouldn't have any impact on DIN. */
358
if (val & 0x8000) {
763
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
359
lan9118_phy_reset(s);
764
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
360
- break;
765
+ writel(GPIO(0) + GP_N_DOUT, 0x12345678);
361
- }
766
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x12345678);
362
- s->control = val & 0x7980;
767
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x12345678);
363
- /* Complete autonegotiation immediately. */
768
+}
364
- if (val & 0x1000) {
769
+
365
- s->status |= 0x0020;
770
+static void test_pullup_pulldown(void)
366
+ } else {
771
+{
367
+ s->control = val & 0x7980;
772
+ gpio_reset(0);
368
+ /* Complete autonegotiation immediately. */
773
+
369
+ if (val & 0x1000) {
774
+ /*
370
+ s->status |= 0x0020;
775
+ * When output is disabled, and PD is the inverse of PU, PU should be
371
+ }
776
+ * reflected on DIN. If PD is not the inverse of PU, the state of DIN is
372
}
777
+ * undefined, so we don't test that.
373
break;
778
+ */
374
case 4: /* Auto-neg advertisement */
779
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
375
s->advertise = (val & 0x2d7f) | 0x80;
780
+ /* DOUT shouldn't have any impact on DIN. */
376
break;
781
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
377
- /* TODO 17, 18, 27, 31 */
782
+ writel(GPIO(0) + GP_N_PU, 0x23456789);
378
case 30: /* Interrupt mask */
783
+ writel(GPIO(0) + GP_N_PD, ~0x23456789U);
379
s->int_mask = val & 0xff;
784
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PU), ==, 0x23456789);
380
lan9118_phy_update_irq(s);
785
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PD), ==, ~0x23456789U);
381
break;
786
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x23456789);
382
+ case 17:
787
+}
383
+ case 18:
788
+
384
+ case 27:
789
+static void test_output_enable(void)
385
+ case 31:
790
+{
386
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
791
+ gpio_reset(0);
387
+ __func__, reg);
792
+
388
+ break;
793
+ /*
389
default:
794
+ * With all pins weakly pulled down, and DOUT all-ones, OE should be
390
- qemu_log_mask(LOG_GUEST_ERROR,
795
+ * reflected on DIN.
391
- "lan9118_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
796
+ */
392
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
797
+ writel(GPIO(0) + GP_N_DOUT, 0xffffffff);
393
+ __func__, reg);
798
+ writel(GPIO(0) + GP_N_PU, 0x00000000);
394
+ break;
799
+ writel(GPIO(0) + GP_N_PD, 0xffffffff);
395
}
800
+ writel(GPIO(0) + GP_N_OE, 0x3456789a);
396
}
801
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3456789a);
397
802
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3456789a);
398
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
803
+
399
804
+ writel(GPIO(0) + GP_N_OEC, 0x00030002);
400
/* Autonegotiation status mirrors link status. */
805
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x34547898);
401
if (link_down) {
806
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x34547898);
402
+ trace_lan9118_phy_update_link("down");
807
+
403
s->status &= ~0x0024;
808
+ writel(GPIO(0) + GP_N_OES, 0x0000f001);
404
s->ints |= PHY_INT_DOWN;
809
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3454f899);
405
} else {
810
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3454f899);
406
+ trace_lan9118_phy_update_link("up");
811
+}
407
s->status |= 0x0024;
812
+
408
s->ints |= PHY_INT_ENERGYON;
813
+static void test_open_drain(void)
409
s->ints |= PHY_INT_AUTONEG_COMPLETE;
814
+{
410
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
815
+ gpio_reset(0);
411
816
+
412
void lan9118_phy_reset(Lan9118PhyState *s)
817
+ /*
413
{
818
+ * Upper half of DOUT drives a 1 only if the corresponding bit in OTYP is
414
+ trace_lan9118_phy_reset();
819
+ * not set. If OTYP is set, DIN is determined by PU/PD. Lower half of
415
+
820
+ * DOUT always drives a 0 regardless of OTYP; PU/PD have no effect. When
416
s->control = 0x3000;
821
+ * OE is 0, output is determined by PU/PD; OTYP has no effect.
417
s->status = 0x7809;
822
+ */
418
s->advertise = 0x01e1;
823
+ writel(GPIO(0) + GP_N_OTYP, 0x456789ab);
419
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_lan9118_phy = {
824
+ writel(GPIO(0) + GP_N_OE, 0xf0f0f0f0);
420
.version_id = 1,
825
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
421
.minimum_version_id = 1,
826
+ writel(GPIO(0) + GP_N_PU, 0xff00ff00);
422
.fields = (const VMStateField[]) {
827
+ writel(GPIO(0) + GP_N_PD, 0x00ff00ff);
423
- VMSTATE_UINT16(control, Lan9118PhyState),
828
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OTYP), ==, 0x456789ab);
424
VMSTATE_UINT16(status, Lan9118PhyState),
829
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff900f00);
425
+ VMSTATE_UINT16(control, Lan9118PhyState),
830
+}
426
VMSTATE_UINT16(advertise, Lan9118PhyState),
831
+
427
VMSTATE_UINT16(ints, Lan9118PhyState),
832
+static void test_polarity(void)
428
VMSTATE_UINT16(int_mask, Lan9118PhyState),
833
+{
429
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
834
+ gpio_reset(0);
835
+
836
+ /*
837
+ * In push-pull mode, DIN should reflect DOUT because the signal is
838
+ * inverted in both directions.
839
+ */
840
+ writel(GPIO(0) + GP_N_OTYP, 0x00000000);
841
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
842
+ writel(GPIO(0) + GP_N_DOUT, 0x56789abc);
843
+ writel(GPIO(0) + GP_N_POL, 0x6789abcd);
844
+ g_assert_cmphex(readl(GPIO(0) + GP_N_POL), ==, 0x6789abcd);
845
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x56789abc);
846
+
847
+ /*
848
+ * When turning off the drivers, DIN should reflect the inverse of the
849
+ * pulled-up lines.
850
+ */
851
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
852
+ writel(GPIO(0) + GP_N_POL, 0xffffffff);
853
+ writel(GPIO(0) + GP_N_PU, 0x789abcde);
854
+ writel(GPIO(0) + GP_N_PD, ~0x789abcdeU);
855
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, ~0x789abcdeU);
856
+
857
+ /*
858
+ * In open-drain mode, DOUT=1 will appear to drive the pin high (since DIN
859
+ * is inverted), while DOUT=0 will leave the pin floating.
860
+ */
861
+ writel(GPIO(0) + GP_N_OTYP, 0xffffffff);
862
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
863
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
864
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
865
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
866
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff00ffff);
867
+}
868
+
869
+static void test_input_mask(void)
870
+{
871
+ gpio_reset(0);
872
+
873
+ /* IEM=0 forces the input to zero before polarity inversion. */
874
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
875
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
876
+ writel(GPIO(0) + GP_N_POL, 0xffff0000);
877
+ writel(GPIO(0) + GP_N_IEM, 0x87654321);
878
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff9a4300);
879
+}
880
+
881
+static void test_temp_lock(void)
882
+{
883
+ gpio_reset(0);
884
+
885
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
886
+
887
+ /* Make sure we're unlocked initially. */
888
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
889
+ /* Writing any value to TLOCK1 will lock. */
890
+ writel(GPIO(0) + GP_N_TLOCK1, 0);
891
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
892
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
893
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
894
+ /* Now, try to unlock. */
895
+ gpio_unlock(0);
896
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
897
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
898
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
899
+
900
+ /* Try it again, but write TLOCK2 to lock. */
901
+ writel(GPIO(0) + GP_N_TLOCK2, 0);
902
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
903
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
904
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
905
+ /* Now, try to unlock. */
906
+ gpio_unlock(0);
907
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
908
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
909
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
910
+}
911
+
912
+static void test_events_level(void)
913
+{
914
+ gpio_reset(0);
915
+
916
+ writel(GPIO(0) + GP_N_EVTYP, 0x00000000);
917
+ writel(GPIO(0) + GP_N_DOUT, 0xba987654);
918
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
919
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
920
+
921
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
922
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
923
+ writel(GPIO(0) + GP_N_DOUT, 0x00000000);
924
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
925
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
926
+ writel(GPIO(0) + GP_N_EVST, 0x00007654);
927
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba980000);
928
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
929
+ writel(GPIO(0) + GP_N_EVST, 0xba980000);
930
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
931
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
932
+}
933
+
934
+static void test_events_rising_edge(void)
935
+{
936
+ gpio_reset(0);
937
+
938
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
939
+ writel(GPIO(0) + GP_N_EVBE, 0x00000000);
940
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
941
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
942
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
943
+
944
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
945
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
946
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
947
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x0000ff00);
948
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
949
+ writel(GPIO(0) + GP_N_DOUT, 0x00ff0000);
950
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
951
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
952
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
953
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ff0f00);
954
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
955
+ writel(GPIO(0) + GP_N_EVST, 0x00ff0f00);
956
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
957
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
958
+}
959
+
960
+static void test_events_both_edges(void)
961
+{
962
+ gpio_reset(0);
963
+
964
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
965
+ writel(GPIO(0) + GP_N_EVBE, 0xffffffff);
966
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
967
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
968
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
969
+
970
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
971
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
972
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
973
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
974
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
975
+ writel(GPIO(0) + GP_N_DOUT, 0xef00ff08);
976
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ffff08);
977
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
978
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
979
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ff0f08);
980
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
981
+ writel(GPIO(0) + GP_N_EVST, 0x10ff0f08);
982
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
983
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
984
+}
985
+
986
+static void test_gpion_irq(gconstpointer test_data)
987
+{
988
+ intptr_t n = (intptr_t)test_data;
989
+
990
+ gpio_reset(n);
991
+
992
+ writel(GPIO(n) + GP_N_EVTYP, 0x00000000);
993
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
994
+ writel(GPIO(n) + GP_N_OE, 0xffffffff);
995
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
996
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
997
+
998
+ /* Trigger an event; interrupts are masked. */
999
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00000000);
1000
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1001
+ writel(GPIO(n) + GP_N_DOS, 0x00008000);
1002
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00008000);
1003
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1004
+
1005
+ /* Unmask all event interrupts; verify that the interrupt fired. */
1006
+ writel(GPIO(n) + GP_N_EVEN, 0xffffffff);
1007
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1008
+
1009
+ /* Clear the current bit, set a new bit, irq stays asserted. */
1010
+ writel(GPIO(n) + GP_N_DOC, 0x00008000);
1011
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1012
+ writel(GPIO(n) + GP_N_DOS, 0x00000200);
1013
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1014
+ writel(GPIO(n) + GP_N_EVST, 0x00008000);
1015
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1016
+
1017
+ /* Mask/unmask the event that's currently active. */
1018
+ writel(GPIO(n) + GP_N_EVENC, 0x00000200);
1019
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1020
+ writel(GPIO(n) + GP_N_EVENS, 0x00000200);
1021
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1022
+
1023
+ /* Clear the input and the status bit, irq is deasserted. */
1024
+ writel(GPIO(n) + GP_N_DOC, 0x00000200);
1025
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1026
+ writel(GPIO(n) + GP_N_EVST, 0x00000200);
1027
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1028
+}
1029
+
1030
+int main(int argc, char **argv)
1031
+{
1032
+ int ret;
1033
+ int i;
1034
+
1035
+ g_test_init(&argc, &argv, NULL);
1036
+ g_test_set_nonfatal_assertions();
1037
+
1038
+ qtest_add_func("/npcm7xx_gpio/dout_to_din", test_dout_to_din);
1039
+ qtest_add_func("/npcm7xx_gpio/pullup_pulldown", test_pullup_pulldown);
1040
+ qtest_add_func("/npcm7xx_gpio/output_enable", test_output_enable);
1041
+ qtest_add_func("/npcm7xx_gpio/open_drain", test_open_drain);
1042
+ qtest_add_func("/npcm7xx_gpio/polarity", test_polarity);
1043
+ qtest_add_func("/npcm7xx_gpio/input_mask", test_input_mask);
1044
+ qtest_add_func("/npcm7xx_gpio/temp_lock", test_temp_lock);
1045
+ qtest_add_func("/npcm7xx_gpio/events/level", test_events_level);
1046
+ qtest_add_func("/npcm7xx_gpio/events/rising_edge", test_events_rising_edge);
1047
+ qtest_add_func("/npcm7xx_gpio/events/both_edges", test_events_both_edges);
1048
+
1049
+ for (i = 0; i < NR_GPIO_DEVICES; i++) {
1050
+ g_autofree char *test_name =
1051
+ g_strdup_printf("/npcm7xx_gpio/gpio[%d]/irq", i);
1052
+ qtest_add_data_func(test_name, (void *)(intptr_t)i, test_gpion_irq);
1053
+ }
1054
+
1055
+ qtest_start("-machine npcm750-evb");
1056
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic");
1057
+ ret = g_test_run();
1058
+ qtest_end();
1059
+
1060
+ return ret;
1061
+}
1062
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
1063
index XXXXXXX..XXXXXXX 100644
430
index XXXXXXX..XXXXXXX 100644
1064
--- a/hw/gpio/meson.build
431
--- a/hw/net/Kconfig
1065
+++ b/hw/gpio/meson.build
432
+++ b/hw/net/Kconfig
1066
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c'))
433
@@ -XXX,XX +XXX,XX @@ config ALLWINNER_SUN8I_EMAC
1067
softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
434
1068
435
config IMX_FEC
1069
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
436
bool
1070
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c'))
437
+ select LAN9118_PHY
1071
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_gpio.c'))
438
1072
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c'))
439
config CADENCE
1073
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c'))
440
bool
1074
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
441
diff --git a/hw/net/trace-events b/hw/net/trace-events
1075
index XXXXXXX..XXXXXXX 100644
442
index XXXXXXX..XXXXXXX 100644
1076
--- a/hw/gpio/trace-events
443
--- a/hw/net/trace-events
1077
+++ b/hw/gpio/trace-events
444
+++ b/hw/net/trace-events
1078
@@ -XXX,XX +XXX,XX @@
445
@@ -XXX,XX +XXX,XX @@ allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u"
1079
# See docs/devel/tracing.txt for syntax documentation.
446
allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64
1080
447
allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64
1081
+# npcm7xx_gpio.c
448
1082
+npcm7xx_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
449
+# lan9118_phy.c
1083
+npcm7xx_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
450
+lan9118_phy_read(uint16_t val, int reg) "[0x%02x] -> 0x%04" PRIx16
1084
+npcm7xx_gpio_set_input(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
451
+lan9118_phy_write(uint16_t val, int reg) "[0x%02x] <- 0x%04" PRIx16
1085
+npcm7xx_gpio_set_output(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
452
+lan9118_phy_update_link(const char *s) "%s"
1086
+npcm7xx_gpio_update_events(const char *id, uint32_t evst, uint32_t even) "%s evst: 0x%08" PRIx32 " even: 0x%08" PRIx32
453
+lan9118_phy_reset(void) ""
1087
+
454
+
1088
# nrf51_gpio.c
455
# lance.c
1089
nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
456
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x"
1090
nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
457
lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x"
1091
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
458
@@ -XXX,XX +XXX,XX @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries"
1092
index XXXXXXX..XXXXXXX 100644
459
i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
1093
--- a/tests/qtest/meson.build
460
1094
+++ b/tests/qtest/meson.build
461
# imx_fec.c
1095
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
462
-imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]"
1096
['prom-env-test', 'boot-serial-test']
463
imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)"
1097
464
-imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]"
1098
qtests_npcm7xx = \
465
imx_phy_write_num(int phy, int configured) "write request to unconfigured phy %d (configured %d)"
1099
- ['npcm7xx_rng-test',
466
-imx_phy_update_link(const char *s) "%s"
1100
+ ['npcm7xx_gpio-test',
467
-imx_phy_reset(void) ""
1101
+ 'npcm7xx_rng-test',
468
imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x"
1102
'npcm7xx_timer-test',
469
imx_enet_read_bd(uint64_t addr, int flags, int len, int data, int options, int status) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x option 0x%04x status 0x%04x"
1103
'npcm7xx_watchdog_timer-test']
470
imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit"
1104
qtests_arm = \
1105
--
471
--
1106
2.20.1
472
2.34.1
1107
1108
diff view generated by jsdifflib
1
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Use of 0x%d - make up our mind as 0x%x
3
Turns 0x70 into 0xe0 (== 0x70 << 1) which adds the missing MII_ANLPAR_TX and
4
fixes the MSB of selector field to be zero, as specified in the datasheet.
4
5
5
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
6
Fixes: 2a424990170b "LAN9118 emulation"
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
7
Acked-by: Eric Auger <eric.auger@redhat.com>
8
Tested-by: Guenter Roeck <linux@roeck-us.net>
8
Message-id: 20201014193355.53074-1-dgilbert@redhat.com
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20241102125724.532843-4-shentey@gmail.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
12
---
11
hw/arm/trace-events | 2 +-
13
hw/net/lan9118_phy.c | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
14
1 file changed, 1 insertion(+), 1 deletion(-)
13
15
14
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
16
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/trace-events
18
--- a/hw/net/lan9118_phy.c
17
+++ b/hw/arm/trace-events
19
+++ b/hw/net/lan9118_phy.c
18
@@ -XXX,XX +XXX,XX @@ smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
20
@@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
19
smmuv3_decode_cd(uint32_t oas) "oas=%d"
21
val = s->advertise;
20
smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d had:%d"
22
break;
21
smmuv3_cmdq_cfgi_ste(int streamid) "streamid =%d"
23
case 5: /* Auto-neg Link Partner Ability */
22
-smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%d - end=0x%d"
24
- val = 0x0f71;
23
+smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
25
+ val = 0x0fe1;
24
smmuv3_cmdq_cfgi_cd(uint32_t sid) "streamid = %d"
26
break;
25
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid %d (hits=%d, misses=%d, hit rate=%d)"
27
case 6: /* Auto-neg Expansion */
26
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid %d (hits=%d, misses=%d, hit rate=%d)"
28
val = 1;
27
--
29
--
28
2.20.1
30
2.34.1
29
30
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Generic watchdog device model implementation as per ARM SBSA v6.0
3
Prefer named constants over magic values for better readability.
4
4
5
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
6
Message-id: 20201027015927.29495-2-shashi.mallela@linaro.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
7
Tested-by: Guenter Roeck <linux@roeck-us.net>
8
Message-id: 20241102125724.532843-5-shentey@gmail.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
include/hw/watchdog/sbsa_gwdt.h | 79 +++++++++
11
include/hw/net/mii.h | 6 +++++
11
hw/watchdog/sbsa_gwdt.c | 293 ++++++++++++++++++++++++++++++++
12
hw/net/lan9118_phy.c | 63 ++++++++++++++++++++++++++++----------------
12
hw/arm/Kconfig | 1 +
13
2 files changed, 46 insertions(+), 23 deletions(-)
13
hw/watchdog/Kconfig | 3 +
14
hw/watchdog/meson.build | 1 +
15
5 files changed, 377 insertions(+)
16
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
17
create mode 100644 hw/watchdog/sbsa_gwdt.c
18
14
19
diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
15
diff --git a/include/hw/net/mii.h b/include/hw/net/mii.h
20
new file mode 100644
16
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX
17
--- a/include/hw/net/mii.h
22
--- /dev/null
18
+++ b/include/hw/net/mii.h
23
+++ b/include/hw/watchdog/sbsa_gwdt.h
24
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
25
+/*
20
#define MII_BMSR_JABBER (1 << 1) /* Jabber detected */
26
+ * Copyright (c) 2020 Linaro Limited
21
#define MII_BMSR_EXTCAP (1 << 0) /* Ext-reg capability */
27
+ *
22
28
+ * Authors:
23
+#define MII_ANAR_RFAULT (1 << 13) /* Say we can detect faults */
29
+ * Shashi Mallela <shashi.mallela@linaro.org>
24
#define MII_ANAR_PAUSE_ASYM (1 << 11) /* Try for asymmetric pause */
30
+ *
25
#define MII_ANAR_PAUSE (1 << 10) /* Try for pause */
31
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
26
#define MII_ANAR_TXFD (1 << 8)
32
+ * option) any later version. See the COPYING file in the top-level directory.
27
@@ -XXX,XX +XXX,XX @@
33
+ *
28
#define MII_ANAR_10FD (1 << 6)
34
+ */
29
#define MII_ANAR_10 (1 << 5)
30
#define MII_ANAR_CSMACD (1 << 0)
31
+#define MII_ANAR_SELECT (0x001f) /* Selector bits */
32
33
#define MII_ANLPAR_ACK (1 << 14)
34
#define MII_ANLPAR_PAUSEASY (1 << 11) /* can pause asymmetrically */
35
@@ -XXX,XX +XXX,XX @@
36
#define RTL8201CP_PHYID1 0x0000
37
#define RTL8201CP_PHYID2 0x8201
38
39
+/* SMSC LAN9118 */
40
+#define SMSCLAN9118_PHYID1 0x0007
41
+#define SMSCLAN9118_PHYID2 0xc0d1
35
+
42
+
36
+#ifndef WDT_SBSA_GWDT_H
43
/* RealTek 8211E */
37
+#define WDT_SBSA_GWDT_H
44
#define RTL8211E_PHYID1 0x001c
38
+
45
#define RTL8211E_PHYID2 0xc915
39
+#include "qemu/bitops.h"
46
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
40
+#include "hw/sysbus.h"
47
index XXXXXXX..XXXXXXX 100644
41
+#include "hw/irq.h"
48
--- a/hw/net/lan9118_phy.c
42
+
49
+++ b/hw/net/lan9118_phy.c
43
+#define TYPE_WDT_SBSA "sbsa_gwdt"
44
+#define SBSA_GWDT(obj) \
45
+ OBJECT_CHECK(SBSA_GWDTState, (obj), TYPE_WDT_SBSA)
46
+#define SBSA_GWDT_CLASS(klass) \
47
+ OBJECT_CLASS_CHECK(SBSA_GWDTClass, (klass), TYPE_WDT_SBSA)
48
+#define SBSA_GWDT_GET_CLASS(obj) \
49
+ OBJECT_GET_CLASS(SBSA_GWDTClass, (obj), TYPE_WDT_SBSA)
50
+
51
+/* SBSA Generic Watchdog register definitions */
52
+/* refresh frame */
53
+#define SBSA_GWDT_WRR 0x000
54
+
55
+/* control frame */
56
+#define SBSA_GWDT_WCS 0x000
57
+#define SBSA_GWDT_WOR 0x008
58
+#define SBSA_GWDT_WORU 0x00C
59
+#define SBSA_GWDT_WCV 0x010
60
+#define SBSA_GWDT_WCVU 0x014
61
+
62
+/* Watchdog Interface Identification Register */
63
+#define SBSA_GWDT_W_IIDR 0xFCC
64
+
65
+/* Watchdog Control and Status Register Bits */
66
+#define SBSA_GWDT_WCS_EN BIT(0)
67
+#define SBSA_GWDT_WCS_WS0 BIT(1)
68
+#define SBSA_GWDT_WCS_WS1 BIT(2)
69
+
70
+#define SBSA_GWDT_WOR_MASK 0x0000FFFF
71
+
72
+/*
73
+ * Watchdog Interface Identification Register definition
74
+ * considering JEP106 code for ARM in Bits [11:0]
75
+ */
76
+#define SBSA_GWDT_ID 0x1043B
77
+
78
+/* 2 Separate memory regions for each of refresh & control register frames */
79
+#define SBSA_GWDT_RMMIO_SIZE 0x1000
80
+#define SBSA_GWDT_CMMIO_SIZE 0x1000
81
+
82
+#define SBSA_TIMER_FREQ 62500000 /* Hz */
83
+
84
+typedef struct SBSA_GWDTState {
85
+ /* <private> */
86
+ SysBusDevice parent_obj;
87
+
88
+ /*< public >*/
89
+ MemoryRegion rmmio;
90
+ MemoryRegion cmmio;
91
+ qemu_irq irq;
92
+
93
+ QEMUTimer *timer;
94
+
95
+ uint32_t id;
96
+ uint32_t wcs;
97
+ uint32_t worl;
98
+ uint32_t woru;
99
+ uint32_t wcvl;
100
+ uint32_t wcvu;
101
+} SBSA_GWDTState;
102
+
103
+#endif /* WDT_SBSA_GWDT_H */
104
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
105
new file mode 100644
106
index XXXXXXX..XXXXXXX
107
--- /dev/null
108
+++ b/hw/watchdog/sbsa_gwdt.c
109
@@ -XXX,XX +XXX,XX @@
50
@@ -XXX,XX +XXX,XX @@
110
+/*
51
111
+ * Generic watchdog device model for SBSA
52
#include "qemu/osdep.h"
112
+ *
53
#include "hw/net/lan9118_phy.h"
113
+ * The watchdog device has been implemented as revision 1 variant of
54
+#include "hw/net/mii.h"
114
+ * the ARM SBSA specification v6.0
55
#include "hw/irq.h"
115
+ * (https://developer.arm.com/documentation/den0029/d?lang=en)
56
#include "hw/resettable.h"
116
+ *
57
#include "migration/vmstate.h"
117
+ * Copyright Linaro.org 2020
58
@@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
118
+ *
59
uint16_t val;
119
+ * Authors:
60
120
+ * Shashi Mallela <shashi.mallela@linaro.org>
61
switch (reg) {
121
+ *
62
- case 0: /* Basic Control */
122
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
63
+ case MII_BMCR:
123
+ * option) any later version. See the COPYING file in the top-level directory.
64
val = s->control;
124
+ *
65
break;
125
+ */
66
- case 1: /* Basic Status */
126
+
67
+ case MII_BMSR:
127
+#include "qemu/osdep.h"
68
val = s->status;
128
+#include "sysemu/reset.h"
69
break;
129
+#include "sysemu/watchdog.h"
70
- case 2: /* ID1 */
130
+#include "hw/watchdog/sbsa_gwdt.h"
71
- val = 0x0007;
131
+#include "qemu/timer.h"
72
+ case MII_PHYID1:
132
+#include "migration/vmstate.h"
73
+ val = SMSCLAN9118_PHYID1;
133
+#include "qemu/log.h"
74
break;
134
+#include "qemu/module.h"
75
- case 3: /* ID2 */
135
+
76
- val = 0xc0d1;
136
+static WatchdogTimerModel model = {
77
+ case MII_PHYID2:
137
+ .wdt_name = TYPE_WDT_SBSA,
78
+ val = SMSCLAN9118_PHYID2;
138
+ .wdt_description = "SBSA-compliant generic watchdog device",
79
break;
139
+};
80
- case 4: /* Auto-neg advertisement */
140
+
81
+ case MII_ANAR:
141
+static const VMStateDescription vmstate_sbsa_gwdt = {
82
val = s->advertise;
142
+ .name = "sbsa-gwdt",
83
break;
143
+ .version_id = 1,
84
- case 5: /* Auto-neg Link Partner Ability */
144
+ .minimum_version_id = 1,
85
- val = 0x0fe1;
145
+ .fields = (VMStateField[]) {
86
+ case MII_ANLPAR:
146
+ VMSTATE_TIMER_PTR(timer, SBSA_GWDTState),
87
+ val = MII_ANLPAR_PAUSEASY | MII_ANLPAR_PAUSE | MII_ANLPAR_T4 |
147
+ VMSTATE_UINT32(wcs, SBSA_GWDTState),
88
+ MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD |
148
+ VMSTATE_UINT32(worl, SBSA_GWDTState),
89
+ MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
149
+ VMSTATE_UINT32(woru, SBSA_GWDTState),
90
break;
150
+ VMSTATE_UINT32(wcvl, SBSA_GWDTState),
91
- case 6: /* Auto-neg Expansion */
151
+ VMSTATE_UINT32(wcvu, SBSA_GWDTState),
92
- val = 1;
152
+ VMSTATE_END_OF_LIST()
93
+ case MII_ANER:
153
+ }
94
+ val = MII_ANER_NWAY;
154
+};
95
break;
155
+
96
case 29: /* Interrupt source. */
156
+typedef enum WdtRefreshType {
97
val = s->ints;
157
+ EXPLICIT_REFRESH = 0,
98
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
158
+ TIMEOUT_REFRESH = 1,
99
trace_lan9118_phy_write(val, reg);
159
+} WdtRefreshType;
100
160
+
101
switch (reg) {
161
+static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size)
102
- case 0: /* Basic Control */
162
+{
103
- if (val & 0x8000) {
163
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
104
+ case MII_BMCR:
164
+ uint32_t ret = 0;
105
+ if (val & MII_BMCR_RESET) {
165
+
106
lan9118_phy_reset(s);
166
+ switch (addr) {
107
} else {
167
+ case SBSA_GWDT_WRR:
108
- s->control = val & 0x7980;
168
+ /* watch refresh read has no effect and returns 0 */
109
+ s->control = val & (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 |
169
+ ret = 0;
110
+ MII_BMCR_AUTOEN | MII_BMCR_PDOWN | MII_BMCR_FD |
170
+ break;
111
+ MII_BMCR_CTST);
171
+ case SBSA_GWDT_W_IIDR:
112
/* Complete autonegotiation immediately. */
172
+ ret = s->id;
113
- if (val & 0x1000) {
173
+ break;
114
- s->status |= 0x0020;
174
+ default:
115
+ if (val & MII_BMCR_AUTOEN) {
175
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame read :"
116
+ s->status |= MII_BMSR_AN_COMP;
176
+ " 0x%x\n", (int)addr);
117
}
177
+ }
118
}
178
+ return ret;
119
break;
179
+}
120
- case 4: /* Auto-neg advertisement */
180
+
121
- s->advertise = (val & 0x2d7f) | 0x80;
181
+static uint64_t sbsa_gwdt_read(void *opaque, hwaddr addr, unsigned int size)
122
+ case MII_ANAR:
182
+{
123
+ s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM |
183
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
124
+ MII_ANAR_PAUSE | MII_ANAR_10FD | MII_ANAR_10 |
184
+ uint32_t ret = 0;
125
+ MII_ANAR_SELECT))
185
+
126
+ | MII_ANAR_TX;
186
+ switch (addr) {
127
break;
187
+ case SBSA_GWDT_WCS:
128
case 30: /* Interrupt mask */
188
+ ret = s->wcs;
129
s->int_mask = val & 0xff;
189
+ break;
130
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
190
+ case SBSA_GWDT_WOR:
131
/* Autonegotiation status mirrors link status. */
191
+ ret = s->worl;
132
if (link_down) {
192
+ break;
133
trace_lan9118_phy_update_link("down");
193
+ case SBSA_GWDT_WORU:
134
- s->status &= ~0x0024;
194
+ ret = s->woru;
135
+ s->status &= ~(MII_BMSR_AN_COMP | MII_BMSR_LINK_ST);
195
+ break;
136
s->ints |= PHY_INT_DOWN;
196
+ case SBSA_GWDT_WCV:
137
} else {
197
+ ret = s->wcvl;
138
trace_lan9118_phy_update_link("up");
198
+ break;
139
- s->status |= 0x0024;
199
+ case SBSA_GWDT_WCVU:
140
+ s->status |= MII_BMSR_AN_COMP | MII_BMSR_LINK_ST;
200
+ ret = s->wcvu;
141
s->ints |= PHY_INT_ENERGYON;
201
+ break;
142
s->ints |= PHY_INT_AUTONEG_COMPLETE;
202
+ case SBSA_GWDT_W_IIDR:
143
}
203
+ ret = s->id;
144
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_reset(Lan9118PhyState *s)
204
+ break;
145
{
205
+ default:
146
trace_lan9118_phy_reset();
206
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame read :"
147
207
+ " 0x%x\n", (int)addr);
148
- s->control = 0x3000;
208
+ }
149
- s->status = 0x7809;
209
+ return ret;
150
- s->advertise = 0x01e1;
210
+}
151
+ s->control = MII_BMCR_AUTOEN | MII_BMCR_SPEED100;
211
+
152
+ s->status = MII_BMSR_100TX_FD
212
+static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
153
+ | MII_BMSR_100TX_HD
213
+{
154
+ | MII_BMSR_10T_FD
214
+ uint64_t timeout = 0;
155
+ | MII_BMSR_10T_HD
215
+
156
+ | MII_BMSR_AUTONEG
216
+ timer_del(s->timer);
157
+ | MII_BMSR_EXTCAP;
217
+
158
+ s->advertise = MII_ANAR_TXFD
218
+ if (s->wcs & SBSA_GWDT_WCS_EN) {
159
+ | MII_ANAR_TX
219
+ /*
160
+ | MII_ANAR_10FD
220
+ * Extract the upper 16 bits from woru & 32 bits from worl
161
+ | MII_ANAR_10
221
+ * registers to construct the 48 bit offset value
162
+ | MII_ANAR_CSMACD;
222
+ */
163
s->int_mask = 0;
223
+ timeout = s->woru;
164
s->ints = 0;
224
+ timeout <<= 32;
165
lan9118_phy_update_link(s, s->link_down);
225
+ timeout |= s->worl;
226
+ timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, SBSA_TIMER_FREQ);
227
+ timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
228
+
229
+ if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
230
+ (!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
231
+ /* store the current timeout value into compare registers */
232
+ s->wcvu = timeout >> 32;
233
+ s->wcvl = timeout;
234
+ }
235
+ timer_mod(s->timer, timeout);
236
+ }
237
+}
238
+
239
+static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data,
240
+ unsigned size) {
241
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
242
+
243
+ if (offset == SBSA_GWDT_WRR) {
244
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
245
+
246
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
247
+ } else {
248
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame write :"
249
+ " 0x%x\n", (int)offset);
250
+ }
251
+}
252
+
253
+static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
254
+ unsigned size) {
255
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
256
+
257
+ switch (offset) {
258
+ case SBSA_GWDT_WCS:
259
+ s->wcs = data & SBSA_GWDT_WCS_EN;
260
+ qemu_set_irq(s->irq, 0);
261
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
262
+ break;
263
+
264
+ case SBSA_GWDT_WOR:
265
+ s->worl = data;
266
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
267
+ qemu_set_irq(s->irq, 0);
268
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
269
+ break;
270
+
271
+ case SBSA_GWDT_WORU:
272
+ s->woru = data & SBSA_GWDT_WOR_MASK;
273
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
274
+ qemu_set_irq(s->irq, 0);
275
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
276
+ break;
277
+
278
+ case SBSA_GWDT_WCV:
279
+ s->wcvl = data;
280
+ break;
281
+
282
+ case SBSA_GWDT_WCVU:
283
+ s->wcvu = data;
284
+ break;
285
+
286
+ default:
287
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :"
288
+ " 0x%x\n", (int)offset);
289
+ }
290
+ return;
291
+}
292
+
293
+static void wdt_sbsa_gwdt_reset(DeviceState *dev)
294
+{
295
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
296
+
297
+ timer_del(s->timer);
298
+
299
+ s->wcs = 0;
300
+ s->wcvl = 0;
301
+ s->wcvu = 0;
302
+ s->worl = 0;
303
+ s->woru = 0;
304
+ s->id = SBSA_GWDT_ID;
305
+}
306
+
307
+static void sbsa_gwdt_timer_sysinterrupt(void *opaque)
308
+{
309
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
310
+
311
+ if (!(s->wcs & SBSA_GWDT_WCS_WS0)) {
312
+ s->wcs |= SBSA_GWDT_WCS_WS0;
313
+ sbsa_gwdt_update_timer(s, TIMEOUT_REFRESH);
314
+ qemu_set_irq(s->irq, 1);
315
+ } else {
316
+ s->wcs |= SBSA_GWDT_WCS_WS1;
317
+ qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
318
+ /*
319
+ * Reset the watchdog only if the guest gets notified about
320
+ * expiry. watchdog_perform_action() may temporarily relinquish
321
+ * the BQL; reset before triggering the action to avoid races with
322
+ * sbsa_gwdt instructions.
323
+ */
324
+ switch (get_watchdog_action()) {
325
+ case WATCHDOG_ACTION_DEBUG:
326
+ case WATCHDOG_ACTION_NONE:
327
+ case WATCHDOG_ACTION_PAUSE:
328
+ break;
329
+ default:
330
+ wdt_sbsa_gwdt_reset(DEVICE(s));
331
+ }
332
+ watchdog_perform_action();
333
+ }
334
+}
335
+
336
+static const MemoryRegionOps sbsa_gwdt_rops = {
337
+ .read = sbsa_gwdt_rread,
338
+ .write = sbsa_gwdt_rwrite,
339
+ .endianness = DEVICE_LITTLE_ENDIAN,
340
+ .valid.min_access_size = 4,
341
+ .valid.max_access_size = 4,
342
+ .valid.unaligned = false,
343
+};
344
+
345
+static const MemoryRegionOps sbsa_gwdt_ops = {
346
+ .read = sbsa_gwdt_read,
347
+ .write = sbsa_gwdt_write,
348
+ .endianness = DEVICE_LITTLE_ENDIAN,
349
+ .valid.min_access_size = 4,
350
+ .valid.max_access_size = 4,
351
+ .valid.unaligned = false,
352
+};
353
+
354
+static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
355
+{
356
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
357
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
358
+
359
+ memory_region_init_io(&s->rmmio, OBJECT(dev),
360
+ &sbsa_gwdt_rops, s,
361
+ "sbsa_gwdt.refresh",
362
+ SBSA_GWDT_RMMIO_SIZE);
363
+
364
+ memory_region_init_io(&s->cmmio, OBJECT(dev),
365
+ &sbsa_gwdt_ops, s,
366
+ "sbsa_gwdt.control",
367
+ SBSA_GWDT_CMMIO_SIZE);
368
+
369
+ sysbus_init_mmio(sbd, &s->rmmio);
370
+ sysbus_init_mmio(sbd, &s->cmmio);
371
+
372
+ sysbus_init_irq(sbd, &s->irq);
373
+
374
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt,
375
+ dev);
376
+}
377
+
378
+static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
379
+{
380
+ DeviceClass *dc = DEVICE_CLASS(klass);
381
+
382
+ dc->realize = wdt_sbsa_gwdt_realize;
383
+ dc->reset = wdt_sbsa_gwdt_reset;
384
+ dc->hotpluggable = false;
385
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
386
+ dc->vmsd = &vmstate_sbsa_gwdt;
387
+}
388
+
389
+static const TypeInfo wdt_sbsa_gwdt_info = {
390
+ .class_init = wdt_sbsa_gwdt_class_init,
391
+ .parent = TYPE_SYS_BUS_DEVICE,
392
+ .name = TYPE_WDT_SBSA,
393
+ .instance_size = sizeof(SBSA_GWDTState),
394
+};
395
+
396
+static void wdt_sbsa_gwdt_register_types(void)
397
+{
398
+ watchdog_add_model(&model);
399
+ type_register_static(&wdt_sbsa_gwdt_info);
400
+}
401
+
402
+type_init(wdt_sbsa_gwdt_register_types)
403
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
404
index XXXXXXX..XXXXXXX 100644
405
--- a/hw/arm/Kconfig
406
+++ b/hw/arm/Kconfig
407
@@ -XXX,XX +XXX,XX @@ config SBSA_REF
408
select PL031 # RTC
409
select PL061 # GPIO
410
select USB_EHCI_SYSBUS
411
+ select WDT_SBSA
412
413
config SABRELITE
414
bool
415
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
416
index XXXXXXX..XXXXXXX 100644
417
--- a/hw/watchdog/Kconfig
418
+++ b/hw/watchdog/Kconfig
419
@@ -XXX,XX +XXX,XX @@ config WDT_DIAG288
420
421
config WDT_IMX2
422
bool
423
+
424
+config WDT_SBSA
425
+ bool
426
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
427
index XXXXXXX..XXXXXXX 100644
428
--- a/hw/watchdog/meson.build
429
+++ b/hw/watchdog/meson.build
430
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
431
softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
432
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
433
softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
434
+softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
435
--
166
--
436
2.20.1
167
2.34.1
437
438
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
These are all of the defines required to parse
3
The real device advertises this mode and the device model already advertises
4
GNU_PROPERTY_AARCH64_FEATURE_1_AND, copied from binutils.
4
100 mbps half duplex and 10 mbps full+half duplex. So advertise this mode to
5
Other missing defines related to other GNU program headers
5
make the model more realistic.
6
and notes are elided for now.
7
6
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
10
Message-id: 20201021173749.111103-4-richard.henderson@linaro.org
9
Tested-by: Guenter Roeck <linux@roeck-us.net>
10
Message-id: 20241102125724.532843-6-shentey@gmail.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
12
---
13
include/elf.h | 22 ++++++++++++++++++++++
13
hw/net/lan9118_phy.c | 4 ++--
14
1 file changed, 22 insertions(+)
14
1 file changed, 2 insertions(+), 2 deletions(-)
15
15
16
diff --git a/include/elf.h b/include/elf.h
16
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/elf.h
18
--- a/hw/net/lan9118_phy.c
19
+++ b/include/elf.h
19
+++ b/hw/net/lan9118_phy.c
20
@@ -XXX,XX +XXX,XX @@ typedef int64_t Elf64_Sxword;
20
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
21
#define PT_NOTE 4
21
break;
22
#define PT_SHLIB 5
22
case MII_ANAR:
23
#define PT_PHDR 6
23
s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM |
24
+#define PT_LOOS 0x60000000
24
- MII_ANAR_PAUSE | MII_ANAR_10FD | MII_ANAR_10 |
25
+#define PT_HIOS 0x6fffffff
25
- MII_ANAR_SELECT))
26
#define PT_LOPROC 0x70000000
26
+ MII_ANAR_PAUSE | MII_ANAR_TXFD | MII_ANAR_10FD |
27
#define PT_HIPROC 0x7fffffff
27
+ MII_ANAR_10 | MII_ANAR_SELECT))
28
28
| MII_ANAR_TX;
29
+#define PT_GNU_PROPERTY (PT_LOOS + 0x474e553)
29
break;
30
+
30
case 30: /* Interrupt mask */
31
#define PT_MIPS_REGINFO 0x70000000
32
#define PT_MIPS_RTPROC 0x70000001
33
#define PT_MIPS_OPTIONS 0x70000002
34
@@ -XXX,XX +XXX,XX @@ typedef struct elf64_shdr {
35
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
36
#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension regs */
37
38
+/* Defined note types for GNU systems. */
39
+
40
+#define NT_GNU_PROPERTY_TYPE_0 5 /* Program property */
41
+
42
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */
43
+
44
+#define GNU_PROPERTY_STACK_SIZE 1
45
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2
46
+
47
+#define GNU_PROPERTY_LOPROC 0xc0000000
48
+#define GNU_PROPERTY_HIPROC 0xdfffffff
49
+#define GNU_PROPERTY_LOUSER 0xe0000000
50
+#define GNU_PROPERTY_HIUSER 0xffffffff
51
+
52
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
53
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1u << 0)
54
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1u << 1)
55
+
56
/*
57
* Physical entry point into the kernel.
58
*
59
--
31
--
60
2.20.1
32
2.34.1
61
62
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
For IEEE fused multiply-add, the (0 * inf) + NaN case should raise
2
Invalid for the multiplication of 0 by infinity. Currently we handle
3
this in the per-architecture ifdef ladder in pickNaNMulAdd().
4
However, since this isn't really architecture specific we can hoist
5
it up to the generic code.
2
6
3
The BCM2835 CPRMAN is the clock manager of the SoC. It is composed of a
7
For the cases where the infzero test in pickNaNMulAdd was
4
main oscillator, and several sub-components (PLLs, multiplexers, ...) to
8
returning 2, we can delete the check entirely and allow the
5
generate the BCM2835 clock tree.
9
code to fall into the normal pick-a-NaN handling, because this
10
will return 2 anyway (input 'c' being the only NaN in this case).
11
For the cases where infzero was returning 3 to indicate "return
12
the default NaN", we must retain that "return 3".
6
13
7
This commit adds a skeleton of the CPRMAN, with a dummy register
14
For Arm, this looks like it might be a behaviour change because we
8
read/write implementation. It embeds the main oscillator (xosc) from
15
used to set float_flag_invalid | float_flag_invalid_imz only if C is
9
which all the clocks will be derived.
16
a quiet NaN. However, it is not, because Arm target code never looks
17
at float_flag_invalid_imz, and for the (0 * inf) + SNaN case we
18
already raised float_flag_invalid via the "abc_mask &
19
float_cmask_snan" check in pick_nan_muladd.
10
20
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
21
For any target architecture using the "default implementation" at the
12
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
22
bottom of the ifdef, this is a behaviour change but will be fixing a
13
Signed-off-by: Luc Michel <luc@lmichel.fr>
23
bug (where we failed to raise the Invalid exception for (0 * inf +
14
Tested-by: Guenter Roeck <linux@roeck-us.net>
24
QNaN). The architectures using the default case are:
25
* hppa
26
* i386
27
* sh4
28
* tricore
29
30
The x86, Tricore and SH4 CPU architecture manuals are clear that this
31
should have raised Invalid; HPPA is a bit vaguer but still seems
32
clear enough.
33
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
34
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
35
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
36
Message-id: 20241202131347.498124-2-peter.maydell@linaro.org
16
---
37
---
17
include/hw/arm/bcm2835_peripherals.h | 3 +-
38
fpu/softfloat-parts.c.inc | 13 +++++++------
18
include/hw/misc/bcm2835_cprman.h | 37 +++++
39
fpu/softfloat-specialize.c.inc | 29 +----------------------------
19
include/hw/misc/bcm2835_cprman_internals.h | 24 +++
40
2 files changed, 8 insertions(+), 34 deletions(-)
20
hw/arm/bcm2835_peripherals.c | 11 +-
21
hw/misc/bcm2835_cprman.c | 163 +++++++++++++++++++++
22
hw/misc/meson.build | 1 +
23
hw/misc/trace-events | 5 +
24
7 files changed, 242 insertions(+), 2 deletions(-)
25
create mode 100644 include/hw/misc/bcm2835_cprman.h
26
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
27
create mode 100644 hw/misc/bcm2835_cprman.c
28
41
29
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
42
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
30
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
31
--- a/include/hw/arm/bcm2835_peripherals.h
44
--- a/fpu/softfloat-parts.c.inc
32
+++ b/include/hw/arm/bcm2835_peripherals.h
45
+++ b/fpu/softfloat-parts.c.inc
33
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
34
#include "hw/misc/bcm2835_mbox.h"
47
int ab_mask, int abc_mask)
35
#include "hw/misc/bcm2835_mphi.h"
48
{
36
#include "hw/misc/bcm2835_thermal.h"
49
int which;
37
+#include "hw/misc/bcm2835_cprman.h"
50
+ bool infzero = (ab_mask == float_cmask_infzero);
38
#include "hw/sd/sdhci.h"
51
39
#include "hw/sd/bcm2835_sdhost.h"
52
if (unlikely(abc_mask & float_cmask_snan)) {
40
#include "hw/gpio/bcm2835_gpio.h"
53
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
41
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
42
UnimplementedDeviceState txp;
43
UnimplementedDeviceState armtmr;
44
UnimplementedDeviceState powermgt;
45
- UnimplementedDeviceState cprman;
46
+ BCM2835CprmanState cprman;
47
PL011State uart0;
48
BCM2835AuxState aux;
49
BCM2835FBState fb;
50
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
51
new file mode 100644
52
index XXXXXXX..XXXXXXX
53
--- /dev/null
54
+++ b/include/hw/misc/bcm2835_cprman.h
55
@@ -XXX,XX +XXX,XX @@
56
+/*
57
+ * BCM2835 CPRMAN clock manager
58
+ *
59
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
60
+ *
61
+ * SPDX-License-Identifier: GPL-2.0-or-later
62
+ */
63
+
64
+#ifndef HW_MISC_CPRMAN_H
65
+#define HW_MISC_CPRMAN_H
66
+
67
+#include "hw/sysbus.h"
68
+#include "hw/qdev-clock.h"
69
+
70
+#define TYPE_BCM2835_CPRMAN "bcm2835-cprman"
71
+
72
+typedef struct BCM2835CprmanState BCM2835CprmanState;
73
+
74
+DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
75
+ TYPE_BCM2835_CPRMAN)
76
+
77
+#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
78
+
79
+struct BCM2835CprmanState {
80
+ /*< private >*/
81
+ SysBusDevice parent_obj;
82
+
83
+ /*< public >*/
84
+ MemoryRegion iomem;
85
+
86
+ uint32_t regs[CPRMAN_NUM_REGS];
87
+ uint32_t xosc_freq;
88
+
89
+ Clock *xosc;
90
+};
91
+
92
+#endif
93
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
94
new file mode 100644
95
index XXXXXXX..XXXXXXX
96
--- /dev/null
97
+++ b/include/hw/misc/bcm2835_cprman_internals.h
98
@@ -XXX,XX +XXX,XX @@
99
+/*
100
+ * BCM2835 CPRMAN clock manager
101
+ *
102
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
103
+ *
104
+ * SPDX-License-Identifier: GPL-2.0-or-later
105
+ */
106
+
107
+#ifndef HW_MISC_CPRMAN_INTERNALS_H
108
+#define HW_MISC_CPRMAN_INTERNALS_H
109
+
110
+#include "hw/registerfields.h"
111
+#include "hw/misc/bcm2835_cprman.h"
112
+
113
+/* Register map */
114
+
115
+/*
116
+ * This field is common to all registers. Each register write value must match
117
+ * the CPRMAN_PASSWORD magic value in its 8 MSB.
118
+ */
119
+FIELD(CPRMAN, PASSWORD, 24, 8)
120
+#define CPRMAN_PASSWORD 0x5a
121
+
122
+#endif
123
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
124
index XXXXXXX..XXXXXXX 100644
125
--- a/hw/arm/bcm2835_peripherals.c
126
+++ b/hw/arm/bcm2835_peripherals.c
127
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_init(Object *obj)
128
/* DWC2 */
129
object_initialize_child(obj, "dwc2", &s->dwc2, TYPE_DWC2_USB);
130
131
+ /* CPRMAN clock manager */
132
+ object_initialize_child(obj, "cprman", &s->cprman, TYPE_BCM2835_CPRMAN);
133
+
134
object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr",
135
OBJECT(&s->gpu_bus_mr));
136
}
137
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
138
return;
139
}
54
}
140
55
141
+ /* CPRMAN clock manager */
56
- which = pickNaNMulAdd(a->cls, b->cls, c->cls,
142
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->cprman), errp)) {
57
- ab_mask == float_cmask_infzero, s);
143
+ return;
58
+ if (infzero) {
144
+ }
59
+ /* This is (0 * inf) + NaN or (inf * 0) + NaN */
145
+ memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
60
+ float_raise(float_flag_invalid | float_flag_invalid_imz, s);
146
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
147
+
148
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
149
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
150
sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
151
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
152
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
153
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
154
create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
155
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
156
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
157
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
158
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
159
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
160
new file mode 100644
161
index XXXXXXX..XXXXXXX
162
--- /dev/null
163
+++ b/hw/misc/bcm2835_cprman.c
164
@@ -XXX,XX +XXX,XX @@
165
+/*
166
+ * BCM2835 CPRMAN clock manager
167
+ *
168
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
169
+ *
170
+ * SPDX-License-Identifier: GPL-2.0-or-later
171
+ */
172
+
173
+/*
174
+ * This peripheral is roughly divided into 3 main parts:
175
+ * - the PLLs
176
+ * - the PLL channels
177
+ * - the clock muxes
178
+ *
179
+ * A main oscillator (xosc) feeds all the PLLs. Each PLLs has one or more
180
+ * channels. Those channel are then connected to the clock muxes. Each mux has
181
+ * multiples sources (usually the xosc, some of the PLL channels and some "test
182
+ * debug" clocks). A mux is configured to select a given source through its
183
+ * control register. Each mux has one output clock that also goes out of the
184
+ * CPRMAN. This output clock usually connects to another peripheral in the SoC
185
+ * (so a given mux is dedicated to a peripheral).
186
+ *
187
+ * At each level (PLL, channel and mux), the clock can be altered through
188
+ * dividers (and multipliers in case of the PLLs), and can be disabled (in this
189
+ * case, the next levels see no clock).
190
+ *
191
+ * This can be sum-up as follows (this is an example and not the actual BCM2835
192
+ * clock tree):
193
+ *
194
+ * /-->[PLL]-|->[PLL channel]--... [mux]--> to peripherals
195
+ * | |->[PLL channel] muxes takes [mux]
196
+ * | \->[PLL channel] inputs from [mux]
197
+ * | some channels [mux]
198
+ * [xosc]---|-->[PLL]-|->[PLL channel] and other srcs [mux]
199
+ * | \->[PLL channel] ...-->[mux]
200
+ * | [mux]
201
+ * \-->[PLL]--->[PLL channel] [mux]
202
+ *
203
+ * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
204
+ * tree configuration.
205
+ */
206
+
207
+#include "qemu/osdep.h"
208
+#include "qemu/log.h"
209
+#include "migration/vmstate.h"
210
+#include "hw/qdev-properties.h"
211
+#include "hw/misc/bcm2835_cprman.h"
212
+#include "hw/misc/bcm2835_cprman_internals.h"
213
+#include "trace.h"
214
+
215
+/* CPRMAN "top level" model */
216
+
217
+static uint64_t cprman_read(void *opaque, hwaddr offset,
218
+ unsigned size)
219
+{
220
+ BCM2835CprmanState *s = CPRMAN(opaque);
221
+ uint64_t r = 0;
222
+ size_t idx = offset / sizeof(uint32_t);
223
+
224
+ switch (idx) {
225
+ default:
226
+ r = s->regs[idx];
227
+ }
61
+ }
228
+
62
+
229
+ trace_bcm2835_cprman_read(offset, r);
63
+ which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
230
+ return r;
64
231
+}
65
if (s->default_nan_mode || which == 3) {
66
- /*
67
- * Note that this check is after pickNaNMulAdd so that function
68
- * has an opportunity to set the Invalid flag for infzero.
69
- */
70
parts_default_nan(a, s);
71
return a;
72
}
73
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
74
index XXXXXXX..XXXXXXX 100644
75
--- a/fpu/softfloat-specialize.c.inc
76
+++ b/fpu/softfloat-specialize.c.inc
77
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
78
* the default NaN
79
*/
80
if (infzero && is_qnan(c_cls)) {
81
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
82
return 3;
83
}
84
85
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
86
* case sets InvalidOp and returns the default NaN
87
*/
88
if (infzero) {
89
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
90
return 3;
91
}
92
/* Prefer sNaN over qNaN, in the a, b, c order. */
93
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
94
* For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
95
* case sets InvalidOp and returns the input value 'c'
96
*/
97
- if (infzero) {
98
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
99
- return 2;
100
- }
101
/* Prefer sNaN over qNaN, in the c, a, b order. */
102
if (is_snan(c_cls)) {
103
return 2;
104
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
105
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
106
* case sets InvalidOp and returns the input value 'c'
107
*/
108
- if (infzero) {
109
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
110
- return 2;
111
- }
232
+
112
+
233
+static void cprman_write(void *opaque, hwaddr offset,
113
/* Prefer sNaN over qNaN, in the c, a, b order. */
234
+ uint64_t value, unsigned size)
114
if (is_snan(c_cls)) {
235
+{
115
return 2;
236
+ BCM2835CprmanState *s = CPRMAN(opaque);
116
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
237
+ size_t idx = offset / sizeof(uint32_t);
117
* to return an input NaN if we have one (ie c) rather than generating
238
+
118
* a default NaN
239
+ if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) {
119
*/
240
+ trace_bcm2835_cprman_write_invalid_magic(offset, value);
120
- if (infzero) {
241
+ return;
121
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
242
+ }
122
- return 2;
243
+
123
- }
244
+ value &= ~R_CPRMAN_PASSWORD_MASK;
124
245
+
125
/* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
246
+ trace_bcm2835_cprman_write(offset, value);
126
* otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
247
+ s->regs[idx] = value;
127
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
248
+
128
return 1;
249
+}
129
}
250
+
130
#elif defined(TARGET_RISCV)
251
+static const MemoryRegionOps cprman_ops = {
131
- /* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */
252
+ .read = cprman_read,
132
- if (infzero) {
253
+ .write = cprman_write,
133
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
254
+ .endianness = DEVICE_LITTLE_ENDIAN,
134
- }
255
+ .valid = {
135
return 3; /* default NaN */
256
+ /*
136
#elif defined(TARGET_S390X)
257
+ * Although this hasn't been checked against real hardware, nor the
137
if (infzero) {
258
+ * information can be found in a datasheet, it seems reasonable because
138
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
259
+ * of the "PASSWORD" magic value found in every registers.
139
return 3;
260
+ */
140
}
261
+ .min_access_size = 4,
141
262
+ .max_access_size = 4,
142
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
263
+ .unaligned = false,
143
return 2;
264
+ },
144
}
265
+ .impl = {
145
#elif defined(TARGET_SPARC)
266
+ .max_access_size = 4,
146
- /* For (inf,0,nan) return c. */
267
+ },
147
- if (infzero) {
268
+};
148
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
269
+
149
- return 2;
270
+static void cprman_reset(DeviceState *dev)
150
- }
271
+{
151
/* Prefer SNaN over QNaN, order C, B, A. */
272
+ BCM2835CprmanState *s = CPRMAN(dev);
152
if (is_snan(c_cls)) {
273
+
153
return 2;
274
+ memset(s->regs, 0, sizeof(s->regs));
154
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
275
+
155
* For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
276
+ clock_update_hz(s->xosc, s->xosc_freq);
156
* an input NaN if we have one (ie c).
277
+}
157
*/
278
+
158
- if (infzero) {
279
+static void cprman_init(Object *obj)
159
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
280
+{
160
- return 2;
281
+ BCM2835CprmanState *s = CPRMAN(obj);
161
- }
282
+
162
if (status->use_first_nan) {
283
+ s->xosc = clock_new(obj, "xosc");
163
if (is_nan(a_cls)) {
284
+
164
return 0;
285
+ memory_region_init_io(&s->iomem, obj, &cprman_ops,
286
+ s, "bcm2835-cprman", 0x2000);
287
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
288
+}
289
+
290
+static const VMStateDescription cprman_vmstate = {
291
+ .name = TYPE_BCM2835_CPRMAN,
292
+ .version_id = 1,
293
+ .minimum_version_id = 1,
294
+ .fields = (VMStateField[]) {
295
+ VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS),
296
+ VMSTATE_END_OF_LIST()
297
+ }
298
+};
299
+
300
+static Property cprman_properties[] = {
301
+ DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000),
302
+ DEFINE_PROP_END_OF_LIST()
303
+};
304
+
305
+static void cprman_class_init(ObjectClass *klass, void *data)
306
+{
307
+ DeviceClass *dc = DEVICE_CLASS(klass);
308
+
309
+ dc->reset = cprman_reset;
310
+ dc->vmsd = &cprman_vmstate;
311
+ device_class_set_props(dc, cprman_properties);
312
+}
313
+
314
+static const TypeInfo cprman_info = {
315
+ .name = TYPE_BCM2835_CPRMAN,
316
+ .parent = TYPE_SYS_BUS_DEVICE,
317
+ .instance_size = sizeof(BCM2835CprmanState),
318
+ .class_init = cprman_class_init,
319
+ .instance_init = cprman_init,
320
+};
321
+
322
+static void cprman_register_types(void)
323
+{
324
+ type_register_static(&cprman_info);
325
+}
326
+
327
+type_init(cprman_register_types);
328
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
329
index XXXXXXX..XXXXXXX 100644
330
--- a/hw/misc/meson.build
331
+++ b/hw/misc/meson.build
332
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
333
'bcm2835_property.c',
334
'bcm2835_rng.c',
335
'bcm2835_thermal.c',
336
+ 'bcm2835_cprman.c',
337
))
338
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
339
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c'))
340
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
341
index XXXXXXX..XXXXXXX 100644
342
--- a/hw/misc/trace-events
343
+++ b/hw/misc/trace-events
344
@@ -XXX,XX +XXX,XX @@ grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx6
345
# pca9552.c
346
pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]"
347
pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, unsigned current_state) "%s GPIO id:%u status: %u -> %u"
348
+
349
+# bcm2835_cprman.c
350
+bcm2835_cprman_read(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
351
+bcm2835_cprman_write(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
352
+bcm2835_cprman_write_invalid_magic(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
353
--
165
--
354
2.20.1
166
2.34.1
355
356
diff view generated by jsdifflib
New patch
1
If the target sets default_nan_mode then we're always going to return
2
the default NaN, and pickNaNMulAdd() no longer has any side effects.
3
For consistency with pickNaN(), check for default_nan_mode before
4
calling pickNaNMulAdd().
1
5
6
When we convert pickNaNMulAdd() to allow runtime selection of the NaN
7
propagation rule, this means we won't have to make the targets which
8
use default_nan_mode also set a propagation rule.
9
10
Since RiscV always uses default_nan_mode, this allows us to remove
11
its ifdef case from pickNaNMulAdd().
12
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20241202131347.498124-3-peter.maydell@linaro.org
16
---
17
fpu/softfloat-parts.c.inc | 8 ++++++--
18
fpu/softfloat-specialize.c.inc | 9 +++++++--
19
2 files changed, 13 insertions(+), 4 deletions(-)
20
21
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
22
index XXXXXXX..XXXXXXX 100644
23
--- a/fpu/softfloat-parts.c.inc
24
+++ b/fpu/softfloat-parts.c.inc
25
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
26
float_raise(float_flag_invalid | float_flag_invalid_imz, s);
27
}
28
29
- which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
30
+ if (s->default_nan_mode) {
31
+ which = 3;
32
+ } else {
33
+ which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
34
+ }
35
36
- if (s->default_nan_mode || which == 3) {
37
+ if (which == 3) {
38
parts_default_nan(a, s);
39
return a;
40
}
41
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
42
index XXXXXXX..XXXXXXX 100644
43
--- a/fpu/softfloat-specialize.c.inc
44
+++ b/fpu/softfloat-specialize.c.inc
45
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
46
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
47
bool infzero, float_status *status)
48
{
49
+ /*
50
+ * We guarantee not to require the target to tell us how to
51
+ * pick a NaN if we're always returning the default NaN.
52
+ * But if we're not in default-NaN mode then the target must
53
+ * specify.
54
+ */
55
+ assert(!status->default_nan_mode);
56
#if defined(TARGET_ARM)
57
/* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
58
* the default NaN
59
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
60
} else {
61
return 1;
62
}
63
-#elif defined(TARGET_RISCV)
64
- return 3; /* default NaN */
65
#elif defined(TARGET_S390X)
66
if (infzero) {
67
return 3;
68
--
69
2.34.1
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
IEEE 758 does not define a fixed rule for what NaN to return in
2
2
the case of a fused multiply-add of inf * 0 + NaN. Different
3
The CPRMAN PLLs generate a clock based on a prescaler, a multiplier and
3
architectures thus do different things:
4
a divider. The prescaler doubles the parent (xosc) frequency, then the
4
* some return the default NaN
5
multiplier/divider are applied. The multiplier has an integer and a
5
* some return the input NaN
6
fractional part.
6
* Arm returns the default NaN if the input NaN is quiet,
7
7
and the input NaN if it is signalling
8
This commit also implements the CPRMAN CM_LOCK register. This register
8
9
reports which PLL is currently locked. We consider a PLL has being
9
We want to make this logic be runtime selected rather than
10
locked as soon as it is enabled (on real hardware, there is a delay
10
hardcoded into the binary, because:
11
after turning a PLL on, for it to stabilize).
11
* this will let us have multiple targets in one QEMU binary
12
12
* the Arm FEAT_AFP architectural feature includes letting
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
the guest select a NaN propagation rule at runtime
14
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
15
Signed-off-by: Luc Michel <luc@lmichel.fr>
15
In this commit we add an enum for the propagation rule, the field in
16
Tested-by: Guenter Roeck <linux@roeck-us.net>
16
float_status, and the corresponding getters and setters. We change
17
pickNaNMulAdd to honour this, but because all targets still leave
18
this field at its default 0 value, the fallback logic will pick the
19
rule type with the old ifdef ladder.
20
21
Note that four architectures both use the muladd softfloat functions
22
and did not have a branch of the ifdef ladder to specify their
23
behaviour (and so were ending up with the "default" case, probably
24
wrongly): i386, HPPA, SH4 and Tricore. SH4 and Tricore both set
25
default_nan_mode, and so will never get into pickNaNMulAdd(). For
26
HPPA and i386 we retain the same behaviour as the old default-case,
27
which is to not ever return the default NaN. This might not be
28
correct but it is not a behaviour change.
29
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
30
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
31
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
32
Message-id: 20241202131347.498124-4-peter.maydell@linaro.org
18
---
33
---
19
include/hw/misc/bcm2835_cprman_internals.h | 8 +++
34
include/fpu/softfloat-helpers.h | 11 ++++
20
hw/misc/bcm2835_cprman.c | 64 +++++++++++++++++++++-
35
include/fpu/softfloat-types.h | 23 +++++++++
21
2 files changed, 71 insertions(+), 1 deletion(-)
36
fpu/softfloat-specialize.c.inc | 91 ++++++++++++++++++++++-----------
22
37
3 files changed, 95 insertions(+), 30 deletions(-)
23
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
38
39
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
24
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/misc/bcm2835_cprman_internals.h
41
--- a/include/fpu/softfloat-helpers.h
26
+++ b/include/hw/misc/bcm2835_cprman_internals.h
42
+++ b/include/fpu/softfloat-helpers.h
27
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
43
@@ -XXX,XX +XXX,XX @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
28
REG32(A2W_PLLH_FRAC, 0x1260)
44
status->float_2nan_prop_rule = rule;
29
REG32(A2W_PLLB_FRAC, 0x12e0)
45
}
30
46
31
+/* misc registers */
47
+static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
32
+REG32(CM_LOCK, 0x114)
48
+ float_status *status)
33
+ FIELD(CM_LOCK, FLOCKH, 12, 1)
49
+{
34
+ FIELD(CM_LOCK, FLOCKD, 11, 1)
50
+ status->float_infzeronan_rule = rule;
35
+ FIELD(CM_LOCK, FLOCKC, 10, 1)
51
+}
36
+ FIELD(CM_LOCK, FLOCKB, 9, 1)
52
+
37
+ FIELD(CM_LOCK, FLOCKA, 8, 1)
53
static inline void set_flush_to_zero(bool val, float_status *status)
54
{
55
status->flush_to_zero = val;
56
@@ -XXX,XX +XXX,XX @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
57
return status->float_2nan_prop_rule;
58
}
59
60
+static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status)
61
+{
62
+ return status->float_infzeronan_rule;
63
+}
64
+
65
static inline bool get_flush_to_zero(float_status *status)
66
{
67
return status->flush_to_zero;
68
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
69
index XXXXXXX..XXXXXXX 100644
70
--- a/include/fpu/softfloat-types.h
71
+++ b/include/fpu/softfloat-types.h
72
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
73
float_2nan_prop_x87,
74
} Float2NaNPropRule;
75
76
+/*
77
+ * Rule for result of fused multiply-add 0 * Inf + NaN.
78
+ * This must be a NaN, but implementations differ on whether this
79
+ * is the input NaN or the default NaN.
80
+ *
81
+ * You don't need to set this if default_nan_mode is enabled.
82
+ * When not in default-NaN mode, it is an error for the target
83
+ * not to set the rule in float_status if it uses muladd, and we
84
+ * will assert if we need to handle an input NaN and no rule was
85
+ * selected.
86
+ */
87
+typedef enum __attribute__((__packed__)) {
88
+ /* No propagation rule specified */
89
+ float_infzeronan_none = 0,
90
+ /* Result is never the default NaN (so always the input NaN) */
91
+ float_infzeronan_dnan_never,
92
+ /* Result is always the default NaN */
93
+ float_infzeronan_dnan_always,
94
+ /* Result is the default NaN if the input NaN is quiet */
95
+ float_infzeronan_dnan_if_qnan,
96
+} FloatInfZeroNaNRule;
38
+
97
+
39
/*
98
/*
40
* This field is common to all registers. Each register write value must match
99
* Floating Point Status. Individual architectures may maintain
41
* the CPRMAN_PASSWORD magic value in its 8 MSB.
100
* several versions of float_status for different functions. The
42
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
101
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
102
FloatRoundMode float_rounding_mode;
103
FloatX80RoundPrec floatx80_rounding_precision;
104
Float2NaNPropRule float_2nan_prop_rule;
105
+ FloatInfZeroNaNRule float_infzeronan_rule;
106
bool tininess_before_rounding;
107
/* should denormalised results go to zero and set the inexact flag? */
108
bool flush_to_zero;
109
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
43
index XXXXXXX..XXXXXXX 100644
110
index XXXXXXX..XXXXXXX 100644
44
--- a/hw/misc/bcm2835_cprman.c
111
--- a/fpu/softfloat-specialize.c.inc
45
+++ b/hw/misc/bcm2835_cprman.c
112
+++ b/fpu/softfloat-specialize.c.inc
46
@@ -XXX,XX +XXX,XX @@
113
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
47
114
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
48
/* PLL */
115
bool infzero, float_status *status)
49
50
+static bool pll_is_locked(const CprmanPllState *pll)
51
+{
52
+ return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
53
+ && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST);
54
+}
55
+
56
static void pll_update(CprmanPllState *pll)
57
{
116
{
58
- clock_update(pll->out, 0);
117
+ FloatInfZeroNaNRule rule = status->float_infzeronan_rule;
59
+ uint64_t freq, ndiv, fdiv, pdiv;
118
+
60
+
119
/*
61
+ if (!pll_is_locked(pll)) {
120
* We guarantee not to require the target to tell us how to
62
+ clock_update(pll->out, 0);
121
* pick a NaN if we're always returning the default NaN.
63
+ return;
122
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
123
* specify.
124
*/
125
assert(!status->default_nan_mode);
126
+
127
+ if (rule == float_infzeronan_none) {
128
+ /*
129
+ * Temporarily fall back to ifdef ladder
130
+ */
131
#if defined(TARGET_ARM)
132
- /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
133
- * the default NaN
134
- */
135
- if (infzero && is_qnan(c_cls)) {
136
- return 3;
137
+ /*
138
+ * For ARM, the (inf,zero,qnan) case returns the default NaN,
139
+ * but (inf,zero,snan) returns the input NaN.
140
+ */
141
+ rule = float_infzeronan_dnan_if_qnan;
142
+#elif defined(TARGET_MIPS)
143
+ if (snan_bit_is_one(status)) {
144
+ /*
145
+ * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
146
+ * case sets InvalidOp and returns the default NaN
147
+ */
148
+ rule = float_infzeronan_dnan_always;
149
+ } else {
150
+ /*
151
+ * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
152
+ * case sets InvalidOp and returns the input value 'c'
153
+ */
154
+ rule = float_infzeronan_dnan_never;
155
+ }
156
+#elif defined(TARGET_PPC) || defined(TARGET_SPARC) || \
157
+ defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
158
+ defined(TARGET_I386) || defined(TARGET_LOONGARCH)
159
+ /*
160
+ * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
161
+ * case sets InvalidOp and returns the input value 'c'
162
+ */
163
+ /*
164
+ * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
165
+ * to return an input NaN if we have one (ie c) rather than generating
166
+ * a default NaN
167
+ */
168
+ rule = float_infzeronan_dnan_never;
169
+#elif defined(TARGET_S390X)
170
+ rule = float_infzeronan_dnan_always;
171
+#endif
172
}
173
174
+ if (infzero) {
175
+ /*
176
+ * Inf * 0 + NaN -- some implementations return the default NaN here,
177
+ * and some return the input NaN.
178
+ */
179
+ switch (rule) {
180
+ case float_infzeronan_dnan_never:
181
+ return 2;
182
+ case float_infzeronan_dnan_always:
183
+ return 3;
184
+ case float_infzeronan_dnan_if_qnan:
185
+ return is_qnan(c_cls) ? 3 : 2;
186
+ default:
187
+ g_assert_not_reached();
188
+ }
64
+ }
189
+ }
65
+
190
+
66
+ pdiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PDIV);
191
+#if defined(TARGET_ARM)
67
+
192
+
68
+ if (!pdiv) {
193
/* This looks different from the ARM ARM pseudocode, because the ARM ARM
69
+ clock_update(pll->out, 0);
194
* puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
70
+ return;
195
*/
71
+ }
196
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
72
+
197
}
73
+ ndiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, NDIV);
198
#elif defined(TARGET_MIPS)
74
+ fdiv = FIELD_EX32(*pll->reg_a2w_frac, A2W_PLLx_FRAC, FRAC);
199
if (snan_bit_is_one(status)) {
75
+
200
- /*
76
+ if (pll->reg_a2w_ana[1] & pll->prediv_mask) {
201
- * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
77
+ /* The prescaler doubles the parent frequency */
202
- * case sets InvalidOp and returns the default NaN
78
+ ndiv *= 2;
203
- */
79
+ fdiv *= 2;
204
- if (infzero) {
80
+ }
205
- return 3;
81
+
206
- }
82
+ /*
207
/* Prefer sNaN over qNaN, in the a, b, c order. */
83
+ * We have a multiplier with an integer part (ndiv) and a fractional part
208
if (is_snan(a_cls)) {
84
+ * (fdiv), and a divider (pdiv).
209
return 0;
85
+ */
210
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
86
+ freq = clock_get_hz(pll->xosc_in) *
211
return 2;
87
+ ((ndiv << R_A2W_PLLx_FRAC_FRAC_LENGTH) + fdiv);
212
}
88
+ freq /= pdiv;
213
} else {
89
+ freq >>= R_A2W_PLLx_FRAC_FRAC_LENGTH;
214
- /*
90
+
215
- * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
91
+ clock_update_hz(pll->out, freq);
216
- * case sets InvalidOp and returns the input value 'c'
92
}
217
- */
93
218
/* Prefer sNaN over qNaN, in the c, a, b order. */
94
static void pll_xosc_update(void *opaque)
219
if (is_snan(c_cls)) {
95
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
220
return 2;
96
221
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
97
/* CPRMAN "top level" model */
222
}
98
223
}
99
+static uint32_t get_cm_lock(const BCM2835CprmanState *s)
224
#elif defined(TARGET_LOONGARCH64)
100
+{
225
- /*
101
+ static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = {
226
- * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
102
+ [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT,
227
- * case sets InvalidOp and returns the input value 'c'
103
+ [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT,
228
- */
104
+ [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT,
229
-
105
+ [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT,
230
/* Prefer sNaN over qNaN, in the c, a, b order. */
106
+ [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT,
231
if (is_snan(c_cls)) {
107
+ };
232
return 2;
108
+
233
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
109
+ uint32_t r = 0;
234
return 1;
110
+ size_t i;
235
}
111
+
236
#elif defined(TARGET_PPC)
112
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
237
- /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
113
+ r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i];
238
- * to return an input NaN if we have one (ie c) rather than generating
114
+ }
239
- * a default NaN
115
+
240
- */
116
+ return r;
241
-
117
+}
242
/* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
118
+
243
* otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
119
static uint64_t cprman_read(void *opaque, hwaddr offset,
244
*/
120
unsigned size)
245
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
121
{
246
return 1;
122
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
247
}
123
size_t idx = offset / sizeof(uint32_t);
248
#elif defined(TARGET_S390X)
124
249
- if (infzero) {
125
switch (idx) {
250
- return 3;
126
+ case R_CM_LOCK:
251
- }
127
+ r = get_cm_lock(s);
252
-
128
+ break;
253
if (is_snan(a_cls)) {
129
+
254
return 0;
130
default:
255
} else if (is_snan(b_cls)) {
131
r = s->regs[idx];
132
}
133
--
256
--
134
2.20.1
257
2.34.1
135
136
diff view generated by jsdifflib
New patch
1
Explicitly set a rule in the softfloat tests for the inf-zero-nan
2
muladd special case. In meson.build we put -DTARGET_ARM in fpcflags,
3
and so we should select here the Arm rule of
4
float_infzeronan_dnan_if_qnan.
1
5
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20241202131347.498124-5-peter.maydell@linaro.org
9
---
10
tests/fp/fp-bench.c | 5 +++++
11
tests/fp/fp-test.c | 5 +++++
12
2 files changed, 10 insertions(+)
13
14
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/fp/fp-bench.c
17
+++ b/tests/fp/fp-bench.c
18
@@ -XXX,XX +XXX,XX @@ static void run_bench(void)
19
{
20
bench_func_t f;
21
22
+ /*
23
+ * These implementation-defined choices for various things IEEE
24
+ * doesn't specify match those used by the Arm architecture.
25
+ */
26
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
27
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
28
29
f = bench_funcs[operation][precision];
30
g_assert(f);
31
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/tests/fp/fp-test.c
34
+++ b/tests/fp/fp-test.c
35
@@ -XXX,XX +XXX,XX @@ void run_test(void)
36
{
37
unsigned int i;
38
39
+ /*
40
+ * These implementation-defined choices for various things IEEE
41
+ * doesn't specify match those used by the Arm architecture.
42
+ */
43
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
44
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
45
46
genCases_setLevel(test_level);
47
verCases_maxErrorCount = n_max_errors;
48
--
49
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the Arm target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-6-peter.maydell@linaro.org
7
---
8
target/arm/cpu.c | 3 +++
9
fpu/softfloat-specialize.c.inc | 8 +-------
10
2 files changed, 4 insertions(+), 7 deletions(-)
11
12
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/cpu.c
15
+++ b/target/arm/cpu.c
16
@@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
17
* * tininess-before-rounding
18
* * 2-input NaN propagation prefers SNaN over QNaN, and then
19
* operand A over operand B (see FPProcessNaNs() pseudocode)
20
+ * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
21
+ * and the input NaN if it is signalling
22
*/
23
static void arm_set_default_fp_behaviours(float_status *s)
24
{
25
set_float_detect_tininess(float_tininess_before_rounding, s);
26
set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
27
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
28
}
29
30
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
31
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
32
index XXXXXXX..XXXXXXX 100644
33
--- a/fpu/softfloat-specialize.c.inc
34
+++ b/fpu/softfloat-specialize.c.inc
35
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
36
/*
37
* Temporarily fall back to ifdef ladder
38
*/
39
-#if defined(TARGET_ARM)
40
- /*
41
- * For ARM, the (inf,zero,qnan) case returns the default NaN,
42
- * but (inf,zero,snan) returns the input NaN.
43
- */
44
- rule = float_infzeronan_dnan_if_qnan;
45
-#elif defined(TARGET_MIPS)
46
+#if defined(TARGET_MIPS)
47
if (snan_bit_is_one(status)) {
48
/*
49
* For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
50
--
51
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for s390, so we
2
can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-7-peter.maydell@linaro.org
7
---
8
target/s390x/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/s390x/cpu.c
15
+++ b/target/s390x/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
17
set_float_detect_tininess(float_tininess_before_rounding,
18
&env->fpu_status);
19
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status);
20
+ set_float_infzeronan_rule(float_infzeronan_dnan_always,
21
+ &env->fpu_status);
22
/* fall through */
23
case RESET_TYPE_S390_CPU_NORMAL:
24
env->psw.mask &= ~PSW_MASK_RI;
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
* a default NaN
31
*/
32
rule = float_infzeronan_dnan_never;
33
-#elif defined(TARGET_S390X)
34
- rule = float_infzeronan_dnan_always;
35
#endif
36
}
37
38
--
39
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the PPC target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-8-peter.maydell@linaro.org
7
---
8
target/ppc/cpu_init.c | 7 +++++++
9
fpu/softfloat-specialize.c.inc | 7 +------
10
2 files changed, 8 insertions(+), 6 deletions(-)
11
12
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/ppc/cpu_init.c
15
+++ b/target/ppc/cpu_init.c
16
@@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
17
*/
18
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
19
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status);
20
+ /*
21
+ * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
22
+ * to return an input NaN if we have one (ie c) rather than generating
23
+ * a default NaN
24
+ */
25
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
26
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status);
27
28
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
29
ppc_spr_t *spr = &env->spr_cb[i];
30
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
31
index XXXXXXX..XXXXXXX 100644
32
--- a/fpu/softfloat-specialize.c.inc
33
+++ b/fpu/softfloat-specialize.c.inc
34
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
35
*/
36
rule = float_infzeronan_dnan_never;
37
}
38
-#elif defined(TARGET_PPC) || defined(TARGET_SPARC) || \
39
+#elif defined(TARGET_SPARC) || \
40
defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
41
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
42
/*
43
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
44
* case sets InvalidOp and returns the input value 'c'
45
*/
46
- /*
47
- * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
48
- * to return an input NaN if we have one (ie c) rather than generating
49
- * a default NaN
50
- */
51
rule = float_infzeronan_dnan_never;
52
#endif
53
}
54
--
55
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the MIPS target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-9-peter.maydell@linaro.org
7
---
8
target/mips/fpu_helper.h | 9 +++++++++
9
target/mips/msa.c | 4 ++++
10
fpu/softfloat-specialize.c.inc | 16 +---------------
11
3 files changed, 14 insertions(+), 15 deletions(-)
12
13
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/mips/fpu_helper.h
16
+++ b/target/mips/fpu_helper.h
17
@@ -XXX,XX +XXX,XX @@ static inline void restore_flush_mode(CPUMIPSState *env)
18
static inline void restore_snan_bit_mode(CPUMIPSState *env)
19
{
20
bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
21
+ FloatInfZeroNaNRule izn_rule;
22
23
/*
24
* With nan2008, SNaNs are silenced in the usual way.
25
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
26
*/
27
set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status);
28
set_default_nan_mode(!nan2008, &env->active_fpu.fp_status);
29
+ /*
30
+ * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
31
+ * case sets InvalidOp and returns the default NaN.
32
+ * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
33
+ * case sets InvalidOp and returns the input value 'c'.
34
+ */
35
+ izn_rule = nan2008 ? float_infzeronan_dnan_never : float_infzeronan_dnan_always;
36
+ set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status);
37
}
38
39
static inline void restore_fp_status(CPUMIPSState *env)
40
diff --git a/target/mips/msa.c b/target/mips/msa.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/target/mips/msa.c
43
+++ b/target/mips/msa.c
44
@@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env)
45
46
/* set proper signanling bit meaning ("1" means "quiet") */
47
set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
48
+
49
+ /* Inf * 0 + NaN returns the input NaN */
50
+ set_float_infzeronan_rule(float_infzeronan_dnan_never,
51
+ &env->active_tc.msa_fp_status);
52
}
53
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
54
index XXXXXXX..XXXXXXX 100644
55
--- a/fpu/softfloat-specialize.c.inc
56
+++ b/fpu/softfloat-specialize.c.inc
57
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
58
/*
59
* Temporarily fall back to ifdef ladder
60
*/
61
-#if defined(TARGET_MIPS)
62
- if (snan_bit_is_one(status)) {
63
- /*
64
- * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
65
- * case sets InvalidOp and returns the default NaN
66
- */
67
- rule = float_infzeronan_dnan_always;
68
- } else {
69
- /*
70
- * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
71
- * case sets InvalidOp and returns the input value 'c'
72
- */
73
- rule = float_infzeronan_dnan_never;
74
- }
75
-#elif defined(TARGET_SPARC) || \
76
+#if defined(TARGET_SPARC) || \
77
defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
78
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
79
/*
80
--
81
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the SPARC target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-10-peter.maydell@linaro.org
7
---
8
target/sparc/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 3 +--
10
2 files changed, 3 insertions(+), 2 deletions(-)
11
12
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/sparc/cpu.c
15
+++ b/target/sparc/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
17
* the CPU state struct so it won't get zeroed on reset.
18
*/
19
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status);
20
+ /* For inf * 0 + NaN, return the input NaN */
21
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
22
23
cpu_exec_realizefn(cs, &local_err);
24
if (local_err != NULL) {
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
/*
31
* Temporarily fall back to ifdef ladder
32
*/
33
-#if defined(TARGET_SPARC) || \
34
- defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
35
+#if defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
36
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
37
/*
38
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
39
--
40
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the xtensa target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-11-peter.maydell@linaro.org
7
---
8
target/xtensa/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 2 +-
10
2 files changed, 3 insertions(+), 1 deletion(-)
11
12
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/xtensa/cpu.c
15
+++ b/target/xtensa/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
17
reset_mmu(env);
18
cs->halted = env->runstall;
19
#endif
20
+ /* For inf * 0 + NaN, return the input NaN */
21
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
22
set_no_signaling_nans(!dfpu, &env->fp_status);
23
xtensa_use_first_nan(env, !dfpu);
24
}
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
/*
31
* Temporarily fall back to ifdef ladder
32
*/
33
-#if defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
34
+#if defined(TARGET_HPPA) || \
35
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
36
/*
37
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
38
--
39
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the x86 target.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-12-peter.maydell@linaro.org
6
---
7
target/i386/tcg/fpu_helper.c | 7 +++++++
8
fpu/softfloat-specialize.c.inc | 2 +-
9
2 files changed, 8 insertions(+), 1 deletion(-)
10
11
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/target/i386/tcg/fpu_helper.c
14
+++ b/target/i386/tcg/fpu_helper.c
15
@@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env)
16
*/
17
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status);
18
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status);
19
+ /*
20
+ * Only SSE has multiply-add instructions. In the SDM Section 14.5.2
21
+ * "Fused-Multiply-ADD (FMA) Numeric Behavior" the NaN handling is
22
+ * specified -- for 0 * inf + NaN the input NaN is selected, and if
23
+ * there are multiple input NaNs they are selected in the order a, b, c.
24
+ */
25
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status);
26
}
27
28
static inline uint8_t save_exception_flags(CPUX86State *env)
29
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
30
index XXXXXXX..XXXXXXX 100644
31
--- a/fpu/softfloat-specialize.c.inc
32
+++ b/fpu/softfloat-specialize.c.inc
33
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
34
* Temporarily fall back to ifdef ladder
35
*/
36
#if defined(TARGET_HPPA) || \
37
- defined(TARGET_I386) || defined(TARGET_LOONGARCH)
38
+ defined(TARGET_LOONGARCH)
39
/*
40
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
41
* case sets InvalidOp and returns the input value 'c'
42
--
43
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the loongarch target.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-13-peter.maydell@linaro.org
6
---
7
target/loongarch/tcg/fpu_helper.c | 5 +++++
8
fpu/softfloat-specialize.c.inc | 7 +------
9
2 files changed, 6 insertions(+), 6 deletions(-)
10
11
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/target/loongarch/tcg/fpu_helper.c
14
+++ b/target/loongarch/tcg/fpu_helper.c
15
@@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env)
16
&env->fp_status);
17
set_flush_to_zero(0, &env->fp_status);
18
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
19
+ /*
20
+ * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
21
+ * case sets InvalidOp and returns the input value 'c'
22
+ */
23
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
24
}
25
26
int ieee_ex_to_loongarch(int xcpt)
27
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
28
index XXXXXXX..XXXXXXX 100644
29
--- a/fpu/softfloat-specialize.c.inc
30
+++ b/fpu/softfloat-specialize.c.inc
31
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
32
/*
33
* Temporarily fall back to ifdef ladder
34
*/
35
-#if defined(TARGET_HPPA) || \
36
- defined(TARGET_LOONGARCH)
37
- /*
38
- * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
39
- * case sets InvalidOp and returns the input value 'c'
40
- */
41
+#if defined(TARGET_HPPA)
42
rule = float_infzeronan_dnan_never;
43
#endif
44
}
45
--
46
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the HPPA target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
As this is the last target to be converted to explicitly setting
5
the rule, we can remove the fallback code in pickNaNMulAdd()
6
entirely.
7
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20241202131347.498124-14-peter.maydell@linaro.org
11
---
12
target/hppa/fpu_helper.c | 2 ++
13
fpu/softfloat-specialize.c.inc | 13 +------------
14
2 files changed, 3 insertions(+), 12 deletions(-)
15
16
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/hppa/fpu_helper.c
19
+++ b/target/hppa/fpu_helper.c
20
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
21
* HPPA does note implement a CPU reset method at all...
22
*/
23
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
24
+ /* For inf * 0 + NaN, return the input NaN */
25
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
26
}
27
28
void cpu_hppa_loaded_fr0(CPUHPPAState *env)
29
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
30
index XXXXXXX..XXXXXXX 100644
31
--- a/fpu/softfloat-specialize.c.inc
32
+++ b/fpu/softfloat-specialize.c.inc
33
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
34
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
35
bool infzero, float_status *status)
36
{
37
- FloatInfZeroNaNRule rule = status->float_infzeronan_rule;
38
-
39
/*
40
* We guarantee not to require the target to tell us how to
41
* pick a NaN if we're always returning the default NaN.
42
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
43
*/
44
assert(!status->default_nan_mode);
45
46
- if (rule == float_infzeronan_none) {
47
- /*
48
- * Temporarily fall back to ifdef ladder
49
- */
50
-#if defined(TARGET_HPPA)
51
- rule = float_infzeronan_dnan_never;
52
-#endif
53
- }
54
-
55
if (infzero) {
56
/*
57
* Inf * 0 + NaN -- some implementations return the default NaN here,
58
* and some return the input NaN.
59
*/
60
- switch (rule) {
61
+ switch (status->float_infzeronan_rule) {
62
case float_infzeronan_dnan_never:
63
return 2;
64
case float_infzeronan_dnan_always:
65
--
66
2.34.1
diff view generated by jsdifflib
New patch
1
The new implementation of pickNaNMulAdd() will find it convenient
2
to know whether at least one of the three arguments to the muladd
3
was a signaling NaN. We already calculate that in the caller,
4
so pass it in as a new bool have_snan.
1
5
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20241202131347.498124-15-peter.maydell@linaro.org
9
---
10
fpu/softfloat-parts.c.inc | 5 +++--
11
fpu/softfloat-specialize.c.inc | 2 +-
12
2 files changed, 4 insertions(+), 3 deletions(-)
13
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
15
index XXXXXXX..XXXXXXX 100644
16
--- a/fpu/softfloat-parts.c.inc
17
+++ b/fpu/softfloat-parts.c.inc
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
19
{
20
int which;
21
bool infzero = (ab_mask == float_cmask_infzero);
22
+ bool have_snan = (abc_mask & float_cmask_snan);
23
24
- if (unlikely(abc_mask & float_cmask_snan)) {
25
+ if (unlikely(have_snan)) {
26
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
27
}
28
29
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
30
if (s->default_nan_mode) {
31
which = 3;
32
} else {
33
- which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
34
+ which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, have_snan, s);
35
}
36
37
if (which == 3) {
38
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
39
index XXXXXXX..XXXXXXX 100644
40
--- a/fpu/softfloat-specialize.c.inc
41
+++ b/fpu/softfloat-specialize.c.inc
42
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
43
| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
44
*----------------------------------------------------------------------------*/
45
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
46
- bool infzero, float_status *status)
47
+ bool infzero, bool have_snan, float_status *status)
48
{
49
/*
50
* We guarantee not to require the target to tell us how to
51
--
52
2.34.1
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
IEEE 758 does not define a fixed rule for which NaN to pick as the
2
2
result if both operands of a 3-operand fused multiply-add operation
3
This simple mux sits between the PLL channels and the DSI0E and DSI0P
3
are NaNs. As a result different architectures have ended up with
4
clock muxes. This mux selects between PLLA-DSI0 and PLLD-DSI0 channel
4
different rules for propagating NaNs.
5
and outputs the selected signal to source number 4 of DSI0E/P clock
5
6
muxes. It is controlled by the cm_dsi0hsck register.
6
QEMU currently hardcodes the NaN propagation logic into the binary
7
7
because pickNaNMulAdd() has an ifdef ladder for different targets.
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
We want to make the propagation rule instead be selectable at
9
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
runtime, because:
10
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
* this will let us have multiple targets in one QEMU binary
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
* the Arm FEAT_AFP architectural feature includes letting
12
the guest select a NaN propagation rule at runtime
13
14
In this commit we add an enum for the propagation rule, the field in
15
float_status, and the corresponding getters and setters. We change
16
pickNaNMulAdd to honour this, but because all targets still leave
17
this field at its default 0 value, the fallback logic will pick the
18
rule type with the old ifdef ladder.
19
20
It's valid not to set a propagation rule if default_nan_mode is
21
enabled, because in that case there's no need to pick a NaN; all the
22
callers of pickNaNMulAdd() catch this case and skip calling it.
23
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
26
Message-id: 20241202131347.498124-16-peter.maydell@linaro.org
13
---
27
---
14
include/hw/misc/bcm2835_cprman.h | 15 +++++
28
include/fpu/softfloat-helpers.h | 11 +++
15
include/hw/misc/bcm2835_cprman_internals.h | 6 ++
29
include/fpu/softfloat-types.h | 55 +++++++++++
16
hw/misc/bcm2835_cprman.c | 74 +++++++++++++++++++++-
30
fpu/softfloat-specialize.c.inc | 167 ++++++++------------------------
17
3 files changed, 94 insertions(+), 1 deletion(-)
31
3 files changed, 107 insertions(+), 126 deletions(-)
18
32
19
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
33
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
20
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/misc/bcm2835_cprman.h
35
--- a/include/fpu/softfloat-helpers.h
22
+++ b/include/hw/misc/bcm2835_cprman.h
36
+++ b/include/fpu/softfloat-helpers.h
23
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanClockMuxState {
37
@@ -XXX,XX +XXX,XX @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
24
struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
38
status->float_2nan_prop_rule = rule;
25
} CprmanClockMuxState;
39
}
26
40
27
+typedef struct CprmanDsi0HsckMuxState {
41
+static inline void set_float_3nan_prop_rule(Float3NaNPropRule rule,
28
+ /*< private >*/
42
+ float_status *status)
29
+ DeviceState parent_obj;
43
+{
30
+
44
+ status->float_3nan_prop_rule = rule;
31
+ /*< public >*/
45
+}
32
+ CprmanClockMux id;
46
+
33
+
47
static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
34
+ uint32_t *reg_cm;
48
float_status *status)
35
+
49
{
36
+ Clock *plla_in;
50
@@ -XXX,XX +XXX,XX @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
37
+ Clock *plld_in;
51
return status->float_2nan_prop_rule;
38
+ Clock *out;
52
}
39
+} CprmanDsi0HsckMuxState;
53
40
+
54
+static inline Float3NaNPropRule get_float_3nan_prop_rule(float_status *status)
41
struct BCM2835CprmanState {
55
+{
42
/*< private >*/
56
+ return status->float_3nan_prop_rule;
43
SysBusDevice parent_obj;
57
+}
44
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
58
+
45
CprmanPllState plls[CPRMAN_NUM_PLL];
59
static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status)
46
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
60
{
47
CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
61
return status->float_infzeronan_rule;
48
+ CprmanDsi0HsckMuxState dsi0hsck_mux;
62
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
49
50
uint32_t regs[CPRMAN_NUM_REGS];
51
uint32_t xosc_freq;
52
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
53
index XXXXXXX..XXXXXXX 100644
63
index XXXXXXX..XXXXXXX 100644
54
--- a/include/hw/misc/bcm2835_cprman_internals.h
64
--- a/include/fpu/softfloat-types.h
55
+++ b/include/hw/misc/bcm2835_cprman_internals.h
65
+++ b/include/fpu/softfloat-types.h
56
@@ -XXX,XX +XXX,XX @@
66
@@ -XXX,XX +XXX,XX @@ this code that are retained.
57
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
67
#ifndef SOFTFLOAT_TYPES_H
58
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
68
#define SOFTFLOAT_TYPES_H
59
#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
69
60
+#define TYPE_CPRMAN_DSI0HSCK_MUX "bcm2835-cprman-dsi0hsck-mux"
70
+#include "hw/registerfields.h"
61
62
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
63
TYPE_CPRMAN_PLL)
64
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
65
TYPE_CPRMAN_PLL_CHANNEL)
66
DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
67
TYPE_CPRMAN_CLOCK_MUX)
68
+DECLARE_INSTANCE_CHECKER(CprmanDsi0HsckMuxState, CPRMAN_DSI0HSCK_MUX,
69
+ TYPE_CPRMAN_DSI0HSCK_MUX)
70
71
/* Register map */
72
73
@@ -XXX,XX +XXX,XX @@ REG32(CM_LOCK, 0x114)
74
FIELD(CM_LOCK, FLOCKB, 9, 1)
75
FIELD(CM_LOCK, FLOCKA, 8, 1)
76
77
+REG32(CM_DSI0HSCK, 0x120)
78
+ FIELD(CM_DSI0HSCK, SELPLLD, 0, 1)
79
+
71
+
80
/*
72
/*
81
* This field is common to all registers. Each register write value must match
73
* Software IEC/IEEE floating-point types.
82
* the CPRMAN_PASSWORD magic value in its 8 MSB.
74
*/
83
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
75
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
76
float_2nan_prop_x87,
77
} Float2NaNPropRule;
78
79
+/*
80
+ * 3-input NaN propagation rule, for fused multiply-add. Individual
81
+ * architectures have different rules for which input NaN is
82
+ * propagated to the output when there is more than one NaN on the
83
+ * input.
84
+ *
85
+ * If default_nan_mode is enabled then it is valid not to set a NaN
86
+ * propagation rule, because the softfloat code guarantees not to try
87
+ * to pick a NaN to propagate in default NaN mode. When not in
88
+ * default-NaN mode, it is an error for the target not to set the rule
89
+ * in float_status if it uses a muladd, and we will assert if we need
90
+ * to handle an input NaN and no rule was selected.
91
+ *
92
+ * The naming scheme for Float3NaNPropRule values is:
93
+ * float_3nan_prop_s_abc:
94
+ * = "Prefer SNaN over QNaN, then operand A over B over C"
95
+ * float_3nan_prop_abc:
96
+ * = "Prefer A over B over C regardless of SNaN vs QNAN"
97
+ *
98
+ * For QEMU, the multiply-add operation is A * B + C.
99
+ */
100
+
101
+/*
102
+ * We set the Float3NaNPropRule enum values up so we can select the
103
+ * right value in pickNaNMulAdd in a data driven way.
104
+ */
105
+FIELD(3NAN, 1ST, 0, 2) /* which operand is most preferred ? */
106
+FIELD(3NAN, 2ND, 2, 2) /* which operand is next most preferred ? */
107
+FIELD(3NAN, 3RD, 4, 2) /* which operand is least preferred ? */
108
+FIELD(3NAN, SNAN, 6, 1) /* do we prefer SNaN over QNaN ? */
109
+
110
+#define PROPRULE(X, Y, Z) \
111
+ ((X << R_3NAN_1ST_SHIFT) | (Y << R_3NAN_2ND_SHIFT) | (Z << R_3NAN_3RD_SHIFT))
112
+
113
+typedef enum __attribute__((__packed__)) {
114
+ float_3nan_prop_none = 0, /* No propagation rule specified */
115
+ float_3nan_prop_abc = PROPRULE(0, 1, 2),
116
+ float_3nan_prop_acb = PROPRULE(0, 2, 1),
117
+ float_3nan_prop_bac = PROPRULE(1, 0, 2),
118
+ float_3nan_prop_bca = PROPRULE(1, 2, 0),
119
+ float_3nan_prop_cab = PROPRULE(2, 0, 1),
120
+ float_3nan_prop_cba = PROPRULE(2, 1, 0),
121
+ float_3nan_prop_s_abc = float_3nan_prop_abc | R_3NAN_SNAN_MASK,
122
+ float_3nan_prop_s_acb = float_3nan_prop_acb | R_3NAN_SNAN_MASK,
123
+ float_3nan_prop_s_bac = float_3nan_prop_bac | R_3NAN_SNAN_MASK,
124
+ float_3nan_prop_s_bca = float_3nan_prop_bca | R_3NAN_SNAN_MASK,
125
+ float_3nan_prop_s_cab = float_3nan_prop_cab | R_3NAN_SNAN_MASK,
126
+ float_3nan_prop_s_cba = float_3nan_prop_cba | R_3NAN_SNAN_MASK,
127
+} Float3NaNPropRule;
128
+
129
+#undef PROPRULE
130
+
131
/*
132
* Rule for result of fused multiply-add 0 * Inf + NaN.
133
* This must be a NaN, but implementations differ on whether this
134
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
135
FloatRoundMode float_rounding_mode;
136
FloatX80RoundPrec floatx80_rounding_precision;
137
Float2NaNPropRule float_2nan_prop_rule;
138
+ Float3NaNPropRule float_3nan_prop_rule;
139
FloatInfZeroNaNRule float_infzeronan_rule;
140
bool tininess_before_rounding;
141
/* should denormalised results go to zero and set the inexact flag? */
142
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
84
index XXXXXXX..XXXXXXX 100644
143
index XXXXXXX..XXXXXXX 100644
85
--- a/hw/misc/bcm2835_cprman.c
144
--- a/fpu/softfloat-specialize.c.inc
86
+++ b/hw/misc/bcm2835_cprman.c
145
+++ b/fpu/softfloat-specialize.c.inc
87
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_clock_mux_info = {
146
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
88
};
147
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
89
148
bool infzero, bool have_snan, float_status *status)
90
149
{
91
+/* DSI0HSCK mux */
150
+ FloatClass cls[3] = { a_cls, b_cls, c_cls };
92
+
151
+ Float3NaNPropRule rule = status->float_3nan_prop_rule;
93
+static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
152
+ int which;
94
+{
153
+
95
+ bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD);
154
/*
96
+ Clock *src = src_is_plld ? s->plld_in : s->plla_in;
155
* We guarantee not to require the target to tell us how to
97
+
156
* pick a NaN if we're always returning the default NaN.
98
+ clock_update(s->out, clock_get(src));
157
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
99
+}
100
+
101
+static void dsi0hsck_mux_in_update(void *opaque)
102
+{
103
+ dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
104
+}
105
+
106
+static void dsi0hsck_mux_init(Object *obj)
107
+{
108
+ CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
109
+ DeviceState *dev = DEVICE(obj);
110
+
111
+ s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s);
112
+ s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s);
113
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
114
+}
115
+
116
+static const VMStateDescription dsi0hsck_mux_vmstate = {
117
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
118
+ .version_id = 1,
119
+ .minimum_version_id = 1,
120
+ .fields = (VMStateField[]) {
121
+ VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState),
122
+ VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState),
123
+ VMSTATE_END_OF_LIST()
124
+ }
125
+};
126
+
127
+static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data)
128
+{
129
+ DeviceClass *dc = DEVICE_CLASS(klass);
130
+
131
+ dc->vmsd = &dsi0hsck_mux_vmstate;
132
+}
133
+
134
+static const TypeInfo cprman_dsi0hsck_mux_info = {
135
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
136
+ .parent = TYPE_DEVICE,
137
+ .instance_size = sizeof(CprmanDsi0HsckMuxState),
138
+ .class_init = dsi0hsck_mux_class_init,
139
+ .instance_init = dsi0hsck_mux_init,
140
+};
141
+
142
+
143
/* CPRMAN "top level" model */
144
145
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
146
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
147
case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
148
update_mux_from_cm(s, idx);
149
break;
150
+
151
+ case R_CM_DSI0HSCK:
152
+ dsi0hsck_mux_update(&s->dsi0hsck_mux);
153
+ break;
154
}
155
}
156
157
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
158
device_cold_reset(DEVICE(&s->channels[i]));
159
}
160
161
+ device_cold_reset(DEVICE(&s->dsi0hsck_mux));
162
+
163
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
164
device_cold_reset(DEVICE(&s->clock_muxes[i]));
165
}
166
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
167
set_pll_channel_init_info(s, &s->channels[i], i);
168
}
169
170
+ object_initialize_child(obj, "dsi0hsck-mux",
171
+ &s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX);
172
+ s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK];
173
+
174
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
175
char *alias;
176
177
@@ -XXX,XX +XXX,XX @@ static void connect_mux_sources(BCM2835CprmanState *s,
178
if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
179
src = s->gnd;
180
} else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
181
- src = s->gnd; /* TODO */
182
+ src = s->dsi0hsck_mux.out;
183
} else if (i < CPRMAN_CLOCK_SRC_PLLA) {
184
src = CLK_SRC_MAPPING[i];
185
} else {
186
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
187
}
158
}
188
}
159
}
189
160
190
+ clock_set_source(s->dsi0hsck_mux.plla_in,
161
+ if (rule == float_3nan_prop_none) {
191
+ s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out);
162
#if defined(TARGET_ARM)
192
+ clock_set_source(s->dsi0hsck_mux.plld_in,
163
-
193
+ s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out);
164
- /* This looks different from the ARM ARM pseudocode, because the ARM ARM
194
+
165
- * puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
195
+ if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) {
166
- */
196
+ return;
167
- if (is_snan(c_cls)) {
168
- return 2;
169
- } else if (is_snan(a_cls)) {
170
- return 0;
171
- } else if (is_snan(b_cls)) {
172
- return 1;
173
- } else if (is_qnan(c_cls)) {
174
- return 2;
175
- } else if (is_qnan(a_cls)) {
176
- return 0;
177
- } else {
178
- return 1;
179
- }
180
+ /*
181
+ * This looks different from the ARM ARM pseudocode, because the ARM ARM
182
+ * puts the operands to a fused mac operation (a*b)+c in the order c,a,b
183
+ */
184
+ rule = float_3nan_prop_s_cab;
185
#elif defined(TARGET_MIPS)
186
- if (snan_bit_is_one(status)) {
187
- /* Prefer sNaN over qNaN, in the a, b, c order. */
188
- if (is_snan(a_cls)) {
189
- return 0;
190
- } else if (is_snan(b_cls)) {
191
- return 1;
192
- } else if (is_snan(c_cls)) {
193
- return 2;
194
- } else if (is_qnan(a_cls)) {
195
- return 0;
196
- } else if (is_qnan(b_cls)) {
197
- return 1;
198
+ if (snan_bit_is_one(status)) {
199
+ rule = float_3nan_prop_s_abc;
200
} else {
201
- return 2;
202
+ rule = float_3nan_prop_s_cab;
203
}
204
- } else {
205
- /* Prefer sNaN over qNaN, in the c, a, b order. */
206
- if (is_snan(c_cls)) {
207
- return 2;
208
- } else if (is_snan(a_cls)) {
209
- return 0;
210
- } else if (is_snan(b_cls)) {
211
- return 1;
212
- } else if (is_qnan(c_cls)) {
213
- return 2;
214
- } else if (is_qnan(a_cls)) {
215
- return 0;
216
- } else {
217
- return 1;
218
- }
219
- }
220
#elif defined(TARGET_LOONGARCH64)
221
- /* Prefer sNaN over qNaN, in the c, a, b order. */
222
- if (is_snan(c_cls)) {
223
- return 2;
224
- } else if (is_snan(a_cls)) {
225
- return 0;
226
- } else if (is_snan(b_cls)) {
227
- return 1;
228
- } else if (is_qnan(c_cls)) {
229
- return 2;
230
- } else if (is_qnan(a_cls)) {
231
- return 0;
232
- } else {
233
- return 1;
234
- }
235
+ rule = float_3nan_prop_s_cab;
236
#elif defined(TARGET_PPC)
237
- /* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
238
- * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
239
- */
240
- if (is_nan(a_cls)) {
241
- return 0;
242
- } else if (is_nan(c_cls)) {
243
- return 2;
244
- } else {
245
- return 1;
246
- }
247
+ /*
248
+ * If fRA is a NaN return it; otherwise if fRB is a NaN return it;
249
+ * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
250
+ */
251
+ rule = float_3nan_prop_acb;
252
#elif defined(TARGET_S390X)
253
- if (is_snan(a_cls)) {
254
- return 0;
255
- } else if (is_snan(b_cls)) {
256
- return 1;
257
- } else if (is_snan(c_cls)) {
258
- return 2;
259
- } else if (is_qnan(a_cls)) {
260
- return 0;
261
- } else if (is_qnan(b_cls)) {
262
- return 1;
263
- } else {
264
- return 2;
265
- }
266
+ rule = float_3nan_prop_s_abc;
267
#elif defined(TARGET_SPARC)
268
- /* Prefer SNaN over QNaN, order C, B, A. */
269
- if (is_snan(c_cls)) {
270
- return 2;
271
- } else if (is_snan(b_cls)) {
272
- return 1;
273
- } else if (is_snan(a_cls)) {
274
- return 0;
275
- } else if (is_qnan(c_cls)) {
276
- return 2;
277
- } else if (is_qnan(b_cls)) {
278
- return 1;
279
- } else {
280
- return 0;
281
- }
282
+ rule = float_3nan_prop_s_cba;
283
#elif defined(TARGET_XTENSA)
284
- /*
285
- * For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
286
- * an input NaN if we have one (ie c).
287
- */
288
- if (status->use_first_nan) {
289
- if (is_nan(a_cls)) {
290
- return 0;
291
- } else if (is_nan(b_cls)) {
292
- return 1;
293
+ if (status->use_first_nan) {
294
+ rule = float_3nan_prop_abc;
295
} else {
296
- return 2;
297
+ rule = float_3nan_prop_cba;
298
}
299
- } else {
300
- if (is_nan(c_cls)) {
301
- return 2;
302
- } else if (is_nan(b_cls)) {
303
- return 1;
304
- } else {
305
- return 0;
306
- }
307
- }
308
#else
309
- /* A default implementation: prefer a to b to c.
310
- * This is unlikely to actually match any real implementation.
311
- */
312
- if (is_nan(a_cls)) {
313
- return 0;
314
- } else if (is_nan(b_cls)) {
315
- return 1;
316
- } else {
317
- return 2;
318
- }
319
+ rule = float_3nan_prop_abc;
320
#endif
197
+ }
321
+ }
198
+
322
+
199
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
323
+ assert(rule != float_3nan_prop_none);
200
CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
324
+ if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
201
325
+ /* We have at least one SNaN input and should prefer it */
202
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
326
+ do {
203
type_register_static(&cprman_pll_info);
327
+ which = rule & R_3NAN_1ST_MASK;
204
type_register_static(&cprman_pll_channel_info);
328
+ rule >>= R_3NAN_1ST_LENGTH;
205
type_register_static(&cprman_clock_mux_info);
329
+ } while (!is_snan(cls[which]));
206
+ type_register_static(&cprman_dsi0hsck_mux_info);
330
+ } else {
331
+ do {
332
+ which = rule & R_3NAN_1ST_MASK;
333
+ rule >>= R_3NAN_1ST_LENGTH;
334
+ } while (!is_nan(cls[which]));
335
+ }
336
+ return which;
207
}
337
}
208
338
209
type_init(cprman_register_types);
339
/*----------------------------------------------------------------------------
210
--
340
--
211
2.20.1
341
2.34.1
212
213
diff view generated by jsdifflib
New patch
1
Explicitly set a rule in the softfloat tests for propagating NaNs in
2
the muladd case. In meson.build we put -DTARGET_ARM in fpcflags, and
3
so we should select here the Arm rule of float_3nan_prop_s_cab.
1
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20241202131347.498124-17-peter.maydell@linaro.org
8
---
9
tests/fp/fp-bench.c | 1 +
10
tests/fp/fp-test.c | 1 +
11
2 files changed, 2 insertions(+)
12
13
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/fp/fp-bench.c
16
+++ b/tests/fp/fp-bench.c
17
@@ -XXX,XX +XXX,XX @@ static void run_bench(void)
18
* doesn't specify match those used by the Arm architecture.
19
*/
20
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
21
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status);
22
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
23
24
f = bench_funcs[operation][precision];
25
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/tests/fp/fp-test.c
28
+++ b/tests/fp/fp-test.c
29
@@ -XXX,XX +XXX,XX @@ void run_test(void)
30
* doesn't specify match those used by the Arm architecture.
31
*/
32
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
33
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf);
34
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
35
36
genCases_setLevel(test_level);
37
--
38
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for Arm, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-18-peter.maydell@linaro.org
7
---
8
target/arm/cpu.c | 5 +++++
9
fpu/softfloat-specialize.c.inc | 8 +-------
10
2 files changed, 6 insertions(+), 7 deletions(-)
11
12
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/cpu.c
15
+++ b/target/arm/cpu.c
16
@@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
17
* * tininess-before-rounding
18
* * 2-input NaN propagation prefers SNaN over QNaN, and then
19
* operand A over operand B (see FPProcessNaNs() pseudocode)
20
+ * * 3-input NaN propagation prefers SNaN over QNaN, and then
21
+ * operand C over A over B (see FPProcessNaNs3() pseudocode,
22
+ * but note that for QEMU muladd is a * b + c, whereas for
23
+ * the pseudocode function the arguments are in the order c, a, b.
24
* * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
25
* and the input NaN if it is signalling
26
*/
27
@@ -XXX,XX +XXX,XX @@ static void arm_set_default_fp_behaviours(float_status *s)
28
{
29
set_float_detect_tininess(float_tininess_before_rounding, s);
30
set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
31
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
32
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
33
}
34
35
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
36
index XXXXXXX..XXXXXXX 100644
37
--- a/fpu/softfloat-specialize.c.inc
38
+++ b/fpu/softfloat-specialize.c.inc
39
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
40
}
41
42
if (rule == float_3nan_prop_none) {
43
-#if defined(TARGET_ARM)
44
- /*
45
- * This looks different from the ARM ARM pseudocode, because the ARM ARM
46
- * puts the operands to a fused mac operation (a*b)+c in the order c,a,b
47
- */
48
- rule = float_3nan_prop_s_cab;
49
-#elif defined(TARGET_MIPS)
50
+#if defined(TARGET_MIPS)
51
if (snan_bit_is_one(status)) {
52
rule = float_3nan_prop_s_abc;
53
} else {
54
--
55
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for loongarch, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-19-peter.maydell@linaro.org
7
---
8
target/loongarch/tcg/fpu_helper.c | 1 +
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 1 insertion(+), 2 deletions(-)
11
12
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/loongarch/tcg/fpu_helper.c
15
+++ b/target/loongarch/tcg/fpu_helper.c
16
@@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env)
17
* case sets InvalidOp and returns the input value 'c'
18
*/
19
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
20
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &env->fp_status);
21
}
22
23
int ieee_ex_to_loongarch(int xcpt)
24
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
25
index XXXXXXX..XXXXXXX 100644
26
--- a/fpu/softfloat-specialize.c.inc
27
+++ b/fpu/softfloat-specialize.c.inc
28
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
29
} else {
30
rule = float_3nan_prop_s_cab;
31
}
32
-#elif defined(TARGET_LOONGARCH64)
33
- rule = float_3nan_prop_s_cab;
34
#elif defined(TARGET_PPC)
35
/*
36
* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
37
--
38
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for PPC, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-20-peter.maydell@linaro.org
7
---
8
target/ppc/cpu_init.c | 8 ++++++++
9
fpu/softfloat-specialize.c.inc | 6 ------
10
2 files changed, 8 insertions(+), 6 deletions(-)
11
12
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/ppc/cpu_init.c
15
+++ b/target/ppc/cpu_init.c
16
@@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
17
*/
18
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
19
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status);
20
+ /*
21
+ * NaN propagation for fused multiply-add:
22
+ * if fRA is a NaN return it; otherwise if fRB is a NaN return it;
23
+ * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
24
+ * whereas QEMU labels the operands as (a * b) + c.
25
+ */
26
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->fp_status);
27
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->vec_status);
28
/*
29
* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
30
* to return an input NaN if we have one (ie c) rather than generating
31
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
32
index XXXXXXX..XXXXXXX 100644
33
--- a/fpu/softfloat-specialize.c.inc
34
+++ b/fpu/softfloat-specialize.c.inc
35
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
36
} else {
37
rule = float_3nan_prop_s_cab;
38
}
39
-#elif defined(TARGET_PPC)
40
- /*
41
- * If fRA is a NaN return it; otherwise if fRB is a NaN return it;
42
- * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
43
- */
44
- rule = float_3nan_prop_acb;
45
#elif defined(TARGET_S390X)
46
rule = float_3nan_prop_s_abc;
47
#elif defined(TARGET_SPARC)
48
--
49
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for s390x, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-21-peter.maydell@linaro.org
7
---
8
target/s390x/cpu.c | 1 +
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 1 insertion(+), 2 deletions(-)
11
12
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/s390x/cpu.c
15
+++ b/target/s390x/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
17
set_float_detect_tininess(float_tininess_before_rounding,
18
&env->fpu_status);
19
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status);
20
+ set_float_3nan_prop_rule(float_3nan_prop_s_abc, &env->fpu_status);
21
set_float_infzeronan_rule(float_infzeronan_dnan_always,
22
&env->fpu_status);
23
/* fall through */
24
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
25
index XXXXXXX..XXXXXXX 100644
26
--- a/fpu/softfloat-specialize.c.inc
27
+++ b/fpu/softfloat-specialize.c.inc
28
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
29
} else {
30
rule = float_3nan_prop_s_cab;
31
}
32
-#elif defined(TARGET_S390X)
33
- rule = float_3nan_prop_s_abc;
34
#elif defined(TARGET_SPARC)
35
rule = float_3nan_prop_s_cba;
36
#elif defined(TARGET_XTENSA)
37
--
38
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for SPARC, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-22-peter.maydell@linaro.org
7
---
8
target/sparc/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/sparc/cpu.c
15
+++ b/target/sparc/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
17
* the CPU state struct so it won't get zeroed on reset.
18
*/
19
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status);
20
+ /* For fused-multiply add, prefer SNaN over QNaN, then C->B->A */
21
+ set_float_3nan_prop_rule(float_3nan_prop_s_cba, &env->fp_status);
22
/* For inf * 0 + NaN, return the input NaN */
23
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
24
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
} else {
31
rule = float_3nan_prop_s_cab;
32
}
33
-#elif defined(TARGET_SPARC)
34
- rule = float_3nan_prop_s_cba;
35
#elif defined(TARGET_XTENSA)
36
if (status->use_first_nan) {
37
rule = float_3nan_prop_abc;
38
--
39
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for Arm, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-23-peter.maydell@linaro.org
7
---
8
target/mips/fpu_helper.h | 4 ++++
9
target/mips/msa.c | 3 +++
10
fpu/softfloat-specialize.c.inc | 8 +-------
11
3 files changed, 8 insertions(+), 7 deletions(-)
12
13
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/mips/fpu_helper.h
16
+++ b/target/mips/fpu_helper.h
17
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
18
{
19
bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
20
FloatInfZeroNaNRule izn_rule;
21
+ Float3NaNPropRule nan3_rule;
22
23
/*
24
* With nan2008, SNaNs are silenced in the usual way.
25
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
26
*/
27
izn_rule = nan2008 ? float_infzeronan_dnan_never : float_infzeronan_dnan_always;
28
set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status);
29
+ nan3_rule = nan2008 ? float_3nan_prop_s_cab : float_3nan_prop_s_abc;
30
+ set_float_3nan_prop_rule(nan3_rule, &env->active_fpu.fp_status);
31
+
32
}
33
34
static inline void restore_fp_status(CPUMIPSState *env)
35
diff --git a/target/mips/msa.c b/target/mips/msa.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/mips/msa.c
38
+++ b/target/mips/msa.c
39
@@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env)
40
set_float_2nan_prop_rule(float_2nan_prop_s_ab,
41
&env->active_tc.msa_fp_status);
42
43
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab,
44
+ &env->active_tc.msa_fp_status);
45
+
46
/* clear float_status exception flags */
47
set_float_exception_flags(0, &env->active_tc.msa_fp_status);
48
49
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
50
index XXXXXXX..XXXXXXX 100644
51
--- a/fpu/softfloat-specialize.c.inc
52
+++ b/fpu/softfloat-specialize.c.inc
53
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
54
}
55
56
if (rule == float_3nan_prop_none) {
57
-#if defined(TARGET_MIPS)
58
- if (snan_bit_is_one(status)) {
59
- rule = float_3nan_prop_s_abc;
60
- } else {
61
- rule = float_3nan_prop_s_cab;
62
- }
63
-#elif defined(TARGET_XTENSA)
64
+#if defined(TARGET_XTENSA)
65
if (status->use_first_nan) {
66
rule = float_3nan_prop_abc;
67
} else {
68
--
69
2.34.1
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the Float3NaNPropRule explicitly for xtensa, and remove the
2
ifdef from pickNaNMulAdd().
2
3
3
The realize() function is clearly composed of two parts,
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
each described by a comment:
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-24-peter.maydell@linaro.org
7
---
8
target/xtensa/fpu_helper.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 8 --------
10
2 files changed, 2 insertions(+), 8 deletions(-)
5
11
6
void realize()
12
diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c
7
{
8
/* common peripherals from bcm2835 */
9
...
10
/* bcm2836 interrupt controller (and mailboxes, etc.) */
11
...
12
}
13
14
Split the two part, so we can reuse the common part with other
15
SoCs from this family.
16
17
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
18
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
19
Message-id: 20201024170127.3592182-6-f4bug@amsat.org
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
---
22
hw/arm/bcm2836.c | 22 ++++++++++++++++++----
23
1 file changed, 18 insertions(+), 4 deletions(-)
24
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
26
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/arm/bcm2836.c
14
--- a/target/xtensa/fpu_helper.c
28
+++ b/hw/arm/bcm2836.c
15
+++ b/target/xtensa/fpu_helper.c
29
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
16
@@ -XXX,XX +XXX,XX @@ void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
30
qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
17
set_use_first_nan(use_first, &env->fp_status);
18
set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
19
&env->fp_status);
20
+ set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba,
21
+ &env->fp_status);
22
}
23
24
void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
31
}
30
}
32
31
33
- object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
32
if (rule == float_3nan_prop_none) {
34
+ if (bc->ctrl_base) {
33
-#if defined(TARGET_XTENSA)
35
+ object_initialize_child(obj, "control", &s->control,
34
- if (status->use_first_nan) {
36
+ TYPE_BCM2836_CONTROL);
35
- rule = float_3nan_prop_abc;
37
+ }
36
- } else {
38
37
- rule = float_3nan_prop_cba;
39
object_initialize_child(obj, "peripherals", &s->peripherals,
38
- }
40
TYPE_BCM2835_PERIPHERALS);
39
-#else
41
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
40
rule = float_3nan_prop_abc;
42
"vcram-size");
41
-#endif
43
}
44
45
-static void bcm2836_realize(DeviceState *dev, Error **errp)
46
+static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
47
{
48
BCM283XState *s = BCM283X(dev);
49
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
50
Object *obj;
51
- int n;
52
53
/* common peripherals from bcm2835 */
54
55
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
56
object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj);
57
58
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) {
59
- return;
60
+ return false;
61
}
42
}
62
43
63
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
44
assert(rule != float_3nan_prop_none);
64
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
65
66
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
67
bc->peri_base, 1);
68
+ return true;
69
+}
70
+
71
+static void bcm2836_realize(DeviceState *dev, Error **errp)
72
+{
73
+ BCM283XState *s = BCM283X(dev);
74
+ BCM283XClass *bc = BCM283X_GET_CLASS(dev);
75
+ int n;
76
+
77
+ if (!bcm283x_common_realize(dev, errp)) {
78
+ return;
79
+ }
80
81
/* bcm2836 interrupt controller (and mailboxes, etc.) */
82
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
83
--
45
--
84
2.20.1
46
2.34.1
85
86
diff view generated by jsdifflib
1
From: Zenghui Yu <yuzenghui@huawei.com>
1
Set the Float3NaNPropRule explicitly for i386. We had no
2
i386-specific behaviour in the old ifdef ladder, so we were using the
3
default "prefer a then b then c" fallback; this is actually the
4
correct per-the-spec handling for i386.
2
5
3
Ensure the vSMMUv3 will be restored before all PCIe devices so that DMA
4
translation can work properly during migration.
5
6
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
7
Message-id: 20201019091508.197-1-yuzenghui@huawei.com
8
Acked-by: Eric Auger <eric.auger@redhat.com>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20241202131347.498124-25-peter.maydell@linaro.org
10
---
9
---
11
hw/arm/smmuv3.c | 1 +
10
target/i386/tcg/fpu_helper.c | 1 +
12
1 file changed, 1 insertion(+)
11
1 file changed, 1 insertion(+)
13
12
14
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
13
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/smmuv3.c
15
--- a/target/i386/tcg/fpu_helper.c
17
+++ b/hw/arm/smmuv3.c
16
+++ b/target/i386/tcg/fpu_helper.c
18
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_smmuv3 = {
17
@@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env)
19
.name = "smmuv3",
18
* there are multiple input NaNs they are selected in the order a, b, c.
20
.version_id = 1,
19
*/
21
.minimum_version_id = 1,
20
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status);
22
+ .priority = MIG_PRI_IOMMU,
21
+ set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status);
23
.fields = (VMStateField[]) {
22
}
24
VMSTATE_UINT32(features, SMMUv3State),
23
25
VMSTATE_UINT8(sid_size, SMMUv3State),
24
static inline uint8_t save_exception_flags(CPUX86State *env)
26
--
25
--
27
2.20.1
26
2.34.1
28
29
diff view generated by jsdifflib
1
From: Havard Skinnemoen <hskinnemoen@google.com>
1
Set the Float3NaNPropRule explicitly for HPPA, and remove the
2
ifdef from pickNaNMulAdd().
2
3
3
The NPCM730 and NPCM750 chips have a single USB host port shared between
4
HPPA is the only target that was using the default branch of the
4
a USB 2.0 EHCI host controller and a USB 1.1 OHCI host controller. This
5
ifdef ladder (other targets either do not use muladd or set
5
adds support for both of them.
6
default_nan_mode), so we can remove the ifdef fallback entirely now
7
(allowing the "rule not set" case to fall into the default of the
8
switch statement and assert).
6
9
7
Testing notes:
10
We add a TODO note that the HPPA rule is probably wrong; this is
8
* With -device usb-kbd, qemu will automatically insert a full-speed
11
not a behavioural change for this refactoring.
9
hub, and the keyboard becomes controlled by the OHCI controller.
10
* With -device usb-kbd,bus=usb-bus.0,port=1, the keyboard is directly
11
attached to the port without any hubs, and the device becomes
12
controlled by the EHCI controller since it's high speed capable.
13
* With -device usb-kbd,bus=usb-bus.0,port=1,usb_version=1, the
14
keyboard is directly attached to the port, but it only advertises
15
itself as full-speed capable, so it becomes controlled by the OHCI
16
controller.
17
12
18
In all cases, the keyboard device enumerates correctly.
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20241202131347.498124-26-peter.maydell@linaro.org
16
---
17
target/hppa/fpu_helper.c | 8 ++++++++
18
fpu/softfloat-specialize.c.inc | 4 ----
19
2 files changed, 8 insertions(+), 4 deletions(-)
19
20
20
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
21
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
21
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
22
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
---
25
docs/system/arm/nuvoton.rst | 2 +-
26
hw/usb/hcd-ehci.h | 1 +
27
include/hw/arm/npcm7xx.h | 4 ++++
28
hw/arm/npcm7xx.c | 27 +++++++++++++++++++++++++--
29
hw/usb/hcd-ehci-sysbus.c | 19 +++++++++++++++++++
30
5 files changed, 50 insertions(+), 3 deletions(-)
31
32
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
33
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
34
--- a/docs/system/arm/nuvoton.rst
23
--- a/target/hppa/fpu_helper.c
35
+++ b/docs/system/arm/nuvoton.rst
24
+++ b/target/hppa/fpu_helper.c
36
@@ -XXX,XX +XXX,XX @@ Supported devices
25
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
37
* OTP controllers (no protection features)
26
* HPPA does note implement a CPU reset method at all...
38
* Flash Interface Unit (FIU; no protection features)
27
*/
39
* Random Number Generator (RNG)
28
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
40
+ * USB host (USBH)
29
+ /*
41
30
+ * TODO: The HPPA architecture reference only documents its NaN
42
Missing devices
31
+ * propagation rule for 2-operand operations. Testing on real hardware
43
---------------
32
+ * might be necessary to confirm whether this order for muladd is correct.
44
@@ -XXX,XX +XXX,XX @@ Missing devices
33
+ * Not preferring the SNaN is almost certainly incorrect as it diverges
45
* eSPI slave interface
34
+ * from the documented rules for 2-operand operations.
46
35
+ */
47
* Ethernet controllers (GMAC and EMC)
36
+ set_float_3nan_prop_rule(float_3nan_prop_abc, &env->fp_status);
48
- * USB host (USBH)
37
/* For inf * 0 + NaN, return the input NaN */
49
* USB device (USBD)
38
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
50
* SMBus controller (SMBF)
39
}
51
* Peripheral SPI controller (PSPI)
40
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
52
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
53
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
54
--- a/hw/usb/hcd-ehci.h
42
--- a/fpu/softfloat-specialize.c.inc
55
+++ b/hw/usb/hcd-ehci.h
43
+++ b/fpu/softfloat-specialize.c.inc
56
@@ -XXX,XX +XXX,XX @@ struct EHCIPCIState {
44
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
57
#define TYPE_PLATFORM_EHCI "platform-ehci-usb"
45
}
58
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
59
#define TYPE_AW_H3_EHCI "aw-h3-ehci-usb"
60
+#define TYPE_NPCM7XX_EHCI "npcm7xx-ehci-usb"
61
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
62
#define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb"
63
#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
64
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
65
index XXXXXXX..XXXXXXX 100644
66
--- a/include/hw/arm/npcm7xx.h
67
+++ b/include/hw/arm/npcm7xx.h
68
@@ -XXX,XX +XXX,XX @@
69
#include "hw/nvram/npcm7xx_otp.h"
70
#include "hw/timer/npcm7xx_timer.h"
71
#include "hw/ssi/npcm7xx_fiu.h"
72
+#include "hw/usb/hcd-ehci.h"
73
+#include "hw/usb/hcd-ohci.h"
74
#include "target/arm/cpu.h"
75
76
#define NPCM7XX_MAX_NUM_CPUS (2)
77
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
78
NPCM7xxOTPState fuse_array;
79
NPCM7xxMCState mc;
80
NPCM7xxRNGState rng;
81
+ EHCISysBusState ehci;
82
+ OHCISysBusState ohci;
83
NPCM7xxFIUState fiu[2];
84
} NPCM7xxState;
85
86
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/arm/npcm7xx.c
89
+++ b/hw/arm/npcm7xx.c
90
@@ -XXX,XX +XXX,XX @@
91
#define NPCM7XX_MC_BA (0xf0824000)
92
#define NPCM7XX_RNG_BA (0xf000b000)
93
94
+/* USB Host modules */
95
+#define NPCM7XX_EHCI_BA (0xf0806000)
96
+#define NPCM7XX_OHCI_BA (0xf0807000)
97
+
98
/* Internal AHB SRAM */
99
#define NPCM7XX_RAM3_BA (0xc0008000)
100
#define NPCM7XX_RAM3_SZ (4 * KiB)
101
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
102
NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
103
NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
104
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
105
+ NPCM7XX_EHCI_IRQ = 61,
106
+ NPCM7XX_OHCI_IRQ = 62,
107
};
108
109
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
110
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
111
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
112
}
46
}
113
47
114
+ object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
48
- if (rule == float_3nan_prop_none) {
115
+ object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
49
- rule = float_3nan_prop_abc;
116
+
50
- }
117
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
51
-
118
for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
52
assert(rule != float_3nan_prop_none);
119
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
53
if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
120
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
54
/* We have at least one SNaN input and should prefer it */
121
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
122
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
123
124
+ /* USB Host */
125
+ object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
126
+ &error_abort);
127
+ sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_abort);
128
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0, NPCM7XX_EHCI_BA);
129
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0,
130
+ npcm7xx_irq(s, NPCM7XX_EHCI_IRQ));
131
+
132
+ object_property_set_str(OBJECT(&s->ohci), "masterbus", "usb-bus.0",
133
+ &error_abort);
134
+ object_property_set_uint(OBJECT(&s->ohci), "num-ports", 1, &error_abort);
135
+ sysbus_realize(SYS_BUS_DEVICE(&s->ohci), &error_abort);
136
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci), 0, NPCM7XX_OHCI_BA);
137
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
138
+ npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
139
+
140
/*
141
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
142
* specified, but this is a programming error.
143
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
144
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
145
create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
146
create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB);
147
- create_unimplemented_device("npcm7xx.ehci", 0xf0806000, 4 * KiB);
148
- create_unimplemented_device("npcm7xx.ohci", 0xf0807000, 4 * KiB);
149
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
150
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
151
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
152
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/hw/usb/hcd-ehci-sysbus.c
155
+++ b/hw/usb/hcd-ehci-sysbus.c
156
@@ -XXX,XX +XXX,XX @@ static const TypeInfo ehci_aw_h3_type_info = {
157
.class_init = ehci_aw_h3_class_init,
158
};
159
160
+static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data)
161
+{
162
+ SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
163
+ DeviceClass *dc = DEVICE_CLASS(oc);
164
+
165
+ sec->capsbase = 0x0;
166
+ sec->opregbase = 0x10;
167
+ sec->portscbase = 0x44;
168
+ sec->portnr = 1;
169
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
170
+}
171
+
172
+static const TypeInfo ehci_npcm7xx_type_info = {
173
+ .name = TYPE_NPCM7XX_EHCI,
174
+ .parent = TYPE_SYS_BUS_EHCI,
175
+ .class_init = ehci_npcm7xx_class_init,
176
+};
177
+
178
static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
179
{
180
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
181
@@ -XXX,XX +XXX,XX @@ static void ehci_sysbus_register_types(void)
182
type_register_static(&ehci_platform_type_info);
183
type_register_static(&ehci_exynos4210_type_info);
184
type_register_static(&ehci_aw_h3_type_info);
185
+ type_register_static(&ehci_npcm7xx_type_info);
186
type_register_static(&ehci_tegra2_type_info);
187
type_register_static(&ehci_ppc4xx_type_info);
188
type_register_static(&ehci_fusbh200_type_info);
189
--
55
--
190
2.20.1
56
2.34.1
191
192
diff view generated by jsdifflib
New patch
1
The use_first_nan field in float_status was an xtensa-specific way to
2
select at runtime from two different NaN propagation rules. Now that
3
xtensa is using the target-agnostic NaN propagation rule selection
4
that we've just added, we can remove use_first_nan, because there is
5
no longer any code that reads it.
1
6
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20241202131347.498124-27-peter.maydell@linaro.org
10
---
11
include/fpu/softfloat-helpers.h | 5 -----
12
include/fpu/softfloat-types.h | 1 -
13
target/xtensa/fpu_helper.c | 1 -
14
3 files changed, 7 deletions(-)
15
16
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/fpu/softfloat-helpers.h
19
+++ b/include/fpu/softfloat-helpers.h
20
@@ -XXX,XX +XXX,XX @@ static inline void set_snan_bit_is_one(bool val, float_status *status)
21
status->snan_bit_is_one = val;
22
}
23
24
-static inline void set_use_first_nan(bool val, float_status *status)
25
-{
26
- status->use_first_nan = val;
27
-}
28
-
29
static inline void set_no_signaling_nans(bool val, float_status *status)
30
{
31
status->no_signaling_nans = val;
32
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/fpu/softfloat-types.h
35
+++ b/include/fpu/softfloat-types.h
36
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
37
* softfloat-specialize.inc.c)
38
*/
39
bool snan_bit_is_one;
40
- bool use_first_nan;
41
bool no_signaling_nans;
42
/* should overflowed results subtract re_bias to its exponent? */
43
bool rebias_overflow;
44
diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/target/xtensa/fpu_helper.c
47
+++ b/target/xtensa/fpu_helper.c
48
@@ -XXX,XX +XXX,XX @@ static const struct {
49
50
void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
51
{
52
- set_use_first_nan(use_first, &env->fp_status);
53
set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
54
&env->fp_status);
55
set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba,
56
--
57
2.34.1
diff view generated by jsdifflib
New patch
1
Currently m68k_cpu_reset_hold() calls floatx80_default_nan(NULL)
2
to get the NaN bit pattern to reset the FPU registers. This
3
works because it happens that our implementation of
4
floatx80_default_nan() doesn't actually look at the float_status
5
pointer except for TARGET_MIPS. However, this isn't guaranteed,
6
and to be able to remove the ifdef in floatx80_default_nan()
7
we're going to need a real float_status here.
1
8
9
Rearrange m68k_cpu_reset_hold() so that we initialize env->fp_status
10
earlier, and thus can pass it to floatx80_default_nan().
11
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20241202131347.498124-28-peter.maydell@linaro.org
15
---
16
target/m68k/cpu.c | 12 +++++++-----
17
1 file changed, 7 insertions(+), 5 deletions(-)
18
19
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/target/m68k/cpu.c
22
+++ b/target/m68k/cpu.c
23
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
24
CPUState *cs = CPU(obj);
25
M68kCPUClass *mcc = M68K_CPU_GET_CLASS(obj);
26
CPUM68KState *env = cpu_env(cs);
27
- floatx80 nan = floatx80_default_nan(NULL);
28
+ floatx80 nan;
29
int i;
30
31
if (mcc->parent_phases.hold) {
32
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
33
#else
34
cpu_m68k_set_sr(env, SR_S | SR_I);
35
#endif
36
- for (i = 0; i < 8; i++) {
37
- env->fregs[i].d = nan;
38
- }
39
- cpu_m68k_set_fpcr(env, 0);
40
/*
41
* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
42
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
43
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
44
* preceding paragraph for nonsignaling NaNs.
45
*/
46
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
47
+
48
+ nan = floatx80_default_nan(&env->fp_status);
49
+ for (i = 0; i < 8; i++) {
50
+ env->fregs[i].d = nan;
51
+ }
52
+ cpu_m68k_set_fpcr(env, 0);
53
env->fpsr = 0;
54
55
/* TODO: We should set PC from the interrupt vector. */
56
--
57
2.34.1
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
We create our 128-bit default NaN by calling parts64_default_nan()
2
and then adjusting the result. We can do the same trick for creating
3
the floatx80 default NaN, which lets us drop a target ifdef.
2
4
3
PLLs are composed of multiple channels. Each channel outputs one clock
5
floatx80 is used only by:
4
signal. They are modeled as one device taking the PLL generated clock as
6
i386
5
input, and outputting a new clock.
7
m68k
8
arm nwfpe old floating-point emulation emulation support
9
(which is essentially dead, especially the parts involving floatx80)
10
PPC (only in the xsrqpxp instruction, which just rounds an input
11
value by converting to floatx80 and back, so will never generate
12
the default NaN)
6
13
7
A channel shares the CM register with its parent PLL, and has its own
14
The floatx80 default NaN as currently implemented is:
8
A2W_CTRL register. A write to the CM register will trigger an update of
15
m68k: sign = 0, exp = 1...1, int = 1, frac = 1....1
9
the PLL and all its channels, while a write to an A2W_CTRL channel
16
i386: sign = 1, exp = 1...1, int = 1, frac = 10...0
10
register will update the required channel only.
11
17
12
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
18
These are the same as the parts64_default_nan for these architectures.
13
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
19
14
Signed-off-by: Luc Michel <luc@lmichel.fr>
20
This is technically a possible behaviour change for arm linux-user
15
Tested-by: Guenter Roeck <linux@roeck-us.net>
21
nwfpe emulation emulation, because the default NaN will now have the
22
sign bit clear. But we were already generating a different floatx80
23
default NaN from the real kernel emulation we are supposedly
24
following, which appears to use an all-bits-1 value:
25
https://elixir.bootlin.com/linux/v6.12/source/arch/arm/nwfpe/softfloat-specialize#L267
26
27
This won't affect the only "real" use of the nwfpe emulation, which
28
is ancient binaries that used it as part of the old floating point
29
calling convention; that only uses loads and stores of 32 and 64 bit
30
floats, not any of the floatx80 behaviour the original hardware had.
31
We also get the nwfpe float64 default NaN value wrong:
32
https://elixir.bootlin.com/linux/v6.12/source/arch/arm/nwfpe/softfloat-specialize#L166
33
so if we ever cared about this obscure corner the right fix would be
34
to correct that so nwfpe used its own default-NaN setting rather
35
than the Arm VFP one.
36
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
38
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
39
Message-id: 20241202131347.498124-29-peter.maydell@linaro.org
17
---
40
---
18
include/hw/misc/bcm2835_cprman.h | 44 ++++++
41
fpu/softfloat-specialize.c.inc | 20 ++++++++++----------
19
include/hw/misc/bcm2835_cprman_internals.h | 146 +++++++++++++++++++
42
1 file changed, 10 insertions(+), 10 deletions(-)
20
hw/misc/bcm2835_cprman.c | 155 +++++++++++++++++++--
21
3 files changed, 337 insertions(+), 8 deletions(-)
22
43
23
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
44
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
24
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/misc/bcm2835_cprman.h
46
--- a/fpu/softfloat-specialize.c.inc
26
+++ b/include/hw/misc/bcm2835_cprman.h
47
+++ b/fpu/softfloat-specialize.c.inc
27
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPll {
48
@@ -XXX,XX +XXX,XX @@ static void parts128_silence_nan(FloatParts128 *p, float_status *status)
28
CPRMAN_NUM_PLL
49
floatx80 floatx80_default_nan(float_status *status)
29
} CprmanPll;
50
{
30
51
floatx80 r;
31
+typedef enum CprmanPllChannel {
52
+ /*
32
+ CPRMAN_PLLA_CHANNEL_DSI0 = 0,
53
+ * Extrapolate from the choices made by parts64_default_nan to fill
33
+ CPRMAN_PLLA_CHANNEL_CORE,
54
+ * in the floatx80 format. We assume that floatx80's explicit
34
+ CPRMAN_PLLA_CHANNEL_PER,
55
+ * integer bit is always set (this is true for i386 and m68k,
35
+ CPRMAN_PLLA_CHANNEL_CCP2,
56
+ * which are the only real users of this format).
36
+
57
+ */
37
+ CPRMAN_PLLC_CHANNEL_CORE2,
58
+ FloatParts64 p64;
38
+ CPRMAN_PLLC_CHANNEL_CORE1,
59
+ parts64_default_nan(&p64, status);
39
+ CPRMAN_PLLC_CHANNEL_PER,
60
40
+ CPRMAN_PLLC_CHANNEL_CORE0,
61
- /* None of the targets that have snan_bit_is_one use floatx80. */
41
+
62
- assert(!snan_bit_is_one(status));
42
+ CPRMAN_PLLD_CHANNEL_DSI0,
63
-#if defined(TARGET_M68K)
43
+ CPRMAN_PLLD_CHANNEL_CORE,
64
- r.low = UINT64_C(0xFFFFFFFFFFFFFFFF);
44
+ CPRMAN_PLLD_CHANNEL_PER,
65
- r.high = 0x7FFF;
45
+ CPRMAN_PLLD_CHANNEL_DSI1,
66
-#else
46
+
67
- /* X86 */
47
+ CPRMAN_PLLH_CHANNEL_AUX,
68
- r.low = UINT64_C(0xC000000000000000);
48
+ CPRMAN_PLLH_CHANNEL_RCAL,
69
- r.high = 0xFFFF;
49
+ CPRMAN_PLLH_CHANNEL_PIX,
70
-#endif
50
+
71
+ r.high = 0x7FFF | (p64.sign << 15);
51
+ CPRMAN_PLLB_CHANNEL_ARM,
72
+ r.low = (1ULL << DECOMPOSED_BINARY_POINT) | p64.frac;
52
+
53
+ CPRMAN_NUM_PLL_CHANNEL,
54
+} CprmanPllChannel;
55
+
56
typedef struct CprmanPllState {
57
/*< private >*/
58
DeviceState parent_obj;
59
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllState {
60
Clock *out;
61
} CprmanPllState;
62
63
+typedef struct CprmanPllChannelState {
64
+ /*< private >*/
65
+ DeviceState parent_obj;
66
+
67
+ /*< public >*/
68
+ CprmanPllChannel id;
69
+ CprmanPll parent;
70
+
71
+ uint32_t *reg_cm;
72
+ uint32_t hold_mask;
73
+ uint32_t load_mask;
74
+ uint32_t *reg_a2w_ctrl;
75
+ int fixed_divider;
76
+
77
+ Clock *pll_in;
78
+ Clock *out;
79
+} CprmanPllChannelState;
80
+
81
struct BCM2835CprmanState {
82
/*< private >*/
83
SysBusDevice parent_obj;
84
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
85
MemoryRegion iomem;
86
87
CprmanPllState plls[CPRMAN_NUM_PLL];
88
+ CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
89
90
uint32_t regs[CPRMAN_NUM_REGS];
91
uint32_t xosc_freq;
92
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
93
index XXXXXXX..XXXXXXX 100644
94
--- a/include/hw/misc/bcm2835_cprman_internals.h
95
+++ b/include/hw/misc/bcm2835_cprman_internals.h
96
@@ -XXX,XX +XXX,XX @@
97
#include "hw/misc/bcm2835_cprman.h"
98
99
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
100
+#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
101
102
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
103
TYPE_CPRMAN_PLL)
104
+DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
105
+ TYPE_CPRMAN_PLL_CHANNEL)
106
107
/* Register map */
108
109
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
110
REG32(A2W_PLLH_FRAC, 0x1260)
111
REG32(A2W_PLLB_FRAC, 0x12e0)
112
113
+/* PLL channels */
114
+REG32(A2W_PLLA_DSI0, 0x1300)
115
+ FIELD(A2W_PLLx_CHANNELy, DIV, 0, 8)
116
+ FIELD(A2W_PLLx_CHANNELy, DISABLE, 8, 1)
117
+REG32(A2W_PLLA_CORE, 0x1400)
118
+REG32(A2W_PLLA_PER, 0x1500)
119
+REG32(A2W_PLLA_CCP2, 0x1600)
120
+
121
+REG32(A2W_PLLC_CORE2, 0x1320)
122
+REG32(A2W_PLLC_CORE1, 0x1420)
123
+REG32(A2W_PLLC_PER, 0x1520)
124
+REG32(A2W_PLLC_CORE0, 0x1620)
125
+
126
+REG32(A2W_PLLD_DSI0, 0x1340)
127
+REG32(A2W_PLLD_CORE, 0x1440)
128
+REG32(A2W_PLLD_PER, 0x1540)
129
+REG32(A2W_PLLD_DSI1, 0x1640)
130
+
131
+REG32(A2W_PLLH_AUX, 0x1360)
132
+REG32(A2W_PLLH_RCAL, 0x1460)
133
+REG32(A2W_PLLH_PIX, 0x1560)
134
+REG32(A2W_PLLH_STS, 0x1660)
135
+
136
+REG32(A2W_PLLB_ARM, 0x13e0)
137
+
138
/* misc registers */
139
REG32(CM_LOCK, 0x114)
140
FIELD(CM_LOCK, FLOCKH, 12, 1)
141
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_init_info(BCM2835CprmanState *s,
142
pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
143
}
144
145
+
146
+/* PLL channel init info */
147
+typedef struct PLLChannelInitInfo {
148
+ const char *name;
149
+ CprmanPll parent;
150
+ size_t cm_offset;
151
+ uint32_t cm_hold_mask;
152
+ uint32_t cm_load_mask;
153
+ size_t a2w_ctrl_offset;
154
+ unsigned int fixed_divider;
155
+} PLLChannelInitInfo;
156
+
157
+#define FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_) \
158
+ .parent = CPRMAN_ ## pll_, \
159
+ .cm_offset = R_CM_ ## pll_, \
160
+ .cm_load_mask = R_CM_ ## pll_ ## _ ## LOAD ## channel_ ## _MASK, \
161
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _ ## channel_
162
+
163
+#define FILL_PLL_CHANNEL_INIT_INFO(pll_, channel_) \
164
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
165
+ .cm_hold_mask = R_CM_ ## pll_ ## _ ## HOLD ## channel_ ## _MASK, \
166
+ .fixed_divider = 1
167
+
168
+#define FILL_PLL_CHANNEL_INIT_INFO_nohold(pll_, channel_) \
169
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
170
+ .cm_hold_mask = 0
171
+
172
+static PLLChannelInitInfo PLL_CHANNEL_INIT_INFO[] = {
173
+ [CPRMAN_PLLA_CHANNEL_DSI0] = {
174
+ .name = "plla-dsi0",
175
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, DSI0),
176
+ },
177
+ [CPRMAN_PLLA_CHANNEL_CORE] = {
178
+ .name = "plla-core",
179
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CORE),
180
+ },
181
+ [CPRMAN_PLLA_CHANNEL_PER] = {
182
+ .name = "plla-per",
183
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, PER),
184
+ },
185
+ [CPRMAN_PLLA_CHANNEL_CCP2] = {
186
+ .name = "plla-ccp2",
187
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CCP2),
188
+ },
189
+
190
+ [CPRMAN_PLLC_CHANNEL_CORE2] = {
191
+ .name = "pllc-core2",
192
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE2),
193
+ },
194
+ [CPRMAN_PLLC_CHANNEL_CORE1] = {
195
+ .name = "pllc-core1",
196
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE1),
197
+ },
198
+ [CPRMAN_PLLC_CHANNEL_PER] = {
199
+ .name = "pllc-per",
200
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, PER),
201
+ },
202
+ [CPRMAN_PLLC_CHANNEL_CORE0] = {
203
+ .name = "pllc-core0",
204
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE0),
205
+ },
206
+
207
+ [CPRMAN_PLLD_CHANNEL_DSI0] = {
208
+ .name = "plld-dsi0",
209
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI0),
210
+ },
211
+ [CPRMAN_PLLD_CHANNEL_CORE] = {
212
+ .name = "plld-core",
213
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, CORE),
214
+ },
215
+ [CPRMAN_PLLD_CHANNEL_PER] = {
216
+ .name = "plld-per",
217
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, PER),
218
+ },
219
+ [CPRMAN_PLLD_CHANNEL_DSI1] = {
220
+ .name = "plld-dsi1",
221
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI1),
222
+ },
223
+
224
+ [CPRMAN_PLLH_CHANNEL_AUX] = {
225
+ .name = "pllh-aux",
226
+ .fixed_divider = 1,
227
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, AUX),
228
+ },
229
+ [CPRMAN_PLLH_CHANNEL_RCAL] = {
230
+ .name = "pllh-rcal",
231
+ .fixed_divider = 10,
232
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, RCAL),
233
+ },
234
+ [CPRMAN_PLLH_CHANNEL_PIX] = {
235
+ .name = "pllh-pix",
236
+ .fixed_divider = 10,
237
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, PIX),
238
+ },
239
+
240
+ [CPRMAN_PLLB_CHANNEL_ARM] = {
241
+ .name = "pllb-arm",
242
+ FILL_PLL_CHANNEL_INIT_INFO(PLLB, ARM),
243
+ },
244
+};
245
+
246
+#undef FILL_PLL_CHANNEL_INIT_INFO_nohold
247
+#undef FILL_PLL_CHANNEL_INIT_INFO
248
+#undef FILL_PLL_CHANNEL_INIT_INFO_common
249
+
250
+static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
251
+ CprmanPllChannelState *channel,
252
+ CprmanPllChannel id)
253
+{
254
+ channel->id = id;
255
+ channel->parent = PLL_CHANNEL_INIT_INFO[id].parent;
256
+ channel->reg_cm = &s->regs[PLL_CHANNEL_INIT_INFO[id].cm_offset];
257
+ channel->hold_mask = PLL_CHANNEL_INIT_INFO[id].cm_hold_mask;
258
+ channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask;
259
+ channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset];
260
+ channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
261
+}
262
+
263
#endif
264
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
265
index XXXXXXX..XXXXXXX 100644
266
--- a/hw/misc/bcm2835_cprman.c
267
+++ b/hw/misc/bcm2835_cprman.c
268
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
269
};
270
271
272
+/* PLL channel */
273
+
274
+static void pll_channel_update(CprmanPllChannelState *channel)
275
+{
276
+ clock_update(channel->out, 0);
277
+}
278
+
279
+/* Update a PLL and all its channels */
280
+static void pll_update_all_channels(BCM2835CprmanState *s,
281
+ CprmanPllState *pll)
282
+{
283
+ size_t i;
284
+
285
+ pll_update(pll);
286
+
287
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
288
+ CprmanPllChannelState *channel = &s->channels[i];
289
+ if (channel->parent == pll->id) {
290
+ pll_channel_update(channel);
291
+ }
292
+ }
293
+}
294
+
295
+static void pll_channel_pll_in_update(void *opaque)
296
+{
297
+ pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
298
+}
299
+
300
+static void pll_channel_init(Object *obj)
301
+{
302
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
303
+
304
+ s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
305
+ pll_channel_pll_in_update, s);
306
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
307
+}
308
+
309
+static const VMStateDescription pll_channel_vmstate = {
310
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
311
+ .version_id = 1,
312
+ .minimum_version_id = 1,
313
+ .fields = (VMStateField[]) {
314
+ VMSTATE_CLOCK(pll_in, CprmanPllChannelState),
315
+ VMSTATE_END_OF_LIST()
316
+ }
317
+};
318
+
319
+static void pll_channel_class_init(ObjectClass *klass, void *data)
320
+{
321
+ DeviceClass *dc = DEVICE_CLASS(klass);
322
+
323
+ dc->vmsd = &pll_channel_vmstate;
324
+}
325
+
326
+static const TypeInfo cprman_pll_channel_info = {
327
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
328
+ .parent = TYPE_DEVICE,
329
+ .instance_size = sizeof(CprmanPllChannelState),
330
+ .class_init = pll_channel_class_init,
331
+ .instance_init = pll_channel_init,
332
+};
333
+
334
+
335
/* CPRMAN "top level" model */
336
337
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
338
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
339
return r;
73
return r;
340
}
74
}
341
75
342
-#define CASE_PLL_REGS(pll_) \
343
- case R_CM_ ## pll_: \
344
+static inline void update_pll_and_channels_from_cm(BCM2835CprmanState *s,
345
+ size_t idx)
346
+{
347
+ size_t i;
348
+
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ if (PLL_INIT_INFO[i].cm_offset == idx) {
351
+ pll_update_all_channels(s, &s->plls[i]);
352
+ return;
353
+ }
354
+ }
355
+}
356
+
357
+static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
358
+{
359
+ size_t i;
360
+
361
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
362
+ if (PLL_CHANNEL_INIT_INFO[i].a2w_ctrl_offset == idx) {
363
+ pll_channel_update(&s->channels[i]);
364
+ return;
365
+ }
366
+ }
367
+}
368
+
369
+#define CASE_PLL_A2W_REGS(pll_) \
370
case R_A2W_ ## pll_ ## _CTRL: \
371
case R_A2W_ ## pll_ ## _ANA0: \
372
case R_A2W_ ## pll_ ## _ANA1: \
373
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
374
s->regs[idx] = value;
375
376
switch (idx) {
377
- CASE_PLL_REGS(PLLA) :
378
+ case R_CM_PLLA ... R_CM_PLLH:
379
+ case R_CM_PLLB:
380
+ /*
381
+ * A given CM_PLLx register is shared by both the PLL and the channels
382
+ * of this PLL.
383
+ */
384
+ update_pll_and_channels_from_cm(s, idx);
385
+ break;
386
+
387
+ CASE_PLL_A2W_REGS(PLLA) :
388
pll_update(&s->plls[CPRMAN_PLLA]);
389
break;
390
391
- CASE_PLL_REGS(PLLC) :
392
+ CASE_PLL_A2W_REGS(PLLC) :
393
pll_update(&s->plls[CPRMAN_PLLC]);
394
break;
395
396
- CASE_PLL_REGS(PLLD) :
397
+ CASE_PLL_A2W_REGS(PLLD) :
398
pll_update(&s->plls[CPRMAN_PLLD]);
399
break;
400
401
- CASE_PLL_REGS(PLLH) :
402
+ CASE_PLL_A2W_REGS(PLLH) :
403
pll_update(&s->plls[CPRMAN_PLLH]);
404
break;
405
406
- CASE_PLL_REGS(PLLB) :
407
+ CASE_PLL_A2W_REGS(PLLB) :
408
pll_update(&s->plls[CPRMAN_PLLB]);
409
break;
410
+
411
+ case R_A2W_PLLA_DSI0:
412
+ case R_A2W_PLLA_CORE:
413
+ case R_A2W_PLLA_PER:
414
+ case R_A2W_PLLA_CCP2:
415
+ case R_A2W_PLLC_CORE2:
416
+ case R_A2W_PLLC_CORE1:
417
+ case R_A2W_PLLC_PER:
418
+ case R_A2W_PLLC_CORE0:
419
+ case R_A2W_PLLD_DSI0:
420
+ case R_A2W_PLLD_CORE:
421
+ case R_A2W_PLLD_PER:
422
+ case R_A2W_PLLD_DSI1:
423
+ case R_A2W_PLLH_AUX:
424
+ case R_A2W_PLLH_RCAL:
425
+ case R_A2W_PLLH_PIX:
426
+ case R_A2W_PLLB_ARM:
427
+ update_channel_from_a2w(s, idx);
428
+ break;
429
}
430
}
431
432
-#undef CASE_PLL_REGS
433
+#undef CASE_PLL_A2W_REGS
434
435
static const MemoryRegionOps cprman_ops = {
436
.read = cprman_read,
437
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
438
device_cold_reset(DEVICE(&s->plls[i]));
439
}
440
441
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
442
+ device_cold_reset(DEVICE(&s->channels[i]));
443
+ }
444
+
445
clock_update_hz(s->xosc, s->xosc_freq);
446
}
447
448
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
449
set_pll_init_info(s, &s->plls[i], i);
450
}
451
452
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
453
+ object_initialize_child(obj, PLL_CHANNEL_INIT_INFO[i].name,
454
+ &s->channels[i],
455
+ TYPE_CPRMAN_PLL_CHANNEL);
456
+ set_pll_channel_init_info(s, &s->channels[i], i);
457
+ }
458
+
459
s->xosc = clock_new(obj, "xosc");
460
461
memory_region_init_io(&s->iomem, obj, &cprman_ops,
462
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
463
return;
464
}
465
}
466
+
467
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
468
+ CprmanPllChannelState *channel = &s->channels[i];
469
+ CprmanPll parent = PLL_CHANNEL_INIT_INFO[i].parent;
470
+ Clock *parent_clk = s->plls[parent].out;
471
+
472
+ clock_set_source(channel->pll_in, parent_clk);
473
+
474
+ if (!qdev_realize(DEVICE(channel), NULL, errp)) {
475
+ return;
476
+ }
477
+ }
478
}
479
480
static const VMStateDescription cprman_vmstate = {
481
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
482
{
483
type_register_static(&cprman_info);
484
type_register_static(&cprman_pll_info);
485
+ type_register_static(&cprman_pll_channel_info);
486
}
487
488
type_init(cprman_register_types);
489
--
76
--
490
2.20.1
77
2.34.1
491
492
diff view generated by jsdifflib
New patch
1
In target/loongarch's helper_fclass_s() and helper_fclass_d() we pass
2
a zero-initialized float_status struct to float32_is_quiet_nan() and
3
float64_is_quiet_nan(), with the cryptic comment "for
4
snan_bit_is_one".
1
5
6
This pattern appears to have been copied from target/riscv, where it
7
is used because the functions there do not have ready access to the
8
CPU state struct. The comment presumably refers to the fact that the
9
main reason the is_quiet_nan() functions want the float_state is
10
because they want to know about the snan_bit_is_one config.
11
12
In the loongarch helpers, though, we have the CPU state struct
13
to hand. Use the usual env->fp_status here. This avoids our needing
14
to track that we need to update the initializer of the local
15
float_status structs when the core softfloat code adds new
16
options for targets to configure their behaviour.
17
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Message-id: 20241202131347.498124-30-peter.maydell@linaro.org
21
---
22
target/loongarch/tcg/fpu_helper.c | 6 ++----
23
1 file changed, 2 insertions(+), 4 deletions(-)
24
25
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/target/loongarch/tcg/fpu_helper.c
28
+++ b/target/loongarch/tcg/fpu_helper.c
29
@@ -XXX,XX +XXX,XX @@ uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj)
30
} else if (float32_is_zero_or_denormal(f)) {
31
return sign ? 1 << 4 : 1 << 8;
32
} else if (float32_is_any_nan(f)) {
33
- float_status s = { }; /* for snan_bit_is_one */
34
- return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
35
+ return float32_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
36
} else {
37
return sign ? 1 << 3 : 1 << 7;
38
}
39
@@ -XXX,XX +XXX,XX @@ uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj)
40
} else if (float64_is_zero_or_denormal(f)) {
41
return sign ? 1 << 4 : 1 << 8;
42
} else if (float64_is_any_nan(f)) {
43
- float_status s = { }; /* for snan_bit_is_one */
44
- return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
45
+ return float64_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
46
} else {
47
return sign ? 1 << 3 : 1 << 7;
48
}
49
--
50
2.34.1
diff view generated by jsdifflib
New patch
1
In the frem helper, we have a local float_status because we want to
2
execute the floatx80_div() with a custom rounding mode. Instead of
3
zero-initializing the local float_status and then having to set it up
4
with the m68k standard behaviour (including the NaN propagation rule
5
and copying the rounding precision from env->fp_status), initialize
6
it as a complete copy of env->fp_status. This will avoid our having
7
to add new code in this function for every new config knob we add
8
to fp_status.
1
9
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20241202131347.498124-31-peter.maydell@linaro.org
13
---
14
target/m68k/fpu_helper.c | 6 ++----
15
1 file changed, 2 insertions(+), 4 deletions(-)
16
17
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/m68k/fpu_helper.c
20
+++ b/target/m68k/fpu_helper.c
21
@@ -XXX,XX +XXX,XX @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
22
23
fp_rem = floatx80_rem(val1->d, val0->d, &env->fp_status);
24
if (!floatx80_is_any_nan(fp_rem)) {
25
- float_status fp_status = { };
26
+ /* Use local temporary fp_status to set different rounding mode */
27
+ float_status fp_status = env->fp_status;
28
uint32_t quotient;
29
int sign;
30
31
/* Calculate quotient directly using round to nearest mode */
32
- set_float_2nan_prop_rule(float_2nan_prop_ab, &fp_status);
33
set_float_rounding_mode(float_round_nearest_even, &fp_status);
34
- set_floatx80_rounding_precision(
35
- get_floatx80_rounding_precision(&env->fp_status), &fp_status);
36
fp_quot.d = floatx80_div(val1->d, val0->d, &fp_status);
37
38
sign = extractFloatx80Sign(fp_quot.d);
39
--
40
2.34.1
diff view generated by jsdifflib
New patch
1
In cf_fpu_gdb_get_reg() and cf_fpu_gdb_set_reg() we do the conversion
2
from float64 to floatx80 using a scratch float_status, because we
3
don't want the conversion to affect the CPU's floating point exception
4
status. Currently we use a zero-initialized float_status. This will
5
get steadily more awkward as we add config knobs to float_status
6
that the target must initialize. Avoid having to add any of that
7
configuration here by instead initializing our local float_status
8
from the env->fp_status.
1
9
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20241202131347.498124-32-peter.maydell@linaro.org
13
---
14
target/m68k/helper.c | 6 ++++--
15
1 file changed, 4 insertions(+), 2 deletions(-)
16
17
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/m68k/helper.c
20
+++ b/target/m68k/helper.c
21
@@ -XXX,XX +XXX,XX @@ static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
22
CPUM68KState *env = &cpu->env;
23
24
if (n < 8) {
25
- float_status s = {};
26
+ /* Use scratch float_status so any exceptions don't change CPU state */
27
+ float_status s = env->fp_status;
28
return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
29
}
30
switch (n) {
31
@@ -XXX,XX +XXX,XX @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
32
CPUM68KState *env = &cpu->env;
33
34
if (n < 8) {
35
- float_status s = {};
36
+ /* Use scratch float_status so any exceptions don't change CPU state */
37
+ float_status s = env->fp_status;
38
env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
39
return 8;
40
}
41
--
42
2.34.1
diff view generated by jsdifflib
1
The armv7m systick timer is a 24-bit decrementing, wrap-on-zero,
1
In the helper functions flcmps and flcmpd we use a scratch float_status
2
clear-on-write counter. Our current implementation has various
2
so that we don't change the CPU state if the comparison raises any
3
bugs and dubious workarounds in it (for instance see
3
floating point exception flags. Instead of zero-initializing this
4
https://bugs.launchpad.net/qemu/+bug/1872237).
4
scratch float_status, initialize it as a copy of env->fp_status. This
5
avoids the need to explicitly initialize settings like the NaN
6
propagation rule or others we might add to softfloat in future.
5
7
6
We have an implementation of a simple decrementing counter
8
To do this we need to pass the CPU env pointer in to the helper.
7
and we put a lot of effort into making sure it handles the
8
interesting corner cases (like "spend a cycle at 0 before
9
reloading") -- ptimer.
10
11
Rewrite the systick timer to use a ptimer rather than
12
a raw QEMU timer.
13
14
Unfortunately this is a migration compatibility break,
15
which will affect all M-profile boards.
16
17
Among other bugs, this fixes
18
https://bugs.launchpad.net/qemu/+bug/1872237 :
19
now writes to SYST_CVR when the timer is enabled correctly
20
do nothing; when the timer is enabled via SYST_CSR.ENABLE,
21
the ptimer code will (because of POLICY_NO_IMMEDIATE_RELOAD)
22
arrange that after one timer tick the counter is reloaded
23
from SYST_RVR and then counts down from there, as the
24
architecture requires.
25
9
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
28
Message-id: 20201015151829.14656-3-peter.maydell@linaro.org
12
Message-id: 20241202131347.498124-33-peter.maydell@linaro.org
29
---
13
---
30
include/hw/timer/armv7m_systick.h | 3 +-
14
target/sparc/helper.h | 4 ++--
31
hw/timer/armv7m_systick.c | 124 +++++++++++++-----------------
15
target/sparc/fop_helper.c | 8 ++++----
32
2 files changed, 54 insertions(+), 73 deletions(-)
16
target/sparc/translate.c | 4 ++--
17
3 files changed, 8 insertions(+), 8 deletions(-)
33
18
34
diff --git a/include/hw/timer/armv7m_systick.h b/include/hw/timer/armv7m_systick.h
19
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
35
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
36
--- a/include/hw/timer/armv7m_systick.h
21
--- a/target/sparc/helper.h
37
+++ b/include/hw/timer/armv7m_systick.h
22
+++ b/target/sparc/helper.h
38
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_3(fcmpd, TCG_CALL_NO_WG, i32, env, f64, f64)
39
24
DEF_HELPER_FLAGS_3(fcmped, TCG_CALL_NO_WG, i32, env, f64, f64)
40
#include "hw/sysbus.h"
25
DEF_HELPER_FLAGS_3(fcmpq, TCG_CALL_NO_WG, i32, env, i128, i128)
41
#include "qom/object.h"
26
DEF_HELPER_FLAGS_3(fcmpeq, TCG_CALL_NO_WG, i32, env, i128, i128)
42
+#include "hw/ptimer.h"
27
-DEF_HELPER_FLAGS_2(flcmps, TCG_CALL_NO_RWG_SE, i32, f32, f32)
43
28
-DEF_HELPER_FLAGS_2(flcmpd, TCG_CALL_NO_RWG_SE, i32, f64, f64)
44
#define TYPE_SYSTICK "armv7m_systick"
29
+DEF_HELPER_FLAGS_3(flcmps, TCG_CALL_NO_RWG_SE, i32, env, f32, f32)
45
30
+DEF_HELPER_FLAGS_3(flcmpd, TCG_CALL_NO_RWG_SE, i32, env, f64, f64)
46
@@ -XXX,XX +XXX,XX @@ struct SysTickState {
31
DEF_HELPER_2(raise_exception, noreturn, env, int)
47
uint32_t control;
32
48
uint32_t reload;
33
DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_WG, f64, env, f64, f64)
49
int64_t tick;
34
diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c
50
- QEMUTimer *timer;
51
+ ptimer_state *ptimer;
52
MemoryRegion iomem;
53
qemu_irq irq;
54
};
55
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
56
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/timer/armv7m_systick.c
36
--- a/target/sparc/fop_helper.c
58
+++ b/hw/timer/armv7m_systick.c
37
+++ b/target/sparc/fop_helper.c
59
@@ -XXX,XX +XXX,XX @@ static inline int64_t systick_scale(SysTickState *s)
38
@@ -XXX,XX +XXX,XX @@ uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2)
60
}
39
return finish_fcmp(env, r, GETPC());
61
}
40
}
62
41
63
-static void systick_reload(SysTickState *s, int reset)
42
-uint32_t helper_flcmps(float32 src1, float32 src2)
64
-{
43
+uint32_t helper_flcmps(CPUSPARCState *env, float32 src1, float32 src2)
65
- /* The Cortex-M3 Devices Generic User Guide says that "When the
66
- * ENABLE bit is set to 1, the counter loads the RELOAD value from the
67
- * SYST RVR register and then counts down". So, we need to check the
68
- * ENABLE bit before reloading the value.
69
- */
70
- trace_systick_reload();
71
-
72
- if ((s->control & SYSTICK_ENABLE) == 0) {
73
- return;
74
- }
75
-
76
- if (reset) {
77
- s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
78
- }
79
- s->tick += (s->reload + 1) * systick_scale(s);
80
- timer_mod(s->timer, s->tick);
81
-}
82
-
83
static void systick_timer_tick(void *opaque)
84
{
44
{
85
SysTickState *s = (SysTickState *)opaque;
45
/*
86
@@ -XXX,XX +XXX,XX @@ static void systick_timer_tick(void *opaque)
46
* FLCMP never raises an exception nor modifies any FSR fields.
87
/* Tell the NVIC to pend the SysTick exception */
47
* Perform the comparison with a dummy fp environment.
88
qemu_irq_pulse(s->irq);
48
*/
89
}
49
- float_status discard = { };
90
- if (s->reload == 0) {
50
+ float_status discard = env->fp_status;
91
- s->control &= ~SYSTICK_ENABLE;
51
FloatRelation r;
92
- } else {
52
93
- systick_reload(s, 0);
53
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
94
+ if (ptimer_get_limit(s->ptimer) == 0) {
54
@@ -XXX,XX +XXX,XX @@ uint32_t helper_flcmps(float32 src1, float32 src2)
95
+ /*
55
g_assert_not_reached();
96
+ * Timer expiry with SYST_RVR zero disables the timer
97
+ * (but doesn't clear SYST_CSR.ENABLE)
98
+ */
99
+ ptimer_stop(s->ptimer);
100
}
101
}
56
}
102
57
103
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
58
-uint32_t helper_flcmpd(float64 src1, float64 src2)
104
s->control &= ~SYSTICK_COUNTFLAG;
59
+uint32_t helper_flcmpd(CPUSPARCState *env, float64 src1, float64 src2)
105
break;
60
{
106
case 0x4: /* SysTick Reload Value. */
61
- float_status discard = { };
107
- val = s->reload;
62
+ float_status discard = env->fp_status;
108
+ val = ptimer_get_limit(s->ptimer);
63
FloatRelation r;
109
break;
64
110
case 0x8: /* SysTick Current Value. */
65
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
111
- {
66
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
112
- int64_t t;
67
index XXXXXXX..XXXXXXX 100644
113
-
68
--- a/target/sparc/translate.c
114
- if ((s->control & SYSTICK_ENABLE) == 0) {
69
+++ b/target/sparc/translate.c
115
- val = 0;
70
@@ -XXX,XX +XXX,XX @@ static bool trans_FLCMPs(DisasContext *dc, arg_FLCMPs *a)
116
- break;
71
117
- }
72
src1 = gen_load_fpr_F(dc, a->rs1);
118
- t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
73
src2 = gen_load_fpr_F(dc, a->rs2);
119
- if (t >= s->tick) {
74
- gen_helper_flcmps(cpu_fcc[a->cc], src1, src2);
120
- val = 0;
75
+ gen_helper_flcmps(cpu_fcc[a->cc], tcg_env, src1, src2);
121
- break;
76
return advance_pc(dc);
122
- }
123
- val = ((s->tick - (t + 1)) / systick_scale(s)) + 1;
124
- /* The interrupt in triggered when the timer reaches zero.
125
- However the counter is not reloaded until the next clock
126
- tick. This is a hack to return zero during the first tick. */
127
- if (val > s->reload) {
128
- val = 0;
129
- }
130
+ val = ptimer_get_count(s->ptimer);
131
break;
132
- }
133
case 0xc: /* SysTick Calibration Value. */
134
val = 10000;
135
break;
136
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
137
switch (addr) {
138
case 0x0: /* SysTick Control and Status. */
139
{
140
- uint32_t oldval = s->control;
141
+ uint32_t oldval;
142
143
+ ptimer_transaction_begin(s->ptimer);
144
+ oldval = s->control;
145
s->control &= 0xfffffff8;
146
s->control |= value & 7;
147
+
148
if ((oldval ^ value) & SYSTICK_ENABLE) {
149
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
150
if (value & SYSTICK_ENABLE) {
151
- if (s->tick) {
152
- s->tick += now;
153
- timer_mod(s->timer, s->tick);
154
- } else {
155
- systick_reload(s, 1);
156
- }
157
+ /*
158
+ * Always reload the period in case board code has
159
+ * changed system_clock_scale. If we ever replace that
160
+ * global with a more sensible API then we might be able
161
+ * to set the period only when it actually changes.
162
+ */
163
+ ptimer_set_period(s->ptimer, systick_scale(s));
164
+ ptimer_run(s->ptimer, 0);
165
} else {
166
- timer_del(s->timer);
167
- s->tick -= now;
168
- if (s->tick < 0) {
169
- s->tick = 0;
170
- }
171
+ ptimer_stop(s->ptimer);
172
}
173
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
174
- /* This is a hack. Force the timer to be reloaded
175
- when the reference clock is changed. */
176
- systick_reload(s, 1);
177
+ ptimer_set_period(s->ptimer, systick_scale(s));
178
}
179
+ ptimer_transaction_commit(s->ptimer);
180
break;
181
}
182
case 0x4: /* SysTick Reload Value. */
183
- s->reload = value;
184
+ ptimer_transaction_begin(s->ptimer);
185
+ ptimer_set_limit(s->ptimer, value & 0xffffff, 0);
186
+ ptimer_transaction_commit(s->ptimer);
187
break;
188
- case 0x8: /* SysTick Current Value. Writes reload the timer. */
189
- systick_reload(s, 1);
190
+ case 0x8: /* SysTick Current Value. */
191
+ /*
192
+ * Writing any value clears SYST_CVR to zero and clears
193
+ * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR
194
+ * on the next clock edge unless SYST_RVR is zero.
195
+ */
196
+ ptimer_transaction_begin(s->ptimer);
197
+ if (ptimer_get_limit(s->ptimer) == 0) {
198
+ ptimer_stop(s->ptimer);
199
+ }
200
+ ptimer_set_count(s->ptimer, 0);
201
s->control &= ~SYSTICK_COUNTFLAG;
202
+ ptimer_transaction_commit(s->ptimer);
203
break;
204
default:
205
qemu_log_mask(LOG_GUEST_ERROR,
206
@@ -XXX,XX +XXX,XX @@ static void systick_reset(DeviceState *dev)
207
*/
208
assert(system_clock_scale != 0);
209
210
+ ptimer_transaction_begin(s->ptimer);
211
s->control = 0;
212
- s->reload = 0;
213
- s->tick = 0;
214
- timer_del(s->timer);
215
+ ptimer_stop(s->ptimer);
216
+ ptimer_set_count(s->ptimer, 0);
217
+ ptimer_set_limit(s->ptimer, 0, 0);
218
+ ptimer_set_period(s->ptimer, systick_scale(s));
219
+ ptimer_transaction_commit(s->ptimer);
220
}
77
}
221
78
222
static void systick_instance_init(Object *obj)
79
@@ -XXX,XX +XXX,XX @@ static bool trans_FLCMPd(DisasContext *dc, arg_FLCMPd *a)
223
@@ -XXX,XX +XXX,XX @@ static void systick_instance_init(Object *obj)
80
224
static void systick_realize(DeviceState *dev, Error **errp)
81
src1 = gen_load_fpr_D(dc, a->rs1);
225
{
82
src2 = gen_load_fpr_D(dc, a->rs2);
226
SysTickState *s = SYSTICK(dev);
83
- gen_helper_flcmpd(cpu_fcc[a->cc], src1, src2);
227
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
84
+ gen_helper_flcmpd(cpu_fcc[a->cc], tcg_env, src1, src2);
228
+ s->ptimer = ptimer_init(systick_timer_tick, s,
85
return advance_pc(dc);
229
+ PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
230
+ PTIMER_POLICY_NO_COUNTER_ROUND_DOWN |
231
+ PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
232
+ PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
233
}
86
}
234
87
235
static const VMStateDescription vmstate_systick = {
236
.name = "armv7m_systick",
237
- .version_id = 1,
238
- .minimum_version_id = 1,
239
+ .version_id = 2,
240
+ .minimum_version_id = 2,
241
.fields = (VMStateField[]) {
242
VMSTATE_UINT32(control, SysTickState),
243
- VMSTATE_UINT32(reload, SysTickState),
244
VMSTATE_INT64(tick, SysTickState),
245
- VMSTATE_TIMER_PTR(timer, SysTickState),
246
+ VMSTATE_PTIMER(ptimer, SysTickState),
247
VMSTATE_END_OF_LIST()
248
}
249
};
250
--
88
--
251
2.20.1
89
2.34.1
252
253
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
In the helper_compute_fprf functions, we pass a dummy float_status
2
in to the is_signaling_nan() function. This is unnecessary, because
3
we have convenient access to the CPU env pointer here and that
4
is already set up with the correct values for the snan_bit_is_one
5
and no_signaling_nans config settings. is_signaling_nan() doesn't
6
ever update the fp_status with any exception flags, so there is
7
no reason not to use env->fp_status here.
2
8
3
The CPRMAN (clock controller) was mapped at the watchdog/power manager
9
Use env->fp_status instead of the dummy fp_status.
4
address. It was also split into two unimplemented peripherals (CM and
5
A2W) but this is really the same one, as shown by this extract of the
6
Raspberry Pi 3 Linux device tree:
7
10
8
watchdog@7e100000 {
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
compatible = "brcm,bcm2835-pm\0brcm,bcm2835-pm-wdt";
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
[...]
13
Message-id: 20241202131347.498124-34-peter.maydell@linaro.org
11
reg = <0x7e100000 0x114 0x7e00a000 0x24>;
14
---
12
[...]
15
target/ppc/fpu_helper.c | 3 +--
13
};
16
1 file changed, 1 insertion(+), 2 deletions(-)
14
17
15
[...]
18
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
16
cprman@7e101000 {
17
compatible = "brcm,bcm2835-cprman";
18
[...]
19
reg = <0x7e101000 0x2000>;
20
[...]
21
};
22
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Signed-off-by: Luc Michel <luc@lmichel.fr>
25
Tested-by: Guenter Roeck <linux@roeck-us.net>
26
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
---
29
include/hw/arm/bcm2835_peripherals.h | 2 +-
30
include/hw/arm/raspi_platform.h | 5 ++---
31
hw/arm/bcm2835_peripherals.c | 4 ++--
32
3 files changed, 5 insertions(+), 6 deletions(-)
33
34
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
35
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
36
--- a/include/hw/arm/bcm2835_peripherals.h
20
--- a/target/ppc/fpu_helper.c
37
+++ b/include/hw/arm/bcm2835_peripherals.h
21
+++ b/target/ppc/fpu_helper.c
38
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
22
@@ -XXX,XX +XXX,XX @@ void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
39
BCM2835MphiState mphi;
23
} else if (tp##_is_infinity(arg)) { \
40
UnimplementedDeviceState txp;
24
fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \
41
UnimplementedDeviceState armtmr;
25
} else { \
42
+ UnimplementedDeviceState powermgt;
26
- float_status dummy = { }; /* snan_bit_is_one = 0 */ \
43
UnimplementedDeviceState cprman;
27
- if (tp##_is_signaling_nan(arg, &dummy)) { \
44
- UnimplementedDeviceState a2w;
28
+ if (tp##_is_signaling_nan(arg, &env->fp_status)) { \
45
PL011State uart0;
29
fprf = 0x00 << FPSCR_FPRF; \
46
BCM2835AuxState aux;
30
} else { \
47
BCM2835FBState fb;
31
fprf = 0x11 << FPSCR_FPRF; \
48
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/include/hw/arm/raspi_platform.h
51
+++ b/include/hw/arm/raspi_platform.h
52
@@ -XXX,XX +XXX,XX @@
53
#define ARMCTRL_TIMER0_1_OFFSET (ARM_OFFSET + 0x400) /* Timer 0 and 1 (SP804) */
54
#define ARMCTRL_0_SBM_OFFSET (ARM_OFFSET + 0x800) /* User 0 (ARM) Semaphores
55
* Doorbells & Mailboxes */
56
-#define CPRMAN_OFFSET 0x100000 /* Power Management, Watchdog */
57
-#define CM_OFFSET 0x101000 /* Clock Management */
58
-#define A2W_OFFSET 0x102000 /* Reset controller */
59
+#define PM_OFFSET 0x100000 /* Power Management */
60
+#define CPRMAN_OFFSET 0x101000 /* Clock Management */
61
#define AVS_OFFSET 0x103000 /* Audio Video Standard */
62
#define RNG_OFFSET 0x104000
63
#define GPIO_OFFSET 0x200000
64
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/hw/arm/bcm2835_peripherals.c
67
+++ b/hw/arm/bcm2835_peripherals.c
68
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
69
70
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
71
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
72
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
73
- create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
74
+ create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
75
+ create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
76
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
77
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
78
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
79
--
32
--
80
2.20.1
33
2.34.1
81
82
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The note test requires gcc 10 for -mbranch-protection=standard.
3
Now that float_status has a bunch of fp parameters,
4
The mmap test uses PROT_BTI and does not require special compiler support.
4
it is easier to copy an existing structure than create
5
one from scratch. Begin by copying the structure that
6
corresponds to the FPSR and make only the adjustments
7
required for BFloat16 semantics.
5
8
6
Acked-by: Alex Bennée <alex.bennee@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20241203203949.483774-2-richard.henderson@linaro.org
9
Message-id: 20201021173749.111103-13-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
14
---
12
tests/tcg/aarch64/bti-1.c | 62 ++++++++++++++++
15
target/arm/tcg/vec_helper.c | 20 +++++++-------------
13
tests/tcg/aarch64/bti-2.c | 116 ++++++++++++++++++++++++++++++
16
1 file changed, 7 insertions(+), 13 deletions(-)
14
tests/tcg/aarch64/bti-crt.inc.c | 51 +++++++++++++
15
tests/tcg/aarch64/Makefile.target | 10 +++
16
tests/tcg/configure.sh | 4 ++
17
5 files changed, 243 insertions(+)
18
create mode 100644 tests/tcg/aarch64/bti-1.c
19
create mode 100644 tests/tcg/aarch64/bti-2.c
20
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
21
17
22
diff --git a/tests/tcg/aarch64/bti-1.c b/tests/tcg/aarch64/bti-1.c
18
diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c
23
new file mode 100644
19
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX
20
--- a/target/arm/tcg/vec_helper.c
25
--- /dev/null
21
+++ b/target/arm/tcg/vec_helper.c
26
+++ b/tests/tcg/aarch64/bti-1.c
22
@@ -XXX,XX +XXX,XX @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp)
27
@@ -XXX,XX +XXX,XX @@
23
* no effect on AArch32 instructions.
28
+/*
24
*/
29
+ * Branch target identification, basic notskip cases.
25
bool ebf = is_a64(env) && env->vfp.fpcr & FPCR_EBF;
30
+ */
26
- *statusp = (float_status){
27
- .tininess_before_rounding = float_tininess_before_rounding,
28
- .float_rounding_mode = float_round_to_odd_inf,
29
- .flush_to_zero = true,
30
- .flush_inputs_to_zero = true,
31
- .default_nan_mode = true,
32
- };
31
+
33
+
32
+#include "bti-crt.inc.c"
34
+ *statusp = env->vfp.fp_status;
33
+
35
+ set_default_nan_mode(true, statusp);
34
+static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc)
36
35
+{
37
if (ebf) {
36
+ uc->uc_mcontext.pc += 8;
38
- float_status *fpst = &env->vfp.fp_status;
37
+ uc->uc_mcontext.pstate = 1;
39
- set_flush_to_zero(get_flush_to_zero(fpst), statusp);
38
+}
40
- set_flush_inputs_to_zero(get_flush_inputs_to_zero(fpst), statusp);
39
+
41
- set_float_rounding_mode(get_float_rounding_mode(fpst), statusp);
40
+#define NOP "nop"
42
-
41
+#define BTI_N "hint #32"
43
/* EBF=1 needs to do a step with round-to-odd semantics */
42
+#define BTI_C "hint #34"
44
*oddstatusp = *statusp;
43
+#define BTI_J "hint #36"
45
set_float_rounding_mode(float_round_to_odd, oddstatusp);
44
+#define BTI_JC "hint #38"
46
+ } else {
45
+
47
+ set_flush_to_zero(true, statusp);
46
+#define BTYPE_1(DEST) \
48
+ set_flush_inputs_to_zero(true, statusp);
47
+ asm("mov %0,#1; adr x16, 1f; br x16; 1: " DEST "; mov %0,#0" \
49
+ set_float_rounding_mode(float_round_to_odd_inf, statusp);
48
+ : "=r"(skipped) : : "x16")
50
}
49
+
51
-
50
+#define BTYPE_2(DEST) \
52
return ebf;
51
+ asm("mov %0,#1; adr x16, 1f; blr x16; 1: " DEST "; mov %0,#0" \
53
}
52
+ : "=r"(skipped) : : "x16", "x30")
53
+
54
+#define BTYPE_3(DEST) \
55
+ asm("mov %0,#1; adr x15, 1f; br x15; 1: " DEST "; mov %0,#0" \
56
+ : "=r"(skipped) : : "x15")
57
+
58
+#define TEST(WHICH, DEST, EXPECT) \
59
+ do { WHICH(DEST); fail += skipped ^ EXPECT; } while (0)
60
+
61
+
62
+int main()
63
+{
64
+ int fail = 0;
65
+ int skipped;
66
+
67
+ /* Signal-like with SA_SIGINFO. */
68
+ signal_info(SIGILL, skip2_sigill);
69
+
70
+ TEST(BTYPE_1, NOP, 1);
71
+ TEST(BTYPE_1, BTI_N, 1);
72
+ TEST(BTYPE_1, BTI_C, 0);
73
+ TEST(BTYPE_1, BTI_J, 0);
74
+ TEST(BTYPE_1, BTI_JC, 0);
75
+
76
+ TEST(BTYPE_2, NOP, 1);
77
+ TEST(BTYPE_2, BTI_N, 1);
78
+ TEST(BTYPE_2, BTI_C, 0);
79
+ TEST(BTYPE_2, BTI_J, 1);
80
+ TEST(BTYPE_2, BTI_JC, 0);
81
+
82
+ TEST(BTYPE_3, NOP, 1);
83
+ TEST(BTYPE_3, BTI_N, 1);
84
+ TEST(BTYPE_3, BTI_C, 1);
85
+ TEST(BTYPE_3, BTI_J, 0);
86
+ TEST(BTYPE_3, BTI_JC, 0);
87
+
88
+ return fail;
89
+}
90
diff --git a/tests/tcg/aarch64/bti-2.c b/tests/tcg/aarch64/bti-2.c
91
new file mode 100644
92
index XXXXXXX..XXXXXXX
93
--- /dev/null
94
+++ b/tests/tcg/aarch64/bti-2.c
95
@@ -XXX,XX +XXX,XX @@
96
+/*
97
+ * Branch target identification, basic notskip cases.
98
+ */
99
+
100
+#include <stdio.h>
101
+#include <signal.h>
102
+#include <string.h>
103
+#include <unistd.h>
104
+#include <sys/mman.h>
105
+
106
+#ifndef PROT_BTI
107
+#define PROT_BTI 0x10
108
+#endif
109
+
110
+static void skip2_sigill(int sig, siginfo_t *info, void *vuc)
111
+{
112
+ ucontext_t *uc = vuc;
113
+ uc->uc_mcontext.pc += 8;
114
+ uc->uc_mcontext.pstate = 1;
115
+}
116
+
117
+#define NOP "nop"
118
+#define BTI_N "hint #32"
119
+#define BTI_C "hint #34"
120
+#define BTI_J "hint #36"
121
+#define BTI_JC "hint #38"
122
+
123
+#define BTYPE_1(DEST) \
124
+ "mov x1, #1\n\t" \
125
+ "adr x16, 1f\n\t" \
126
+ "br x16\n" \
127
+"1: " DEST "\n\t" \
128
+ "mov x1, #0"
129
+
130
+#define BTYPE_2(DEST) \
131
+ "mov x1, #1\n\t" \
132
+ "adr x16, 1f\n\t" \
133
+ "blr x16\n" \
134
+"1: " DEST "\n\t" \
135
+ "mov x1, #0"
136
+
137
+#define BTYPE_3(DEST) \
138
+ "mov x1, #1\n\t" \
139
+ "adr x15, 1f\n\t" \
140
+ "br x15\n" \
141
+"1: " DEST "\n\t" \
142
+ "mov x1, #0"
143
+
144
+#define TEST(WHICH, DEST, EXPECT) \
145
+ WHICH(DEST) "\n" \
146
+ ".if " #EXPECT "\n\t" \
147
+ "eor x1, x1," #EXPECT "\n" \
148
+ ".endif\n\t" \
149
+ "add x0, x0, x1\n\t"
150
+
151
+asm("\n"
152
+"test_begin:\n\t"
153
+ BTI_C "\n\t"
154
+ "mov x2, x30\n\t"
155
+ "mov x0, #0\n\t"
156
+
157
+ TEST(BTYPE_1, NOP, 1)
158
+ TEST(BTYPE_1, BTI_N, 1)
159
+ TEST(BTYPE_1, BTI_C, 0)
160
+ TEST(BTYPE_1, BTI_J, 0)
161
+ TEST(BTYPE_1, BTI_JC, 0)
162
+
163
+ TEST(BTYPE_2, NOP, 1)
164
+ TEST(BTYPE_2, BTI_N, 1)
165
+ TEST(BTYPE_2, BTI_C, 0)
166
+ TEST(BTYPE_2, BTI_J, 1)
167
+ TEST(BTYPE_2, BTI_JC, 0)
168
+
169
+ TEST(BTYPE_3, NOP, 1)
170
+ TEST(BTYPE_3, BTI_N, 1)
171
+ TEST(BTYPE_3, BTI_C, 1)
172
+ TEST(BTYPE_3, BTI_J, 0)
173
+ TEST(BTYPE_3, BTI_JC, 0)
174
+
175
+ "ret x2\n"
176
+"test_end:"
177
+);
178
+
179
+int main()
180
+{
181
+ struct sigaction sa;
182
+ void *tb, *te;
183
+
184
+ void *p = mmap(0, getpagesize(),
185
+ PROT_EXEC | PROT_READ | PROT_WRITE | PROT_BTI,
186
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
187
+ if (p == MAP_FAILED) {
188
+ perror("mmap");
189
+ return 1;
190
+ }
191
+
192
+ memset(&sa, 0, sizeof(sa));
193
+ sa.sa_sigaction = skip2_sigill;
194
+ sa.sa_flags = SA_SIGINFO;
195
+ if (sigaction(SIGILL, &sa, NULL) < 0) {
196
+ perror("sigaction");
197
+ return 1;
198
+ }
199
+
200
+ /*
201
+ * ??? With "extern char test_begin[]", some compiler versions
202
+ * will use :got references, and some linker versions will
203
+ * resolve this reference to a static symbol incorrectly.
204
+ * Bypass this error by using a pc-relative reference directly.
205
+ */
206
+ asm("adr %0, test_begin; adr %1, test_end" : "=r"(tb), "=r"(te));
207
+
208
+ memcpy(p, tb, te - tb);
209
+
210
+ return ((int (*)(void))p)();
211
+}
212
diff --git a/tests/tcg/aarch64/bti-crt.inc.c b/tests/tcg/aarch64/bti-crt.inc.c
213
new file mode 100644
214
index XXXXXXX..XXXXXXX
215
--- /dev/null
216
+++ b/tests/tcg/aarch64/bti-crt.inc.c
217
@@ -XXX,XX +XXX,XX @@
218
+/*
219
+ * Minimal user-environment for testing BTI.
220
+ *
221
+ * Normal libc is not (yet) built with BTI support enabled,
222
+ * and so could generate a BTI TRAP before ever reaching main.
223
+ */
224
+
225
+#include <stdlib.h>
226
+#include <signal.h>
227
+#include <ucontext.h>
228
+#include <asm/unistd.h>
229
+
230
+int main(void);
231
+
232
+void _start(void)
233
+{
234
+ exit(main());
235
+}
236
+
237
+void exit(int ret)
238
+{
239
+ register int x0 __asm__("x0") = ret;
240
+ register int x8 __asm__("x8") = __NR_exit;
241
+
242
+ asm volatile("svc #0" : : "r"(x0), "r"(x8));
243
+ __builtin_unreachable();
244
+}
245
+
246
+/*
247
+ * Irritatingly, the user API struct sigaction does not match the
248
+ * kernel API struct sigaction. So for simplicity, isolate the
249
+ * kernel ABI here, and make this act like signal.
250
+ */
251
+void signal_info(int sig, void (*fn)(int, siginfo_t *, ucontext_t *))
252
+{
253
+ struct kernel_sigaction {
254
+ void (*handler)(int, siginfo_t *, ucontext_t *);
255
+ unsigned long flags;
256
+ unsigned long restorer;
257
+ unsigned long mask;
258
+ } sa = { fn, SA_SIGINFO, 0, 0 };
259
+
260
+ register int x0 __asm__("x0") = sig;
261
+ register void *x1 __asm__("x1") = &sa;
262
+ register void *x2 __asm__("x2") = 0;
263
+ register int x3 __asm__("x3") = sizeof(unsigned long);
264
+ register int x8 __asm__("x8") = __NR_rt_sigaction;
265
+
266
+ asm volatile("svc #0"
267
+ : : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory");
268
+}
269
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
270
index XXXXXXX..XXXXXXX 100644
271
--- a/tests/tcg/aarch64/Makefile.target
272
+++ b/tests/tcg/aarch64/Makefile.target
273
@@ -XXX,XX +XXX,XX @@ run-pauth-%: QEMU_OPTS += -cpu max
274
run-plugin-pauth-%: QEMU_OPTS += -cpu max
275
endif
276
277
+# BTI Tests
278
+# bti-1 tests the elf notes, so we require special compiler support.
279
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_BTI),)
280
+AARCH64_TESTS += bti-1
281
+bti-1: CFLAGS += -mbranch-protection=standard
282
+bti-1: LDFLAGS += -nostdlib
283
+endif
284
+# bti-2 tests PROT_BTI, so no special compiler support required.
285
+AARCH64_TESTS += bti-2
286
+
287
# Semihosting smoke test for linux-user
288
AARCH64_TESTS += semihosting
289
run-semihosting: semihosting
290
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
291
index XXXXXXX..XXXXXXX 100755
292
--- a/tests/tcg/configure.sh
293
+++ b/tests/tcg/configure.sh
294
@@ -XXX,XX +XXX,XX @@ for target in $target_list; do
295
-march=armv8.3-a -o $TMPE $TMPC; then
296
echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
297
fi
298
+ if do_compiler "$target_compiler" $target_compiler_cflags \
299
+ -mbranch-protection=standard -o $TMPE $TMPC; then
300
+ echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
301
+ fi
302
;;
303
esac
304
54
305
--
55
--
306
2.20.1
56
2.34.1
307
57
308
58
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Currently we hardcode the default NaN value in parts64_default_nan()
2
using a compile-time ifdef ladder. This is awkward for two cases:
3
* for single-QEMU-binary we can't hard-code target-specifics like this
4
* for Arm FEAT_AFP the default NaN value depends on FPCR.AH
5
(specifically the sign bit is different)
2
6
3
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Add a field to float_status to specify the default NaN value; fall
4
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
back to the old ifdef behaviour if these are not set.
5
Message-id: 20201024170127.3592182-7-f4bug@amsat.org
9
10
The default NaN value is specified by setting a uint8_t to a
11
pattern corresponding to the sign and upper fraction parts of
12
the NaN; the lower bits of the fraction are set from bit 0 of
13
the pattern.
14
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20241202131347.498124-35-peter.maydell@linaro.org
7
---
18
---
8
include/hw/arm/bcm2836.h | 1 +
19
include/fpu/softfloat-helpers.h | 11 +++++++
9
hw/arm/bcm2836.c | 34 ++++++++++++++++++++++++++++++++++
20
include/fpu/softfloat-types.h | 10 ++++++
10
hw/arm/raspi.c | 2 ++
21
fpu/softfloat-specialize.c.inc | 55 ++++++++++++++++++++-------------
11
3 files changed, 37 insertions(+)
22
3 files changed, 54 insertions(+), 22 deletions(-)
12
23
13
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
24
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
14
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
15
--- a/include/hw/arm/bcm2836.h
26
--- a/include/fpu/softfloat-helpers.h
16
+++ b/include/hw/arm/bcm2836.h
27
+++ b/include/fpu/softfloat-helpers.h
17
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_TYPE(BCM283XState, BCM283XClass, BCM283X)
28
@@ -XXX,XX +XXX,XX @@ static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
18
* them, code using these devices should always handle them via the
29
status->float_infzeronan_rule = rule;
19
* BCM283x base class, so they have no BCM2836(obj) etc macros.
20
*/
21
+#define TYPE_BCM2835 "bcm2835"
22
#define TYPE_BCM2836 "bcm2836"
23
#define TYPE_BCM2837 "bcm2837"
24
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/arm/bcm2836.c
28
+++ b/hw/arm/bcm2836.c
29
@@ -XXX,XX +XXX,XX @@ static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
30
return true;
31
}
30
}
32
31
33
+static void bcm2835_realize(DeviceState *dev, Error **errp)
32
+static inline void set_float_default_nan_pattern(uint8_t dnan_pattern,
33
+ float_status *status)
34
+{
34
+{
35
+ BCM283XState *s = BCM283X(dev);
35
+ status->default_nan_pattern = dnan_pattern;
36
+
37
+ if (!bcm283x_common_realize(dev, errp)) {
38
+ return;
39
+ }
40
+
41
+ if (!qdev_realize(DEVICE(&s->cpu[0].core), NULL, errp)) {
42
+ return;
43
+ }
44
+
45
+ /* Connect irq/fiq outputs from the interrupt controller. */
46
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
47
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_IRQ));
48
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
49
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_FIQ));
50
+}
36
+}
51
+
37
+
52
static void bcm2836_realize(DeviceState *dev, Error **errp)
38
static inline void set_flush_to_zero(bool val, float_status *status)
53
{
39
{
54
BCM283XState *s = BCM283X(dev);
40
status->flush_to_zero = val;
55
@@ -XXX,XX +XXX,XX @@ static void bcm283x_class_init(ObjectClass *oc, void *data)
41
@@ -XXX,XX +XXX,XX @@ static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status
56
dc->user_creatable = false;
42
return status->float_infzeronan_rule;
57
}
43
}
58
44
59
+static void bcm2835_class_init(ObjectClass *oc, void *data)
45
+static inline uint8_t get_float_default_nan_pattern(float_status *status)
60
+{
46
+{
61
+ DeviceClass *dc = DEVICE_CLASS(oc);
47
+ return status->default_nan_pattern;
62
+ BCM283XClass *bc = BCM283X_CLASS(oc);
48
+}
63
+
49
+
64
+ bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
50
static inline bool get_flush_to_zero(float_status *status)
65
+ bc->core_count = 1;
51
{
66
+ bc->peri_base = 0x20000000;
52
return status->flush_to_zero;
67
+ dc->realize = bcm2835_realize;
53
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
68
+};
54
index XXXXXXX..XXXXXXX 100644
55
--- a/include/fpu/softfloat-types.h
56
+++ b/include/fpu/softfloat-types.h
57
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
58
/* should denormalised inputs go to zero and set the input_denormal flag? */
59
bool flush_inputs_to_zero;
60
bool default_nan_mode;
61
+ /*
62
+ * The pattern to use for the default NaN. Here the high bit specifies
63
+ * the default NaN's sign bit, and bits 6..0 specify the high bits of the
64
+ * fractional part. The low bits of the fractional part are copies of bit 0.
65
+ * The exponent of the default NaN is (as for any NaN) always all 1s.
66
+ * Note that a value of 0 here is not a valid NaN. The target must set
67
+ * this to the correct non-zero value, or we will assert when trying to
68
+ * create a default NaN.
69
+ */
70
+ uint8_t default_nan_pattern;
71
/*
72
* The flags below are not used on all specializations and may
73
* constant fold away (see snan_bit_is_one()/no_signalling_nans() in
74
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
75
index XXXXXXX..XXXXXXX 100644
76
--- a/fpu/softfloat-specialize.c.inc
77
+++ b/fpu/softfloat-specialize.c.inc
78
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
79
{
80
bool sign = 0;
81
uint64_t frac;
82
+ uint8_t dnan_pattern = status->default_nan_pattern;
83
84
+ if (dnan_pattern == 0) {
85
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
86
- /* !snan_bit_is_one, set all bits */
87
- frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
88
-#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
89
+ /* Sign bit clear, all frac bits set */
90
+ dnan_pattern = 0b01111111;
91
+#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
92
|| defined(TARGET_MICROBLAZE)
93
- /* !snan_bit_is_one, set sign and msb */
94
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
95
- sign = 1;
96
+ /* Sign bit set, most significant frac bit set */
97
+ dnan_pattern = 0b11000000;
98
#elif defined(TARGET_HPPA)
99
- /* snan_bit_is_one, set msb-1. */
100
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2);
101
+ /* Sign bit clear, msb-1 frac bit set */
102
+ dnan_pattern = 0b00100000;
103
#elif defined(TARGET_HEXAGON)
104
- sign = 1;
105
- frac = ~0ULL;
106
+ /* Sign bit set, all frac bits set. */
107
+ dnan_pattern = 0b11111111;
108
#else
109
- /*
110
- * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
111
- * S390, SH4, TriCore, and Xtensa. Our other supported targets
112
- * do not have floating-point.
113
- */
114
- if (snan_bit_is_one(status)) {
115
- /* set all bits other than msb */
116
- frac = (1ULL << (DECOMPOSED_BINARY_POINT - 1)) - 1;
117
- } else {
118
- /* set msb */
119
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
120
- }
121
+ /*
122
+ * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
123
+ * S390, SH4, TriCore, and Xtensa. Our other supported targets
124
+ * do not have floating-point.
125
+ */
126
+ if (snan_bit_is_one(status)) {
127
+ /* sign bit clear, set all frac bits other than msb */
128
+ dnan_pattern = 0b00111111;
129
+ } else {
130
+ /* sign bit clear, set frac msb */
131
+ dnan_pattern = 0b01000000;
132
+ }
133
#endif
134
+ }
135
+ assert(dnan_pattern != 0);
69
+
136
+
70
static void bcm2836_class_init(ObjectClass *oc, void *data)
137
+ sign = dnan_pattern >> 7;
71
{
138
+ /*
72
DeviceClass *dc = DEVICE_CLASS(oc);
139
+ * Place default_nan_pattern [6:0] into bits [62:56],
73
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
140
+ * and replecate bit [0] down into [55:0]
74
141
+ */
75
static const TypeInfo bcm283x_types[] = {
142
+ frac = deposit64(0, DECOMPOSED_BINARY_POINT - 7, 7, dnan_pattern);
76
{
143
+ frac = deposit64(frac, 0, DECOMPOSED_BINARY_POINT - 7, -(dnan_pattern & 1));
77
+ .name = TYPE_BCM2835,
144
78
+ .parent = TYPE_BCM283X,
145
*p = (FloatParts64) {
79
+ .class_init = bcm2835_class_init,
146
.cls = float_class_qnan,
80
+ }, {
81
.name = TYPE_BCM2836,
82
.parent = TYPE_BCM283X,
83
.class_init = bcm2836_class_init,
84
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/hw/arm/raspi.c
87
+++ b/hw/arm/raspi.c
88
@@ -XXX,XX +XXX,XX @@ FIELD(REV_CODE, MEMORY_SIZE, 20, 3);
89
FIELD(REV_CODE, STYLE, 23, 1);
90
91
typedef enum RaspiProcessorId {
92
+ PROCESSOR_ID_BCM2835 = 0,
93
PROCESSOR_ID_BCM2836 = 1,
94
PROCESSOR_ID_BCM2837 = 2,
95
} RaspiProcessorId;
96
@@ -XXX,XX +XXX,XX @@ static const struct {
97
const char *type;
98
int cores_count;
99
} soc_property[] = {
100
+ [PROCESSOR_ID_BCM2835] = {TYPE_BCM2835, 1},
101
[PROCESSOR_ID_BCM2836] = {TYPE_BCM2836, BCM283X_NCPUS},
102
[PROCESSOR_ID_BCM2837] = {TYPE_BCM2837, BCM283X_NCPUS},
103
};
104
--
147
--
105
2.20.1
148
2.34.1
106
107
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly for the tests/fp code.
2
2
3
The nanosecond unit greatly limits the dynamic range we can display in
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
clock value traces, for values in the order of 1GHz and more. The
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
internal representation can go way beyond this value and it is quite
5
Message-id: 20241202131347.498124-36-peter.maydell@linaro.org
6
common for today's clocks to be within those ranges.
6
---
7
tests/fp/fp-bench.c | 1 +
8
tests/fp/fp-test-log2.c | 1 +
9
tests/fp/fp-test.c | 1 +
10
3 files changed, 3 insertions(+)
7
11
8
For example, a frequency between 500MHz+ and 1GHz will be displayed as
12
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
9
1ns. Beyond 1GHz, it will show up as 0ns.
10
11
Replace nanosecond periods traces with frequencies in the Hz unit
12
to have more dynamic range in the trace output.
13
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
16
Signed-off-by: Luc Michel <luc@lmichel.fr>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
---
21
hw/core/clock.c | 6 +++---
22
hw/core/trace-events | 4 ++--
23
2 files changed, 5 insertions(+), 5 deletions(-)
24
25
diff --git a/hw/core/clock.c b/hw/core/clock.c
26
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/core/clock.c
14
--- a/tests/fp/fp-bench.c
28
+++ b/hw/core/clock.c
15
+++ b/tests/fp/fp-bench.c
29
@@ -XXX,XX +XXX,XX @@ bool clock_set(Clock *clk, uint64_t period)
16
@@ -XXX,XX +XXX,XX @@ static void run_bench(void)
30
if (clk->period == period) {
17
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
31
return false;
18
set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status);
32
}
19
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
33
- trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
20
+ set_float_default_nan_pattern(0b01000000, &soft_status);
34
- CLOCK_PERIOD_TO_NS(period));
21
35
+ trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
22
f = bench_funcs[operation][precision];
36
+ CLOCK_PERIOD_TO_HZ(period));
23
g_assert(f);
37
clk->period = period;
24
diff --git a/tests/fp/fp-test-log2.c b/tests/fp/fp-test-log2.c
38
39
return true;
40
@@ -XXX,XX +XXX,XX @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
41
if (child->period != clk->period) {
42
child->period = clk->period;
43
trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
44
- CLOCK_PERIOD_TO_NS(clk->period),
45
+ CLOCK_PERIOD_TO_HZ(clk->period),
46
call_callbacks);
47
if (call_callbacks && child->callback) {
48
child->callback(child->callback_opaque);
49
diff --git a/hw/core/trace-events b/hw/core/trace-events
50
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
51
--- a/hw/core/trace-events
26
--- a/tests/fp/fp-test-log2.c
52
+++ b/hw/core/trace-events
27
+++ b/tests/fp/fp-test-log2.c
53
@@ -XXX,XX +XXX,XX @@ resettable_transitional_function(void *obj, const char *objtype) "obj=%p(%s)"
28
@@ -XXX,XX +XXX,XX @@ int main(int ac, char **av)
54
# clock.c
29
int i;
55
clock_set_source(const char *clk, const char *src) "'%s', src='%s'"
30
56
clock_disconnect(const char *clk) "'%s'"
31
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
57
-clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64
32
+ set_float_default_nan_pattern(0b01000000, &qsf);
58
+clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', %"PRIu64"Hz->%"PRIu64"Hz"
33
set_float_rounding_mode(float_round_nearest_even, &qsf);
59
clock_propagate(const char *clk) "'%s'"
34
60
-clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d"
35
test.d = 0.0;
61
+clock_update(const char *clk, const char *src, uint64_t hz, int cb) "'%s', src='%s', val=%"PRIu64"Hz cb=%d"
36
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/fp/fp-test.c
39
+++ b/tests/fp/fp-test.c
40
@@ -XXX,XX +XXX,XX @@ void run_test(void)
41
*/
42
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
43
set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf);
44
+ set_float_default_nan_pattern(0b01000000, &qsf);
45
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
46
47
genCases_setLevel(test_level);
62
--
48
--
63
2.20.1
49
2.34.1
64
65
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly, and remove the ifdef from
2
parts64_default_nan().
2
3
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
5
Signed-off-by: Luc Michel <luc@lmichel.fr>
6
Tested-by: Guenter Roeck <linux@roeck-us.net>
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-37-peter.maydell@linaro.org
9
---
7
---
10
include/hw/clock.h | 5 +++++
8
target/microblaze/cpu.c | 2 ++
11
1 file changed, 5 insertions(+)
9
fpu/softfloat-specialize.c.inc | 3 +--
10
2 files changed, 3 insertions(+), 2 deletions(-)
12
11
13
diff --git a/include/hw/clock.h b/include/hw/clock.h
12
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
14
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
15
--- a/include/hw/clock.h
14
--- a/target/microblaze/cpu.c
16
+++ b/include/hw/clock.h
15
+++ b/target/microblaze/cpu.c
17
@@ -XXX,XX +XXX,XX @@ extern const VMStateDescription vmstate_clock;
16
@@ -XXX,XX +XXX,XX @@ static void mb_cpu_reset_hold(Object *obj, ResetType type)
18
VMSTATE_CLOCK_V(field, state, 0)
17
* this architecture.
19
#define VMSTATE_CLOCK_V(field, state, version) \
18
*/
20
VMSTATE_STRUCT_POINTER_V(field, state, version, vmstate_clock, Clock)
19
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
21
+#define VMSTATE_ARRAY_CLOCK(field, state, num) \
20
+ /* Default NaN: sign bit set, most significant frac bit set */
22
+ VMSTATE_ARRAY_CLOCK_V(field, state, num, 0)
21
+ set_float_default_nan_pattern(0b11000000, &env->fp_status);
23
+#define VMSTATE_ARRAY_CLOCK_V(field, state, num, version) \
22
24
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(field, state, num, version, \
23
#if defined(CONFIG_USER_ONLY)
25
+ vmstate_clock, Clock)
24
/* start in user mode with interrupts enabled. */
26
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
27
/**
26
index XXXXXXX..XXXXXXX 100644
28
* clock_setup_canonical_path:
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
30
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
31
/* Sign bit clear, all frac bits set */
32
dnan_pattern = 0b01111111;
33
-#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
34
- || defined(TARGET_MICROBLAZE)
35
+#elif defined(TARGET_I386) || defined(TARGET_X86_64)
36
/* Sign bit set, most significant frac bit set */
37
dnan_pattern = 0b11000000;
38
#elif defined(TARGET_HPPA)
29
--
39
--
30
2.20.1
40
2.34.1
31
32
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
Set the default NaN pattern explicitly, and remove the ifdef from
2
parts64_default_nan().
2
3
3
Included the newly implemented SBSA generic watchdog device model into
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
SBSA platform
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-38-peter.maydell@linaro.org
7
---
8
target/i386/tcg/fpu_helper.c | 4 ++++
9
fpu/softfloat-specialize.c.inc | 3 ---
10
2 files changed, 4 insertions(+), 3 deletions(-)
5
11
6
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
12
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20201027015927.29495-3-shashi.mallela@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
hw/arm/sbsa-ref.c | 23 +++++++++++++++++++++++
12
1 file changed, 23 insertions(+)
13
14
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
15
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/sbsa-ref.c
14
--- a/target/i386/tcg/fpu_helper.c
17
+++ b/hw/arm/sbsa-ref.c
15
+++ b/target/i386/tcg/fpu_helper.c
18
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env)
19
#include "hw/qdev-properties.h"
17
*/
20
#include "hw/usb.h"
18
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status);
21
#include "hw/char/pl011.h"
19
set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status);
22
+#include "hw/watchdog/sbsa_gwdt.h"
20
+ /* Default NaN: sign bit set, most significant frac bit set */
23
#include "net/net.h"
21
+ set_float_default_nan_pattern(0b11000000, &env->fp_status);
24
#include "qom/object.h"
22
+ set_float_default_nan_pattern(0b11000000, &env->mmx_status);
25
23
+ set_float_default_nan_pattern(0b11000000, &env->sse_status);
26
@@ -XXX,XX +XXX,XX @@ enum {
27
SBSA_GIC_DIST,
28
SBSA_GIC_REDIST,
29
SBSA_SECURE_EC,
30
+ SBSA_GWDT,
31
+ SBSA_GWDT_REFRESH,
32
+ SBSA_GWDT_CONTROL,
33
SBSA_SMMU,
34
SBSA_UART,
35
SBSA_RTC,
36
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry sbsa_ref_memmap[] = {
37
[SBSA_GIC_DIST] = { 0x40060000, 0x00010000 },
38
[SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 },
39
[SBSA_SECURE_EC] = { 0x50000000, 0x00001000 },
40
+ [SBSA_GWDT_REFRESH] = { 0x50010000, 0x00001000 },
41
+ [SBSA_GWDT_CONTROL] = { 0x50011000, 0x00001000 },
42
[SBSA_UART] = { 0x60000000, 0x00001000 },
43
[SBSA_RTC] = { 0x60010000, 0x00001000 },
44
[SBSA_GPIO] = { 0x60020000, 0x00001000 },
45
@@ -XXX,XX +XXX,XX @@ static const int sbsa_ref_irqmap[] = {
46
[SBSA_AHCI] = 10,
47
[SBSA_EHCI] = 11,
48
[SBSA_SMMU] = 12, /* ... to 15 */
49
+ [SBSA_GWDT] = 16,
50
};
51
52
static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
53
@@ -XXX,XX +XXX,XX @@ static void create_rtc(const SBSAMachineState *sms)
54
sysbus_create_simple("pl031", base, qdev_get_gpio_in(sms->gic, irq));
55
}
24
}
56
25
57
+static void create_wdt(const SBSAMachineState *sms)
26
static inline uint8_t save_exception_flags(CPUX86State *env)
58
+{
27
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
59
+ hwaddr rbase = sbsa_ref_memmap[SBSA_GWDT_REFRESH].base;
28
index XXXXXXX..XXXXXXX 100644
60
+ hwaddr cbase = sbsa_ref_memmap[SBSA_GWDT_CONTROL].base;
29
--- a/fpu/softfloat-specialize.c.inc
61
+ DeviceState *dev = qdev_new(TYPE_WDT_SBSA);
30
+++ b/fpu/softfloat-specialize.c.inc
62
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
31
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
63
+ int irq = sbsa_ref_irqmap[SBSA_GWDT];
32
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
64
+
33
/* Sign bit clear, all frac bits set */
65
+ sysbus_realize_and_unref(s, &error_fatal);
34
dnan_pattern = 0b01111111;
66
+ sysbus_mmio_map(s, 0, rbase);
35
-#elif defined(TARGET_I386) || defined(TARGET_X86_64)
67
+ sysbus_mmio_map(s, 1, cbase);
36
- /* Sign bit set, most significant frac bit set */
68
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(sms->gic, irq));
37
- dnan_pattern = 0b11000000;
69
+}
38
#elif defined(TARGET_HPPA)
70
+
39
/* Sign bit clear, msb-1 frac bit set */
71
static DeviceState *gpio_key_dev;
40
dnan_pattern = 0b00100000;
72
static void sbsa_ref_powerdown_req(Notifier *n, void *opaque)
73
{
74
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
75
76
create_rtc(sms);
77
78
+ create_wdt(sms);
79
+
80
create_gpio(sms);
81
82
create_ahci(sms);
83
--
41
--
84
2.20.1
42
2.34.1
85
86
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly, and remove the ifdef from
2
parts64_default_nan().
2
3
3
A clock mux can be configured to select one of its 10 sources through
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
the CM_CTL register. It also embeds yet another clock divider, composed
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
of an integer part and a fractional part. The number of bits of each
6
Message-id: 20241202131347.498124-39-peter.maydell@linaro.org
6
part is mux dependent.
7
---
8
target/hppa/fpu_helper.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 3 ---
10
2 files changed, 2 insertions(+), 3 deletions(-)
7
11
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
hw/misc/bcm2835_cprman.c | 53 +++++++++++++++++++++++++++++++++++++++-
15
1 file changed, 52 insertions(+), 1 deletion(-)
16
17
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
18
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/misc/bcm2835_cprman.c
14
--- a/target/hppa/fpu_helper.c
20
+++ b/hw/misc/bcm2835_cprman.c
15
+++ b/target/hppa/fpu_helper.c
21
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
16
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
22
17
set_float_3nan_prop_rule(float_3nan_prop_abc, &env->fp_status);
23
/* clock mux */
18
/* For inf * 0 + NaN, return the input NaN */
24
19
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
25
+static bool clock_mux_is_enabled(CprmanClockMuxState *mux)
20
+ /* Default NaN: sign bit clear, msb-1 frac bit set */
26
+{
21
+ set_float_default_nan_pattern(0b00100000, &env->fp_status);
27
+ return FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, ENABLE);
28
+}
29
+
30
static void clock_mux_update(CprmanClockMuxState *mux)
31
{
32
- clock_update(mux->out, 0);
33
+ uint64_t freq;
34
+ uint32_t div, src = FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, SRC);
35
+ bool enabled = clock_mux_is_enabled(mux);
36
+
37
+ *mux->reg_ctl = FIELD_DP32(*mux->reg_ctl, CM_CLOCKx_CTL, BUSY, enabled);
38
+
39
+ if (!enabled) {
40
+ clock_update(mux->out, 0);
41
+ return;
42
+ }
43
+
44
+ freq = clock_get_hz(mux->srcs[src]);
45
+
46
+ if (mux->int_bits == 0 && mux->frac_bits == 0) {
47
+ clock_update_hz(mux->out, freq);
48
+ return;
49
+ }
50
+
51
+ /*
52
+ * The divider has an integer and a fractional part. The size of each part
53
+ * varies with the muxes (int_bits and frac_bits). Both parts are
54
+ * concatenated, with the integer part always starting at bit 12.
55
+ *
56
+ * 31 12 11 0
57
+ * ------------------------------
58
+ * CM_DIV | | int | frac | |
59
+ * ------------------------------
60
+ * <-----> <------>
61
+ * int_bits frac_bits
62
+ */
63
+ div = extract32(*mux->reg_div,
64
+ R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits,
65
+ mux->int_bits + mux->frac_bits);
66
+
67
+ if (!div) {
68
+ clock_update(mux->out, 0);
69
+ return;
70
+ }
71
+
72
+ freq = muldiv64(freq, 1 << mux->frac_bits, div);
73
+
74
+ clock_update_hz(mux->out, freq);
75
}
22
}
76
23
77
static void clock_mux_src_update(void *opaque)
24
void cpu_hppa_loaded_fr0(CPUHPPAState *env)
78
{
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
79
CprmanClockMuxState **backref = opaque;
26
index XXXXXXX..XXXXXXX 100644
80
CprmanClockMuxState *s = *backref;
27
--- a/fpu/softfloat-specialize.c.inc
81
+ CprmanClockMuxSource src = backref - s->backref;
28
+++ b/fpu/softfloat-specialize.c.inc
82
+
29
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
83
+ if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) {
30
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
84
+ return;
31
/* Sign bit clear, all frac bits set */
85
+ }
32
dnan_pattern = 0b01111111;
86
33
-#elif defined(TARGET_HPPA)
87
clock_mux_update(s);
34
- /* Sign bit clear, msb-1 frac bit set */
88
}
35
- dnan_pattern = 0b00100000;
36
#elif defined(TARGET_HEXAGON)
37
/* Sign bit set, all frac bits set. */
38
dnan_pattern = 0b11111111;
89
--
39
--
90
2.20.1
40
2.34.1
91
92
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly for the alpha target.
2
2
3
Connect the 'uart-out' clock from the CPRMAN to the PL011 instance.
4
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Luc Michel <luc@lmichel.fr>
7
Tested-by: Guenter Roeck <linux@roeck-us.net>
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-40-peter.maydell@linaro.org
10
---
6
---
11
hw/arm/bcm2835_peripherals.c | 2 ++
7
target/alpha/cpu.c | 2 ++
12
1 file changed, 2 insertions(+)
8
1 file changed, 2 insertions(+)
13
9
14
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
10
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
15
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/bcm2835_peripherals.c
12
--- a/target/alpha/cpu.c
17
+++ b/hw/arm/bcm2835_peripherals.c
13
+++ b/target/alpha/cpu.c
18
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
14
@@ -XXX,XX +XXX,XX @@ static void alpha_cpu_initfn(Object *obj)
19
}
15
* operand in Fa. That is float_2nan_prop_ba.
20
memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
16
*/
21
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
17
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
22
+ qdev_connect_clock_in(DEVICE(&s->uart0), "clk",
18
+ /* Default NaN: sign bit clear, msb frac bit set */
23
+ qdev_get_clock_out(DEVICE(&s->cprman), "uart-out"));
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
24
20
#if defined(CONFIG_USER_ONLY)
25
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
21
env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
26
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
22
cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
27
--
23
--
28
2.20.1
24
2.34.1
29
30
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly for the arm target.
2
This includes setting it for the old linux-user nwfpe emulation.
3
For nwfpe, our default doesn't match the real kernel, but we
4
avoid making a behaviour change in this commit.
2
5
3
Add a clock input to the PL011 UART so we can compute the current baud
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
rate and trace it. This is intended for developers who wish to use QEMU
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
to e.g. debug their firmware or to figure out the baud rate configured
8
Message-id: 20241202131347.498124-41-peter.maydell@linaro.org
6
by an unknown/closed source binary.
9
---
10
linux-user/arm/nwfpe/fpa11.c | 5 +++++
11
target/arm/cpu.c | 2 ++
12
2 files changed, 7 insertions(+)
7
13
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
include/hw/char/pl011.h | 1 +
15
hw/char/pl011.c | 45 +++++++++++++++++++++++++++++++++++++++++
16
hw/char/trace-events | 1 +
17
3 files changed, 47 insertions(+)
18
19
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
20
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/char/pl011.h
16
--- a/linux-user/arm/nwfpe/fpa11.c
22
+++ b/include/hw/char/pl011.h
17
+++ b/linux-user/arm/nwfpe/fpa11.c
23
@@ -XXX,XX +XXX,XX @@ struct PL011State {
18
@@ -XXX,XX +XXX,XX @@ void resetFPA11(void)
24
int read_trigger;
19
* this late date.
25
CharBackend chr;
20
*/
26
qemu_irq irq[6];
21
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status);
27
+ Clock *clk;
22
+ /*
28
const unsigned char *id;
23
+ * Use the same default NaN value as Arm VFP. This doesn't match
29
};
24
+ * the Linux kernel's nwfpe emulation, which uses an all-1s value.
30
25
+ */
31
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
26
+ set_float_default_nan_pattern(0b01000000, &fpa11->fp_status);
27
}
28
29
void SetRoundingMode(const unsigned int opcode)
30
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
32
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/char/pl011.c
32
--- a/target/arm/cpu.c
34
+++ b/hw/char/pl011.c
33
+++ b/target/arm/cpu.c
35
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
36
#include "hw/char/pl011.h"
35
* the pseudocode function the arguments are in the order c, a, b.
37
#include "hw/irq.h"
36
* * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
38
#include "hw/sysbus.h"
37
* and the input NaN if it is signalling
39
+#include "hw/qdev-clock.h"
38
+ * * Default NaN has sign bit clear, msb frac bit set
40
#include "migration/vmstate.h"
39
*/
41
#include "chardev/char-fe.h"
40
static void arm_set_default_fp_behaviours(float_status *s)
42
#include "qemu/log.h"
41
{
43
@@ -XXX,XX +XXX,XX @@ static void pl011_set_read_trigger(PL011State *s)
42
@@ -XXX,XX +XXX,XX @@ static void arm_set_default_fp_behaviours(float_status *s)
44
s->read_trigger = 1;
43
set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
44
set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
45
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
46
+ set_float_default_nan_pattern(0b01000000, s);
45
}
47
}
46
48
47
+static unsigned int pl011_get_baudrate(const PL011State *s)
49
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
48
+{
49
+ uint64_t clk;
50
+
51
+ if (s->fbrd == 0) {
52
+ return 0;
53
+ }
54
+
55
+ clk = clock_get_hz(s->clk);
56
+ return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
57
+}
58
+
59
+static void pl011_trace_baudrate_change(const PL011State *s)
60
+{
61
+ trace_pl011_baudrate_change(pl011_get_baudrate(s),
62
+ clock_get_hz(s->clk),
63
+ s->ibrd, s->fbrd);
64
+}
65
+
66
static void pl011_write(void *opaque, hwaddr offset,
67
uint64_t value, unsigned size)
68
{
69
@@ -XXX,XX +XXX,XX @@ static void pl011_write(void *opaque, hwaddr offset,
70
break;
71
case 9: /* UARTIBRD */
72
s->ibrd = value;
73
+ pl011_trace_baudrate_change(s);
74
break;
75
case 10: /* UARTFBRD */
76
s->fbrd = value;
77
+ pl011_trace_baudrate_change(s);
78
break;
79
case 11: /* UARTLCR_H */
80
/* Reset the FIFO state on FIFO enable or disable */
81
@@ -XXX,XX +XXX,XX @@ static void pl011_event(void *opaque, QEMUChrEvent event)
82
pl011_put_fifo(opaque, 0x400);
83
}
84
85
+static void pl011_clock_update(void *opaque)
86
+{
87
+ PL011State *s = PL011(opaque);
88
+
89
+ pl011_trace_baudrate_change(s);
90
+}
91
+
92
static const MemoryRegionOps pl011_ops = {
93
.read = pl011_read,
94
.write = pl011_write,
95
.endianness = DEVICE_NATIVE_ENDIAN,
96
};
97
98
+static const VMStateDescription vmstate_pl011_clock = {
99
+ .name = "pl011/clock",
100
+ .version_id = 1,
101
+ .minimum_version_id = 1,
102
+ .fields = (VMStateField[]) {
103
+ VMSTATE_CLOCK(clk, PL011State),
104
+ VMSTATE_END_OF_LIST()
105
+ }
106
+};
107
+
108
static const VMStateDescription vmstate_pl011 = {
109
.name = "pl011",
110
.version_id = 2,
111
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pl011 = {
112
VMSTATE_INT32(read_count, PL011State),
113
VMSTATE_INT32(read_trigger, PL011State),
114
VMSTATE_END_OF_LIST()
115
+ },
116
+ .subsections = (const VMStateDescription * []) {
117
+ &vmstate_pl011_clock,
118
+ NULL
119
}
120
};
121
122
@@ -XXX,XX +XXX,XX @@ static void pl011_init(Object *obj)
123
sysbus_init_irq(sbd, &s->irq[i]);
124
}
125
126
+ s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s);
127
+
128
s->read_trigger = 1;
129
s->ifl = 0x12;
130
s->cr = 0x300;
131
diff --git a/hw/char/trace-events b/hw/char/trace-events
132
index XXXXXXX..XXXXXXX 100644
133
--- a/hw/char/trace-events
134
+++ b/hw/char/trace-events
135
@@ -XXX,XX +XXX,XX @@ pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
136
pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
137
pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d"
138
pl011_put_fifo_full(void) "FIFO now full, RXFF set"
139
+pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
140
141
# cmsdk-apb-uart.c
142
cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
143
--
50
--
144
2.20.1
51
2.34.1
145
146
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly for loongarch.
2
2
3
The clock multiplexers are the last clock stage in the CPRMAN. Each mux
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
outputs one clock signal that goes out of the CPRMAN to the SoC
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
peripherals.
5
Message-id: 20241202131347.498124-42-peter.maydell@linaro.org
6
---
7
target/loongarch/tcg/fpu_helper.c | 2 ++
8
1 file changed, 2 insertions(+)
6
9
7
Each mux has at most 10 sources. The sources 0 to 3 are common to all
10
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
8
muxes. They are:
9
0. ground (no clock signal)
10
1. the main oscillator (xosc)
11
2. "test debug 0" clock
12
3. "test debug 1" clock
13
14
Test debug 0 and 1 are actual clock muxes that can be used as sources to
15
other muxes (for debug purpose).
16
17
Sources 4 to 9 are mux specific and can be unpopulated (grounded). Those
18
sources are fed by the PLL channels outputs.
19
20
One corner case exists for DSI0E and DSI0P muxes. They have their source
21
number 4 connected to an intermediate multiplexer that can select
22
between PLLA-DSI0 and PLLD-DSI0 channel. This multiplexer is called
23
DSI0HSCK and is not a clock mux as such. It is really a simple mux from
24
the hardware point of view (see https://elinux.org/The_Undocumented_Pi).
25
This mux is not implemented in this commit.
26
27
Note that there is some muxes for which sources are unknown (because of
28
a lack of documentation). For those cases all the sources are connected
29
to ground in this implementation.
30
31
Each clock mux output is exported by the CPRMAN at the qdev level,
32
adding the suffix '-out' to the mux name to form the output clock name.
33
(E.g. the 'uart' mux sees its output exported as 'uart-out' at the
34
CPRMAN level.)
35
36
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
37
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
38
Signed-off-by: Luc Michel <luc@lmichel.fr>
39
Tested-by: Guenter Roeck <linux@roeck-us.net>
40
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
41
---
42
include/hw/misc/bcm2835_cprman.h | 85 +++++
43
include/hw/misc/bcm2835_cprman_internals.h | 422 +++++++++++++++++++++
44
hw/misc/bcm2835_cprman.c | 151 ++++++++
45
3 files changed, 658 insertions(+)
46
47
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
48
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
49
--- a/include/hw/misc/bcm2835_cprman.h
12
--- a/target/loongarch/tcg/fpu_helper.c
50
+++ b/include/hw/misc/bcm2835_cprman.h
13
+++ b/target/loongarch/tcg/fpu_helper.c
51
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPllChannel {
14
@@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env)
52
CPRMAN_PLLB_CHANNEL_ARM,
15
*/
53
16
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
54
CPRMAN_NUM_PLL_CHANNEL,
17
set_float_3nan_prop_rule(float_3nan_prop_s_cab, &env->fp_status);
55
+
18
+ /* Default NaN: sign bit clear, msb frac bit set */
56
+ /* Special values used when connecting clock sources to clocks */
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
57
+ CPRMAN_CLOCK_SRC_NORMAL = -1,
58
+ CPRMAN_CLOCK_SRC_FORCE_GROUND = -2,
59
+ CPRMAN_CLOCK_SRC_DSI0HSCK = -3,
60
} CprmanPllChannel;
61
62
+typedef enum CprmanClockMux {
63
+ CPRMAN_CLOCK_GNRIC,
64
+ CPRMAN_CLOCK_VPU,
65
+ CPRMAN_CLOCK_SYS,
66
+ CPRMAN_CLOCK_PERIA,
67
+ CPRMAN_CLOCK_PERII,
68
+ CPRMAN_CLOCK_H264,
69
+ CPRMAN_CLOCK_ISP,
70
+ CPRMAN_CLOCK_V3D,
71
+ CPRMAN_CLOCK_CAM0,
72
+ CPRMAN_CLOCK_CAM1,
73
+ CPRMAN_CLOCK_CCP2,
74
+ CPRMAN_CLOCK_DSI0E,
75
+ CPRMAN_CLOCK_DSI0P,
76
+ CPRMAN_CLOCK_DPI,
77
+ CPRMAN_CLOCK_GP0,
78
+ CPRMAN_CLOCK_GP1,
79
+ CPRMAN_CLOCK_GP2,
80
+ CPRMAN_CLOCK_HSM,
81
+ CPRMAN_CLOCK_OTP,
82
+ CPRMAN_CLOCK_PCM,
83
+ CPRMAN_CLOCK_PWM,
84
+ CPRMAN_CLOCK_SLIM,
85
+ CPRMAN_CLOCK_SMI,
86
+ CPRMAN_CLOCK_TEC,
87
+ CPRMAN_CLOCK_TD0,
88
+ CPRMAN_CLOCK_TD1,
89
+ CPRMAN_CLOCK_TSENS,
90
+ CPRMAN_CLOCK_TIMER,
91
+ CPRMAN_CLOCK_UART,
92
+ CPRMAN_CLOCK_VEC,
93
+ CPRMAN_CLOCK_PULSE,
94
+ CPRMAN_CLOCK_SDC,
95
+ CPRMAN_CLOCK_ARM,
96
+ CPRMAN_CLOCK_AVEO,
97
+ CPRMAN_CLOCK_EMMC,
98
+ CPRMAN_CLOCK_EMMC2,
99
+
100
+ CPRMAN_NUM_CLOCK_MUX
101
+} CprmanClockMux;
102
+
103
+typedef enum CprmanClockMuxSource {
104
+ CPRMAN_CLOCK_SRC_GND = 0,
105
+ CPRMAN_CLOCK_SRC_XOSC,
106
+ CPRMAN_CLOCK_SRC_TD0,
107
+ CPRMAN_CLOCK_SRC_TD1,
108
+ CPRMAN_CLOCK_SRC_PLLA,
109
+ CPRMAN_CLOCK_SRC_PLLC,
110
+ CPRMAN_CLOCK_SRC_PLLD,
111
+ CPRMAN_CLOCK_SRC_PLLH,
112
+ CPRMAN_CLOCK_SRC_PLLC_CORE1,
113
+ CPRMAN_CLOCK_SRC_PLLC_CORE2,
114
+
115
+ CPRMAN_NUM_CLOCK_MUX_SRC
116
+} CprmanClockMuxSource;
117
+
118
typedef struct CprmanPllState {
119
/*< private >*/
120
DeviceState parent_obj;
121
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllChannelState {
122
Clock *out;
123
} CprmanPllChannelState;
124
125
+typedef struct CprmanClockMuxState {
126
+ /*< private >*/
127
+ DeviceState parent_obj;
128
+
129
+ /*< public >*/
130
+ CprmanClockMux id;
131
+
132
+ uint32_t *reg_ctl;
133
+ uint32_t *reg_div;
134
+ int int_bits;
135
+ int frac_bits;
136
+
137
+ Clock *srcs[CPRMAN_NUM_CLOCK_MUX_SRC];
138
+ Clock *out;
139
+
140
+ /*
141
+ * Used by clock srcs update callback to retrieve both the clock and the
142
+ * source number.
143
+ */
144
+ struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
145
+} CprmanClockMuxState;
146
+
147
struct BCM2835CprmanState {
148
/*< private >*/
149
SysBusDevice parent_obj;
150
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
151
152
CprmanPllState plls[CPRMAN_NUM_PLL];
153
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
154
+ CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
155
156
uint32_t regs[CPRMAN_NUM_REGS];
157
uint32_t xosc_freq;
158
159
Clock *xosc;
160
+ Clock *gnd;
161
};
162
163
#endif
164
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
165
index XXXXXXX..XXXXXXX 100644
166
--- a/include/hw/misc/bcm2835_cprman_internals.h
167
+++ b/include/hw/misc/bcm2835_cprman_internals.h
168
@@ -XXX,XX +XXX,XX @@
169
170
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
171
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
172
+#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
173
174
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
175
TYPE_CPRMAN_PLL)
176
DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
177
TYPE_CPRMAN_PLL_CHANNEL)
178
+DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
179
+ TYPE_CPRMAN_CLOCK_MUX)
180
181
/* Register map */
182
183
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLH_STS, 0x1660)
184
185
REG32(A2W_PLLB_ARM, 0x13e0)
186
187
+/* Clock muxes */
188
+REG32(CM_GNRICCTL, 0x000)
189
+ FIELD(CM_CLOCKx_CTL, SRC, 0, 4)
190
+ FIELD(CM_CLOCKx_CTL, ENABLE, 4, 1)
191
+ FIELD(CM_CLOCKx_CTL, KILL, 5, 1)
192
+ FIELD(CM_CLOCKx_CTL, GATE, 6, 1)
193
+ FIELD(CM_CLOCKx_CTL, BUSY, 7, 1)
194
+ FIELD(CM_CLOCKx_CTL, BUSYD, 8, 1)
195
+ FIELD(CM_CLOCKx_CTL, MASH, 9, 2)
196
+ FIELD(CM_CLOCKx_CTL, FLIP, 11, 1)
197
+REG32(CM_GNRICDIV, 0x004)
198
+ FIELD(CM_CLOCKx_DIV, FRAC, 0, 12)
199
+REG32(CM_VPUCTL, 0x008)
200
+REG32(CM_VPUDIV, 0x00c)
201
+REG32(CM_SYSCTL, 0x010)
202
+REG32(CM_SYSDIV, 0x014)
203
+REG32(CM_PERIACTL, 0x018)
204
+REG32(CM_PERIADIV, 0x01c)
205
+REG32(CM_PERIICTL, 0x020)
206
+REG32(CM_PERIIDIV, 0x024)
207
+REG32(CM_H264CTL, 0x028)
208
+REG32(CM_H264DIV, 0x02c)
209
+REG32(CM_ISPCTL, 0x030)
210
+REG32(CM_ISPDIV, 0x034)
211
+REG32(CM_V3DCTL, 0x038)
212
+REG32(CM_V3DDIV, 0x03c)
213
+REG32(CM_CAM0CTL, 0x040)
214
+REG32(CM_CAM0DIV, 0x044)
215
+REG32(CM_CAM1CTL, 0x048)
216
+REG32(CM_CAM1DIV, 0x04c)
217
+REG32(CM_CCP2CTL, 0x050)
218
+REG32(CM_CCP2DIV, 0x054)
219
+REG32(CM_DSI0ECTL, 0x058)
220
+REG32(CM_DSI0EDIV, 0x05c)
221
+REG32(CM_DSI0PCTL, 0x060)
222
+REG32(CM_DSI0PDIV, 0x064)
223
+REG32(CM_DPICTL, 0x068)
224
+REG32(CM_DPIDIV, 0x06c)
225
+REG32(CM_GP0CTL, 0x070)
226
+REG32(CM_GP0DIV, 0x074)
227
+REG32(CM_GP1CTL, 0x078)
228
+REG32(CM_GP1DIV, 0x07c)
229
+REG32(CM_GP2CTL, 0x080)
230
+REG32(CM_GP2DIV, 0x084)
231
+REG32(CM_HSMCTL, 0x088)
232
+REG32(CM_HSMDIV, 0x08c)
233
+REG32(CM_OTPCTL, 0x090)
234
+REG32(CM_OTPDIV, 0x094)
235
+REG32(CM_PCMCTL, 0x098)
236
+REG32(CM_PCMDIV, 0x09c)
237
+REG32(CM_PWMCTL, 0x0a0)
238
+REG32(CM_PWMDIV, 0x0a4)
239
+REG32(CM_SLIMCTL, 0x0a8)
240
+REG32(CM_SLIMDIV, 0x0ac)
241
+REG32(CM_SMICTL, 0x0b0)
242
+REG32(CM_SMIDIV, 0x0b4)
243
+REG32(CM_TCNTCTL, 0x0c0)
244
+REG32(CM_TCNTCNT, 0x0c4)
245
+REG32(CM_TECCTL, 0x0c8)
246
+REG32(CM_TECDIV, 0x0cc)
247
+REG32(CM_TD0CTL, 0x0d0)
248
+REG32(CM_TD0DIV, 0x0d4)
249
+REG32(CM_TD1CTL, 0x0d8)
250
+REG32(CM_TD1DIV, 0x0dc)
251
+REG32(CM_TSENSCTL, 0x0e0)
252
+REG32(CM_TSENSDIV, 0x0e4)
253
+REG32(CM_TIMERCTL, 0x0e8)
254
+REG32(CM_TIMERDIV, 0x0ec)
255
+REG32(CM_UARTCTL, 0x0f0)
256
+REG32(CM_UARTDIV, 0x0f4)
257
+REG32(CM_VECCTL, 0x0f8)
258
+REG32(CM_VECDIV, 0x0fc)
259
+REG32(CM_PULSECTL, 0x190)
260
+REG32(CM_PULSEDIV, 0x194)
261
+REG32(CM_SDCCTL, 0x1a8)
262
+REG32(CM_SDCDIV, 0x1ac)
263
+REG32(CM_ARMCTL, 0x1b0)
264
+REG32(CM_AVEOCTL, 0x1b8)
265
+REG32(CM_AVEODIV, 0x1bc)
266
+REG32(CM_EMMCCTL, 0x1c0)
267
+REG32(CM_EMMCDIV, 0x1c4)
268
+REG32(CM_EMMC2CTL, 0x1d0)
269
+REG32(CM_EMMC2DIV, 0x1d4)
270
+
271
/* misc registers */
272
REG32(CM_LOCK, 0x114)
273
FIELD(CM_LOCK, FLOCKH, 12, 1)
274
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
275
channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
276
}
20
}
277
21
278
+/* Clock mux init info */
22
int ieee_ex_to_loongarch(int xcpt)
279
+typedef struct ClockMuxInitInfo {
280
+ const char *name;
281
+ size_t cm_offset; /* cm_offset[0]->CM_CTL, cm_offset[1]->CM_DIV */
282
+ int int_bits;
283
+ int frac_bits;
284
+
285
+ CprmanPllChannel src_mapping[CPRMAN_NUM_CLOCK_MUX_SRC];
286
+} ClockMuxInitInfo;
287
+
288
+/*
289
+ * Each clock mux can have up to 10 sources. Sources 0 to 3 are always the
290
+ * same (ground, xosc, td0, td1). Sources 4 to 9 are mux specific, and are not
291
+ * always populated. The following macros catch all those cases.
292
+ */
293
+
294
+/* Unknown mapping. Connect everything to ground */
295
+#define SRC_MAPPING_INFO_unknown \
296
+ .src_mapping = { \
297
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* gnd */ \
298
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* xosc */ \
299
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 0 */ \
300
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 1 */ \
301
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll a */ \
302
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c */ \
303
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll d */ \
304
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll h */ \
305
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core1 */ \
306
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core2 */ \
307
+ }
308
+
309
+/* Only the oscillator and the two test debug clocks */
310
+#define SRC_MAPPING_INFO_xosc \
311
+ .src_mapping = { \
312
+ CPRMAN_CLOCK_SRC_NORMAL, \
313
+ CPRMAN_CLOCK_SRC_NORMAL, \
314
+ CPRMAN_CLOCK_SRC_NORMAL, \
315
+ CPRMAN_CLOCK_SRC_NORMAL, \
316
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
317
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
318
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
319
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
320
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
321
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
322
+ }
323
+
324
+/* All the PLL "core" channels */
325
+#define SRC_MAPPING_INFO_core \
326
+ .src_mapping = { \
327
+ CPRMAN_CLOCK_SRC_NORMAL, \
328
+ CPRMAN_CLOCK_SRC_NORMAL, \
329
+ CPRMAN_CLOCK_SRC_NORMAL, \
330
+ CPRMAN_CLOCK_SRC_NORMAL, \
331
+ CPRMAN_PLLA_CHANNEL_CORE, \
332
+ CPRMAN_PLLC_CHANNEL_CORE0, \
333
+ CPRMAN_PLLD_CHANNEL_CORE, \
334
+ CPRMAN_PLLH_CHANNEL_AUX, \
335
+ CPRMAN_PLLC_CHANNEL_CORE1, \
336
+ CPRMAN_PLLC_CHANNEL_CORE2, \
337
+ }
338
+
339
+/* All the PLL "per" channels */
340
+#define SRC_MAPPING_INFO_periph \
341
+ .src_mapping = { \
342
+ CPRMAN_CLOCK_SRC_NORMAL, \
343
+ CPRMAN_CLOCK_SRC_NORMAL, \
344
+ CPRMAN_CLOCK_SRC_NORMAL, \
345
+ CPRMAN_CLOCK_SRC_NORMAL, \
346
+ CPRMAN_PLLA_CHANNEL_PER, \
347
+ CPRMAN_PLLC_CHANNEL_PER, \
348
+ CPRMAN_PLLD_CHANNEL_PER, \
349
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
350
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
351
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
352
+ }
353
+
354
+/*
355
+ * The DSI0 channels. This one got an intermediate mux between the PLL channels
356
+ * and the clock input.
357
+ */
358
+#define SRC_MAPPING_INFO_dsi0 \
359
+ .src_mapping = { \
360
+ CPRMAN_CLOCK_SRC_NORMAL, \
361
+ CPRMAN_CLOCK_SRC_NORMAL, \
362
+ CPRMAN_CLOCK_SRC_NORMAL, \
363
+ CPRMAN_CLOCK_SRC_NORMAL, \
364
+ CPRMAN_CLOCK_SRC_DSI0HSCK, \
365
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
366
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
367
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
368
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
369
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
370
+ }
371
+
372
+/* The DSI1 channel */
373
+#define SRC_MAPPING_INFO_dsi1 \
374
+ .src_mapping = { \
375
+ CPRMAN_CLOCK_SRC_NORMAL, \
376
+ CPRMAN_CLOCK_SRC_NORMAL, \
377
+ CPRMAN_CLOCK_SRC_NORMAL, \
378
+ CPRMAN_CLOCK_SRC_NORMAL, \
379
+ CPRMAN_PLLD_CHANNEL_DSI1, \
380
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
381
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
382
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
383
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
384
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
385
+ }
386
+
387
+#define FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_) \
388
+ SRC_MAPPING_INFO_ ## kind_
389
+
390
+#define FILL_CLOCK_MUX_INIT_INFO(clock_, kind_) \
391
+ .cm_offset = R_CM_ ## clock_ ## CTL, \
392
+ FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_)
393
+
394
+static ClockMuxInitInfo CLOCK_MUX_INIT_INFO[] = {
395
+ [CPRMAN_CLOCK_GNRIC] = {
396
+ .name = "gnric",
397
+ FILL_CLOCK_MUX_INIT_INFO(GNRIC, unknown),
398
+ },
399
+ [CPRMAN_CLOCK_VPU] = {
400
+ .name = "vpu",
401
+ .int_bits = 12,
402
+ .frac_bits = 8,
403
+ FILL_CLOCK_MUX_INIT_INFO(VPU, core),
404
+ },
405
+ [CPRMAN_CLOCK_SYS] = {
406
+ .name = "sys",
407
+ FILL_CLOCK_MUX_INIT_INFO(SYS, unknown),
408
+ },
409
+ [CPRMAN_CLOCK_PERIA] = {
410
+ .name = "peria",
411
+ FILL_CLOCK_MUX_INIT_INFO(PERIA, unknown),
412
+ },
413
+ [CPRMAN_CLOCK_PERII] = {
414
+ .name = "perii",
415
+ FILL_CLOCK_MUX_INIT_INFO(PERII, unknown),
416
+ },
417
+ [CPRMAN_CLOCK_H264] = {
418
+ .name = "h264",
419
+ .int_bits = 4,
420
+ .frac_bits = 8,
421
+ FILL_CLOCK_MUX_INIT_INFO(H264, core),
422
+ },
423
+ [CPRMAN_CLOCK_ISP] = {
424
+ .name = "isp",
425
+ .int_bits = 4,
426
+ .frac_bits = 8,
427
+ FILL_CLOCK_MUX_INIT_INFO(ISP, core),
428
+ },
429
+ [CPRMAN_CLOCK_V3D] = {
430
+ .name = "v3d",
431
+ FILL_CLOCK_MUX_INIT_INFO(V3D, core),
432
+ },
433
+ [CPRMAN_CLOCK_CAM0] = {
434
+ .name = "cam0",
435
+ .int_bits = 4,
436
+ .frac_bits = 8,
437
+ FILL_CLOCK_MUX_INIT_INFO(CAM0, periph),
438
+ },
439
+ [CPRMAN_CLOCK_CAM1] = {
440
+ .name = "cam1",
441
+ .int_bits = 4,
442
+ .frac_bits = 8,
443
+ FILL_CLOCK_MUX_INIT_INFO(CAM1, periph),
444
+ },
445
+ [CPRMAN_CLOCK_CCP2] = {
446
+ .name = "ccp2",
447
+ FILL_CLOCK_MUX_INIT_INFO(CCP2, unknown),
448
+ },
449
+ [CPRMAN_CLOCK_DSI0E] = {
450
+ .name = "dsi0e",
451
+ .int_bits = 4,
452
+ .frac_bits = 8,
453
+ FILL_CLOCK_MUX_INIT_INFO(DSI0E, dsi0),
454
+ },
455
+ [CPRMAN_CLOCK_DSI0P] = {
456
+ .name = "dsi0p",
457
+ .int_bits = 0,
458
+ .frac_bits = 0,
459
+ FILL_CLOCK_MUX_INIT_INFO(DSI0P, dsi0),
460
+ },
461
+ [CPRMAN_CLOCK_DPI] = {
462
+ .name = "dpi",
463
+ .int_bits = 4,
464
+ .frac_bits = 8,
465
+ FILL_CLOCK_MUX_INIT_INFO(DPI, periph),
466
+ },
467
+ [CPRMAN_CLOCK_GP0] = {
468
+ .name = "gp0",
469
+ .int_bits = 12,
470
+ .frac_bits = 12,
471
+ FILL_CLOCK_MUX_INIT_INFO(GP0, periph),
472
+ },
473
+ [CPRMAN_CLOCK_GP1] = {
474
+ .name = "gp1",
475
+ .int_bits = 12,
476
+ .frac_bits = 12,
477
+ FILL_CLOCK_MUX_INIT_INFO(GP1, periph),
478
+ },
479
+ [CPRMAN_CLOCK_GP2] = {
480
+ .name = "gp2",
481
+ .int_bits = 12,
482
+ .frac_bits = 12,
483
+ FILL_CLOCK_MUX_INIT_INFO(GP2, periph),
484
+ },
485
+ [CPRMAN_CLOCK_HSM] = {
486
+ .name = "hsm",
487
+ .int_bits = 4,
488
+ .frac_bits = 8,
489
+ FILL_CLOCK_MUX_INIT_INFO(HSM, periph),
490
+ },
491
+ [CPRMAN_CLOCK_OTP] = {
492
+ .name = "otp",
493
+ .int_bits = 4,
494
+ .frac_bits = 0,
495
+ FILL_CLOCK_MUX_INIT_INFO(OTP, xosc),
496
+ },
497
+ [CPRMAN_CLOCK_PCM] = {
498
+ .name = "pcm",
499
+ .int_bits = 12,
500
+ .frac_bits = 12,
501
+ FILL_CLOCK_MUX_INIT_INFO(PCM, periph),
502
+ },
503
+ [CPRMAN_CLOCK_PWM] = {
504
+ .name = "pwm",
505
+ .int_bits = 12,
506
+ .frac_bits = 12,
507
+ FILL_CLOCK_MUX_INIT_INFO(PWM, periph),
508
+ },
509
+ [CPRMAN_CLOCK_SLIM] = {
510
+ .name = "slim",
511
+ .int_bits = 12,
512
+ .frac_bits = 12,
513
+ FILL_CLOCK_MUX_INIT_INFO(SLIM, periph),
514
+ },
515
+ [CPRMAN_CLOCK_SMI] = {
516
+ .name = "smi",
517
+ .int_bits = 4,
518
+ .frac_bits = 8,
519
+ FILL_CLOCK_MUX_INIT_INFO(SMI, periph),
520
+ },
521
+ [CPRMAN_CLOCK_TEC] = {
522
+ .name = "tec",
523
+ .int_bits = 6,
524
+ .frac_bits = 0,
525
+ FILL_CLOCK_MUX_INIT_INFO(TEC, xosc),
526
+ },
527
+ [CPRMAN_CLOCK_TD0] = {
528
+ .name = "td0",
529
+ FILL_CLOCK_MUX_INIT_INFO(TD0, unknown),
530
+ },
531
+ [CPRMAN_CLOCK_TD1] = {
532
+ .name = "td1",
533
+ FILL_CLOCK_MUX_INIT_INFO(TD1, unknown),
534
+ },
535
+ [CPRMAN_CLOCK_TSENS] = {
536
+ .name = "tsens",
537
+ .int_bits = 5,
538
+ .frac_bits = 0,
539
+ FILL_CLOCK_MUX_INIT_INFO(TSENS, xosc),
540
+ },
541
+ [CPRMAN_CLOCK_TIMER] = {
542
+ .name = "timer",
543
+ .int_bits = 6,
544
+ .frac_bits = 12,
545
+ FILL_CLOCK_MUX_INIT_INFO(TIMER, xosc),
546
+ },
547
+ [CPRMAN_CLOCK_UART] = {
548
+ .name = "uart",
549
+ .int_bits = 10,
550
+ .frac_bits = 12,
551
+ FILL_CLOCK_MUX_INIT_INFO(UART, periph),
552
+ },
553
+ [CPRMAN_CLOCK_VEC] = {
554
+ .name = "vec",
555
+ .int_bits = 4,
556
+ .frac_bits = 0,
557
+ FILL_CLOCK_MUX_INIT_INFO(VEC, periph),
558
+ },
559
+ [CPRMAN_CLOCK_PULSE] = {
560
+ .name = "pulse",
561
+ FILL_CLOCK_MUX_INIT_INFO(PULSE, xosc),
562
+ },
563
+ [CPRMAN_CLOCK_SDC] = {
564
+ .name = "sdram",
565
+ .int_bits = 6,
566
+ .frac_bits = 0,
567
+ FILL_CLOCK_MUX_INIT_INFO(SDC, core),
568
+ },
569
+ [CPRMAN_CLOCK_ARM] = {
570
+ .name = "arm",
571
+ FILL_CLOCK_MUX_INIT_INFO(ARM, unknown),
572
+ },
573
+ [CPRMAN_CLOCK_AVEO] = {
574
+ .name = "aveo",
575
+ .int_bits = 4,
576
+ .frac_bits = 0,
577
+ FILL_CLOCK_MUX_INIT_INFO(AVEO, periph),
578
+ },
579
+ [CPRMAN_CLOCK_EMMC] = {
580
+ .name = "emmc",
581
+ .int_bits = 4,
582
+ .frac_bits = 8,
583
+ FILL_CLOCK_MUX_INIT_INFO(EMMC, periph),
584
+ },
585
+ [CPRMAN_CLOCK_EMMC2] = {
586
+ .name = "emmc2",
587
+ .int_bits = 4,
588
+ .frac_bits = 8,
589
+ FILL_CLOCK_MUX_INIT_INFO(EMMC2, unknown),
590
+ },
591
+};
592
+
593
+#undef FILL_CLOCK_MUX_INIT_INFO
594
+#undef FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO
595
+#undef SRC_MAPPING_INFO_dsi1
596
+#undef SRC_MAPPING_INFO_dsi0
597
+#undef SRC_MAPPING_INFO_periph
598
+#undef SRC_MAPPING_INFO_core
599
+#undef SRC_MAPPING_INFO_xosc
600
+#undef SRC_MAPPING_INFO_unknown
601
+
602
+static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
603
+ CprmanClockMuxState *mux,
604
+ CprmanClockMux id)
605
+{
606
+ mux->id = id;
607
+ mux->reg_ctl = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset];
608
+ mux->reg_div = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset + 1];
609
+ mux->int_bits = CLOCK_MUX_INIT_INFO[id].int_bits;
610
+ mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
611
+}
612
+
613
#endif
614
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
615
index XXXXXXX..XXXXXXX 100644
616
--- a/hw/misc/bcm2835_cprman.c
617
+++ b/hw/misc/bcm2835_cprman.c
618
@@ -XXX,XX +XXX,XX @@
619
*
620
* The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
621
* tree configuration.
622
+ *
623
+ * The CPRMAN exposes clock outputs with the name of the clock mux suffixed
624
+ * with "-out" (e.g. "uart-out", "h264-out", ...).
625
*/
626
627
#include "qemu/osdep.h"
628
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
629
};
630
631
632
+/* clock mux */
633
+
634
+static void clock_mux_update(CprmanClockMuxState *mux)
635
+{
636
+ clock_update(mux->out, 0);
637
+}
638
+
639
+static void clock_mux_src_update(void *opaque)
640
+{
641
+ CprmanClockMuxState **backref = opaque;
642
+ CprmanClockMuxState *s = *backref;
643
+
644
+ clock_mux_update(s);
645
+}
646
+
647
+static void clock_mux_init(Object *obj)
648
+{
649
+ CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
650
+ size_t i;
651
+
652
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
653
+ char *name = g_strdup_printf("srcs[%zu]", i);
654
+ s->backref[i] = s;
655
+ s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
656
+ clock_mux_src_update,
657
+ &s->backref[i]);
658
+ g_free(name);
659
+ }
660
+
661
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
662
+}
663
+
664
+static const VMStateDescription clock_mux_vmstate = {
665
+ .name = TYPE_CPRMAN_CLOCK_MUX,
666
+ .version_id = 1,
667
+ .minimum_version_id = 1,
668
+ .fields = (VMStateField[]) {
669
+ VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState,
670
+ CPRMAN_NUM_CLOCK_MUX_SRC),
671
+ VMSTATE_END_OF_LIST()
672
+ }
673
+};
674
+
675
+static void clock_mux_class_init(ObjectClass *klass, void *data)
676
+{
677
+ DeviceClass *dc = DEVICE_CLASS(klass);
678
+
679
+ dc->vmsd = &clock_mux_vmstate;
680
+}
681
+
682
+static const TypeInfo cprman_clock_mux_info = {
683
+ .name = TYPE_CPRMAN_CLOCK_MUX,
684
+ .parent = TYPE_DEVICE,
685
+ .instance_size = sizeof(CprmanClockMuxState),
686
+ .class_init = clock_mux_class_init,
687
+ .instance_init = clock_mux_init,
688
+};
689
+
690
+
691
/* CPRMAN "top level" model */
692
693
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
694
@@ -XXX,XX +XXX,XX @@ static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
695
}
696
}
697
698
+static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx)
699
+{
700
+ size_t i;
701
+
702
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
703
+ if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx) ||
704
+ (CLOCK_MUX_INIT_INFO[i].cm_offset + 4 == idx)) {
705
+ /* matches CM_CTL or CM_DIV mux register */
706
+ clock_mux_update(&s->clock_muxes[i]);
707
+ return;
708
+ }
709
+ }
710
+}
711
+
712
#define CASE_PLL_A2W_REGS(pll_) \
713
case R_A2W_ ## pll_ ## _CTRL: \
714
case R_A2W_ ## pll_ ## _ANA0: \
715
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
716
case R_A2W_PLLB_ARM:
717
update_channel_from_a2w(s, idx);
718
break;
719
+
720
+ case R_CM_GNRICCTL ... R_CM_SMIDIV:
721
+ case R_CM_TCNTCNT ... R_CM_VECDIV:
722
+ case R_CM_PULSECTL ... R_CM_PULSEDIV:
723
+ case R_CM_SDCCTL ... R_CM_ARMCTL:
724
+ case R_CM_AVEOCTL ... R_CM_EMMCDIV:
725
+ case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
726
+ update_mux_from_cm(s, idx);
727
+ break;
728
}
729
}
730
731
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
732
device_cold_reset(DEVICE(&s->channels[i]));
733
}
734
735
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
736
+ device_cold_reset(DEVICE(&s->clock_muxes[i]));
737
+ }
738
+
739
clock_update_hz(s->xosc, s->xosc_freq);
740
}
741
742
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
743
set_pll_channel_init_info(s, &s->channels[i], i);
744
}
745
746
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
747
+ char *alias;
748
+
749
+ object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name,
750
+ &s->clock_muxes[i],
751
+ TYPE_CPRMAN_CLOCK_MUX);
752
+ set_clock_mux_init_info(s, &s->clock_muxes[i], i);
753
+
754
+ /* Expose muxes output as CPRMAN outputs */
755
+ alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name);
756
+ qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias);
757
+ g_free(alias);
758
+ }
759
+
760
s->xosc = clock_new(obj, "xosc");
761
+ s->gnd = clock_new(obj, "gnd");
762
+
763
+ clock_set(s->gnd, 0);
764
765
memory_region_init_io(&s->iomem, obj, &cprman_ops,
766
s, "bcm2835-cprman", 0x2000);
767
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
768
}
769
770
+static void connect_mux_sources(BCM2835CprmanState *s,
771
+ CprmanClockMuxState *mux,
772
+ const CprmanPllChannel *clk_mapping)
773
+{
774
+ size_t i;
775
+ Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out;
776
+ Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out;
777
+
778
+ /* For sources from 0 to 3. Source 4 to 9 are mux specific */
779
+ Clock * const CLK_SRC_MAPPING[] = {
780
+ [CPRMAN_CLOCK_SRC_GND] = s->gnd,
781
+ [CPRMAN_CLOCK_SRC_XOSC] = s->xosc,
782
+ [CPRMAN_CLOCK_SRC_TD0] = td0,
783
+ [CPRMAN_CLOCK_SRC_TD1] = td1,
784
+ };
785
+
786
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
787
+ CprmanPllChannel mapping = clk_mapping[i];
788
+ Clock *src;
789
+
790
+ if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
791
+ src = s->gnd;
792
+ } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
793
+ src = s->gnd; /* TODO */
794
+ } else if (i < CPRMAN_CLOCK_SRC_PLLA) {
795
+ src = CLK_SRC_MAPPING[i];
796
+ } else {
797
+ src = s->channels[mapping].out;
798
+ }
799
+
800
+ clock_set_source(mux->srcs[i], src);
801
+ }
802
+}
803
+
804
static void cprman_realize(DeviceState *dev, Error **errp)
805
{
806
BCM2835CprmanState *s = CPRMAN(dev);
807
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
808
return;
809
}
810
}
811
+
812
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
813
+ CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
814
+
815
+ connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping);
816
+
817
+ if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
818
+ return;
819
+ }
820
+ }
821
}
822
823
static const VMStateDescription cprman_vmstate = {
824
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
825
type_register_static(&cprman_info);
826
type_register_static(&cprman_pll_info);
827
type_register_static(&cprman_pll_channel_info);
828
+ type_register_static(&cprman_clock_mux_info);
829
}
830
831
type_init(cprman_register_types);
832
--
23
--
833
2.20.1
24
2.34.1
834
835
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the default NaN pattern explicitly for m68k.
2
2
3
The Pi 3A+ is a stripped down version of the 3B:
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
- 512 MiB of RAM instead of 1 GiB
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
- no on-board ethernet chipset
5
Message-id: 20241202131347.498124-43-peter.maydell@linaro.org
6
---
7
target/m68k/cpu.c | 2 ++
8
fpu/softfloat-specialize.c.inc | 2 +-
9
2 files changed, 3 insertions(+), 1 deletion(-)
6
10
7
Add it as it is a closer match to what we model.
11
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
8
9
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
10
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Message-id: 20201024170127.3592182-10-f4bug@amsat.org
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
hw/arm/raspi.c | 13 +++++++++++++
15
1 file changed, 13 insertions(+)
16
17
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
18
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/raspi.c
13
--- a/target/m68k/cpu.c
20
+++ b/hw/arm/raspi.c
14
+++ b/target/m68k/cpu.c
21
@@ -XXX,XX +XXX,XX @@ static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
15
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
22
};
16
* preceding paragraph for nonsignaling NaNs.
23
17
*/
24
#ifdef TARGET_AARCH64
18
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
25
+static void raspi3ap_machine_class_init(ObjectClass *oc, void *data)
19
+ /* Default NaN: sign bit clear, all frac bits set */
26
+{
20
+ set_float_default_nan_pattern(0b01111111, &env->fp_status);
27
+ MachineClass *mc = MACHINE_CLASS(oc);
21
28
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
22
nan = floatx80_default_nan(&env->fp_status);
29
+
23
for (i = 0; i < 8; i++) {
30
+ rmc->board_rev = 0x9020e0; /* Revision 1.0 */
24
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
31
+ raspi_machine_class_common_init(mc, rmc->board_rev);
25
index XXXXXXX..XXXXXXX 100644
32
+};
26
--- a/fpu/softfloat-specialize.c.inc
33
+
27
+++ b/fpu/softfloat-specialize.c.inc
34
static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
28
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
35
{
29
uint8_t dnan_pattern = status->default_nan_pattern;
36
MachineClass *mc = MACHINE_CLASS(oc);
30
37
@@ -XXX,XX +XXX,XX @@ static const TypeInfo raspi_machine_types[] = {
31
if (dnan_pattern == 0) {
38
.parent = TYPE_RASPI_MACHINE,
32
-#if defined(TARGET_SPARC) || defined(TARGET_M68K)
39
.class_init = raspi2b_machine_class_init,
33
+#if defined(TARGET_SPARC)
40
#ifdef TARGET_AARCH64
34
/* Sign bit clear, all frac bits set */
41
+ }, {
35
dnan_pattern = 0b01111111;
42
+ .name = MACHINE_TYPE_NAME("raspi3ap"),
36
#elif defined(TARGET_HEXAGON)
43
+ .parent = TYPE_RASPI_MACHINE,
44
+ .class_init = raspi3ap_machine_class_init,
45
}, {
46
.name = MACHINE_TYPE_NAME("raspi3b"),
47
.parent = TYPE_RASPI_MACHINE,
48
--
37
--
49
2.20.1
38
2.34.1
50
51
diff view generated by jsdifflib
1
From: Havard Skinnemoen <hskinnemoen@google.com>
1
Set the default NaN pattern explicitly for MIPS. Note that this
2
is our only target which currently changes the default NaN
3
at runtime (which it was previously doing indirectly when it
4
changed the snan_bit_is_one setting).
2
5
3
This allows us to reuse npcm7xx_timer_pause for the watchdog timer.
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20241202131347.498124-44-peter.maydell@linaro.org
9
---
10
target/mips/fpu_helper.h | 7 +++++++
11
target/mips/msa.c | 3 +++
12
2 files changed, 10 insertions(+)
4
13
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
6
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
9
hw/timer/npcm7xx_timer.c | 6 +++---
10
1 file changed, 3 insertions(+), 3 deletions(-)
11
12
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
13
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/timer/npcm7xx_timer.c
16
--- a/target/mips/fpu_helper.h
15
+++ b/hw/timer/npcm7xx_timer.c
17
+++ b/target/mips/fpu_helper.h
16
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
18
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
17
timer_del(&t->qtimer);
19
set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status);
18
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
20
nan3_rule = nan2008 ? float_3nan_prop_s_cab : float_3nan_prop_s_abc;
19
t->remaining_ns = t->expires_ns - now;
21
set_float_3nan_prop_rule(nan3_rule, &env->active_fpu.fp_status);
20
- if (t->remaining_ns <= 0) {
22
+ /*
21
- npcm7xx_timer_reached_zero(t);
23
+ * With nan2008, the default NaN value has the sign bit clear and the
22
- }
24
+ * frac msb set; with the older mode, the sign bit is clear, and all
25
+ * frac bits except the msb are set.
26
+ */
27
+ set_float_default_nan_pattern(nan2008 ? 0b01000000 : 0b00111111,
28
+ &env->active_fpu.fp_status);
29
23
}
30
}
24
31
25
/*
32
diff --git a/target/mips/msa.c b/target/mips/msa.c
26
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
33
index XXXXXXX..XXXXXXX 100644
27
} else {
34
--- a/target/mips/msa.c
28
t->tcsr &= ~NPCM7XX_TCSR_CACT;
35
+++ b/target/mips/msa.c
29
npcm7xx_timer_pause(t);
36
@@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env)
30
+ if (t->remaining_ns <= 0) {
37
/* Inf * 0 + NaN returns the input NaN */
31
+ npcm7xx_timer_reached_zero(t);
38
set_float_infzeronan_rule(float_infzeronan_dnan_never,
32
+ }
39
&env->active_tc.msa_fp_status);
33
}
40
+ /* Default NaN: sign bit clear, frac msb set */
34
}
41
+ set_float_default_nan_pattern(0b01000000,
42
+ &env->active_tc.msa_fp_status);
35
}
43
}
36
--
44
--
37
2.20.1
45
2.34.1
38
39
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the default NaN pattern explicitly for openrisc.
2
2
3
Similarly to the Pi A, the Pi Zero uses a BCM2835 SoC (ARMv6Z core).
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-45-peter.maydell@linaro.org
6
---
7
target/openrisc/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
4
9
5
The only difference between the revision 1.2 and 1.3 is the latter
10
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
6
exposes a CSI camera connector. As we do not implement the Unicam
7
peripheral, there is no point in exposing a camera connector :)
8
Therefore we choose to model the 1.2 revision.
9
10
Example booting the machine using content from [*]:
11
12
$ qemu-system-arm -M raspi0 -serial stdio \
13
-kernel raspberrypi/firmware/boot/kernel.img \
14
-dtb raspberrypi/firmware/boot/bcm2708-rpi-zero.dtb \
15
-append 'printk.time=0 earlycon=pl011,0x20201000 console=ttyAMA0'
16
[ 0.000000] Booting Linux on physical CPU 0x0
17
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
18
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
19
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
20
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Zero
21
...
22
23
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
24
25
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
26
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
27
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
28
Message-id: 20201024170127.3592182-9-f4bug@amsat.org
29
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
30
---
31
hw/arm/raspi.c | 13 +++++++++++++
32
1 file changed, 13 insertions(+)
33
34
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
35
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
36
--- a/hw/arm/raspi.c
12
--- a/target/openrisc/cpu.c
37
+++ b/hw/arm/raspi.c
13
+++ b/target/openrisc/cpu.c
38
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
14
@@ -XXX,XX +XXX,XX @@ static void openrisc_cpu_reset_hold(Object *obj, ResetType type)
39
mc->default_ram_id = "ram";
15
*/
40
};
16
set_float_2nan_prop_rule(float_2nan_prop_x87, &cpu->env.fp_status);
41
17
42
+static void raspi0_machine_class_init(ObjectClass *oc, void *data)
18
+ /* Default NaN: sign bit clear, frac msb set */
43
+{
19
+ set_float_default_nan_pattern(0b01000000, &cpu->env.fp_status);
44
+ MachineClass *mc = MACHINE_CLASS(oc);
20
45
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
21
#ifndef CONFIG_USER_ONLY
46
+
22
cpu->env.picmr = 0x00000000;
47
+ rmc->board_rev = 0x920092; /* Revision 1.2 */
48
+ raspi_machine_class_common_init(mc, rmc->board_rev);
49
+};
50
+
51
static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
52
{
53
MachineClass *mc = MACHINE_CLASS(oc);
54
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
55
56
static const TypeInfo raspi_machine_types[] = {
57
{
58
+ .name = MACHINE_TYPE_NAME("raspi0"),
59
+ .parent = TYPE_RASPI_MACHINE,
60
+ .class_init = raspi0_machine_class_init,
61
+ }, {
62
.name = MACHINE_TYPE_NAME("raspi1ap"),
63
.parent = TYPE_RASPI_MACHINE,
64
.class_init = raspi1ap_machine_class_init,
65
--
23
--
66
2.20.1
24
2.34.1
67
68
diff view generated by jsdifflib
1
In ptimer_reload(), we call the callback function provided by the
1
Set the default NaN pattern explicitly for ppc.
2
timer device that is using the ptimer. This callback might disable
3
the ptimer. The code mostly handles this correctly, except that
4
we'll still print the warning about "Timer with delta zero,
5
disabling" if the now-disabled timer happened to be set such that it
6
would fire again immediately if it were enabled (eg because the
7
limit/reload value is zero).
8
9
Suppress the spurious warning message and the unnecessary
10
repeat-deletion of the underlying timer in this case.
11
2
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20201015151829.14656-2-peter.maydell@linaro.org
5
Message-id: 20241202131347.498124-46-peter.maydell@linaro.org
15
---
6
---
16
hw/core/ptimer.c | 4 ++++
7
target/ppc/cpu_init.c | 4 ++++
17
1 file changed, 4 insertions(+)
8
1 file changed, 4 insertions(+)
18
9
19
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
10
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/core/ptimer.c
12
--- a/target/ppc/cpu_init.c
22
+++ b/hw/core/ptimer.c
13
+++ b/target/ppc/cpu_init.c
23
@@ -XXX,XX +XXX,XX @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
14
@@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
24
}
15
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
25
16
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status);
26
if (delta == 0) {
17
27
+ if (s->enabled == 0) {
18
+ /* Default NaN: sign bit clear, set frac msb */
28
+ /* trigger callback disabled the timer already */
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
29
+ return;
20
+ set_float_default_nan_pattern(0b01000000, &env->vec_status);
30
+ }
21
+
31
if (!qtest_enabled()) {
22
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
32
fprintf(stderr, "Timer with delta zero, disabling\n");
23
ppc_spr_t *spr = &env->spr_cb[i];
33
}
24
34
--
25
--
35
2.20.1
26
2.34.1
36
37
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly for sh4. Note that sh4
2
is one of the only three targets (the others being HPPA and
3
sometimes MIPS) that has snan_bit_is_one set.
2
4
3
A PLL channel is able to further divide the generated PLL frequency.
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
The divider is given in the CTRL_A2W register. Some channels have an
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
additional fixed divider which is always applied to the signal.
7
Message-id: 20241202131347.498124-47-peter.maydell@linaro.org
8
---
9
target/sh4/cpu.c | 2 ++
10
1 file changed, 2 insertions(+)
6
11
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
hw/misc/bcm2835_cprman.c | 33 ++++++++++++++++++++++++++++++++-
14
1 file changed, 32 insertions(+), 1 deletion(-)
15
16
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
17
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/misc/bcm2835_cprman.c
14
--- a/target/sh4/cpu.c
19
+++ b/hw/misc/bcm2835_cprman.c
15
+++ b/target/sh4/cpu.c
20
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
16
@@ -XXX,XX +XXX,XX @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
21
17
set_flush_to_zero(1, &env->fp_status);
22
/* PLL channel */
18
#endif
23
19
set_default_nan_mode(1, &env->fp_status);
24
+static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
20
+ /* sign bit clear, set all frac bits other than msb */
25
+{
21
+ set_float_default_nan_pattern(0b00111111, &env->fp_status);
26
+ /*
27
+ * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does
28
+ * not set it when enabling the channel, but does clear it when disabling
29
+ * it.
30
+ */
31
+ return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE)
32
+ && !(*channel->reg_cm & channel->hold_mask);
33
+}
34
+
35
static void pll_channel_update(CprmanPllChannelState *channel)
36
{
37
- clock_update(channel->out, 0);
38
+ uint64_t freq, div;
39
+
40
+ if (!pll_channel_is_enabled(channel)) {
41
+ clock_update(channel->out, 0);
42
+ return;
43
+ }
44
+
45
+ div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV);
46
+
47
+ if (!div) {
48
+ /*
49
+ * It seems that when the divider value is 0, it is considered as
50
+ * being maximum by the hardware (see the Linux driver).
51
+ */
52
+ div = R_A2W_PLLx_CHANNELy_DIV_MASK;
53
+ }
54
+
55
+ /* Some channels have an additional fixed divider */
56
+ freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider);
57
+
58
+ clock_update_hz(channel->out, freq);
59
}
22
}
60
23
61
/* Update a PLL and all its channels */
24
static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
62
--
25
--
63
2.20.1
26
2.34.1
64
65
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly for rx.
2
2
3
There are 5 PLLs in the CPRMAN, namely PLL A, C, D, H and B. All of them
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
take the xosc clock as input and produce a new clock.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-48-peter.maydell@linaro.org
6
---
7
target/rx/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
5
9
6
This commit adds a skeleton implementation for the PLLs as sub-devices
10
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
7
of the CPRMAN. The PLLs are instantiated and connected internally to the
8
main oscillator.
9
10
Each PLL has 6 registers : CM, A2W_CTRL, A2W_ANA[0,1,2,3], A2W_FRAC. A
11
write to any of them triggers a call to the (not yet implemented)
12
pll_update function.
13
14
If the main oscillator changes frequency, an update is also triggered.
15
16
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
17
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
18
Signed-off-by: Luc Michel <luc@lmichel.fr>
19
Tested-by: Guenter Roeck <linux@roeck-us.net>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
---
22
include/hw/misc/bcm2835_cprman.h | 29 +++++
23
include/hw/misc/bcm2835_cprman_internals.h | 144 +++++++++++++++++++++
24
hw/misc/bcm2835_cprman.c | 108 ++++++++++++++++
25
3 files changed, 281 insertions(+)
26
27
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
28
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
29
--- a/include/hw/misc/bcm2835_cprman.h
12
--- a/target/rx/cpu.c
30
+++ b/include/hw/misc/bcm2835_cprman.h
13
+++ b/target/rx/cpu.c
31
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
14
@@ -XXX,XX +XXX,XX @@ static void rx_cpu_reset_hold(Object *obj, ResetType type)
32
15
* then prefer dest over source", which is float_2nan_prop_s_ab.
33
#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
16
*/
34
17
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
35
+typedef enum CprmanPll {
18
+ /* Default NaN value: sign bit clear, set frac msb */
36
+ CPRMAN_PLLA = 0,
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
37
+ CPRMAN_PLLC,
38
+ CPRMAN_PLLD,
39
+ CPRMAN_PLLH,
40
+ CPRMAN_PLLB,
41
+
42
+ CPRMAN_NUM_PLL
43
+} CprmanPll;
44
+
45
+typedef struct CprmanPllState {
46
+ /*< private >*/
47
+ DeviceState parent_obj;
48
+
49
+ /*< public >*/
50
+ CprmanPll id;
51
+
52
+ uint32_t *reg_cm;
53
+ uint32_t *reg_a2w_ctrl;
54
+ uint32_t *reg_a2w_ana; /* ANA[0] .. ANA[3] */
55
+ uint32_t prediv_mask; /* prediv bit in ana[1] */
56
+ uint32_t *reg_a2w_frac;
57
+
58
+ Clock *xosc_in;
59
+ Clock *out;
60
+} CprmanPllState;
61
+
62
struct BCM2835CprmanState {
63
/*< private >*/
64
SysBusDevice parent_obj;
65
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
66
/*< public >*/
67
MemoryRegion iomem;
68
69
+ CprmanPllState plls[CPRMAN_NUM_PLL];
70
+
71
uint32_t regs[CPRMAN_NUM_REGS];
72
uint32_t xosc_freq;
73
74
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
75
index XXXXXXX..XXXXXXX 100644
76
--- a/include/hw/misc/bcm2835_cprman_internals.h
77
+++ b/include/hw/misc/bcm2835_cprman_internals.h
78
@@ -XXX,XX +XXX,XX @@
79
#include "hw/registerfields.h"
80
#include "hw/misc/bcm2835_cprman.h"
81
82
+#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
83
+
84
+DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
85
+ TYPE_CPRMAN_PLL)
86
+
87
/* Register map */
88
89
+/* PLLs */
90
+REG32(CM_PLLA, 0x104)
91
+ FIELD(CM_PLLA, LOADDSI0, 0, 1)
92
+ FIELD(CM_PLLA, HOLDDSI0, 1, 1)
93
+ FIELD(CM_PLLA, LOADCCP2, 2, 1)
94
+ FIELD(CM_PLLA, HOLDCCP2, 3, 1)
95
+ FIELD(CM_PLLA, LOADCORE, 4, 1)
96
+ FIELD(CM_PLLA, HOLDCORE, 5, 1)
97
+ FIELD(CM_PLLA, LOADPER, 6, 1)
98
+ FIELD(CM_PLLA, HOLDPER, 7, 1)
99
+ FIELD(CM_PLLx, ANARST, 8, 1)
100
+REG32(CM_PLLC, 0x108)
101
+ FIELD(CM_PLLC, LOADCORE0, 0, 1)
102
+ FIELD(CM_PLLC, HOLDCORE0, 1, 1)
103
+ FIELD(CM_PLLC, LOADCORE1, 2, 1)
104
+ FIELD(CM_PLLC, HOLDCORE1, 3, 1)
105
+ FIELD(CM_PLLC, LOADCORE2, 4, 1)
106
+ FIELD(CM_PLLC, HOLDCORE2, 5, 1)
107
+ FIELD(CM_PLLC, LOADPER, 6, 1)
108
+ FIELD(CM_PLLC, HOLDPER, 7, 1)
109
+REG32(CM_PLLD, 0x10c)
110
+ FIELD(CM_PLLD, LOADDSI0, 0, 1)
111
+ FIELD(CM_PLLD, HOLDDSI0, 1, 1)
112
+ FIELD(CM_PLLD, LOADDSI1, 2, 1)
113
+ FIELD(CM_PLLD, HOLDDSI1, 3, 1)
114
+ FIELD(CM_PLLD, LOADCORE, 4, 1)
115
+ FIELD(CM_PLLD, HOLDCORE, 5, 1)
116
+ FIELD(CM_PLLD, LOADPER, 6, 1)
117
+ FIELD(CM_PLLD, HOLDPER, 7, 1)
118
+REG32(CM_PLLH, 0x110)
119
+ FIELD(CM_PLLH, LOADPIX, 0, 1)
120
+ FIELD(CM_PLLH, LOADAUX, 1, 1)
121
+ FIELD(CM_PLLH, LOADRCAL, 2, 1)
122
+REG32(CM_PLLB, 0x170)
123
+ FIELD(CM_PLLB, LOADARM, 0, 1)
124
+ FIELD(CM_PLLB, HOLDARM, 1, 1)
125
+
126
+REG32(A2W_PLLA_CTRL, 0x1100)
127
+ FIELD(A2W_PLLx_CTRL, NDIV, 0, 10)
128
+ FIELD(A2W_PLLx_CTRL, PDIV, 12, 3)
129
+ FIELD(A2W_PLLx_CTRL, PWRDN, 16, 1)
130
+ FIELD(A2W_PLLx_CTRL, PRST_DISABLE, 17, 1)
131
+REG32(A2W_PLLC_CTRL, 0x1120)
132
+REG32(A2W_PLLD_CTRL, 0x1140)
133
+REG32(A2W_PLLH_CTRL, 0x1160)
134
+REG32(A2W_PLLB_CTRL, 0x11e0)
135
+
136
+REG32(A2W_PLLA_ANA0, 0x1010)
137
+REG32(A2W_PLLA_ANA1, 0x1014)
138
+ FIELD(A2W_PLLx_ANA1, FB_PREDIV, 14, 1)
139
+REG32(A2W_PLLA_ANA2, 0x1018)
140
+REG32(A2W_PLLA_ANA3, 0x101c)
141
+
142
+REG32(A2W_PLLC_ANA0, 0x1030)
143
+REG32(A2W_PLLC_ANA1, 0x1034)
144
+REG32(A2W_PLLC_ANA2, 0x1038)
145
+REG32(A2W_PLLC_ANA3, 0x103c)
146
+
147
+REG32(A2W_PLLD_ANA0, 0x1050)
148
+REG32(A2W_PLLD_ANA1, 0x1054)
149
+REG32(A2W_PLLD_ANA2, 0x1058)
150
+REG32(A2W_PLLD_ANA3, 0x105c)
151
+
152
+REG32(A2W_PLLH_ANA0, 0x1070)
153
+REG32(A2W_PLLH_ANA1, 0x1074)
154
+ FIELD(A2W_PLLH_ANA1, FB_PREDIV, 11, 1)
155
+REG32(A2W_PLLH_ANA2, 0x1078)
156
+REG32(A2W_PLLH_ANA3, 0x107c)
157
+
158
+REG32(A2W_PLLB_ANA0, 0x10f0)
159
+REG32(A2W_PLLB_ANA1, 0x10f4)
160
+REG32(A2W_PLLB_ANA2, 0x10f8)
161
+REG32(A2W_PLLB_ANA3, 0x10fc)
162
+
163
+REG32(A2W_PLLA_FRAC, 0x1200)
164
+ FIELD(A2W_PLLx_FRAC, FRAC, 0, 20)
165
+REG32(A2W_PLLC_FRAC, 0x1220)
166
+REG32(A2W_PLLD_FRAC, 0x1240)
167
+REG32(A2W_PLLH_FRAC, 0x1260)
168
+REG32(A2W_PLLB_FRAC, 0x12e0)
169
+
170
/*
171
* This field is common to all registers. Each register write value must match
172
* the CPRMAN_PASSWORD magic value in its 8 MSB.
173
@@ -XXX,XX +XXX,XX @@
174
FIELD(CPRMAN, PASSWORD, 24, 8)
175
#define CPRMAN_PASSWORD 0x5a
176
177
+/* PLL init info */
178
+typedef struct PLLInitInfo {
179
+ const char *name;
180
+ size_t cm_offset;
181
+ size_t a2w_ctrl_offset;
182
+ size_t a2w_ana_offset;
183
+ uint32_t prediv_mask; /* Prediv bit in ana[1] */
184
+ size_t a2w_frac_offset;
185
+} PLLInitInfo;
186
+
187
+#define FILL_PLL_INIT_INFO(pll_) \
188
+ .cm_offset = R_CM_ ## pll_, \
189
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _CTRL, \
190
+ .a2w_ana_offset = R_A2W_ ## pll_ ## _ANA0, \
191
+ .a2w_frac_offset = R_A2W_ ## pll_ ## _FRAC
192
+
193
+static const PLLInitInfo PLL_INIT_INFO[] = {
194
+ [CPRMAN_PLLA] = {
195
+ .name = "plla",
196
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
197
+ FILL_PLL_INIT_INFO(PLLA),
198
+ },
199
+ [CPRMAN_PLLC] = {
200
+ .name = "pllc",
201
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
202
+ FILL_PLL_INIT_INFO(PLLC),
203
+ },
204
+ [CPRMAN_PLLD] = {
205
+ .name = "plld",
206
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
207
+ FILL_PLL_INIT_INFO(PLLD),
208
+ },
209
+ [CPRMAN_PLLH] = {
210
+ .name = "pllh",
211
+ .prediv_mask = R_A2W_PLLH_ANA1_FB_PREDIV_MASK,
212
+ FILL_PLL_INIT_INFO(PLLH),
213
+ },
214
+ [CPRMAN_PLLB] = {
215
+ .name = "pllb",
216
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
217
+ FILL_PLL_INIT_INFO(PLLB),
218
+ },
219
+};
220
+
221
+#undef FILL_PLL_CHANNEL_INIT_INFO
222
+
223
+static inline void set_pll_init_info(BCM2835CprmanState *s,
224
+ CprmanPllState *pll,
225
+ CprmanPll id)
226
+{
227
+ pll->id = id;
228
+ pll->reg_cm = &s->regs[PLL_INIT_INFO[id].cm_offset];
229
+ pll->reg_a2w_ctrl = &s->regs[PLL_INIT_INFO[id].a2w_ctrl_offset];
230
+ pll->reg_a2w_ana = &s->regs[PLL_INIT_INFO[id].a2w_ana_offset];
231
+ pll->prediv_mask = PLL_INIT_INFO[id].prediv_mask;
232
+ pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
233
+}
234
+
235
#endif
236
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/hw/misc/bcm2835_cprman.c
239
+++ b/hw/misc/bcm2835_cprman.c
240
@@ -XXX,XX +XXX,XX @@
241
#include "hw/misc/bcm2835_cprman_internals.h"
242
#include "trace.h"
243
244
+/* PLL */
245
+
246
+static void pll_update(CprmanPllState *pll)
247
+{
248
+ clock_update(pll->out, 0);
249
+}
250
+
251
+static void pll_xosc_update(void *opaque)
252
+{
253
+ pll_update(CPRMAN_PLL(opaque));
254
+}
255
+
256
+static void pll_init(Object *obj)
257
+{
258
+ CprmanPllState *s = CPRMAN_PLL(obj);
259
+
260
+ s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s);
261
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
262
+}
263
+
264
+static const VMStateDescription pll_vmstate = {
265
+ .name = TYPE_CPRMAN_PLL,
266
+ .version_id = 1,
267
+ .minimum_version_id = 1,
268
+ .fields = (VMStateField[]) {
269
+ VMSTATE_CLOCK(xosc_in, CprmanPllState),
270
+ VMSTATE_END_OF_LIST()
271
+ }
272
+};
273
+
274
+static void pll_class_init(ObjectClass *klass, void *data)
275
+{
276
+ DeviceClass *dc = DEVICE_CLASS(klass);
277
+
278
+ dc->vmsd = &pll_vmstate;
279
+}
280
+
281
+static const TypeInfo cprman_pll_info = {
282
+ .name = TYPE_CPRMAN_PLL,
283
+ .parent = TYPE_DEVICE,
284
+ .instance_size = sizeof(CprmanPllState),
285
+ .class_init = pll_class_init,
286
+ .instance_init = pll_init,
287
+};
288
+
289
+
290
/* CPRMAN "top level" model */
291
292
static uint64_t cprman_read(void *opaque, hwaddr offset,
293
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
294
return r;
295
}
20
}
296
21
297
+#define CASE_PLL_REGS(pll_) \
22
static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
298
+ case R_CM_ ## pll_: \
299
+ case R_A2W_ ## pll_ ## _CTRL: \
300
+ case R_A2W_ ## pll_ ## _ANA0: \
301
+ case R_A2W_ ## pll_ ## _ANA1: \
302
+ case R_A2W_ ## pll_ ## _ANA2: \
303
+ case R_A2W_ ## pll_ ## _ANA3: \
304
+ case R_A2W_ ## pll_ ## _FRAC
305
+
306
static void cprman_write(void *opaque, hwaddr offset,
307
uint64_t value, unsigned size)
308
{
309
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
310
trace_bcm2835_cprman_write(offset, value);
311
s->regs[idx] = value;
312
313
+ switch (idx) {
314
+ CASE_PLL_REGS(PLLA) :
315
+ pll_update(&s->plls[CPRMAN_PLLA]);
316
+ break;
317
+
318
+ CASE_PLL_REGS(PLLC) :
319
+ pll_update(&s->plls[CPRMAN_PLLC]);
320
+ break;
321
+
322
+ CASE_PLL_REGS(PLLD) :
323
+ pll_update(&s->plls[CPRMAN_PLLD]);
324
+ break;
325
+
326
+ CASE_PLL_REGS(PLLH) :
327
+ pll_update(&s->plls[CPRMAN_PLLH]);
328
+ break;
329
+
330
+ CASE_PLL_REGS(PLLB) :
331
+ pll_update(&s->plls[CPRMAN_PLLB]);
332
+ break;
333
+ }
334
}
335
336
+#undef CASE_PLL_REGS
337
+
338
static const MemoryRegionOps cprman_ops = {
339
.read = cprman_read,
340
.write = cprman_write,
341
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps cprman_ops = {
342
static void cprman_reset(DeviceState *dev)
343
{
344
BCM2835CprmanState *s = CPRMAN(dev);
345
+ size_t i;
346
347
memset(s->regs, 0, sizeof(s->regs));
348
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ device_cold_reset(DEVICE(&s->plls[i]));
351
+ }
352
+
353
clock_update_hz(s->xosc, s->xosc_freq);
354
}
355
356
static void cprman_init(Object *obj)
357
{
358
BCM2835CprmanState *s = CPRMAN(obj);
359
+ size_t i;
360
+
361
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
362
+ object_initialize_child(obj, PLL_INIT_INFO[i].name,
363
+ &s->plls[i], TYPE_CPRMAN_PLL);
364
+ set_pll_init_info(s, &s->plls[i], i);
365
+ }
366
367
s->xosc = clock_new(obj, "xosc");
368
369
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
370
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
371
}
372
373
+static void cprman_realize(DeviceState *dev, Error **errp)
374
+{
375
+ BCM2835CprmanState *s = CPRMAN(dev);
376
+ size_t i;
377
+
378
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
379
+ CprmanPllState *pll = &s->plls[i];
380
+
381
+ clock_set_source(pll->xosc_in, s->xosc);
382
+
383
+ if (!qdev_realize(DEVICE(pll), NULL, errp)) {
384
+ return;
385
+ }
386
+ }
387
+}
388
+
389
static const VMStateDescription cprman_vmstate = {
390
.name = TYPE_BCM2835_CPRMAN,
391
.version_id = 1,
392
@@ -XXX,XX +XXX,XX @@ static void cprman_class_init(ObjectClass *klass, void *data)
393
{
394
DeviceClass *dc = DEVICE_CLASS(klass);
395
396
+ dc->realize = cprman_realize;
397
dc->reset = cprman_reset;
398
dc->vmsd = &cprman_vmstate;
399
device_class_set_props(dc, cprman_properties);
400
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_info = {
401
static void cprman_register_types(void)
402
{
403
type_register_static(&cprman_info);
404
+ type_register_static(&cprman_pll_info);
405
}
406
407
type_init(cprman_register_types);
408
--
23
--
409
2.20.1
24
2.34.1
410
411
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the default NaN pattern explicitly for s390x.
2
2
3
The Pi A is almost the first machine released.
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
It uses a BCM2835 SoC which includes a ARMv6Z core.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-49-peter.maydell@linaro.org
6
---
7
target/s390x/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
5
9
6
Example booting the machine using content from [*]
10
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
7
(we use the device tree from the B model):
8
9
$ qemu-system-arm -M raspi1ap -serial stdio \
10
-kernel raspberrypi/firmware/boot/kernel.img \
11
-dtb raspberrypi/firmware/boot/bcm2708-rpi-b-plus.dtb \
12
-append 'earlycon=pl011,0x20201000 console=ttyAMA0'
13
[ 0.000000] Booting Linux on physical CPU 0x0
14
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
15
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
16
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
17
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Model B+
18
...
19
20
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
21
22
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
23
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Message-id: 20201024170127.3592182-8-f4bug@amsat.org
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
---
27
hw/arm/raspi.c | 13 +++++++++++++
28
1 file changed, 13 insertions(+)
29
30
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
31
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
32
--- a/hw/arm/raspi.c
12
--- a/target/s390x/cpu.c
33
+++ b/hw/arm/raspi.c
13
+++ b/target/s390x/cpu.c
34
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
14
@@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
35
mc->default_ram_id = "ram";
15
set_float_3nan_prop_rule(float_3nan_prop_s_abc, &env->fpu_status);
36
};
16
set_float_infzeronan_rule(float_infzeronan_dnan_always,
37
17
&env->fpu_status);
38
+static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
18
+ /* Default NaN value: sign bit clear, frac msb set */
39
+{
19
+ set_float_default_nan_pattern(0b01000000, &env->fpu_status);
40
+ MachineClass *mc = MACHINE_CLASS(oc);
20
/* fall through */
41
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
21
case RESET_TYPE_S390_CPU_NORMAL:
42
+
22
env->psw.mask &= ~PSW_MASK_RI;
43
+ rmc->board_rev = 0x900021; /* Revision 1.1 */
44
+ raspi_machine_class_common_init(mc, rmc->board_rev);
45
+};
46
+
47
static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
48
{
49
MachineClass *mc = MACHINE_CLASS(oc);
50
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
51
52
static const TypeInfo raspi_machine_types[] = {
53
{
54
+ .name = MACHINE_TYPE_NAME("raspi1ap"),
55
+ .parent = TYPE_RASPI_MACHINE,
56
+ .class_init = raspi1ap_machine_class_init,
57
+ }, {
58
.name = MACHINE_TYPE_NAME("raspi2b"),
59
.parent = TYPE_RASPI_MACHINE,
60
.class_init = raspi2b_machine_class_init,
61
--
23
--
62
2.20.1
24
2.34.1
63
64
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the default NaN pattern explicitly for SPARC, and remove
2
the ifdef from parts64_default_nan.
2
3
3
The BCM2835 has only one core. Introduce the core_count field to
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
be able to use values different than BCM283X_NCPUS (4).
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-50-peter.maydell@linaro.org
7
---
8
target/sparc/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 5 +----
10
2 files changed, 3 insertions(+), 4 deletions(-)
5
11
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
12
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20201024170127.3592182-4-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
hw/arm/bcm2836.c | 5 ++++-
12
1 file changed, 4 insertions(+), 1 deletion(-)
13
14
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
15
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/bcm2836.c
14
--- a/target/sparc/cpu.c
17
+++ b/hw/arm/bcm2836.c
15
+++ b/target/sparc/cpu.c
18
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
16
@@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
19
/*< public >*/
17
set_float_3nan_prop_rule(float_3nan_prop_s_cba, &env->fp_status);
20
const char *name;
18
/* For inf * 0 + NaN, return the input NaN */
21
const char *cpu_type;
19
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
22
+ unsigned core_count;
20
+ /* Default NaN value: sign bit clear, all frac bits set */
23
hwaddr peri_base; /* Peripheral base address seen by the CPU */
21
+ set_float_default_nan_pattern(0b01111111, &env->fp_status);
24
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
22
25
int clusterid;
23
cpu_exec_realizefn(cs, &local_err);
26
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
24
if (local_err != NULL) {
27
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
28
int n;
26
index XXXXXXX..XXXXXXX 100644
29
27
--- a/fpu/softfloat-specialize.c.inc
30
- for (n = 0; n < BCM283X_NCPUS; n++) {
28
+++ b/fpu/softfloat-specialize.c.inc
31
+ for (n = 0; n < bc->core_count; n++) {
29
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
32
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
30
uint8_t dnan_pattern = status->default_nan_pattern;
33
bc->cpu_type);
31
34
}
32
if (dnan_pattern == 0) {
35
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
33
-#if defined(TARGET_SPARC)
36
BCM283XClass *bc = BCM283X_CLASS(oc);
34
- /* Sign bit clear, all frac bits set */
37
35
- dnan_pattern = 0b01111111;
38
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
36
-#elif defined(TARGET_HEXAGON)
39
+ bc->core_count = BCM283X_NCPUS;
37
+#if defined(TARGET_HEXAGON)
40
bc->peri_base = 0x3f000000;
38
/* Sign bit set, all frac bits set. */
41
bc->ctrl_base = 0x40000000;
39
dnan_pattern = 0b11111111;
42
bc->clusterid = 0xf;
40
#else
43
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
44
BCM283XClass *bc = BCM283X_CLASS(oc);
45
46
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
47
+ bc->core_count = BCM283X_NCPUS;
48
bc->peri_base = 0x3f000000;
49
bc->ctrl_base = 0x40000000;
50
bc->clusterid = 0x0;
51
--
41
--
52
2.20.1
42
2.34.1
53
54
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the default NaN pattern explicitly for xtensa.
2
2
3
It makes no sense to set enabled-cpus=0 on single core SoCs.
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-51-peter.maydell@linaro.org
6
---
7
target/xtensa/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
4
9
5
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
10
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20201024170127.3592182-5-f4bug@amsat.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
hw/arm/bcm2836.c | 15 +++++++--------
11
1 file changed, 7 insertions(+), 8 deletions(-)
12
13
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
14
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/bcm2836.c
12
--- a/target/xtensa/cpu.c
16
+++ b/hw/arm/bcm2836.c
13
+++ b/target/xtensa/cpu.c
17
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
14
@@ -XXX,XX +XXX,XX @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
18
#define BCM283X_GET_CLASS(obj) \
15
/* For inf * 0 + NaN, return the input NaN */
19
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
16
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
20
17
set_no_signaling_nans(!dfpu, &env->fp_status);
21
+static Property bcm2836_enabled_cores_property =
18
+ /* Default NaN value: sign bit clear, set frac msb */
22
+ DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
23
+
20
xtensa_use_first_nan(env, !dfpu);
24
static void bcm2836_init(Object *obj)
25
{
26
BCM283XState *s = BCM283X(obj);
27
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
28
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
29
bc->cpu_type);
30
}
31
+ if (bc->core_count > 1) {
32
+ qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
33
+ qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
34
+ }
35
36
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
37
38
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
39
}
40
}
21
}
41
22
42
-static Property bcm2836_props[] = {
43
- DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
44
- BCM283X_NCPUS),
45
- DEFINE_PROP_END_OF_LIST()
46
-};
47
-
48
static void bcm283x_class_init(ObjectClass *oc, void *data)
49
{
50
DeviceClass *dc = DEVICE_CLASS(oc);
51
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
52
bc->ctrl_base = 0x40000000;
53
bc->clusterid = 0xf;
54
dc->realize = bcm2836_realize;
55
- device_class_set_props(dc, bcm2836_props);
56
};
57
58
#ifdef TARGET_AARCH64
59
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
60
bc->ctrl_base = 0x40000000;
61
bc->clusterid = 0x0;
62
dc->realize = bcm2836_realize;
63
- device_class_set_props(dc, bcm2836_props);
64
};
65
#endif
66
67
--
23
--
68
2.20.1
24
2.34.1
69
70
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
Set the default NaN pattern explicitly for hexagon.
2
Remove the ifdef from parts64_default_nan(); the only
3
remaining unconverted targets all use the default case.
2
4
3
Those reset values have been extracted from a Raspberry Pi 3 model B
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
v1.2, using the 2020-08-20 version of raspios. The dump was done using
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
the debugfs interface of the CPRMAN driver in Linux (under
7
Message-id: 20241202131347.498124-52-peter.maydell@linaro.org
6
'/sys/kernel/debug/clk'). Each exposed clock tree stage (PLLs, channels
8
---
7
and muxes) can be observed by reading the 'regdump' file (e.g.
9
target/hexagon/cpu.c | 2 ++
8
'plla/regdump').
10
fpu/softfloat-specialize.c.inc | 5 -----
11
2 files changed, 2 insertions(+), 5 deletions(-)
9
12
10
Those values are set by the Raspberry Pi firmware at boot time (Linux
13
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
11
expects them to be set when it boots up).
12
13
Some stages are not exposed by the Linux driver (e.g. the PLL B). For
14
those, the reset values are unknown and left to 0 which implies a
15
disabled output.
16
17
Once booted in QEMU, the final clock tree is very similar to the one
18
visible on real hardware. The differences come from some unimplemented
19
devices for which the driver simply disable the corresponding clock.
20
21
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
22
Signed-off-by: Luc Michel <luc@lmichel.fr>
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Tested-by: Guenter Roeck <linux@roeck-us.net>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
---
27
include/hw/misc/bcm2835_cprman_internals.h | 269 +++++++++++++++++++++
28
hw/misc/bcm2835_cprman.c | 31 +++
29
2 files changed, 300 insertions(+)
30
31
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
32
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/misc/bcm2835_cprman_internals.h
15
--- a/target/hexagon/cpu.c
34
+++ b/include/hw/misc/bcm2835_cprman_internals.h
16
+++ b/target/hexagon/cpu.c
35
@@ -XXX,XX +XXX,XX @@ static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
17
@@ -XXX,XX +XXX,XX @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
36
mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
18
19
set_default_nan_mode(1, &env->fp_status);
20
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
21
+ /* Default NaN value: sign bit set, all frac bits set */
22
+ set_float_default_nan_pattern(0b11111111, &env->fp_status);
37
}
23
}
38
24
39
+
25
static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info)
40
+/*
26
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
41
+ * Object reset info
42
+ * Those values have been dumped from a Raspberry Pi 3 Model B v1.2 using the
43
+ * clk debugfs interface in Linux.
44
+ */
45
+typedef struct PLLResetInfo {
46
+ uint32_t cm;
47
+ uint32_t a2w_ctrl;
48
+ uint32_t a2w_ana[4];
49
+ uint32_t a2w_frac;
50
+} PLLResetInfo;
51
+
52
+static const PLLResetInfo PLL_RESET_INFO[] = {
53
+ [CPRMAN_PLLA] = {
54
+ .cm = 0x0000008a,
55
+ .a2w_ctrl = 0x0002103a,
56
+ .a2w_frac = 0x00098000,
57
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
58
+ },
59
+
60
+ [CPRMAN_PLLC] = {
61
+ .cm = 0x00000228,
62
+ .a2w_ctrl = 0x0002103e,
63
+ .a2w_frac = 0x00080000,
64
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
65
+ },
66
+
67
+ [CPRMAN_PLLD] = {
68
+ .cm = 0x0000020a,
69
+ .a2w_ctrl = 0x00021034,
70
+ .a2w_frac = 0x00015556,
71
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
72
+ },
73
+
74
+ [CPRMAN_PLLH] = {
75
+ .cm = 0x00000000,
76
+ .a2w_ctrl = 0x0002102d,
77
+ .a2w_frac = 0x00000000,
78
+ .a2w_ana = { 0x00900000, 0x0000000c, 0x00000000, 0x00000000 }
79
+ },
80
+
81
+ [CPRMAN_PLLB] = {
82
+ /* unknown */
83
+ .cm = 0x00000000,
84
+ .a2w_ctrl = 0x00000000,
85
+ .a2w_frac = 0x00000000,
86
+ .a2w_ana = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
87
+ }
88
+};
89
+
90
+typedef struct PLLChannelResetInfo {
91
+ /*
92
+ * Even though a PLL channel has a CM register, it shares it with its
93
+ * parent PLL. The parent already takes care of the reset value.
94
+ */
95
+ uint32_t a2w_ctrl;
96
+} PLLChannelResetInfo;
97
+
98
+static const PLLChannelResetInfo PLL_CHANNEL_RESET_INFO[] = {
99
+ [CPRMAN_PLLA_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
100
+ [CPRMAN_PLLA_CHANNEL_CORE] = { .a2w_ctrl = 0x00000003 },
101
+ [CPRMAN_PLLA_CHANNEL_PER] = { .a2w_ctrl = 0x00000000 }, /* unknown */
102
+ [CPRMAN_PLLA_CHANNEL_CCP2] = { .a2w_ctrl = 0x00000100 },
103
+
104
+ [CPRMAN_PLLC_CHANNEL_CORE2] = { .a2w_ctrl = 0x00000100 },
105
+ [CPRMAN_PLLC_CHANNEL_CORE1] = { .a2w_ctrl = 0x00000100 },
106
+ [CPRMAN_PLLC_CHANNEL_PER] = { .a2w_ctrl = 0x00000002 },
107
+ [CPRMAN_PLLC_CHANNEL_CORE0] = { .a2w_ctrl = 0x00000002 },
108
+
109
+ [CPRMAN_PLLD_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
110
+ [CPRMAN_PLLD_CHANNEL_CORE] = { .a2w_ctrl = 0x00000004 },
111
+ [CPRMAN_PLLD_CHANNEL_PER] = { .a2w_ctrl = 0x00000004 },
112
+ [CPRMAN_PLLD_CHANNEL_DSI1] = { .a2w_ctrl = 0x00000100 },
113
+
114
+ [CPRMAN_PLLH_CHANNEL_AUX] = { .a2w_ctrl = 0x00000004 },
115
+ [CPRMAN_PLLH_CHANNEL_RCAL] = { .a2w_ctrl = 0x00000000 },
116
+ [CPRMAN_PLLH_CHANNEL_PIX] = { .a2w_ctrl = 0x00000000 },
117
+
118
+ [CPRMAN_PLLB_CHANNEL_ARM] = { .a2w_ctrl = 0x00000000 }, /* unknown */
119
+};
120
+
121
+typedef struct ClockMuxResetInfo {
122
+ uint32_t cm_ctl;
123
+ uint32_t cm_div;
124
+} ClockMuxResetInfo;
125
+
126
+static const ClockMuxResetInfo CLOCK_MUX_RESET_INFO[] = {
127
+ [CPRMAN_CLOCK_GNRIC] = {
128
+ .cm_ctl = 0, /* unknown */
129
+ .cm_div = 0
130
+ },
131
+
132
+ [CPRMAN_CLOCK_VPU] = {
133
+ .cm_ctl = 0x00000245,
134
+ .cm_div = 0x00003000,
135
+ },
136
+
137
+ [CPRMAN_CLOCK_SYS] = {
138
+ .cm_ctl = 0, /* unknown */
139
+ .cm_div = 0
140
+ },
141
+
142
+ [CPRMAN_CLOCK_PERIA] = {
143
+ .cm_ctl = 0, /* unknown */
144
+ .cm_div = 0
145
+ },
146
+
147
+ [CPRMAN_CLOCK_PERII] = {
148
+ .cm_ctl = 0, /* unknown */
149
+ .cm_div = 0
150
+ },
151
+
152
+ [CPRMAN_CLOCK_H264] = {
153
+ .cm_ctl = 0x00000244,
154
+ .cm_div = 0x00003000,
155
+ },
156
+
157
+ [CPRMAN_CLOCK_ISP] = {
158
+ .cm_ctl = 0x00000244,
159
+ .cm_div = 0x00003000,
160
+ },
161
+
162
+ [CPRMAN_CLOCK_V3D] = {
163
+ .cm_ctl = 0, /* unknown */
164
+ .cm_div = 0
165
+ },
166
+
167
+ [CPRMAN_CLOCK_CAM0] = {
168
+ .cm_ctl = 0x00000000,
169
+ .cm_div = 0x00000000,
170
+ },
171
+
172
+ [CPRMAN_CLOCK_CAM1] = {
173
+ .cm_ctl = 0x00000000,
174
+ .cm_div = 0x00000000,
175
+ },
176
+
177
+ [CPRMAN_CLOCK_CCP2] = {
178
+ .cm_ctl = 0, /* unknown */
179
+ .cm_div = 0
180
+ },
181
+
182
+ [CPRMAN_CLOCK_DSI0E] = {
183
+ .cm_ctl = 0x00000000,
184
+ .cm_div = 0x00000000,
185
+ },
186
+
187
+ [CPRMAN_CLOCK_DSI0P] = {
188
+ .cm_ctl = 0x00000000,
189
+ .cm_div = 0x00000000,
190
+ },
191
+
192
+ [CPRMAN_CLOCK_DPI] = {
193
+ .cm_ctl = 0x00000000,
194
+ .cm_div = 0x00000000,
195
+ },
196
+
197
+ [CPRMAN_CLOCK_GP0] = {
198
+ .cm_ctl = 0x00000200,
199
+ .cm_div = 0x00000000,
200
+ },
201
+
202
+ [CPRMAN_CLOCK_GP1] = {
203
+ .cm_ctl = 0x00000096,
204
+ .cm_div = 0x00014000,
205
+ },
206
+
207
+ [CPRMAN_CLOCK_GP2] = {
208
+ .cm_ctl = 0x00000291,
209
+ .cm_div = 0x00249f00,
210
+ },
211
+
212
+ [CPRMAN_CLOCK_HSM] = {
213
+ .cm_ctl = 0x00000000,
214
+ .cm_div = 0x00000000,
215
+ },
216
+
217
+ [CPRMAN_CLOCK_OTP] = {
218
+ .cm_ctl = 0x00000091,
219
+ .cm_div = 0x00004000,
220
+ },
221
+
222
+ [CPRMAN_CLOCK_PCM] = {
223
+ .cm_ctl = 0x00000200,
224
+ .cm_div = 0x00000000,
225
+ },
226
+
227
+ [CPRMAN_CLOCK_PWM] = {
228
+ .cm_ctl = 0x00000200,
229
+ .cm_div = 0x00000000,
230
+ },
231
+
232
+ [CPRMAN_CLOCK_SLIM] = {
233
+ .cm_ctl = 0x00000200,
234
+ .cm_div = 0x00000000,
235
+ },
236
+
237
+ [CPRMAN_CLOCK_SMI] = {
238
+ .cm_ctl = 0x00000000,
239
+ .cm_div = 0x00000000,
240
+ },
241
+
242
+ [CPRMAN_CLOCK_TEC] = {
243
+ .cm_ctl = 0x00000000,
244
+ .cm_div = 0x00000000,
245
+ },
246
+
247
+ [CPRMAN_CLOCK_TD0] = {
248
+ .cm_ctl = 0, /* unknown */
249
+ .cm_div = 0
250
+ },
251
+
252
+ [CPRMAN_CLOCK_TD1] = {
253
+ .cm_ctl = 0, /* unknown */
254
+ .cm_div = 0
255
+ },
256
+
257
+ [CPRMAN_CLOCK_TSENS] = {
258
+ .cm_ctl = 0x00000091,
259
+ .cm_div = 0x0000a000,
260
+ },
261
+
262
+ [CPRMAN_CLOCK_TIMER] = {
263
+ .cm_ctl = 0x00000291,
264
+ .cm_div = 0x00013333,
265
+ },
266
+
267
+ [CPRMAN_CLOCK_UART] = {
268
+ .cm_ctl = 0x00000296,
269
+ .cm_div = 0x0000a6ab,
270
+ },
271
+
272
+ [CPRMAN_CLOCK_VEC] = {
273
+ .cm_ctl = 0x00000097,
274
+ .cm_div = 0x00002000,
275
+ },
276
+
277
+ [CPRMAN_CLOCK_PULSE] = {
278
+ .cm_ctl = 0, /* unknown */
279
+ .cm_div = 0
280
+ },
281
+
282
+ [CPRMAN_CLOCK_SDC] = {
283
+ .cm_ctl = 0x00004006,
284
+ .cm_div = 0x00003000,
285
+ },
286
+
287
+ [CPRMAN_CLOCK_ARM] = {
288
+ .cm_ctl = 0, /* unknown */
289
+ .cm_div = 0
290
+ },
291
+
292
+ [CPRMAN_CLOCK_AVEO] = {
293
+ .cm_ctl = 0x00000000,
294
+ .cm_div = 0x00000000,
295
+ },
296
+
297
+ [CPRMAN_CLOCK_EMMC] = {
298
+ .cm_ctl = 0x00000295,
299
+ .cm_div = 0x00006000,
300
+ },
301
+
302
+ [CPRMAN_CLOCK_EMMC2] = {
303
+ .cm_ctl = 0, /* unknown */
304
+ .cm_div = 0
305
+ },
306
+};
307
+
308
#endif
309
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
310
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
311
--- a/hw/misc/bcm2835_cprman.c
28
--- a/fpu/softfloat-specialize.c.inc
312
+++ b/hw/misc/bcm2835_cprman.c
29
+++ b/fpu/softfloat-specialize.c.inc
313
@@ -XXX,XX +XXX,XX @@
30
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
314
31
uint8_t dnan_pattern = status->default_nan_pattern;
315
/* PLL */
32
316
33
if (dnan_pattern == 0) {
317
+static void pll_reset(DeviceState *dev)
34
-#if defined(TARGET_HEXAGON)
318
+{
35
- /* Sign bit set, all frac bits set. */
319
+ CprmanPllState *s = CPRMAN_PLL(dev);
36
- dnan_pattern = 0b11111111;
320
+ const PLLResetInfo *info = &PLL_RESET_INFO[s->id];
37
-#else
321
+
38
/*
322
+ *s->reg_cm = info->cm;
39
* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
323
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
40
* S390, SH4, TriCore, and Xtensa. Our other supported targets
324
+ memcpy(s->reg_a2w_ana, info->a2w_ana, sizeof(info->a2w_ana));
41
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
325
+ *s->reg_a2w_frac = info->a2w_frac;
42
/* sign bit clear, set frac msb */
326
+}
43
dnan_pattern = 0b01000000;
327
+
44
}
328
static bool pll_is_locked(const CprmanPllState *pll)
45
-#endif
329
{
46
}
330
return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
47
assert(dnan_pattern != 0);
331
@@ -XXX,XX +XXX,XX @@ static void pll_class_init(ObjectClass *klass, void *data)
332
{
333
DeviceClass *dc = DEVICE_CLASS(klass);
334
335
+ dc->reset = pll_reset;
336
dc->vmsd = &pll_vmstate;
337
}
338
339
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
340
341
/* PLL channel */
342
343
+static void pll_channel_reset(DeviceState *dev)
344
+{
345
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(dev);
346
+ const PLLChannelResetInfo *info = &PLL_CHANNEL_RESET_INFO[s->id];
347
+
348
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
349
+}
350
+
351
static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
352
{
353
/*
354
@@ -XXX,XX +XXX,XX @@ static void pll_channel_class_init(ObjectClass *klass, void *data)
355
{
356
DeviceClass *dc = DEVICE_CLASS(klass);
357
358
+ dc->reset = pll_channel_reset;
359
dc->vmsd = &pll_channel_vmstate;
360
}
361
362
@@ -XXX,XX +XXX,XX @@ static void clock_mux_src_update(void *opaque)
363
clock_mux_update(s);
364
}
365
366
+static void clock_mux_reset(DeviceState *dev)
367
+{
368
+ CprmanClockMuxState *clock = CPRMAN_CLOCK_MUX(dev);
369
+ const ClockMuxResetInfo *info = &CLOCK_MUX_RESET_INFO[clock->id];
370
+
371
+ *clock->reg_ctl = info->cm_ctl;
372
+ *clock->reg_div = info->cm_div;
373
+}
374
+
375
static void clock_mux_init(Object *obj)
376
{
377
CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
378
@@ -XXX,XX +XXX,XX @@ static void clock_mux_class_init(ObjectClass *klass, void *data)
379
{
380
DeviceClass *dc = DEVICE_CLASS(klass);
381
382
+ dc->reset = clock_mux_reset;
383
dc->vmsd = &clock_mux_vmstate;
384
}
385
48
386
--
49
--
387
2.20.1
50
2.34.1
388
389
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the default NaN pattern explicitly for riscv.
2
2
3
No code out of bcm2836.c uses (or requires) the BCM283XInfo
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
declarations. Move it locally to the C source file.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-53-peter.maydell@linaro.org
6
---
7
target/riscv/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
5
9
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
10
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20201024170127.3592182-2-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
include/hw/arm/bcm2836.h | 8 --------
12
hw/arm/bcm2836.c | 14 ++++++++++++++
13
2 files changed, 14 insertions(+), 8 deletions(-)
14
15
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
16
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/arm/bcm2836.h
12
--- a/target/riscv/cpu.c
18
+++ b/include/hw/arm/bcm2836.h
13
+++ b/target/riscv/cpu.c
19
@@ -XXX,XX +XXX,XX @@ struct BCM283XState {
14
@@ -XXX,XX +XXX,XX @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
20
BCM2835PeripheralState peripherals;
15
cs->exception_index = RISCV_EXCP_NONE;
21
};
16
env->load_res = -1;
22
17
set_default_nan_mode(1, &env->fp_status);
23
-typedef struct BCM283XInfo BCM283XInfo;
18
+ /* Default NaN value: sign bit clear, frac msb set */
24
-
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
25
-struct BCM283XClass {
20
env->vill = true;
26
- DeviceClass parent_class;
21
27
- const BCM283XInfo *info;
22
#ifndef CONFIG_USER_ONLY
28
-};
29
-
30
-
31
#endif /* BCM2836_H */
32
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/arm/bcm2836.c
35
+++ b/hw/arm/bcm2836.c
36
@@ -XXX,XX +XXX,XX @@
37
#include "hw/arm/raspi_platform.h"
38
#include "hw/sysbus.h"
39
40
+typedef struct BCM283XInfo BCM283XInfo;
41
+
42
+typedef struct BCM283XClass {
43
+ /*< private >*/
44
+ DeviceClass parent_class;
45
+ /*< public >*/
46
+ const BCM283XInfo *info;
47
+} BCM283XClass;
48
+
49
struct BCM283XInfo {
50
const char *name;
51
const char *cpu_type;
52
@@ -XXX,XX +XXX,XX @@ struct BCM283XInfo {
53
int clusterid;
54
};
55
56
+#define BCM283X_CLASS(klass) \
57
+ OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
58
+#define BCM283X_GET_CLASS(obj) \
59
+ OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
60
+
61
static const BCM283XInfo bcm283x_socs[] = {
62
{
63
.name = TYPE_BCM2836,
64
--
23
--
65
2.20.1
24
2.34.1
66
67
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
Set the default NaN pattern explicitly for tricore.
2
2
3
Remove usage of TypeInfo::class_data. Instead fill the fields in
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
the corresponding class_init().
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-54-peter.maydell@linaro.org
6
---
7
target/tricore/helper.c | 2 ++
8
1 file changed, 2 insertions(+)
5
9
6
So far all children use the same values for almost all fields,
10
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
7
but we are going to add the BCM2711/BCM2838 SoC for the raspi4
8
machine which use different fields.
9
10
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
11
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Message-id: 20201024170127.3592182-3-f4bug@amsat.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
hw/arm/bcm2836.c | 108 ++++++++++++++++++++++-------------------------
16
1 file changed, 51 insertions(+), 57 deletions(-)
17
18
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
19
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/arm/bcm2836.c
12
--- a/target/tricore/helper.c
21
+++ b/hw/arm/bcm2836.c
13
+++ b/target/tricore/helper.c
22
@@ -XXX,XX +XXX,XX @@
14
@@ -XXX,XX +XXX,XX @@ void fpu_set_state(CPUTriCoreState *env)
23
#include "hw/arm/raspi_platform.h"
15
set_flush_to_zero(1, &env->fp_status);
24
#include "hw/sysbus.h"
16
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
25
17
set_default_nan_mode(1, &env->fp_status);
26
-typedef struct BCM283XInfo BCM283XInfo;
18
+ /* Default NaN pattern: sign bit clear, frac msb set */
27
-
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
28
typedef struct BCM283XClass {
29
/*< private >*/
30
DeviceClass parent_class;
31
/*< public >*/
32
- const BCM283XInfo *info;
33
-} BCM283XClass;
34
-
35
-struct BCM283XInfo {
36
const char *name;
37
const char *cpu_type;
38
hwaddr peri_base; /* Peripheral base address seen by the CPU */
39
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
40
int clusterid;
41
-};
42
+} BCM283XClass;
43
44
#define BCM283X_CLASS(klass) \
45
OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
46
#define BCM283X_GET_CLASS(obj) \
47
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
48
49
-static const BCM283XInfo bcm283x_socs[] = {
50
- {
51
- .name = TYPE_BCM2836,
52
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"),
53
- .peri_base = 0x3f000000,
54
- .ctrl_base = 0x40000000,
55
- .clusterid = 0xf,
56
- },
57
-#ifdef TARGET_AARCH64
58
- {
59
- .name = TYPE_BCM2837,
60
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
61
- .peri_base = 0x3f000000,
62
- .ctrl_base = 0x40000000,
63
- .clusterid = 0x0,
64
- },
65
-#endif
66
-};
67
-
68
static void bcm2836_init(Object *obj)
69
{
70
BCM283XState *s = BCM283X(obj);
71
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
72
- const BCM283XInfo *info = bc->info;
73
int n;
74
75
for (n = 0; n < BCM283X_NCPUS; n++) {
76
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
77
- info->cpu_type);
78
+ bc->cpu_type);
79
}
80
81
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
82
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
83
{
84
BCM283XState *s = BCM283X(dev);
85
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
86
- const BCM283XInfo *info = bc->info;
87
Object *obj;
88
int n;
89
90
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
91
"sd-bus");
92
93
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
94
- info->peri_base, 1);
95
+ bc->peri_base, 1);
96
97
/* bcm2836 interrupt controller (and mailboxes, etc.) */
98
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
99
return;
100
}
101
102
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
103
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, bc->ctrl_base);
104
105
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
106
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
107
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
108
109
for (n = 0; n < BCM283X_NCPUS; n++) {
110
/* TODO: this should be converted to a property of ARM_CPU */
111
- s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n;
112
+ s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
113
114
/* set periphbase/CBAR value for CPU-local registers */
115
if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
116
- info->peri_base, errp)) {
117
+ bc->peri_base, errp)) {
118
return;
119
}
120
121
@@ -XXX,XX +XXX,XX @@ static Property bcm2836_props[] = {
122
static void bcm283x_class_init(ObjectClass *oc, void *data)
123
{
124
DeviceClass *dc = DEVICE_CLASS(oc);
125
- BCM283XClass *bc = BCM283X_CLASS(oc);
126
127
- bc->info = data;
128
- dc->realize = bcm2836_realize;
129
- device_class_set_props(dc, bcm2836_props);
130
/* Reason: Must be wired up in code (see raspi_init() function) */
131
dc->user_creatable = false;
132
}
20
}
133
21
134
-static const TypeInfo bcm283x_type_info = {
22
uint32_t psw_read(CPUTriCoreState *env)
135
- .name = TYPE_BCM283X,
136
- .parent = TYPE_DEVICE,
137
- .instance_size = sizeof(BCM283XState),
138
- .instance_init = bcm2836_init,
139
- .class_size = sizeof(BCM283XClass),
140
- .abstract = true,
141
+static void bcm2836_class_init(ObjectClass *oc, void *data)
142
+{
143
+ DeviceClass *dc = DEVICE_CLASS(oc);
144
+ BCM283XClass *bc = BCM283X_CLASS(oc);
145
+
146
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
147
+ bc->peri_base = 0x3f000000;
148
+ bc->ctrl_base = 0x40000000;
149
+ bc->clusterid = 0xf;
150
+ dc->realize = bcm2836_realize;
151
+ device_class_set_props(dc, bcm2836_props);
152
};
153
154
-static void bcm2836_register_types(void)
155
+#ifdef TARGET_AARCH64
156
+static void bcm2837_class_init(ObjectClass *oc, void *data)
157
{
158
- int i;
159
+ DeviceClass *dc = DEVICE_CLASS(oc);
160
+ BCM283XClass *bc = BCM283X_CLASS(oc);
161
162
- type_register_static(&bcm283x_type_info);
163
- for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
164
- TypeInfo ti = {
165
- .name = bcm283x_socs[i].name,
166
- .parent = TYPE_BCM283X,
167
- .class_init = bcm283x_class_init,
168
- .class_data = (void *) &bcm283x_socs[i],
169
- };
170
- type_register(&ti);
171
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
172
+ bc->peri_base = 0x3f000000;
173
+ bc->ctrl_base = 0x40000000;
174
+ bc->clusterid = 0x0;
175
+ dc->realize = bcm2836_realize;
176
+ device_class_set_props(dc, bcm2836_props);
177
+};
178
+#endif
179
+
180
+static const TypeInfo bcm283x_types[] = {
181
+ {
182
+ .name = TYPE_BCM2836,
183
+ .parent = TYPE_BCM283X,
184
+ .class_init = bcm2836_class_init,
185
+#ifdef TARGET_AARCH64
186
+ }, {
187
+ .name = TYPE_BCM2837,
188
+ .parent = TYPE_BCM283X,
189
+ .class_init = bcm2837_class_init,
190
+#endif
191
+ }, {
192
+ .name = TYPE_BCM283X,
193
+ .parent = TYPE_DEVICE,
194
+ .instance_size = sizeof(BCM283XState),
195
+ .instance_init = bcm2836_init,
196
+ .class_size = sizeof(BCM283XClass),
197
+ .class_init = bcm283x_class_init,
198
+ .abstract = true,
199
}
200
-}
201
+};
202
203
-type_init(bcm2836_register_types)
204
+DEFINE_TYPES(bcm283x_types)
205
--
23
--
206
2.20.1
24
2.34.1
207
208
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
1
Now that all our targets have bene converted to explicitly specify
2
their pattern for the default NaN value we can remove the remaining
3
fallback code in parts64_default_nan().
2
4
3
This patch sets min_cpus field for xlnx-versal-virt platform,
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
because it always creates XLNX_VERSAL_NR_ACPUS cpus even with
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
-smp 1 command line option.
7
Message-id: 20241202131347.498124-55-peter.maydell@linaro.org
8
---
9
fpu/softfloat-specialize.c.inc | 14 --------------
10
1 file changed, 14 deletions(-)
6
11
7
Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
12
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Message-id: 160343854912.8460.17915238517799132371.stgit@pasha-ThinkPad-X280
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
hw/arm/xlnx-versal-virt.c | 1 +
14
1 file changed, 1 insertion(+)
15
16
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
17
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/xlnx-versal-virt.c
14
--- a/fpu/softfloat-specialize.c.inc
19
+++ b/hw/arm/xlnx-versal-virt.c
15
+++ b/fpu/softfloat-specialize.c.inc
20
@@ -XXX,XX +XXX,XX @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
16
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
21
17
uint64_t frac;
22
mc->desc = "Xilinx Versal Virtual development board";
18
uint8_t dnan_pattern = status->default_nan_pattern;
23
mc->init = versal_virt_init;
19
24
+ mc->min_cpus = XLNX_VERSAL_NR_ACPUS;
20
- if (dnan_pattern == 0) {
25
mc->max_cpus = XLNX_VERSAL_NR_ACPUS;
21
- /*
26
mc->default_cpus = XLNX_VERSAL_NR_ACPUS;
22
- * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
27
mc->no_cdrom = true;
23
- * S390, SH4, TriCore, and Xtensa. Our other supported targets
24
- * do not have floating-point.
25
- */
26
- if (snan_bit_is_one(status)) {
27
- /* sign bit clear, set all frac bits other than msb */
28
- dnan_pattern = 0b00111111;
29
- } else {
30
- /* sign bit clear, set frac msb */
31
- dnan_pattern = 0b01000000;
32
- }
33
- }
34
assert(dnan_pattern != 0);
35
36
sign = dnan_pattern >> 7;
28
--
37
--
29
2.20.1
38
2.34.1
30
31
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This is a bit clearer than open-coding some of this
3
Inline pickNaNMulAdd into its only caller. This makes
4
with a bare c string.
4
one assert redundant with the immediately preceding IF.
5
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201021173749.111103-9-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20241203203949.483774-3-richard.henderson@linaro.org
9
[PMM: keep comment from old code in new location]
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
---
11
linux-user/elfload.c | 37 ++++++++++++++++++++-----------------
12
fpu/softfloat-parts.c.inc | 41 +++++++++++++++++++++++++-
12
1 file changed, 20 insertions(+), 17 deletions(-)
13
fpu/softfloat-specialize.c.inc | 54 ----------------------------------
14
2 files changed, 40 insertions(+), 55 deletions(-)
13
15
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
16
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/elfload.c
18
--- a/fpu/softfloat-parts.c.inc
17
+++ b/linux-user/elfload.c
19
+++ b/fpu/softfloat-parts.c.inc
18
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
19
#include "qemu/guest-random.h"
20
#include "qemu/units.h"
21
#include "qemu/selfmap.h"
22
+#include "qapi/error.h"
23
24
#ifdef _ARCH_PPC64
25
#undef ARCH_DLINFO
26
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
27
struct elf_phdr *phdr;
28
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
29
int i, retval;
30
- const char *errmsg;
31
+ Error *err = NULL;
32
33
/* First of all, some simple consistency checks */
34
- errmsg = "Invalid ELF image for this architecture";
35
if (!elf_check_ident(ehdr)) {
36
+ error_setg(&err, "Invalid ELF image for this architecture");
37
goto exit_errmsg;
38
}
21
}
39
bswap_ehdr(ehdr);
22
40
if (!elf_check_ehdr(ehdr)) {
23
if (s->default_nan_mode) {
41
+ error_setg(&err, "Invalid ELF image for this architecture");
24
+ /*
42
goto exit_errmsg;
25
+ * We guarantee not to require the target to tell us how to
26
+ * pick a NaN if we're always returning the default NaN.
27
+ * But if we're not in default-NaN mode then the target must
28
+ * specify.
29
+ */
30
which = 3;
31
+ } else if (infzero) {
32
+ /*
33
+ * Inf * 0 + NaN -- some implementations return the
34
+ * default NaN here, and some return the input NaN.
35
+ */
36
+ switch (s->float_infzeronan_rule) {
37
+ case float_infzeronan_dnan_never:
38
+ which = 2;
39
+ break;
40
+ case float_infzeronan_dnan_always:
41
+ which = 3;
42
+ break;
43
+ case float_infzeronan_dnan_if_qnan:
44
+ which = is_qnan(c->cls) ? 3 : 2;
45
+ break;
46
+ default:
47
+ g_assert_not_reached();
48
+ }
49
} else {
50
- which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, have_snan, s);
51
+ FloatClass cls[3] = { a->cls, b->cls, c->cls };
52
+ Float3NaNPropRule rule = s->float_3nan_prop_rule;
53
+
54
+ assert(rule != float_3nan_prop_none);
55
+ if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
56
+ /* We have at least one SNaN input and should prefer it */
57
+ do {
58
+ which = rule & R_3NAN_1ST_MASK;
59
+ rule >>= R_3NAN_1ST_LENGTH;
60
+ } while (!is_snan(cls[which]));
61
+ } else {
62
+ do {
63
+ which = rule & R_3NAN_1ST_MASK;
64
+ rule >>= R_3NAN_1ST_LENGTH;
65
+ } while (!is_nan(cls[which]));
66
+ }
43
}
67
}
44
68
45
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
69
if (which == 3) {
46
g_autofree char *interp_name = NULL;
70
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
47
71
index XXXXXXX..XXXXXXX 100644
48
if (*pinterp_name) {
72
--- a/fpu/softfloat-specialize.c.inc
49
- errmsg = "Multiple PT_INTERP entries";
73
+++ b/fpu/softfloat-specialize.c.inc
50
+ error_setg(&err, "Multiple PT_INTERP entries");
74
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
51
goto exit_errmsg;
52
}
53
+
54
interp_name = g_malloc(eppnt->p_filesz);
55
- if (!interp_name) {
56
- goto exit_perror;
57
- }
58
59
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
60
memcpy(interp_name, bprm_buf + eppnt->p_offset,
61
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
62
retval = pread(image_fd, interp_name, eppnt->p_filesz,
63
eppnt->p_offset);
64
if (retval != eppnt->p_filesz) {
65
- goto exit_perror;
66
+ goto exit_read;
67
}
68
}
69
if (interp_name[eppnt->p_filesz - 1] != 0) {
70
- errmsg = "Invalid PT_INTERP entry";
71
+ error_setg(&err, "Invalid PT_INTERP entry");
72
goto exit_errmsg;
73
}
74
*pinterp_name = g_steal_pointer(&interp_name);
75
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
76
(ehdr->e_type == ET_EXEC ? MAP_FIXED : 0),
77
-1, 0);
78
if (load_addr == -1) {
79
- goto exit_perror;
80
+ goto exit_mmap;
81
}
75
}
82
load_bias = load_addr - loaddr;
83
84
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
85
image_fd, eppnt->p_offset - vaddr_po);
86
87
if (error == -1) {
88
- goto exit_perror;
89
+ goto exit_mmap;
90
}
91
}
92
93
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
94
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
95
Mips_elf_abiflags_v0 abiflags;
96
if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
97
- errmsg = "Invalid PT_MIPS_ABIFLAGS entry";
98
+ error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
99
goto exit_errmsg;
100
}
101
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
102
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
103
retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
104
eppnt->p_offset);
105
if (retval != sizeof(Mips_elf_abiflags_v0)) {
106
- goto exit_perror;
107
+ goto exit_read;
108
}
109
}
110
bswap_mips_abiflags(&abiflags);
111
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
112
113
exit_read:
114
if (retval >= 0) {
115
- errmsg = "Incomplete read of file header";
116
- goto exit_errmsg;
117
+ error_setg(&err, "Incomplete read of file header");
118
+ } else {
119
+ error_setg_errno(&err, errno, "Error reading file header");
120
}
121
- exit_perror:
122
- errmsg = strerror(errno);
123
+ goto exit_errmsg;
124
+ exit_mmap:
125
+ error_setg_errno(&err, errno, "Error mapping file");
126
+ goto exit_errmsg;
127
exit_errmsg:
128
- fprintf(stderr, "%s: %s\n", image_name, errmsg);
129
+ error_reportf_err(err, "%s: ", image_name);
130
exit(-1);
131
}
76
}
132
77
78
-/*----------------------------------------------------------------------------
79
-| Select which NaN to propagate for a three-input operation.
80
-| For the moment we assume that no CPU needs the 'larger significand'
81
-| information.
82
-| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
83
-*----------------------------------------------------------------------------*/
84
-static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
85
- bool infzero, bool have_snan, float_status *status)
86
-{
87
- FloatClass cls[3] = { a_cls, b_cls, c_cls };
88
- Float3NaNPropRule rule = status->float_3nan_prop_rule;
89
- int which;
90
-
91
- /*
92
- * We guarantee not to require the target to tell us how to
93
- * pick a NaN if we're always returning the default NaN.
94
- * But if we're not in default-NaN mode then the target must
95
- * specify.
96
- */
97
- assert(!status->default_nan_mode);
98
-
99
- if (infzero) {
100
- /*
101
- * Inf * 0 + NaN -- some implementations return the default NaN here,
102
- * and some return the input NaN.
103
- */
104
- switch (status->float_infzeronan_rule) {
105
- case float_infzeronan_dnan_never:
106
- return 2;
107
- case float_infzeronan_dnan_always:
108
- return 3;
109
- case float_infzeronan_dnan_if_qnan:
110
- return is_qnan(c_cls) ? 3 : 2;
111
- default:
112
- g_assert_not_reached();
113
- }
114
- }
115
-
116
- assert(rule != float_3nan_prop_none);
117
- if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
118
- /* We have at least one SNaN input and should prefer it */
119
- do {
120
- which = rule & R_3NAN_1ST_MASK;
121
- rule >>= R_3NAN_1ST_LENGTH;
122
- } while (!is_snan(cls[which]));
123
- } else {
124
- do {
125
- which = rule & R_3NAN_1ST_MASK;
126
- rule >>= R_3NAN_1ST_LENGTH;
127
- } while (!is_nan(cls[which]));
128
- }
129
- return which;
130
-}
131
-
132
/*----------------------------------------------------------------------------
133
| Returns 1 if the double-precision floating-point value `a' is a quiet
134
| NaN; otherwise returns 0.
133
--
135
--
134
2.20.1
136
2.34.1
135
137
136
138
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The second loop uses a loop induction variable, and the first
3
Remove "3" as a special case for which and simply
4
does not. Transform the first to match the second, to simplify
4
branch to return the desired value.
5
a following patch moving code between them.
6
5
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-7-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20241203203949.483774-4-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
linux-user/elfload.c | 9 +++++----
11
fpu/softfloat-parts.c.inc | 20 ++++++++++----------
13
1 file changed, 5 insertions(+), 4 deletions(-)
12
1 file changed, 10 insertions(+), 10 deletions(-)
14
13
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
16
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
17
--- a/linux-user/elfload.c
16
--- a/fpu/softfloat-parts.c.inc
18
+++ b/linux-user/elfload.c
17
+++ b/fpu/softfloat-parts.c.inc
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
20
loaddr = -1, hiaddr = 0;
19
* But if we're not in default-NaN mode then the target must
21
info->alignment = 0;
20
* specify.
22
for (i = 0; i < ehdr->e_phnum; ++i) {
21
*/
23
- if (phdr[i].p_type == PT_LOAD) {
22
- which = 3;
24
- abi_ulong a = phdr[i].p_vaddr - phdr[i].p_offset;
23
+ goto default_nan;
25
+ struct elf_phdr *eppnt = phdr + i;
24
} else if (infzero) {
26
+ if (eppnt->p_type == PT_LOAD) {
25
/*
27
+ abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
26
* Inf * 0 + NaN -- some implementations return the
28
if (a < loaddr) {
27
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
29
loaddr = a;
28
*/
30
}
29
switch (s->float_infzeronan_rule) {
31
- a = phdr[i].p_vaddr + phdr[i].p_memsz;
30
case float_infzeronan_dnan_never:
32
+ a = eppnt->p_vaddr + eppnt->p_memsz;
31
- which = 2;
33
if (a > hiaddr) {
32
break;
34
hiaddr = a;
33
case float_infzeronan_dnan_always:
35
}
34
- which = 3;
36
++info->nsegs;
35
- break;
37
- info->alignment |= phdr[i].p_align;
36
+ goto default_nan;
38
+ info->alignment |= eppnt->p_align;
37
case float_infzeronan_dnan_if_qnan:
38
- which = is_qnan(c->cls) ? 3 : 2;
39
+ if (is_qnan(c->cls)) {
40
+ goto default_nan;
41
+ }
42
break;
43
default:
44
g_assert_not_reached();
45
}
46
+ which = 2;
47
} else {
48
FloatClass cls[3] = { a->cls, b->cls, c->cls };
49
Float3NaNPropRule rule = s->float_3nan_prop_rule;
50
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
39
}
51
}
40
}
52
}
41
53
54
- if (which == 3) {
55
- parts_default_nan(a, s);
56
- return a;
57
- }
58
-
59
switch (which) {
60
case 0:
61
break;
62
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
63
parts_silence_nan(a, s);
64
}
65
return a;
66
+
67
+ default_nan:
68
+ parts_default_nan(a, s);
69
+ return a;
70
}
71
72
/*
42
--
73
--
43
2.20.1
74
2.34.1
44
75
45
76
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
For BTI, we need to know if the executable is static or dynamic,
3
Assign the pointer return value to 'a' directly,
4
which means looking for PT_INTERP earlier.
4
rather than going through an intermediary index.
5
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201021173749.111103-8-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20241203203949.483774-5-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
linux-user/elfload.c | 60 +++++++++++++++++++++++---------------------
11
fpu/softfloat-parts.c.inc | 32 ++++++++++----------------------
12
1 file changed, 31 insertions(+), 29 deletions(-)
12
1 file changed, 10 insertions(+), 22 deletions(-)
13
13
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/elfload.c
16
--- a/fpu/softfloat-parts.c.inc
17
+++ b/linux-user/elfload.c
17
+++ b/fpu/softfloat-parts.c.inc
18
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
19
19
FloatPartsN *c, float_status *s,
20
mmap_lock();
20
int ab_mask, int abc_mask)
21
21
{
22
- /* Find the maximum size of the image and allocate an appropriate
22
- int which;
23
- amount of memory to handle that. */
23
bool infzero = (ab_mask == float_cmask_infzero);
24
+ /*
24
bool have_snan = (abc_mask & float_cmask_snan);
25
+ * Find the maximum size of the image and allocate an appropriate
25
+ FloatPartsN *ret;
26
+ * amount of memory to handle that. Locate the interpreter, if any.
26
27
+ */
27
if (unlikely(have_snan)) {
28
loaddr = -1, hiaddr = 0;
28
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
29
info->alignment = 0;
29
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
30
for (i = 0; i < ehdr->e_phnum; ++i) {
30
default:
31
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
31
g_assert_not_reached();
32
}
32
}
33
++info->nsegs;
33
- which = 2;
34
info->alignment |= eppnt->p_align;
34
+ ret = c;
35
+ } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
35
} else {
36
+ g_autofree char *interp_name = NULL;
36
- FloatClass cls[3] = { a->cls, b->cls, c->cls };
37
+
37
+ FloatPartsN *val[3] = { a, b, c };
38
+ if (*pinterp_name) {
38
Float3NaNPropRule rule = s->float_3nan_prop_rule;
39
+ errmsg = "Multiple PT_INTERP entries";
39
40
+ goto exit_errmsg;
40
assert(rule != float_3nan_prop_none);
41
+ }
41
if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
42
+ interp_name = g_malloc(eppnt->p_filesz);
42
/* We have at least one SNaN input and should prefer it */
43
+ if (!interp_name) {
43
do {
44
+ goto exit_perror;
44
- which = rule & R_3NAN_1ST_MASK;
45
+ }
45
+ ret = val[rule & R_3NAN_1ST_MASK];
46
+
46
rule >>= R_3NAN_1ST_LENGTH;
47
+ if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
47
- } while (!is_snan(cls[which]));
48
+ memcpy(interp_name, bprm_buf + eppnt->p_offset,
48
+ } while (!is_snan(ret->cls));
49
+ eppnt->p_filesz);
49
} else {
50
+ } else {
50
do {
51
+ retval = pread(image_fd, interp_name, eppnt->p_filesz,
51
- which = rule & R_3NAN_1ST_MASK;
52
+ eppnt->p_offset);
52
+ ret = val[rule & R_3NAN_1ST_MASK];
53
+ if (retval != eppnt->p_filesz) {
53
rule >>= R_3NAN_1ST_LENGTH;
54
+ goto exit_perror;
54
- } while (!is_nan(cls[which]));
55
+ }
55
+ } while (!is_nan(ret->cls));
56
+ }
57
+ if (interp_name[eppnt->p_filesz - 1] != 0) {
58
+ errmsg = "Invalid PT_INTERP entry";
59
+ goto exit_errmsg;
60
+ }
61
+ *pinterp_name = g_steal_pointer(&interp_name);
62
}
56
}
63
}
57
}
64
58
65
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
59
- switch (which) {
66
if (vaddr_em > info->brk) {
60
- case 0:
67
info->brk = vaddr_em;
61
- break;
68
}
62
- case 1:
69
- } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
63
- a = b;
70
- g_autofree char *interp_name = NULL;
64
- break;
71
-
65
- case 2:
72
- if (*pinterp_name) {
66
- a = c;
73
- errmsg = "Multiple PT_INTERP entries";
67
- break;
74
- goto exit_errmsg;
68
- default:
75
- }
69
- g_assert_not_reached();
76
- interp_name = g_malloc(eppnt->p_filesz);
70
+ if (is_snan(ret->cls)) {
77
- if (!interp_name) {
71
+ parts_silence_nan(ret, s);
78
- goto exit_perror;
72
}
79
- }
73
- if (is_snan(a->cls)) {
80
-
74
- parts_silence_nan(a, s);
81
- if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
75
- }
82
- memcpy(interp_name, bprm_buf + eppnt->p_offset,
76
- return a;
83
- eppnt->p_filesz);
77
+ return ret;
84
- } else {
78
85
- retval = pread(image_fd, interp_name, eppnt->p_filesz,
79
default_nan:
86
- eppnt->p_offset);
80
parts_default_nan(a, s);
87
- if (retval != eppnt->p_filesz) {
88
- goto exit_perror;
89
- }
90
- }
91
- if (interp_name[eppnt->p_filesz - 1] != 0) {
92
- errmsg = "Invalid PT_INTERP entry";
93
- goto exit_errmsg;
94
- }
95
- *pinterp_name = g_steal_pointer(&interp_name);
96
#ifdef TARGET_MIPS
97
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
98
Mips_elf_abiflags_v0 abiflags;
99
--
81
--
100
2.20.1
82
2.34.1
101
83
102
84
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Use the new generic support for NT_GNU_PROPERTY_TYPE_0.
3
While all indices into val[] should be in [0-2], the mask
4
applied is two bits. To help static analysis see there is
5
no possibility of read beyond the end of the array, pad the
6
array to 4 entries, with the final being (implicitly) NULL.
4
7
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20201021173749.111103-12-richard.henderson@linaro.org
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20241203203949.483774-6-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
12
---
10
linux-user/elfload.c | 48 ++++++++++++++++++++++++++++++++++++++++++--
13
fpu/softfloat-parts.c.inc | 2 +-
11
1 file changed, 46 insertions(+), 2 deletions(-)
14
1 file changed, 1 insertion(+), 1 deletion(-)
12
15
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
16
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/elfload.c
18
--- a/fpu/softfloat-parts.c.inc
16
+++ b/linux-user/elfload.c
19
+++ b/fpu/softfloat-parts.c.inc
17
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
20
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
18
21
}
19
#include "elf.h"
22
ret = c;
20
23
} else {
21
+/* We must delay the following stanzas until after "elf.h". */
24
- FloatPartsN *val[3] = { a, b, c };
22
+#if defined(TARGET_AARCH64)
25
+ FloatPartsN *val[R_3NAN_1ST_MASK + 1] = { a, b, c };
23
+
26
Float3NaNPropRule rule = s->float_3nan_prop_rule;
24
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
27
25
+ const uint32_t *data,
28
assert(rule != float_3nan_prop_none);
26
+ struct image_info *info,
27
+ Error **errp)
28
+{
29
+ if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
30
+ if (pr_datasz != sizeof(uint32_t)) {
31
+ error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
32
+ return false;
33
+ }
34
+ /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
35
+ info->note_flags = *data;
36
+ }
37
+ return true;
38
+}
39
+#define ARCH_USE_GNU_PROPERTY 1
40
+
41
+#else
42
+
43
static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
44
const uint32_t *data,
45
struct image_info *info,
46
@@ -XXX,XX +XXX,XX @@ static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
47
}
48
#define ARCH_USE_GNU_PROPERTY 0
49
50
+#endif
51
+
52
struct exec
53
{
54
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
55
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
56
struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
57
struct elf_phdr *phdr;
58
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
59
- int i, retval;
60
+ int i, retval, prot_exec;
61
Error *err = NULL;
62
63
/* First of all, some simple consistency checks */
64
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
65
info->brk = 0;
66
info->elf_flags = ehdr->e_flags;
67
68
+ prot_exec = PROT_EXEC;
69
+#ifdef TARGET_AARCH64
70
+ /*
71
+ * If the BTI feature is present, this indicates that the executable
72
+ * pages of the startup binary should be mapped with PROT_BTI, so that
73
+ * branch targets are enforced.
74
+ *
75
+ * The startup binary is either the interpreter or the static executable.
76
+ * The interpreter is responsible for all pages of a dynamic executable.
77
+ *
78
+ * Elf notes are backward compatible to older cpus.
79
+ * Do not enable BTI unless it is supported.
80
+ */
81
+ if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
82
+ && (pinterp_name == NULL || *pinterp_name == 0)
83
+ && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
84
+ prot_exec |= TARGET_PROT_BTI;
85
+ }
86
+#endif
87
+
88
for (i = 0; i < ehdr->e_phnum; i++) {
89
struct elf_phdr *eppnt = phdr + i;
90
if (eppnt->p_type == PT_LOAD) {
91
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
92
elf_prot |= PROT_WRITE;
93
}
94
if (eppnt->p_flags & PF_X) {
95
- elf_prot |= PROT_EXEC;
96
+ elf_prot |= prot_exec;
97
}
98
99
vaddr = load_bias + eppnt->p_vaddr;
100
--
29
--
101
2.20.1
30
2.34.1
102
31
103
32
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This is generic support, with the code disabled for all targets.
3
This function is part of the public interface and
4
is not "specialized" to any target in any way.
4
5
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20201021173749.111103-11-richard.henderson@linaro.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20241203203949.483774-7-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
linux-user/qemu.h | 4 ++
11
fpu/softfloat.c | 52 ++++++++++++++++++++++++++++++++++
11
linux-user/elfload.c | 157 +++++++++++++++++++++++++++++++++++++++++++
12
fpu/softfloat-specialize.c.inc | 52 ----------------------------------
12
2 files changed, 161 insertions(+)
13
2 files changed, 52 insertions(+), 52 deletions(-)
13
14
14
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
15
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/qemu.h
17
--- a/fpu/softfloat.c
17
+++ b/linux-user/qemu.h
18
+++ b/fpu/softfloat.c
18
@@ -XXX,XX +XXX,XX @@ struct image_info {
19
@@ -XXX,XX +XXX,XX @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr,
19
abi_ulong interpreter_loadmap_addr;
20
*zExpPtr = 1 - shiftCount;
20
abi_ulong interpreter_pt_dynamic_addr;
21
}
21
struct image_info *other_info;
22
23
+/*----------------------------------------------------------------------------
24
+| Takes two extended double-precision floating-point values `a' and `b', one
25
+| of which is a NaN, and returns the appropriate NaN result. If either `a' or
26
+| `b' is a signaling NaN, the invalid exception is raised.
27
+*----------------------------------------------------------------------------*/
22
+
28
+
23
+ /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */
29
+floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
24
+ uint32_t note_flags;
30
+{
31
+ bool aIsLargerSignificand;
32
+ FloatClass a_cls, b_cls;
25
+
33
+
26
#ifdef TARGET_MIPS
34
+ /* This is not complete, but is good enough for pickNaN. */
27
int fp_abi;
35
+ a_cls = (!floatx80_is_any_nan(a)
28
int interp_fp_abi;
36
+ ? float_class_normal
29
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
37
+ : floatx80_is_signaling_nan(a, status)
30
index XXXXXXX..XXXXXXX 100644
38
+ ? float_class_snan
31
--- a/linux-user/elfload.c
39
+ : float_class_qnan);
32
+++ b/linux-user/elfload.c
40
+ b_cls = (!floatx80_is_any_nan(b)
33
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
41
+ ? float_class_normal
34
42
+ : floatx80_is_signaling_nan(b, status)
35
#include "elf.h"
43
+ ? float_class_snan
36
44
+ : float_class_qnan);
37
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
38
+ const uint32_t *data,
39
+ struct image_info *info,
40
+ Error **errp)
41
+{
42
+ g_assert_not_reached();
43
+}
44
+#define ARCH_USE_GNU_PROPERTY 0
45
+
45
+
46
struct exec
46
+ if (is_snan(a_cls) || is_snan(b_cls)) {
47
{
47
+ float_raise(float_flag_invalid, status);
48
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
49
@@ -XXX,XX +XXX,XX @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
50
"@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
51
}
52
53
+enum {
54
+ /* The string "GNU\0" as a magic number. */
55
+ GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
56
+ NOTE_DATA_SZ = 1 * KiB,
57
+ NOTE_NAME_SZ = 4,
58
+ ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
59
+};
60
+
61
+/*
62
+ * Process a single gnu_property entry.
63
+ * Return false for error.
64
+ */
65
+static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
66
+ struct image_info *info, bool have_prev_type,
67
+ uint32_t *prev_type, Error **errp)
68
+{
69
+ uint32_t pr_type, pr_datasz, step;
70
+
71
+ if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
72
+ goto error_data;
73
+ }
74
+ datasz -= *off;
75
+ data += *off / sizeof(uint32_t);
76
+
77
+ if (datasz < 2 * sizeof(uint32_t)) {
78
+ goto error_data;
79
+ }
80
+ pr_type = data[0];
81
+ pr_datasz = data[1];
82
+ data += 2;
83
+ datasz -= 2 * sizeof(uint32_t);
84
+ step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
85
+ if (step > datasz) {
86
+ goto error_data;
87
+ }
48
+ }
88
+
49
+
89
+ /* Properties are supposed to be unique and sorted on pr_type. */
50
+ if (status->default_nan_mode) {
90
+ if (have_prev_type && pr_type <= *prev_type) {
51
+ return floatx80_default_nan(status);
91
+ if (pr_type == *prev_type) {
92
+ error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
93
+ } else {
94
+ error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
95
+ }
96
+ return false;
97
+ }
98
+ *prev_type = pr_type;
99
+
100
+ if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
101
+ return false;
102
+ }
52
+ }
103
+
53
+
104
+ *off += 2 * sizeof(uint32_t) + step;
54
+ if (a.low < b.low) {
105
+ return true;
55
+ aIsLargerSignificand = 0;
106
+
56
+ } else if (b.low < a.low) {
107
+ error_data:
57
+ aIsLargerSignificand = 1;
108
+ error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
58
+ } else {
109
+ return false;
59
+ aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
110
+}
111
+
112
+/* Process NT_GNU_PROPERTY_TYPE_0. */
113
+static bool parse_elf_properties(int image_fd,
114
+ struct image_info *info,
115
+ const struct elf_phdr *phdr,
116
+ char bprm_buf[BPRM_BUF_SIZE],
117
+ Error **errp)
118
+{
119
+ union {
120
+ struct elf_note nhdr;
121
+ uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
122
+ } note;
123
+
124
+ int n, off, datasz;
125
+ bool have_prev_type;
126
+ uint32_t prev_type;
127
+
128
+ /* Unless the arch requires properties, ignore them. */
129
+ if (!ARCH_USE_GNU_PROPERTY) {
130
+ return true;
131
+ }
60
+ }
132
+
61
+
133
+ /* If the properties are crazy large, that's too bad. */
62
+ if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) {
134
+ n = phdr->p_filesz;
63
+ if (is_snan(b_cls)) {
135
+ if (n > sizeof(note)) {
64
+ return floatx80_silence_nan(b, status);
136
+ error_setg(errp, "PT_GNU_PROPERTY too large");
65
+ }
137
+ return false;
66
+ return b;
138
+ }
139
+ if (n < sizeof(note.nhdr)) {
140
+ error_setg(errp, "PT_GNU_PROPERTY too small");
141
+ return false;
142
+ }
143
+
144
+ if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
145
+ memcpy(&note, bprm_buf + phdr->p_offset, n);
146
+ } else {
67
+ } else {
147
+ ssize_t len = pread(image_fd, &note, n, phdr->p_offset);
68
+ if (is_snan(a_cls)) {
148
+ if (len != n) {
69
+ return floatx80_silence_nan(a, status);
149
+ error_setg_errno(errp, errno, "Error reading file header");
150
+ return false;
151
+ }
70
+ }
152
+ }
71
+ return a;
153
+
154
+ /*
155
+ * The contents of a valid PT_GNU_PROPERTY is a sequence
156
+ * of uint32_t -- swap them all now.
157
+ */
158
+#ifdef BSWAP_NEEDED
159
+ for (int i = 0; i < n / 4; i++) {
160
+ bswap32s(note.data + i);
161
+ }
162
+#endif
163
+
164
+ /*
165
+ * Note that nhdr is 3 words, and that the "name" described by namesz
166
+ * immediately follows nhdr and is thus at the 4th word. Further, all
167
+ * of the inputs to the kernel's round_up are multiples of 4.
168
+ */
169
+ if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
170
+ note.nhdr.n_namesz != NOTE_NAME_SZ ||
171
+ note.data[3] != GNU0_MAGIC) {
172
+ error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
173
+ return false;
174
+ }
175
+ off = sizeof(note.nhdr) + NOTE_NAME_SZ;
176
+
177
+ datasz = note.nhdr.n_descsz + off;
178
+ if (datasz > n) {
179
+ error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
180
+ return false;
181
+ }
182
+
183
+ have_prev_type = false;
184
+ prev_type = 0;
185
+ while (1) {
186
+ if (off == datasz) {
187
+ return true; /* end, exit ok */
188
+ }
189
+ if (!parse_elf_property(note.data, &off, datasz, info,
190
+ have_prev_type, &prev_type, errp)) {
191
+ return false;
192
+ }
193
+ have_prev_type = true;
194
+ }
72
+ }
195
+}
73
+}
196
+
74
+
197
/* Load an ELF image into the address space.
75
/*----------------------------------------------------------------------------
198
76
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
199
IMAGE_NAME is the filename of the image, to use in error messages.
77
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
200
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
78
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
201
goto exit_errmsg;
79
index XXXXXXX..XXXXXXX 100644
202
}
80
--- a/fpu/softfloat-specialize.c.inc
203
*pinterp_name = g_steal_pointer(&interp_name);
81
+++ b/fpu/softfloat-specialize.c.inc
204
+ } else if (eppnt->p_type == PT_GNU_PROPERTY) {
82
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_silence_nan(floatx80 a, float_status *status)
205
+ if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
83
return a;
206
+ goto exit_errmsg;
84
}
207
+ }
85
208
}
86
-/*----------------------------------------------------------------------------
209
}
87
-| Takes two extended double-precision floating-point values `a' and `b', one
210
88
-| of which is a NaN, and returns the appropriate NaN result. If either `a' or
89
-| `b' is a signaling NaN, the invalid exception is raised.
90
-*----------------------------------------------------------------------------*/
91
-
92
-floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
93
-{
94
- bool aIsLargerSignificand;
95
- FloatClass a_cls, b_cls;
96
-
97
- /* This is not complete, but is good enough for pickNaN. */
98
- a_cls = (!floatx80_is_any_nan(a)
99
- ? float_class_normal
100
- : floatx80_is_signaling_nan(a, status)
101
- ? float_class_snan
102
- : float_class_qnan);
103
- b_cls = (!floatx80_is_any_nan(b)
104
- ? float_class_normal
105
- : floatx80_is_signaling_nan(b, status)
106
- ? float_class_snan
107
- : float_class_qnan);
108
-
109
- if (is_snan(a_cls) || is_snan(b_cls)) {
110
- float_raise(float_flag_invalid, status);
111
- }
112
-
113
- if (status->default_nan_mode) {
114
- return floatx80_default_nan(status);
115
- }
116
-
117
- if (a.low < b.low) {
118
- aIsLargerSignificand = 0;
119
- } else if (b.low < a.low) {
120
- aIsLargerSignificand = 1;
121
- } else {
122
- aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
123
- }
124
-
125
- if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) {
126
- if (is_snan(b_cls)) {
127
- return floatx80_silence_nan(b, status);
128
- }
129
- return b;
130
- } else {
131
- if (is_snan(a_cls)) {
132
- return floatx80_silence_nan(a, status);
133
- }
134
- return a;
135
- }
136
-}
137
-
138
/*----------------------------------------------------------------------------
139
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
140
| NaN; otherwise returns 0.
211
--
141
--
212
2.20.1
142
2.34.1
213
214
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This is slightly clearer than just using strerror, though
3
Unpacking and repacking the parts may be slightly more work
4
the different forms produced by error_setg_file_open and
4
than we did before, but we get to reuse more code. For a
5
error_setg_errno isn't entirely convenient.
5
code path handling exceptional values, this is an improvement.
6
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-10-richard.henderson@linaro.org
8
Message-id: 20241203203949.483774-8-richard.henderson@linaro.org
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
---
11
---
12
linux-user/elfload.c | 15 ++++++++-------
12
fpu/softfloat.c | 43 +++++--------------------------------------
13
1 file changed, 8 insertions(+), 7 deletions(-)
13
1 file changed, 5 insertions(+), 38 deletions(-)
14
14
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
15
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/linux-user/elfload.c
17
--- a/fpu/softfloat.c
18
+++ b/linux-user/elfload.c
18
+++ b/fpu/softfloat.c
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_interp(const char *filename, struct image_info *info,
19
@@ -XXX,XX +XXX,XX @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr,
20
char bprm_buf[BPRM_BUF_SIZE])
20
21
floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
21
{
22
{
22
int fd, retval;
23
- bool aIsLargerSignificand;
23
+ Error *err = NULL;
24
- FloatClass a_cls, b_cls;
24
25
+ FloatParts128 pa, pb, *pr;
25
fd = open(path(filename), O_RDONLY);
26
26
if (fd < 0) {
27
- /* This is not complete, but is good enough for pickNaN. */
27
- goto exit_perror;
28
- a_cls = (!floatx80_is_any_nan(a)
28
+ error_setg_file_open(&err, errno, filename);
29
- ? float_class_normal
29
+ error_report_err(err);
30
- : floatx80_is_signaling_nan(a, status)
30
+ exit(-1);
31
- ? float_class_snan
32
- : float_class_qnan);
33
- b_cls = (!floatx80_is_any_nan(b)
34
- ? float_class_normal
35
- : floatx80_is_signaling_nan(b, status)
36
- ? float_class_snan
37
- : float_class_qnan);
38
-
39
- if (is_snan(a_cls) || is_snan(b_cls)) {
40
- float_raise(float_flag_invalid, status);
41
- }
42
-
43
- if (status->default_nan_mode) {
44
+ if (!floatx80_unpack_canonical(&pa, a, status) ||
45
+ !floatx80_unpack_canonical(&pb, b, status)) {
46
return floatx80_default_nan(status);
31
}
47
}
32
48
33
retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
49
- if (a.low < b.low) {
34
if (retval < 0) {
50
- aIsLargerSignificand = 0;
35
- goto exit_perror;
51
- } else if (b.low < a.low) {
36
+ error_setg_errno(&err, errno, "Error reading file header");
52
- aIsLargerSignificand = 1;
37
+ error_reportf_err(err, "%s: ", filename);
53
- } else {
38
+ exit(-1);
54
- aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
39
}
55
- }
40
+
41
if (retval < BPRM_BUF_SIZE) {
42
memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
43
}
44
45
load_elf_image(filename, fd, info, NULL, bprm_buf);
46
- return;
47
-
56
-
48
- exit_perror:
57
- if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) {
49
- fprintf(stderr, "%s: %s\n", filename, strerror(errno));
58
- if (is_snan(b_cls)) {
50
- exit(-1);
59
- return floatx80_silence_nan(b, status);
60
- }
61
- return b;
62
- } else {
63
- if (is_snan(a_cls)) {
64
- return floatx80_silence_nan(a, status);
65
- }
66
- return a;
67
- }
68
+ pr = parts_pick_nan(&pa, &pb, status);
69
+ return floatx80_round_pack_canonical(pr, status);
51
}
70
}
52
71
53
static int symfind(const void *s0, const void *s1)
72
/*----------------------------------------------------------------------------
54
--
73
--
55
2.20.1
74
2.34.1
56
57
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The kernel sets btype for the signal handler as if for a call.
3
Inline pickNaN into its only caller. This makes one assert
4
4
redundant with the immediately preceding IF.
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201021173749.111103-2-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Message-id: 20241203203949.483774-9-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
linux-user/aarch64/signal.c | 10 ++++++++--
11
fpu/softfloat-parts.c.inc | 82 +++++++++++++++++++++++++----
11
1 file changed, 8 insertions(+), 2 deletions(-)
12
fpu/softfloat-specialize.c.inc | 96 ----------------------------------
12
13
2 files changed, 73 insertions(+), 105 deletions(-)
13
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
14
15
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/aarch64/signal.c
17
--- a/fpu/softfloat-parts.c.inc
16
+++ b/linux-user/aarch64/signal.c
18
+++ b/fpu/softfloat-parts.c.inc
17
@@ -XXX,XX +XXX,XX @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
19
@@ -XXX,XX +XXX,XX @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
18
+ offsetof(struct target_rt_frame_record, tramp);
20
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
21
float_status *s)
22
{
23
+ int cmp, which;
24
+
25
if (is_snan(a->cls) || is_snan(b->cls)) {
26
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
19
}
27
}
20
env->xregs[0] = usig;
28
21
- env->xregs[31] = frame_addr;
29
if (s->default_nan_mode) {
22
env->xregs[29] = frame_addr + fr_ofs;
30
parts_default_nan(a, s);
23
- env->pc = ka->_sa_handler;
31
- } else {
24
env->xregs[30] = return_addr;
32
- int cmp = frac_cmp(a, b);
25
+ env->xregs[31] = frame_addr;
33
- if (cmp == 0) {
26
+ env->pc = ka->_sa_handler;
34
- cmp = a->sign < b->sign;
35
- }
36
+ return a;
37
+ }
38
39
- if (pickNaN(a->cls, b->cls, cmp > 0, s)) {
40
- a = b;
41
- }
42
+ cmp = frac_cmp(a, b);
43
+ if (cmp == 0) {
44
+ cmp = a->sign < b->sign;
45
+ }
27
+
46
+
28
+ /* Invoke the signal handler as if by indirect call. */
47
+ switch (s->float_2nan_prop_rule) {
29
+ if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
48
+ case float_2nan_prop_s_ab:
30
+ env->btype = 2;
49
if (is_snan(a->cls)) {
50
- parts_silence_nan(a, s);
51
+ which = 0;
52
+ } else if (is_snan(b->cls)) {
53
+ which = 1;
54
+ } else if (is_qnan(a->cls)) {
55
+ which = 0;
56
+ } else {
57
+ which = 1;
58
}
59
+ break;
60
+ case float_2nan_prop_s_ba:
61
+ if (is_snan(b->cls)) {
62
+ which = 1;
63
+ } else if (is_snan(a->cls)) {
64
+ which = 0;
65
+ } else if (is_qnan(b->cls)) {
66
+ which = 1;
67
+ } else {
68
+ which = 0;
69
+ }
70
+ break;
71
+ case float_2nan_prop_ab:
72
+ which = is_nan(a->cls) ? 0 : 1;
73
+ break;
74
+ case float_2nan_prop_ba:
75
+ which = is_nan(b->cls) ? 1 : 0;
76
+ break;
77
+ case float_2nan_prop_x87:
78
+ /*
79
+ * This implements x87 NaN propagation rules:
80
+ * SNaN + QNaN => return the QNaN
81
+ * two SNaNs => return the one with the larger significand, silenced
82
+ * two QNaNs => return the one with the larger significand
83
+ * SNaN and a non-NaN => return the SNaN, silenced
84
+ * QNaN and a non-NaN => return the QNaN
85
+ *
86
+ * If we get down to comparing significands and they are the same,
87
+ * return the NaN with the positive sign bit (if any).
88
+ */
89
+ if (is_snan(a->cls)) {
90
+ if (is_snan(b->cls)) {
91
+ which = cmp > 0 ? 0 : 1;
92
+ } else {
93
+ which = is_qnan(b->cls) ? 1 : 0;
94
+ }
95
+ } else if (is_qnan(a->cls)) {
96
+ if (is_snan(b->cls) || !is_qnan(b->cls)) {
97
+ which = 0;
98
+ } else {
99
+ which = cmp > 0 ? 0 : 1;
100
+ }
101
+ } else {
102
+ which = 1;
103
+ }
104
+ break;
105
+ default:
106
+ g_assert_not_reached();
31
+ }
107
+ }
32
+
108
+
33
if (info) {
109
+ if (which) {
34
tswap_siginfo(&frame->info, info);
110
+ a = b;
35
env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
111
+ }
112
+ if (is_snan(a->cls)) {
113
+ parts_silence_nan(a, s);
114
}
115
return a;
116
}
117
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
118
index XXXXXXX..XXXXXXX 100644
119
--- a/fpu/softfloat-specialize.c.inc
120
+++ b/fpu/softfloat-specialize.c.inc
121
@@ -XXX,XX +XXX,XX @@ bool float32_is_signaling_nan(float32 a_, float_status *status)
122
}
123
}
124
125
-/*----------------------------------------------------------------------------
126
-| Select which NaN to propagate for a two-input operation.
127
-| IEEE754 doesn't specify all the details of this, so the
128
-| algorithm is target-specific.
129
-| The routine is passed various bits of information about the
130
-| two NaNs and should return 0 to select NaN a and 1 for NaN b.
131
-| Note that signalling NaNs are always squashed to quiet NaNs
132
-| by the caller, by calling floatXX_silence_nan() before
133
-| returning them.
134
-|
135
-| aIsLargerSignificand is only valid if both a and b are NaNs
136
-| of some kind, and is true if a has the larger significand,
137
-| or if both a and b have the same significand but a is
138
-| positive but b is negative. It is only needed for the x87
139
-| tie-break rule.
140
-*----------------------------------------------------------------------------*/
141
-
142
-static int pickNaN(FloatClass a_cls, FloatClass b_cls,
143
- bool aIsLargerSignificand, float_status *status)
144
-{
145
- /*
146
- * We guarantee not to require the target to tell us how to
147
- * pick a NaN if we're always returning the default NaN.
148
- * But if we're not in default-NaN mode then the target must
149
- * specify via set_float_2nan_prop_rule().
150
- */
151
- assert(!status->default_nan_mode);
152
-
153
- switch (status->float_2nan_prop_rule) {
154
- case float_2nan_prop_s_ab:
155
- if (is_snan(a_cls)) {
156
- return 0;
157
- } else if (is_snan(b_cls)) {
158
- return 1;
159
- } else if (is_qnan(a_cls)) {
160
- return 0;
161
- } else {
162
- return 1;
163
- }
164
- break;
165
- case float_2nan_prop_s_ba:
166
- if (is_snan(b_cls)) {
167
- return 1;
168
- } else if (is_snan(a_cls)) {
169
- return 0;
170
- } else if (is_qnan(b_cls)) {
171
- return 1;
172
- } else {
173
- return 0;
174
- }
175
- break;
176
- case float_2nan_prop_ab:
177
- if (is_nan(a_cls)) {
178
- return 0;
179
- } else {
180
- return 1;
181
- }
182
- break;
183
- case float_2nan_prop_ba:
184
- if (is_nan(b_cls)) {
185
- return 1;
186
- } else {
187
- return 0;
188
- }
189
- break;
190
- case float_2nan_prop_x87:
191
- /*
192
- * This implements x87 NaN propagation rules:
193
- * SNaN + QNaN => return the QNaN
194
- * two SNaNs => return the one with the larger significand, silenced
195
- * two QNaNs => return the one with the larger significand
196
- * SNaN and a non-NaN => return the SNaN, silenced
197
- * QNaN and a non-NaN => return the QNaN
198
- *
199
- * If we get down to comparing significands and they are the same,
200
- * return the NaN with the positive sign bit (if any).
201
- */
202
- if (is_snan(a_cls)) {
203
- if (is_snan(b_cls)) {
204
- return aIsLargerSignificand ? 0 : 1;
205
- }
206
- return is_qnan(b_cls) ? 1 : 0;
207
- } else if (is_qnan(a_cls)) {
208
- if (is_snan(b_cls) || !is_qnan(b_cls)) {
209
- return 0;
210
- } else {
211
- return aIsLargerSignificand ? 0 : 1;
212
- }
213
- } else {
214
- return 1;
215
- }
216
- default:
217
- g_assert_not_reached();
218
- }
219
-}
220
-
221
/*----------------------------------------------------------------------------
222
| Returns 1 if the double-precision floating-point value `a' is a quiet
223
| NaN; otherwise returns 0.
36
--
224
--
37
2.20.1
225
2.34.1
38
226
39
227
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Fix an unlikely memory leak in load_elf_image().
3
Remember if there was an SNaN, and use that to simplify
4
float_2nan_prop_s_{ab,ba} to only the snan component.
5
Then, fall through to the corresponding
6
float_2nan_prop_{ab,ba} case to handle any remaining
7
nans, which must be quiet.
4
8
5
Fixes: bf858897b7 ("linux-user: Re-use load_elf_image for the main binary.")
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-5-richard.henderson@linaro.org
9
Message-Id: <20201003174944.1972444-1-f4bug@amsat.org>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20241203203949.483774-10-richard.henderson@linaro.org
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
13
---
14
linux-user/elfload.c | 8 ++++----
14
fpu/softfloat-parts.c.inc | 32 ++++++++++++--------------------
15
1 file changed, 4 insertions(+), 4 deletions(-)
15
1 file changed, 12 insertions(+), 20 deletions(-)
16
16
17
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
17
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/linux-user/elfload.c
19
--- a/fpu/softfloat-parts.c.inc
20
+++ b/linux-user/elfload.c
20
+++ b/fpu/softfloat-parts.c.inc
21
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
21
@@ -XXX,XX +XXX,XX @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
22
info->brk = vaddr_em;
22
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
23
}
23
float_status *s)
24
} else if (eppnt->p_type == PT_INTERP && pinterp_name) {
24
{
25
- char *interp_name;
25
+ bool have_snan = false;
26
+ g_autofree char *interp_name = NULL;
26
int cmp, which;
27
27
28
if (*pinterp_name) {
28
if (is_snan(a->cls) || is_snan(b->cls)) {
29
errmsg = "Multiple PT_INTERP entries";
29
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
30
goto exit_errmsg;
30
+ have_snan = true;
31
}
32
- interp_name = malloc(eppnt->p_filesz);
33
+ interp_name = g_malloc(eppnt->p_filesz);
34
if (!interp_name) {
35
goto exit_perror;
36
}
37
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
38
errmsg = "Invalid PT_INTERP entry";
39
goto exit_errmsg;
40
}
41
- *pinterp_name = interp_name;
42
+ *pinterp_name = g_steal_pointer(&interp_name);
43
#ifdef TARGET_MIPS
44
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
45
Mips_elf_abiflags_v0 abiflags;
46
@@ -XXX,XX +XXX,XX @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
47
if (elf_interpreter) {
48
info->load_bias = interp_info.load_bias;
49
info->entry = interp_info.entry;
50
- free(elf_interpreter);
51
+ g_free(elf_interpreter);
52
}
31
}
53
32
54
#ifdef USE_ELF_CORE_DUMP
33
if (s->default_nan_mode) {
34
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
35
36
switch (s->float_2nan_prop_rule) {
37
case float_2nan_prop_s_ab:
38
- if (is_snan(a->cls)) {
39
- which = 0;
40
- } else if (is_snan(b->cls)) {
41
- which = 1;
42
- } else if (is_qnan(a->cls)) {
43
- which = 0;
44
- } else {
45
- which = 1;
46
+ if (have_snan) {
47
+ which = is_snan(a->cls) ? 0 : 1;
48
+ break;
49
}
50
- break;
51
- case float_2nan_prop_s_ba:
52
- if (is_snan(b->cls)) {
53
- which = 1;
54
- } else if (is_snan(a->cls)) {
55
- which = 0;
56
- } else if (is_qnan(b->cls)) {
57
- which = 1;
58
- } else {
59
- which = 0;
60
- }
61
- break;
62
+ /* fall through */
63
case float_2nan_prop_ab:
64
which = is_nan(a->cls) ? 0 : 1;
65
break;
66
+ case float_2nan_prop_s_ba:
67
+ if (have_snan) {
68
+ which = is_snan(b->cls) ? 1 : 0;
69
+ break;
70
+ }
71
+ /* fall through */
72
case float_2nan_prop_ba:
73
which = is_nan(b->cls) ? 1 : 0;
74
break;
55
--
75
--
56
2.20.1
76
2.34.1
57
58
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Fixing this now will clarify following patches.
3
Move the fractional comparison to the end of the
4
float_2nan_prop_x87 case. This is not required for
5
any other 2nan propagation rule. Reorganize the
6
x87 case itself to break out of the switch when the
7
fractional comparison is not required.
4
8
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20201021173749.111103-6-richard.henderson@linaro.org
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Message-id: 20241203203949.483774-11-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
13
---
10
linux-user/elfload.c | 12 +++++++++---
14
fpu/softfloat-parts.c.inc | 19 +++++++++----------
11
1 file changed, 9 insertions(+), 3 deletions(-)
15
1 file changed, 9 insertions(+), 10 deletions(-)
12
16
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
17
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/elfload.c
19
--- a/fpu/softfloat-parts.c.inc
16
+++ b/linux-user/elfload.c
20
+++ b/fpu/softfloat-parts.c.inc
17
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
21
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
18
abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em, vaddr_len;
22
return a;
19
int elf_prot = 0;
23
}
20
24
21
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
25
- cmp = frac_cmp(a, b);
22
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
26
- if (cmp == 0) {
23
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
27
- cmp = a->sign < b->sign;
24
+ if (eppnt->p_flags & PF_R) {
28
- }
25
+ elf_prot |= PROT_READ;
29
-
26
+ }
30
switch (s->float_2nan_prop_rule) {
27
+ if (eppnt->p_flags & PF_W) {
31
case float_2nan_prop_s_ab:
28
+ elf_prot |= PROT_WRITE;
32
if (have_snan) {
29
+ }
33
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
30
+ if (eppnt->p_flags & PF_X) {
34
* return the NaN with the positive sign bit (if any).
31
+ elf_prot |= PROT_EXEC;
35
*/
32
+ }
36
if (is_snan(a->cls)) {
33
37
- if (is_snan(b->cls)) {
34
vaddr = load_bias + eppnt->p_vaddr;
38
- which = cmp > 0 ? 0 : 1;
35
vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
39
- } else {
40
+ if (!is_snan(b->cls)) {
41
which = is_qnan(b->cls) ? 1 : 0;
42
+ break;
43
}
44
} else if (is_qnan(a->cls)) {
45
if (is_snan(b->cls) || !is_qnan(b->cls)) {
46
which = 0;
47
- } else {
48
- which = cmp > 0 ? 0 : 1;
49
+ break;
50
}
51
} else {
52
which = 1;
53
+ break;
54
}
55
+ cmp = frac_cmp(a, b);
56
+ if (cmp == 0) {
57
+ cmp = a->sign < b->sign;
58
+ }
59
+ which = cmp > 0 ? 0 : 1;
60
break;
61
default:
62
g_assert_not_reached();
36
--
63
--
37
2.20.1
64
2.34.1
38
39
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Transform the prot bit to a qemu internal page bit, and save
3
Replace the "index" selecting between A and B with a result variable
4
it in the page tables.
4
of the proper type. This improves clarity within the function.
5
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-3-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Message-id: 20241203203949.483774-12-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
include/exec/cpu-all.h | 2 ++
11
fpu/softfloat-parts.c.inc | 28 +++++++++++++---------------
12
linux-user/syscall_defs.h | 4 ++++
12
1 file changed, 13 insertions(+), 15 deletions(-)
13
target/arm/cpu.h | 5 +++++
14
linux-user/mmap.c | 16 ++++++++++++++++
15
target/arm/translate-a64.c | 6 +++---
16
5 files changed, 30 insertions(+), 3 deletions(-)
17
13
18
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/include/exec/cpu-all.h
16
--- a/fpu/softfloat-parts.c.inc
21
+++ b/include/exec/cpu-all.h
17
+++ b/fpu/softfloat-parts.c.inc
22
@@ -XXX,XX +XXX,XX @@ extern intptr_t qemu_host_page_mask;
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
23
/* FIXME: Code that sets/uses this is broken and needs to go away. */
19
float_status *s)
24
#define PAGE_RESERVED 0x0020
20
{
25
#endif
21
bool have_snan = false;
26
+/* Target-specific bits that will be used via page_get_flags(). */
22
- int cmp, which;
27
+#define PAGE_TARGET_1 0x0080
23
+ FloatPartsN *ret;
28
24
+ int cmp;
29
#if defined(CONFIG_USER_ONLY)
25
30
void page_dump(FILE *f);
26
if (is_snan(a->cls) || is_snan(b->cls)) {
31
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
27
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
32
index XXXXXXX..XXXXXXX 100644
28
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
33
--- a/linux-user/syscall_defs.h
29
switch (s->float_2nan_prop_rule) {
34
+++ b/linux-user/syscall_defs.h
30
case float_2nan_prop_s_ab:
35
@@ -XXX,XX +XXX,XX @@ struct target_winsize {
31
if (have_snan) {
36
#define TARGET_PROT_SEM 0x08
32
- which = is_snan(a->cls) ? 0 : 1;
37
#endif
33
+ ret = is_snan(a->cls) ? a : b;
38
34
break;
39
+#ifdef TARGET_AARCH64
35
}
40
+#define TARGET_PROT_BTI 0x10
36
/* fall through */
41
+#endif
37
case float_2nan_prop_ab:
42
+
38
- which = is_nan(a->cls) ? 0 : 1;
43
/* Common */
39
+ ret = is_nan(a->cls) ? a : b;
44
#define TARGET_MAP_SHARED    0x01        /* Share changes */
40
break;
45
#define TARGET_MAP_PRIVATE    0x02        /* Changes are private */
41
case float_2nan_prop_s_ba:
46
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
42
if (have_snan) {
47
index XXXXXXX..XXXXXXX 100644
43
- which = is_snan(b->cls) ? 1 : 0;
48
--- a/target/arm/cpu.h
44
+ ret = is_snan(b->cls) ? b : a;
49
+++ b/target/arm/cpu.h
45
break;
50
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
46
}
51
#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0)
47
/* fall through */
52
#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1)
48
case float_2nan_prop_ba:
53
49
- which = is_nan(b->cls) ? 1 : 0;
54
+/*
50
+ ret = is_nan(b->cls) ? b : a;
55
+ * AArch64 usage of the PAGE_TARGET_* bits for linux-user.
51
break;
56
+ */
52
case float_2nan_prop_x87:
57
+#define PAGE_BTI PAGE_TARGET_1
53
/*
58
+
54
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
59
/*
55
*/
60
* Naming convention for isar_feature functions:
56
if (is_snan(a->cls)) {
61
* Functions which test 32-bit ID registers should have _aa32_ in
57
if (!is_snan(b->cls)) {
62
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
58
- which = is_qnan(b->cls) ? 1 : 0;
63
index XXXXXXX..XXXXXXX 100644
59
+ ret = is_qnan(b->cls) ? b : a;
64
--- a/linux-user/mmap.c
60
break;
65
+++ b/linux-user/mmap.c
61
}
66
@@ -XXX,XX +XXX,XX @@ static int validate_prot_to_pageflags(int *host_prot, int prot)
62
} else if (is_qnan(a->cls)) {
67
*host_prot = (prot & (PROT_READ | PROT_WRITE))
63
if (is_snan(b->cls) || !is_qnan(b->cls)) {
68
| (prot & PROT_EXEC ? PROT_READ : 0);
64
- which = 0;
69
65
+ ret = a;
70
+#ifdef TARGET_AARCH64
66
break;
71
+ /*
67
}
72
+ * The PROT_BTI bit is only accepted if the cpu supports the feature.
68
} else {
73
+ * Since this is the unusual case, don't bother checking unless
69
- which = 1;
74
+ * the bit has been requested. If set and valid, record the bit
70
+ ret = b;
75
+ * within QEMU's page_flags.
71
break;
76
+ */
72
}
77
+ if (prot & TARGET_PROT_BTI) {
73
cmp = frac_cmp(a, b);
78
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
74
if (cmp == 0) {
79
+ if (cpu_isar_feature(aa64_bti, cpu)) {
75
cmp = a->sign < b->sign;
80
+ valid |= TARGET_PROT_BTI;
76
}
81
+ page_flags |= PAGE_BTI;
77
- which = cmp > 0 ? 0 : 1;
82
+ }
78
+ ret = cmp > 0 ? a : b;
83
+ }
79
break;
84
+#endif
80
default:
85
+
81
g_assert_not_reached();
86
return prot & ~valid ? 0 : page_flags;
82
}
83
84
- if (which) {
85
- a = b;
86
+ if (is_snan(ret->cls)) {
87
+ parts_silence_nan(ret, s);
88
}
89
- if (is_snan(a->cls)) {
90
- parts_silence_nan(a, s);
91
- }
92
- return a;
93
+ return ret;
87
}
94
}
88
95
89
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
96
static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
90
index XXXXXXX..XXXXXXX 100644
91
--- a/target/arm/translate-a64.c
92
+++ b/target/arm/translate-a64.c
93
@@ -XXX,XX +XXX,XX @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
94
*/
95
static bool is_guarded_page(CPUARMState *env, DisasContext *s)
96
{
97
-#ifdef CONFIG_USER_ONLY
98
- return false; /* FIXME */
99
-#else
100
uint64_t addr = s->base.pc_first;
101
+#ifdef CONFIG_USER_ONLY
102
+ return page_get_flags(addr) & PAGE_BTI;
103
+#else
104
int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
105
unsigned int index = tlb_index(env, mmu_idx, addr);
106
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
107
--
97
--
108
2.20.1
98
2.34.1
109
99
110
100
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Leif Lindholm <quic_llindhol@quicinc.com>
2
2
3
The watchdog is part of NPCM7XX's timer module. Its behavior is
3
I'm migrating to Qualcomm's new open source email infrastructure, so
4
controlled by the WTCR register in the timer.
4
update my email address, and update the mailmap to match.
5
5
6
When enabled, the watchdog issues an interrupt signal after a pre-set
6
Signed-off-by: Leif Lindholm <leif.lindholm@oss.qualcomm.com>
7
amount of cycles, and issues a reset signal shortly after that.
7
Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>
8
8
Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com>
9
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Signed-off-by: Hao Wu <wuhaotsh@google.com>
10
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
11
Message-id: 20241205114047.1125842-1-leif.lindholm@oss.qualcomm.com
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
[PMM: deleted blank line at end of npcm_watchdog_timer-test.c]
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
13
---
16
include/hw/misc/npcm7xx_clk.h | 2 +
14
MAINTAINERS | 2 +-
17
include/hw/timer/npcm7xx_timer.h | 48 +++-
15
.mailmap | 5 +++--
18
hw/arm/npcm7xx.c | 12 +
16
2 files changed, 4 insertions(+), 3 deletions(-)
19
hw/misc/npcm7xx_clk.c | 28 ++
20
hw/timer/npcm7xx_timer.c | 266 ++++++++++++++----
21
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 ++++++++++++++++++++++
22
MAINTAINERS | 1 +
23
tests/qtest/meson.build | 2 +-
24
8 files changed, 624 insertions(+), 54 deletions(-)
25
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
26
17
27
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/hw/misc/npcm7xx_clk.h
30
+++ b/include/hw/misc/npcm7xx_clk.h
31
@@ -XXX,XX +XXX,XX @@
32
*/
33
#define NPCM7XX_CLK_NR_REGS (0x70 / sizeof(uint32_t))
34
35
+#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
36
+
37
typedef struct NPCM7xxCLKState {
38
SysBusDevice parent;
39
40
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/hw/timer/npcm7xx_timer.h
43
+++ b/include/hw/timer/npcm7xx_timer.h
44
@@ -XXX,XX +XXX,XX @@
45
*/
46
#define NPCM7XX_TIMER_NR_REGS (0x54 / sizeof(uint32_t))
47
48
+/* The basic watchdog timer period is 2^14 clock cycles. */
49
+#define NPCM7XX_WATCHDOG_BASETIME_SHIFT 14
50
+
51
+#define NPCM7XX_WATCHDOG_RESET_GPIO_OUT "npcm7xx-clk-watchdog-reset-gpio-out"
52
+
53
typedef struct NPCM7xxTimerCtrlState NPCM7xxTimerCtrlState;
54
55
/**
56
- * struct NPCM7xxTimer - Individual timer state.
57
- * @irq: GIC interrupt line to fire on expiration (if enabled).
58
+ * struct NPCM7xxBaseTimer - Basic functionality that both regular timer and
59
+ * watchdog timer use.
60
* @qtimer: QEMU timer that notifies us on expiration.
61
* @expires_ns: Absolute virtual expiration time.
62
* @remaining_ns: Remaining time until expiration if timer is paused.
63
+ */
64
+typedef struct NPCM7xxBaseTimer {
65
+ QEMUTimer qtimer;
66
+ int64_t expires_ns;
67
+ int64_t remaining_ns;
68
+} NPCM7xxBaseTimer;
69
+
70
+/**
71
+ * struct NPCM7xxTimer - Individual timer state.
72
+ * @ctrl: The timer module that owns this timer.
73
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
74
+ * @base_timer: The basic timer functionality for this timer.
75
* @tcsr: The Timer Control and Status Register.
76
* @ticr: The Timer Initial Count Register.
77
*/
78
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxTimer {
79
NPCM7xxTimerCtrlState *ctrl;
80
81
qemu_irq irq;
82
- QEMUTimer qtimer;
83
- int64_t expires_ns;
84
- int64_t remaining_ns;
85
+ NPCM7xxBaseTimer base_timer;
86
87
uint32_t tcsr;
88
uint32_t ticr;
89
} NPCM7xxTimer;
90
91
+/**
92
+ * struct NPCM7xxWatchdogTimer - The watchdog timer state.
93
+ * @ctrl: The timer module that owns this timer.
94
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
95
+ * @reset_signal: The GPIO used to send a reset signal.
96
+ * @base_timer: The basic timer functionality for this timer.
97
+ * @wtcr: The Watchdog Timer Control Register.
98
+ */
99
+typedef struct NPCM7xxWatchdogTimer {
100
+ NPCM7xxTimerCtrlState *ctrl;
101
+
102
+ qemu_irq irq;
103
+ qemu_irq reset_signal;
104
+ NPCM7xxBaseTimer base_timer;
105
+
106
+ uint32_t wtcr;
107
+} NPCM7xxWatchdogTimer;
108
+
109
/**
110
* struct NPCM7xxTimerCtrlState - Timer Module device state.
111
* @parent: System bus device.
112
* @iomem: Memory region through which registers are accessed.
113
+ * @index: The index of this timer module.
114
* @tisr: The Timer Interrupt Status Register.
115
- * @wtcr: The Watchdog Timer Control Register.
116
* @timer: The five individual timers managed by this module.
117
+ * @watchdog_timer: The watchdog timer managed by this module.
118
*/
119
struct NPCM7xxTimerCtrlState {
120
SysBusDevice parent;
121
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
122
MemoryRegion iomem;
123
124
uint32_t tisr;
125
- uint32_t wtcr;
126
127
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
128
+ NPCM7xxWatchdogTimer watchdog_timer;
129
};
130
131
#define TYPE_NPCM7XX_TIMER "npcm7xx-timer"
132
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/hw/arm/npcm7xx.c
135
+++ b/hw/arm/npcm7xx.c
136
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
137
NPCM7XX_TIMER12_IRQ,
138
NPCM7XX_TIMER13_IRQ,
139
NPCM7XX_TIMER14_IRQ,
140
+ NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
141
+ NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
142
+ NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
143
};
144
145
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
146
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
147
qemu_irq irq = npcm7xx_irq(s, first_irq + j);
148
sysbus_connect_irq(sbd, j, irq);
149
}
150
+
151
+ /* IRQ for watchdogs */
152
+ sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL,
153
+ npcm7xx_irq(s, NPCM7XX_WDG0_IRQ + i));
154
+ /* GPIO that connects clk module with watchdog */
155
+ qdev_connect_gpio_out_named(DEVICE(&s->tim[i]),
156
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0,
157
+ qdev_get_gpio_in_named(DEVICE(&s->clk),
158
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, i));
159
}
160
161
/* UART0..3 (16550 compatible) */
162
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/hw/misc/npcm7xx_clk.c
165
+++ b/hw/misc/npcm7xx_clk.c
166
@@ -XXX,XX +XXX,XX @@
167
#include "qemu/osdep.h"
168
169
#include "hw/misc/npcm7xx_clk.h"
170
+#include "hw/timer/npcm7xx_timer.h"
171
#include "migration/vmstate.h"
172
#include "qemu/error-report.h"
173
#include "qemu/log.h"
174
@@ -XXX,XX +XXX,XX @@
175
#include "qemu/timer.h"
176
#include "qemu/units.h"
177
#include "trace.h"
178
+#include "sysemu/watchdog.h"
179
180
#define PLLCON_LOKI BIT(31)
181
#define PLLCON_LOKS BIT(30)
182
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
183
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
184
};
185
186
+/* Register Field Definitions */
187
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
188
+
189
+/* The number of watchdogs that can trigger a reset. */
190
+#define NPCM7XX_NR_WATCHDOGS (3)
191
+
192
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
193
{
194
uint32_t reg = offset / sizeof(uint32_t);
195
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
196
s->regs[reg] = value;
197
}
198
199
+/* Perform reset action triggered by a watchdog */
200
+static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
201
+ int level)
202
+{
203
+ NPCM7xxCLKState *clk = NPCM7XX_CLK(opaque);
204
+ uint32_t rcr;
205
+
206
+ g_assert(n >= 0 && n <= NPCM7XX_NR_WATCHDOGS);
207
+ rcr = clk->regs[NPCM7XX_CLK_WD0RCR + n];
208
+ if (rcr & NPCM7XX_CLK_WDRCR_CA9C) {
209
+ watchdog_perform_action();
210
+ } else {
211
+ qemu_log_mask(LOG_UNIMP,
212
+ "%s: only CPU reset is implemented. (requested 0x%" PRIx32")\n",
213
+ __func__, rcr);
214
+ }
215
+}
216
+
217
static const struct MemoryRegionOps npcm7xx_clk_ops = {
218
.read = npcm7xx_clk_read,
219
.write = npcm7xx_clk_write,
220
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
221
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
222
TYPE_NPCM7XX_CLK, 4 * KiB);
223
sysbus_init_mmio(&s->parent, &s->iomem);
224
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
225
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
226
}
227
228
static const VMStateDescription vmstate_npcm7xx_clk = {
229
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
230
index XXXXXXX..XXXXXXX 100644
231
--- a/hw/timer/npcm7xx_timer.c
232
+++ b/hw/timer/npcm7xx_timer.c
233
@@ -XXX,XX +XXX,XX @@
234
#include "qemu/osdep.h"
235
236
#include "hw/irq.h"
237
+#include "hw/qdev-properties.h"
238
#include "hw/misc/npcm7xx_clk.h"
239
#include "hw/timer/npcm7xx_timer.h"
240
#include "migration/vmstate.h"
241
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxTimerRegisters {
242
#define NPCM7XX_TCSR_PRESCALE_START 0
243
#define NPCM7XX_TCSR_PRESCALE_LEN 8
244
245
+#define NPCM7XX_WTCR_WTCLK(rv) extract32(rv, 10, 2)
246
+#define NPCM7XX_WTCR_FREEZE_EN BIT(9)
247
+#define NPCM7XX_WTCR_WTE BIT(7)
248
+#define NPCM7XX_WTCR_WTIE BIT(6)
249
+#define NPCM7XX_WTCR_WTIS(rv) extract32(rv, 4, 2)
250
+#define NPCM7XX_WTCR_WTIF BIT(3)
251
+#define NPCM7XX_WTCR_WTRF BIT(2)
252
+#define NPCM7XX_WTCR_WTRE BIT(1)
253
+#define NPCM7XX_WTCR_WTR BIT(0)
254
+
255
+/*
256
+ * The number of clock cycles between interrupt and reset in watchdog, used
257
+ * by the software to handle the interrupt before system is reset.
258
+ */
259
+#define NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES 1024
260
+
261
+/* Start or resume the timer. */
262
+static void npcm7xx_timer_start(NPCM7xxBaseTimer *t)
263
+{
264
+ int64_t now;
265
+
266
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
267
+ t->expires_ns = now + t->remaining_ns;
268
+ timer_mod(&t->qtimer, t->expires_ns);
269
+}
270
+
271
+/* Stop counting. Record the time remaining so we can continue later. */
272
+static void npcm7xx_timer_pause(NPCM7xxBaseTimer *t)
273
+{
274
+ int64_t now;
275
+
276
+ timer_del(&t->qtimer);
277
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
278
+ t->remaining_ns = t->expires_ns - now;
279
+}
280
+
281
+/* Delete the timer and reset it to default state. */
282
+static void npcm7xx_timer_clear(NPCM7xxBaseTimer *t)
283
+{
284
+ timer_del(&t->qtimer);
285
+ t->expires_ns = 0;
286
+ t->remaining_ns = 0;
287
+}
288
+
289
/*
290
* Returns the index of timer in the tc->timer array. This can be used to
291
* locate the registers that belong to this timer.
292
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
293
return count;
294
}
295
296
+static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
297
+{
298
+ switch (NPCM7XX_WTCR_WTCLK(t->wtcr)) {
299
+ case 0:
300
+ return 1;
301
+ case 1:
302
+ return 256;
303
+ case 2:
304
+ return 2048;
305
+ case 3:
306
+ return 65536;
307
+ default:
308
+ g_assert_not_reached();
309
+ }
310
+}
311
+
312
+static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
313
+ int64_t cycles)
314
+{
315
+ uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
316
+ int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
317
+
318
+ /*
319
+ * The reset function always clears the current timer. The caller of the
320
+ * this needs to decide whether to start the watchdog timer based on
321
+ * specific flag in WTCR.
322
+ */
323
+ npcm7xx_timer_clear(&t->base_timer);
324
+
325
+ ns *= prescaler;
326
+ t->base_timer.remaining_ns = ns;
327
+}
328
+
329
+static void npcm7xx_watchdog_timer_reset(NPCM7xxWatchdogTimer *t)
330
+{
331
+ int64_t cycles = 1;
332
+ uint32_t s = NPCM7XX_WTCR_WTIS(t->wtcr);
333
+
334
+ g_assert(s <= 3);
335
+
336
+ cycles <<= NPCM7XX_WATCHDOG_BASETIME_SHIFT;
337
+ cycles <<= 2 * s;
338
+
339
+ npcm7xx_watchdog_timer_reset_cycles(t, cycles);
340
+}
341
+
342
/*
343
* Raise the interrupt line if there's a pending interrupt and interrupts are
344
* enabled for this timer. If not, lower it.
345
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t)
346
trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending);
347
}
348
349
-/* Start or resume the timer. */
350
-static void npcm7xx_timer_start(NPCM7xxTimer *t)
351
-{
352
- int64_t now;
353
-
354
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
355
- t->expires_ns = now + t->remaining_ns;
356
- timer_mod(&t->qtimer, t->expires_ns);
357
-}
358
-
359
/*
360
* Called when the counter reaches zero. Sets the interrupt flag, and either
361
* restarts or disables the timer.
362
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
363
tc->tisr |= BIT(index);
364
365
if (t->tcsr & NPCM7XX_TCSR_PERIODIC) {
366
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
367
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
368
if (t->tcsr & NPCM7XX_TCSR_CEN) {
369
- npcm7xx_timer_start(t);
370
+ npcm7xx_timer_start(&t->base_timer);
371
}
372
} else {
373
t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT);
374
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
375
npcm7xx_timer_check_interrupt(t);
376
}
377
378
-/* Stop counting. Record the time remaining so we can continue later. */
379
-static void npcm7xx_timer_pause(NPCM7xxTimer *t)
380
-{
381
- int64_t now;
382
-
383
- timer_del(&t->qtimer);
384
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
385
- t->remaining_ns = t->expires_ns - now;
386
-}
387
388
/*
389
* Restart the timer from its initial value. If the timer was enabled and stays
390
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
391
*/
392
static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr)
393
{
394
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
395
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
396
397
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
398
- npcm7xx_timer_start(t);
399
+ npcm7xx_timer_start(&t->base_timer);
400
}
401
}
402
403
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t)
404
if (t->tcsr & NPCM7XX_TCSR_CEN) {
405
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
406
407
- return npcm7xx_timer_ns_to_count(t, t->expires_ns - now);
408
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.expires_ns - now);
409
}
410
411
- return npcm7xx_timer_ns_to_count(t, t->remaining_ns);
412
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.remaining_ns);
413
}
414
415
static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
416
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
417
418
if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) {
419
/* Recalculate time remaining based on the current TDR value. */
420
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
421
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
422
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
423
- npcm7xx_timer_start(t);
424
+ npcm7xx_timer_start(&t->base_timer);
425
}
426
}
427
428
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
429
if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) {
430
if (new_tcsr & NPCM7XX_TCSR_CEN) {
431
t->tcsr |= NPCM7XX_TCSR_CACT;
432
- npcm7xx_timer_start(t);
433
+ npcm7xx_timer_start(&t->base_timer);
434
} else {
435
t->tcsr &= ~NPCM7XX_TCSR_CACT;
436
- npcm7xx_timer_pause(t);
437
- if (t->remaining_ns <= 0) {
438
+ npcm7xx_timer_pause(&t->base_timer);
439
+ if (t->base_timer.remaining_ns <= 0) {
440
npcm7xx_timer_reached_zero(t);
441
}
442
}
443
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value)
444
if (value & (1U << i)) {
445
npcm7xx_timer_check_interrupt(&s->timer[i]);
446
}
447
+
448
}
449
}
450
451
+static void npcm7xx_timer_write_wtcr(NPCM7xxWatchdogTimer *t, uint32_t new_wtcr)
452
+{
453
+ uint32_t old_wtcr = t->wtcr;
454
+
455
+ /*
456
+ * WTIF and WTRF are cleared by writing 1. Writing 0 makes these bits
457
+ * unchanged.
458
+ */
459
+ if (new_wtcr & NPCM7XX_WTCR_WTIF) {
460
+ new_wtcr &= ~NPCM7XX_WTCR_WTIF;
461
+ } else if (old_wtcr & NPCM7XX_WTCR_WTIF) {
462
+ new_wtcr |= NPCM7XX_WTCR_WTIF;
463
+ }
464
+ if (new_wtcr & NPCM7XX_WTCR_WTRF) {
465
+ new_wtcr &= ~NPCM7XX_WTCR_WTRF;
466
+ } else if (old_wtcr & NPCM7XX_WTCR_WTRF) {
467
+ new_wtcr |= NPCM7XX_WTCR_WTRF;
468
+ }
469
+
470
+ t->wtcr = new_wtcr;
471
+
472
+ if (new_wtcr & NPCM7XX_WTCR_WTR) {
473
+ t->wtcr &= ~NPCM7XX_WTCR_WTR;
474
+ npcm7xx_watchdog_timer_reset(t);
475
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
476
+ npcm7xx_timer_start(&t->base_timer);
477
+ }
478
+ } else if ((old_wtcr ^ new_wtcr) & NPCM7XX_WTCR_WTE) {
479
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
480
+ npcm7xx_timer_start(&t->base_timer);
481
+ } else {
482
+ npcm7xx_timer_pause(&t->base_timer);
483
+ }
484
+ }
485
+
486
+}
487
+
488
static hwaddr npcm7xx_tcsr_index(hwaddr reg)
489
{
490
switch (reg) {
491
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size)
492
break;
493
494
case NPCM7XX_TIMER_WTCR:
495
- value = s->wtcr;
496
+ value = s->watchdog_timer.wtcr;
497
break;
498
499
default:
500
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write(void *opaque, hwaddr offset,
501
return;
502
503
case NPCM7XX_TIMER_WTCR:
504
- qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n",
505
- __func__, value);
506
+ npcm7xx_timer_write_wtcr(&s->watchdog_timer, value);
507
return;
508
}
509
510
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_enter_reset(Object *obj, ResetType type)
511
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
512
NPCM7xxTimer *t = &s->timer[i];
513
514
- timer_del(&t->qtimer);
515
- t->expires_ns = 0;
516
- t->remaining_ns = 0;
517
+ npcm7xx_timer_clear(&t->base_timer);
518
t->tcsr = 0x00000005;
519
t->ticr = 0x00000000;
520
}
521
522
s->tisr = 0x00000000;
523
- s->wtcr = 0x00000400;
524
+ /*
525
+ * Set WTCLK to 1(default) and reset all flags except WTRF.
526
+ * WTRF is not reset during a core domain reset.
527
+ */
528
+ s->watchdog_timer.wtcr = 0x00000400 | (s->watchdog_timer.wtcr &
529
+ NPCM7XX_WTCR_WTRF);
530
+}
531
+
532
+static void npcm7xx_watchdog_timer_expired(void *opaque)
533
+{
534
+ NPCM7xxWatchdogTimer *t = opaque;
535
+
536
+ if (t->wtcr & NPCM7XX_WTCR_WTE) {
537
+ if (t->wtcr & NPCM7XX_WTCR_WTIF) {
538
+ if (t->wtcr & NPCM7XX_WTCR_WTRE) {
539
+ t->wtcr |= NPCM7XX_WTCR_WTRF;
540
+ /* send reset signal to CLK module*/
541
+ qemu_irq_raise(t->reset_signal);
542
+ }
543
+ } else {
544
+ t->wtcr |= NPCM7XX_WTCR_WTIF;
545
+ if (t->wtcr & NPCM7XX_WTCR_WTIE) {
546
+ /* send interrupt */
547
+ qemu_irq_raise(t->irq);
548
+ }
549
+ npcm7xx_watchdog_timer_reset_cycles(t,
550
+ NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES);
551
+ npcm7xx_timer_start(&t->base_timer);
552
+ }
553
+ }
554
}
555
556
static void npcm7xx_timer_hold_reset(Object *obj)
557
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
558
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
559
qemu_irq_lower(s->timer[i].irq);
560
}
561
+ qemu_irq_lower(s->watchdog_timer.irq);
562
}
563
564
static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
565
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
566
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
567
SysBusDevice *sbd = &s->parent;
568
int i;
569
+ NPCM7xxWatchdogTimer *w;
570
571
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
572
NPCM7xxTimer *t = &s->timer[i];
573
t->ctrl = s;
574
- timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t);
575
+ timer_init_ns(&t->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
576
+ npcm7xx_timer_expired, t);
577
sysbus_init_irq(sbd, &t->irq);
578
}
579
580
+ w = &s->watchdog_timer;
581
+ w->ctrl = s;
582
+ timer_init_ns(&w->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
583
+ npcm7xx_watchdog_timer_expired, w);
584
+ sysbus_init_irq(sbd, &w->irq);
585
+
586
memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
587
TYPE_NPCM7XX_TIMER, 4 * KiB);
588
sysbus_init_mmio(sbd, &s->iomem);
589
+ qdev_init_gpio_out_named(dev, &w->reset_signal,
590
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
591
}
592
593
-static const VMStateDescription vmstate_npcm7xx_timer = {
594
- .name = "npcm7xx-timer",
595
+static const VMStateDescription vmstate_npcm7xx_base_timer = {
596
+ .name = "npcm7xx-base-timer",
597
.version_id = 0,
598
.minimum_version_id = 0,
599
.fields = (VMStateField[]) {
600
- VMSTATE_TIMER(qtimer, NPCM7xxTimer),
601
- VMSTATE_INT64(expires_ns, NPCM7xxTimer),
602
- VMSTATE_INT64(remaining_ns, NPCM7xxTimer),
603
+ VMSTATE_TIMER(qtimer, NPCM7xxBaseTimer),
604
+ VMSTATE_INT64(expires_ns, NPCM7xxBaseTimer),
605
+ VMSTATE_INT64(remaining_ns, NPCM7xxBaseTimer),
606
+ VMSTATE_END_OF_LIST(),
607
+ },
608
+};
609
+
610
+static const VMStateDescription vmstate_npcm7xx_timer = {
611
+ .name = "npcm7xx-timer",
612
+ .version_id = 1,
613
+ .minimum_version_id = 1,
614
+ .fields = (VMStateField[]) {
615
+ VMSTATE_STRUCT(base_timer, NPCM7xxTimer,
616
+ 0, vmstate_npcm7xx_base_timer,
617
+ NPCM7xxBaseTimer),
618
VMSTATE_UINT32(tcsr, NPCM7xxTimer),
619
VMSTATE_UINT32(ticr, NPCM7xxTimer),
620
VMSTATE_END_OF_LIST(),
621
},
622
};
623
624
-static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
625
- .name = "npcm7xx-timer-ctrl",
626
+static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
627
+ .name = "npcm7xx-watchdog-timer",
628
.version_id = 0,
629
.minimum_version_id = 0,
630
+ .fields = (VMStateField[]) {
631
+ VMSTATE_STRUCT(base_timer, NPCM7xxWatchdogTimer,
632
+ 0, vmstate_npcm7xx_base_timer,
633
+ NPCM7xxBaseTimer),
634
+ VMSTATE_UINT32(wtcr, NPCM7xxWatchdogTimer),
635
+ VMSTATE_END_OF_LIST(),
636
+ },
637
+};
638
+
639
+static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
640
+ .name = "npcm7xx-timer-ctrl",
641
+ .version_id = 1,
642
+ .minimum_version_id = 1,
643
.fields = (VMStateField[]) {
644
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
645
- VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState),
646
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
647
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
648
NPCM7xxTimer),
649
+ VMSTATE_STRUCT(watchdog_timer, NPCM7xxTimerCtrlState,
650
+ 0, vmstate_npcm7xx_watchdog_timer,
651
+ NPCM7xxWatchdogTimer),
652
VMSTATE_END_OF_LIST(),
653
},
654
};
655
diff --git a/tests/qtest/npcm7xx_watchdog_timer-test.c b/tests/qtest/npcm7xx_watchdog_timer-test.c
656
new file mode 100644
657
index XXXXXXX..XXXXXXX
658
--- /dev/null
659
+++ b/tests/qtest/npcm7xx_watchdog_timer-test.c
660
@@ -XXX,XX +XXX,XX @@
661
+/*
662
+ * QTests for Nuvoton NPCM7xx Timer Watchdog Modules.
663
+ *
664
+ * Copyright 2020 Google LLC
665
+ *
666
+ * This program is free software; you can redistribute it and/or modify it
667
+ * under the terms of the GNU General Public License as published by the
668
+ * Free Software Foundation; either version 2 of the License, or
669
+ * (at your option) any later version.
670
+ *
671
+ * This program is distributed in the hope that it will be useful, but WITHOUT
672
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
673
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
674
+ * for more details.
675
+ */
676
+
677
+#include "qemu/osdep.h"
678
+#include "qemu/timer.h"
679
+
680
+#include "libqos/libqtest.h"
681
+#include "qapi/qmp/qdict.h"
682
+
683
+#define WTCR_OFFSET 0x1c
684
+#define REF_HZ (25000000)
685
+
686
+/* WTCR bit fields */
687
+#define WTCLK(rv) ((rv) << 10)
688
+#define WTE BIT(7)
689
+#define WTIE BIT(6)
690
+#define WTIS(rv) ((rv) << 4)
691
+#define WTIF BIT(3)
692
+#define WTRF BIT(2)
693
+#define WTRE BIT(1)
694
+#define WTR BIT(0)
695
+
696
+typedef struct Watchdog {
697
+ int irq;
698
+ uint64_t base_addr;
699
+} Watchdog;
700
+
701
+static const Watchdog watchdog_list[] = {
702
+ {
703
+ .irq = 47,
704
+ .base_addr = 0xf0008000
705
+ },
706
+ {
707
+ .irq = 48,
708
+ .base_addr = 0xf0009000
709
+ },
710
+ {
711
+ .irq = 49,
712
+ .base_addr = 0xf000a000
713
+ }
714
+};
715
+
716
+static int watchdog_index(const Watchdog *wd)
717
+{
718
+ ptrdiff_t diff = wd - watchdog_list;
719
+
720
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(watchdog_list));
721
+
722
+ return diff;
723
+}
724
+
725
+static uint32_t watchdog_read_wtcr(QTestState *qts, const Watchdog *wd)
726
+{
727
+ return qtest_readl(qts, wd->base_addr + WTCR_OFFSET);
728
+}
729
+
730
+static void watchdog_write_wtcr(QTestState *qts, const Watchdog *wd,
731
+ uint32_t value)
732
+{
733
+ qtest_writel(qts, wd->base_addr + WTCR_OFFSET, value);
734
+}
735
+
736
+static uint32_t watchdog_prescaler(QTestState *qts, const Watchdog *wd)
737
+{
738
+ switch (extract32(watchdog_read_wtcr(qts, wd), 10, 2)) {
739
+ case 0:
740
+ return 1;
741
+ case 1:
742
+ return 256;
743
+ case 2:
744
+ return 2048;
745
+ case 3:
746
+ return 65536;
747
+ default:
748
+ g_assert_not_reached();
749
+ }
750
+}
751
+
752
+static QDict *get_watchdog_action(QTestState *qts)
753
+{
754
+ QDict *ev = qtest_qmp_eventwait_ref(qts, "WATCHDOG");
755
+ QDict *data;
756
+
757
+ data = qdict_get_qdict(ev, "data");
758
+ qobject_ref(data);
759
+ qobject_unref(ev);
760
+ return data;
761
+}
762
+
763
+#define RESET_CYCLES 1024
764
+static uint32_t watchdog_interrupt_cycles(QTestState *qts, const Watchdog *wd)
765
+{
766
+ uint32_t wtis = extract32(watchdog_read_wtcr(qts, wd), 4, 2);
767
+ return 1 << (14 + 2 * wtis);
768
+}
769
+
770
+static int64_t watchdog_calculate_steps(uint32_t count, uint32_t prescale)
771
+{
772
+ return (NANOSECONDS_PER_SECOND / REF_HZ) * count * prescale;
773
+}
774
+
775
+static int64_t watchdog_interrupt_steps(QTestState *qts, const Watchdog *wd)
776
+{
777
+ return watchdog_calculate_steps(watchdog_interrupt_cycles(qts, wd),
778
+ watchdog_prescaler(qts, wd));
779
+}
780
+
781
+/* Check wtcr can be reset to default value */
782
+static void test_init(gconstpointer watchdog)
783
+{
784
+ const Watchdog *wd = watchdog;
785
+ QTestState *qts = qtest_init("-machine quanta-gsj");
786
+
787
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
788
+
789
+ watchdog_write_wtcr(qts, wd, WTCLK(1) | WTRF | WTIF | WTR);
790
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1));
791
+
792
+ qtest_quit(qts);
793
+}
794
+
795
+/* Check a watchdog can generate interrupt and reset actions */
796
+static void test_reset_action(gconstpointer watchdog)
797
+{
798
+ const Watchdog *wd = watchdog;
799
+ QTestState *qts = qtest_init("-machine quanta-gsj");
800
+ QDict *ad;
801
+
802
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
803
+
804
+ watchdog_write_wtcr(qts, wd,
805
+ WTCLK(0) | WTE | WTRF | WTRE | WTIF | WTIE | WTR);
806
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
807
+ WTCLK(0) | WTE | WTRE | WTIE);
808
+
809
+ /* Check a watchdog can generate an interrupt */
810
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
811
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
812
+ WTCLK(0) | WTE | WTIF | WTIE | WTRE);
813
+ g_assert_true(qtest_get_irq(qts, wd->irq));
814
+
815
+ /* Check a watchdog can generate a reset signal */
816
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
817
+ watchdog_prescaler(qts, wd)));
818
+ ad = get_watchdog_action(qts);
819
+ /* The signal is a reset signal */
820
+ g_assert_false(strcmp(qdict_get_str(ad, "action"), "reset"));
821
+ qobject_unref(ad);
822
+ qtest_qmp_eventwait(qts, "RESET");
823
+ /*
824
+ * Make sure WTCR is reset to default except for WTRF bit which shouldn't
825
+ * be reset.
826
+ */
827
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1) | WTRF);
828
+ qtest_quit(qts);
829
+}
830
+
831
+/* Check a watchdog works with all possible WTCLK prescalers and WTIS cycles */
832
+static void test_prescaler(gconstpointer watchdog)
833
+{
834
+ const Watchdog *wd = watchdog;
835
+
836
+ for (int wtclk = 0; wtclk < 4; ++wtclk) {
837
+ for (int wtis = 0; wtis < 4; ++wtis) {
838
+ QTestState *qts = qtest_init("-machine quanta-gsj");
839
+
840
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
841
+ watchdog_write_wtcr(qts, wd,
842
+ WTCLK(wtclk) | WTE | WTIF | WTIS(wtis) | WTIE | WTR);
843
+ /*
844
+ * The interrupt doesn't fire until watchdog_interrupt_steps()
845
+ * cycles passed
846
+ */
847
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd) - 1);
848
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTIF);
849
+ g_assert_false(qtest_get_irq(qts, wd->irq));
850
+ qtest_clock_step(qts, 1);
851
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
852
+ g_assert_true(qtest_get_irq(qts, wd->irq));
853
+
854
+ qtest_quit(qts);
855
+ }
856
+ }
857
+}
858
+
859
+/*
860
+ * Check a watchdog doesn't fire if corresponding flags (WTIE and WTRE) are not
861
+ * set.
862
+ */
863
+static void test_enabling_flags(gconstpointer watchdog)
864
+{
865
+ const Watchdog *wd = watchdog;
866
+ QTestState *qts;
867
+
868
+ /* Neither WTIE or WTRE is set, no interrupt or reset should happen */
869
+ qts = qtest_init("-machine quanta-gsj");
870
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
871
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRF | WTR);
872
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
873
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
874
+ g_assert_false(qtest_get_irq(qts, wd->irq));
875
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
876
+ watchdog_prescaler(qts, wd)));
877
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
878
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
879
+ qtest_quit(qts);
880
+
881
+ /* Only WTIE is set, interrupt is triggered but reset should not happen */
882
+ qts = qtest_init("-machine quanta-gsj");
883
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
884
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
885
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
886
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
887
+ g_assert_true(qtest_get_irq(qts, wd->irq));
888
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
889
+ watchdog_prescaler(qts, wd)));
890
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
891
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
892
+ qtest_quit(qts);
893
+
894
+ /* Only WTRE is set, interrupt is triggered but reset should not happen */
895
+ qts = qtest_init("-machine quanta-gsj");
896
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
897
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRE | WTRF | WTR);
898
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
899
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
900
+ g_assert_false(qtest_get_irq(qts, wd->irq));
901
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
902
+ watchdog_prescaler(qts, wd)));
903
+ g_assert_false(strcmp(qdict_get_str(get_watchdog_action(qts), "action"),
904
+ "reset"));
905
+ qtest_qmp_eventwait(qts, "RESET");
906
+ qtest_quit(qts);
907
+
908
+ /*
909
+ * The case when both flags are set is already tested in
910
+ * test_reset_action().
911
+ */
912
+}
913
+
914
+/* Check a watchdog can pause and resume by setting WTE bits */
915
+static void test_pause(gconstpointer watchdog)
916
+{
917
+ const Watchdog *wd = watchdog;
918
+ QTestState *qts;
919
+ int64_t remaining_steps, steps;
920
+
921
+ qts = qtest_init("-machine quanta-gsj");
922
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
923
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
924
+ remaining_steps = watchdog_interrupt_steps(qts, wd);
925
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
926
+
927
+ /* Run for half of the execution period. */
928
+ steps = remaining_steps / 2;
929
+ remaining_steps -= steps;
930
+ qtest_clock_step(qts, steps);
931
+
932
+ /* Pause the watchdog */
933
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTIE);
934
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
935
+
936
+ /* Run for a long period of time, the watchdog shouldn't fire */
937
+ qtest_clock_step(qts, steps << 4);
938
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
939
+ g_assert_false(qtest_get_irq(qts, wd->irq));
940
+
941
+ /* Resume the watchdog */
942
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIE);
943
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
944
+
945
+ /* Run for the reset of the execution period, the watchdog should fire */
946
+ qtest_clock_step(qts, remaining_steps);
947
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
948
+ WTCLK(0) | WTE | WTIF | WTIE);
949
+ g_assert_true(qtest_get_irq(qts, wd->irq));
950
+
951
+ qtest_quit(qts);
952
+}
953
+
954
+static void watchdog_add_test(const char *name, const Watchdog* wd,
955
+ GTestDataFunc fn)
956
+{
957
+ g_autofree char *full_name = g_strdup_printf(
958
+ "npcm7xx_watchdog_timer[%d]/%s", watchdog_index(wd), name);
959
+ qtest_add_data_func(full_name, wd, fn);
960
+}
961
+#define add_test(name, td) watchdog_add_test(#name, td, test_##name)
962
+
963
+int main(int argc, char **argv)
964
+{
965
+ g_test_init(&argc, &argv, NULL);
966
+ g_test_set_nonfatal_assertions();
967
+
968
+ for (int i = 0; i < ARRAY_SIZE(watchdog_list); ++i) {
969
+ const Watchdog *wd = &watchdog_list[i];
970
+
971
+ add_test(init, wd);
972
+ add_test(reset_action, wd);
973
+ add_test(prescaler, wd);
974
+ add_test(enabling_flags, wd);
975
+ add_test(pause, wd);
976
+ }
977
+
978
+ return g_test_run();
979
+}
980
diff --git a/MAINTAINERS b/MAINTAINERS
18
diff --git a/MAINTAINERS b/MAINTAINERS
981
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
982
--- a/MAINTAINERS
20
--- a/MAINTAINERS
983
+++ b/MAINTAINERS
21
+++ b/MAINTAINERS
984
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
22
@@ -XXX,XX +XXX,XX @@ F: include/hw/ssi/imx_spi.h
985
S: Supported
23
SBSA-REF
986
F: hw/*/npcm7xx*
24
M: Radoslaw Biernacki <rad@semihalf.com>
987
F: include/hw/*/npcm7xx*
25
M: Peter Maydell <peter.maydell@linaro.org>
988
+F: tests/qtest/npcm7xx*
26
-R: Leif Lindholm <quic_llindhol@quicinc.com>
989
F: pc-bios/npcm7xx_bootrom.bin
27
+R: Leif Lindholm <leif.lindholm@oss.qualcomm.com>
990
F: roms/vbootrom
28
R: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
991
29
L: qemu-arm@nongnu.org
992
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
30
S: Maintained
31
diff --git a/.mailmap b/.mailmap
993
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
994
--- a/tests/qtest/meson.build
33
--- a/.mailmap
995
+++ b/tests/qtest/meson.build
34
+++ b/.mailmap
996
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
35
@@ -XXX,XX +XXX,XX @@ Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
997
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
36
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
998
['prom-env-test', 'boot-serial-test']
37
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
999
38
Juan Quintela <quintela@trasno.org> <quintela@redhat.com>
1000
-qtests_npcm7xx = ['npcm7xx_timer-test']
39
-Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org>
1001
+qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
40
-Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com>
1002
qtests_arm = \
41
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <quic_llindhol@quicinc.com>
1003
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
42
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif.lindholm@linaro.org>
1004
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
43
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif@nuviainc.com>
44
Luc Michel <luc@lmichel.fr> <luc.michel@git.antfield.fr>
45
Luc Michel <luc@lmichel.fr> <luc.michel@greensocs.com>
46
Luc Michel <luc@lmichel.fr> <lmichel@kalray.eu>
1005
--
47
--
1006
2.20.1
48
2.34.1
1007
49
1008
50
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Vikram Garhwal <vikram.garhwal@bytedance.com>
2
2
3
When compiling with -Werror=implicit-fallthrough, gcc complains about
3
Previously, maintainer role was paused due to inactive email id. Commit id:
4
missing fallthrough annotations in this file. Looking at the code,
4
c009d715721861984c4987bcc78b7ee183e86d75.
5
the fallthrough is very likely intended here, so add some comments
6
to silence the compiler warnings.
7
5
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
6
Signed-off-by: Vikram Garhwal <vikram.garhwal@bytedance.com>
9
Message-id: 20201020105938.23209-1-thuth@redhat.com
7
Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20241204184205.12952-1-vikram.garhwal@bytedance.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
10
---
13
hw/arm/highbank.c | 2 ++
11
MAINTAINERS | 2 ++
14
1 file changed, 2 insertions(+)
12
1 file changed, 2 insertions(+)
15
13
16
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
14
diff --git a/MAINTAINERS b/MAINTAINERS
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/highbank.c
16
--- a/MAINTAINERS
19
+++ b/hw/arm/highbank.c
17
+++ b/MAINTAINERS
20
@@ -XXX,XX +XXX,XX @@ static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
18
@@ -XXX,XX +XXX,XX @@ F: tests/qtest/fuzz-sb16-test.c
21
address_space_stl_notdirty(&address_space_memory,
19
22
SMP_BOOT_REG + 0x30, 0,
20
Xilinx CAN
23
MEMTXATTRS_UNSPECIFIED, NULL);
21
M: Francisco Iglesias <francisco.iglesias@amd.com>
24
+ /* fallthrough */
22
+M: Vikram Garhwal <vikram.garhwal@bytedance.com>
25
case 3:
23
S: Maintained
26
address_space_stl_notdirty(&address_space_memory,
24
F: hw/net/can/xlnx-*
27
SMP_BOOT_REG + 0x20, 0,
25
F: include/hw/net/xlnx-*
28
MEMTXATTRS_UNSPECIFIED, NULL);
26
@@ -XXX,XX +XXX,XX @@ F: include/hw/rx/
29
+ /* fallthrough */
27
CAN bus subsystem and hardware
30
case 2:
28
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
31
address_space_stl_notdirty(&address_space_memory,
29
M: Francisco Iglesias <francisco.iglesias@amd.com>
32
SMP_BOOT_REG + 0x10, 0,
30
+M: Vikram Garhwal <vikram.garhwal@bytedance.com>
31
S: Maintained
32
W: https://canbus.pages.fel.cvut.cz/
33
F: net/can/*
33
--
34
--
34
2.20.1
35
2.34.1
35
36
diff view generated by jsdifflib