aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/devel/docs.rst12
-rw-r--r--docs/sphinx/hxtool.py16
-rw-r--r--docs/system/arm/raspi.rst2
-rw-r--r--docs/system/i386/xen.rst3
-rw-r--r--hw/arm/Kconfig1
-rw-r--r--hw/arm/bcm2835_peripherals.c17
-rw-r--r--hw/arm/exynos4210.c1
-rw-r--r--hw/arm/exynos4_boards.c8
-rw-r--r--hw/arm/highbank.c11
-rw-r--r--hw/arm/msf2-soc.c3
-rw-r--r--hw/arm/msf2-som.c4
-rw-r--r--hw/arm/musca.c1
-rw-r--r--hw/arm/npcm7xx.c37
-rw-r--r--hw/arm/npcm7xx_boards.c1
-rw-r--r--hw/arm/strongarm.c82
-rw-r--r--hw/arm/trace-events15
-rw-r--r--hw/arm/vexpress.c12
-rw-r--r--hw/arm/xen_arm.c23
-rw-r--r--hw/arm/xilinx_zynq.c6
-rw-r--r--hw/arm/z2.c27
-rw-r--r--hw/core/bus.c67
-rw-r--r--hw/hyperv/vmbus.c7
-rw-r--r--hw/input/adb.c7
-rw-r--r--hw/net/meson.build2
-rw-r--r--hw/net/npcm_gmac.c942
-rw-r--r--hw/net/trace-events19
-rw-r--r--hw/pci-host/designware.c2
-rw-r--r--hw/pci/pci.c10
-rw-r--r--hw/s390x/css-bridge.c5
-rw-r--r--hw/ssi/Kconfig4
-rw-r--r--hw/ssi/bcm2835_spi.c288
-rw-r--r--hw/ssi/meson.build1
-rw-r--r--hw/xen/trace-events21
-rw-r--r--hw/xen/xen-hvm-common.c47
-rw-r--r--hw/xen/xen-mapcache.c59
-rw-r--r--include/hw/arm/bcm2835_peripherals.h3
-rw-r--r--include/hw/arm/msf2-soc.h3
-rw-r--r--include/hw/arm/npcm7xx.h2
-rw-r--r--include/hw/net/npcm_gmac.h343
-rw-r--r--include/hw/qdev-core.h2
-rw-r--r--include/hw/ssi/bcm2835_spi.h81
-rw-r--r--qemu-options.hx16
-rw-r--r--system/vl.c22
-rw-r--r--target/arm/cpu.c4
-rw-r--r--target/arm/helper.c19
-rw-r--r--target/arm/syndrome.h8
-rw-r--r--tests/qtest/meson.build1
-rw-r--r--tests/qtest/npcm_gmac-test.c344
-rw-r--r--tests/qtest/xlnx-versal-trng-test.c19
-rw-r--r--tests/tcg/aarch64/sysregs.c2
50 files changed, 2388 insertions, 244 deletions
diff --git a/docs/devel/docs.rst b/docs/devel/docs.rst
index 7da0679..50ff0d6 100644
--- a/docs/devel/docs.rst
+++ b/docs/devel/docs.rst
@@ -30,6 +30,13 @@ nor the documentation output.
``SRST`` starts a reStructuredText section. Following lines
are put into the documentation verbatim, and discarded from the C output.
+The alternative form ``SRST()`` is used to define a label which can be
+referenced from elsewhere in the rST documentation. The label will take
+the form ``<DOCNAME-HXFILE-LABEL>``, where ``DOCNAME`` is the name of the
+top level rST file, ``HXFILE`` is the filename of the .hx file without
+the ``.hx`` extension, and ``LABEL`` is the text provided within the
+``SRST()`` directive. For example,
+``<system/invocation-qemu-options-initrd>``.
``ERST`` ends the documentation section started with ``SRST``,
and switches back to a C code section.
@@ -53,8 +60,9 @@ text, but in ``hmp-commands.hx`` the C code sections are elements
of an array of structs of type ``HMPCommand`` which define the
name, behaviour and help text for each monitor command.
-In the file ``qemu-options.hx``, do not try to define a
+In the file ``qemu-options.hx``, do not try to explicitly define a
reStructuredText label within a documentation section. This file
is included into two separate Sphinx documents, and some
versions of Sphinx will complain about the duplicate label
-that results.
+that results. Use the ``SRST()`` directive documented above, to
+emit an unambiguous label.
diff --git a/docs/sphinx/hxtool.py b/docs/sphinx/hxtool.py
index 9f6b9d8..3729084 100644
--- a/docs/sphinx/hxtool.py
+++ b/docs/sphinx/hxtool.py
@@ -78,6 +78,14 @@ def parse_archheading(file, lnum, line):
serror(file, lnum, "Invalid ARCHHEADING line")
return match.group(1)
+def parse_srst(file, lnum, line):
+ """Handle an SRST directive"""
+ # The input should be either "SRST", or "SRST(label)".
+ match = re.match(r'SRST(\((.*?)\))?', line)
+ if match is None:
+ serror(file, lnum, "Invalid SRST line")
+ return match.group(2)
+
class HxtoolDocDirective(Directive):
"""Extract rST fragments from the specified .hx file"""
required_argument = 1
@@ -113,6 +121,14 @@ class HxtoolDocDirective(Directive):
serror(hxfile, lnum, 'expected ERST, found SRST')
else:
state = HxState.RST
+ label = parse_srst(hxfile, lnum, line)
+ if label:
+ rstlist.append("", hxfile, lnum - 1)
+ # Build label as _DOCNAME-HXNAME-LABEL
+ hx = os.path.splitext(os.path.basename(hxfile))[0]
+ refline = ".. _" + env.docname + "-" + hx + \
+ "-" + label + ":"
+ rstlist.append(refline, hxfile, lnum - 1)
elif directive == 'ERST':
if state == HxState.CTEXT:
serror(hxfile, lnum, 'expected SRST, found ERST')
diff --git a/docs/system/arm/raspi.rst b/docs/system/arm/raspi.rst
index 922fe37..d0a6f08 100644
--- a/docs/system/arm/raspi.rst
+++ b/docs/system/arm/raspi.rst
@@ -33,11 +33,11 @@ Implemented devices
* USB2 host controller (DWC2 and MPHI)
* MailBox controller (MBOX)
* VideoCore firmware (property)
+ * Peripheral SPI controller (SPI)
Missing devices
---------------
- * Peripheral SPI controller (SPI)
* Analog to Digital Converter (ADC)
* Pulse Width Modulation (PWM)
diff --git a/docs/system/i386/xen.rst b/docs/system/i386/xen.rst
index 8189876..46db5f3 100644
--- a/docs/system/i386/xen.rst
+++ b/docs/system/i386/xen.rst
@@ -132,7 +132,8 @@ The example above provides the guest kernel command line after a separator
(" ``--`` ") on the Xen command line, and does not provide the guest kernel
with an actual initramfs, which would need to listed as a second multiboot
module. For more complicated alternatives, see the command line
-documentation for the ``-initrd`` option.
+:ref:`documentation <system/invocation-qemu-options-initrd>` for the
+``-initrd`` option.
Host OS requirements
--------------------
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index db08a00..980b14d 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -429,6 +429,7 @@ config RASPI
select PL011 # UART
select SDHCI
select USB_DWC2
+ select BCM2835_SPI
config STM32F100_SOC
bool
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 0233038..d5573fd 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -144,6 +144,10 @@ static void bcm2835_peripherals_init(Object *obj)
/* Power Management */
object_initialize_child(obj, "powermgt", &s->powermgt,
TYPE_BCM2835_POWERMGT);
+
+ /* SPI */
+ object_initialize_child(obj, "bcm2835-spi0", &s->spi[0],
+ TYPE_BCM2835_SPI);
}
static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
@@ -402,11 +406,22 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->peri_mr, PM_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->powermgt), 0));
+ /* SPI */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[0]), errp)) {
+ return;
+ }
+
+ memory_region_add_subregion(&s->peri_mr, SPI0_OFFSET,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->spi[0]), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[0]), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->ic),
+ BCM2835_IC_GPU_IRQ,
+ INTERRUPT_SPI));
+
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
- create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
create_unimp(s, &s->bscsl, "bcm2835-spis", BSC_SL_OFFSET, 0x100);
create_unimp(s, &s->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20);
create_unimp(s, &s->i2c[1], "bcm2835-i2c1", BSC1_OFFSET, 0x20);
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 6c428d8..57c77b1 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -556,6 +556,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9"));
+ object_property_add_child(OBJECT(s), "cpu[*]", cpuobj);
/* By default A9 CPUs have EL3 enabled. This board does not currently
* support EL3 so the CPU EL3 property is disabled before realization.
*/
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
index 0039921..2410e2a 100644
--- a/hw/arm/exynos4_boards.c
+++ b/hw/arm/exynos4_boards.c
@@ -34,6 +34,7 @@
#include "hw/qdev-properties.h"
#include "hw/boards.h"
#include "hw/irq.h"
+#include "target/arm/cpu-qom.h"
#define SMDK_LAN9118_BASE_ADDR 0x05000000
@@ -148,12 +149,18 @@ static void smdkc210_init(MachineState *machine)
arm_load_kernel(s->soc.cpu[0], machine, &exynos4_board_binfo);
}
+static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a9"),
+ NULL
+};
+
static void nuri_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Samsung NURI board (Exynos4210)";
mc->init = nuri_init;
+ mc->valid_cpu_types = valid_cpu_types;
mc->max_cpus = EXYNOS4210_NCPUS;
mc->min_cpus = EXYNOS4210_NCPUS;
mc->default_cpus = EXYNOS4210_NCPUS;
@@ -172,6 +179,7 @@ static void smdkc210_class_init(ObjectClass *oc, void *data)
mc->desc = "Samsung SMDKC210 board (Exynos4210)";
mc->init = smdkc210_init;
+ mc->valid_cpu_types = valid_cpu_types;
mc->max_cpus = EXYNOS4210_NCPUS;
mc->min_cpus = EXYNOS4210_NCPUS;
mc->default_cpus = EXYNOS4210_NCPUS;
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index e123747..9fdac1c 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -209,6 +209,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
cpuobj = object_new(machine->cpu_type);
cpu = ARM_CPU(cpuobj);
+ object_property_add_child(OBJECT(machine), "cpu[*]", cpuobj);
object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
&error_abort);
@@ -342,10 +343,15 @@ static void midway_init(MachineState *machine)
static void highbank_class_init(ObjectClass *oc, void *data)
{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a9"),
+ NULL
+ };
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Calxeda Highbank (ECX-1000)";
mc->init = highbank_init;
+ mc->valid_cpu_types = valid_cpu_types;
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
mc->max_cpus = 4;
@@ -361,10 +367,15 @@ static const TypeInfo highbank_type = {
static void midway_class_init(ObjectClass *oc, void *data)
{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a15"),
+ NULL
+ };
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Calxeda Midway (ECX-2000)";
mc->init = midway_init;
+ mc->valid_cpu_types = valid_cpu_types;
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
mc->max_cpus = 4;
diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c
index 35bf1d6..a94a10a 100644
--- a/hw/arm/msf2-soc.c
+++ b/hw/arm/msf2-soc.c
@@ -134,7 +134,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
armv7m = DEVICE(&s->armv7m);
qdev_prop_set_uint32(armv7m, "num-irq", 81);
- qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
+ qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
qdev_prop_set_bit(armv7m, "enable-bitband", true);
qdev_connect_clock_in(armv7m, "cpuclk", s->m3clk);
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
@@ -227,7 +227,6 @@ static Property m2sxxx_soc_properties[] = {
* part name specifies the type of SmartFusion2 device variant(this
* property is for information purpose only.
*/
- DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type),
DEFINE_PROP_STRING("part-name", MSF2State, part_name),
DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE),
DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size,
diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c
index a269cf0..5c415ab 100644
--- a/hw/arm/msf2-som.c
+++ b/hw/arm/msf2-som.c
@@ -47,7 +47,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
DeviceState *dev;
DeviceState *spi_flash;
MSF2State *soc;
- MachineClass *mc = MACHINE_GET_CLASS(machine);
DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
qemu_irq cs_line;
BusState *spi_bus;
@@ -62,8 +61,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
dev = qdev_new(TYPE_MSF2_SOC);
object_property_add_child(OBJECT(machine), "soc", OBJECT(dev));
qdev_prop_set_string(dev, "part-name", "M2S010");
- qdev_prop_set_string(dev, "cpu-type", mc->default_cpu_type);
-
qdev_prop_set_uint64(dev, "eNVM-size", M2S010_ENVM_SIZE);
qdev_prop_set_uint64(dev, "eSRAM-size", M2S010_ESRAM_SIZE);
@@ -108,7 +105,6 @@ static void emcraft_sf2_machine_init(MachineClass *mc)
mc->desc = "SmartFusion2 SOM kit from Emcraft (M2S010)";
mc->init = emcraft_sf2_s2s010_init;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
mc->valid_cpu_types = valid_cpu_types;
}
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
index 770ec1a..e2c9d49 100644
--- a/hw/arm/musca.c
+++ b/hw/arm/musca.c
@@ -605,7 +605,6 @@ static void musca_class_init(ObjectClass *oc, void *data)
mc->default_cpus = 2;
mc->min_cpus = mc->default_cpus;
mc->max_cpus = mc->default_cpus;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mc->valid_cpu_types = valid_cpu_types;
mc->init = musca_init;
}
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index bdc609b..ff3ecde 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -84,8 +84,10 @@ enum NPCM7xxInterrupt {
NPCM7XX_UART1_IRQ,
NPCM7XX_UART2_IRQ,
NPCM7XX_UART3_IRQ,
+ NPCM7XX_GMAC1_IRQ = 14,
NPCM7XX_EMC1RX_IRQ = 15,
NPCM7XX_EMC1TX_IRQ,
+ NPCM7XX_GMAC2_IRQ,
NPCM7XX_MMC_IRQ = 26,
NPCM7XX_PSPI2_IRQ = 28,
NPCM7XX_PSPI1_IRQ = 31,
@@ -229,6 +231,12 @@ static const hwaddr npcm7xx_pspi_addr[] = {
0xf0201000,
};
+/* Register base address for each GMAC Module */
+static const hwaddr npcm7xx_gmac_addr[] = {
+ 0xf0802000,
+ 0xf0804000,
+};
+
static const struct {
hwaddr regs_addr;
uint32_t unconnected_pins;
@@ -457,6 +465,10 @@ static void npcm7xx_init(Object *obj)
object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI);
}
+ for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
+ object_initialize_child(obj, "gmac[*]", &s->gmac[i], TYPE_NPCM_GMAC);
+ }
+
object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
}
@@ -691,6 +703,29 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
}
/*
+ * GMAC Modules. Cannot fail.
+ */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gmac_addr) != ARRAY_SIZE(s->gmac));
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->gmac) != 2);
+ for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->gmac[i]);
+
+ /*
+ * The device exists regardless of whether it's connected to a QEMU
+ * netdev backend. So always instantiate it even if there is no
+ * backend.
+ */
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm7xx_gmac_addr[i]);
+ int irq = i == 0 ? NPCM7XX_GMAC1_IRQ : NPCM7XX_GMAC2_IRQ;
+ /*
+ * N.B. The values for the second argument sysbus_connect_irq are
+ * chosen to match the registration order in npcm7xx_emc_realize.
+ */
+ sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, irq));
+ }
+
+ /*
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
* specified, but this is a programming error.
*/
@@ -752,8 +787,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB);
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
- create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
- create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB);
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
index 2999b8b..e229efb 100644
--- a/hw/arm/npcm7xx_boards.c
+++ b/hw/arm/npcm7xx_boards.c
@@ -465,7 +465,6 @@ static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
mc->no_cdrom = 1;
mc->no_parallel = 1;
mc->default_ram_id = "ram";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
mc->valid_cpu_types = valid_cpu_types;
}
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 7fd99a0..823b493 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -46,8 +46,7 @@
#include "qemu/log.h"
#include "qom/object.h"
#include "target/arm/cpu-qom.h"
-
-//#define DEBUG
+#include "trace.h"
/*
TODO
@@ -66,12 +65,6 @@
- Enhance UART with modem signals
*/
-#ifdef DEBUG
-# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
-#else
-# define DPRINTF(format, ...) do { } while (0)
-#endif
-
static struct {
hwaddr io_base;
int irq;
@@ -151,8 +144,9 @@ static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset,
case ICPR:
return s->pending;
default:
- printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n",
- __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
+ __func__, offset);
return 0;
}
}
@@ -173,8 +167,9 @@ static void strongarm_pic_mem_write(void *opaque, hwaddr offset,
s->int_idle = (value & 1) ? 0 : ~0;
break;
default:
- printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n",
- __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
+ __func__, offset);
break;
}
strongarm_pic_update(s);
@@ -333,7 +328,9 @@ static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr,
((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
default:
- printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad rtc register read 0x"HWADDR_FMT_plx"\n",
+ __func__, addr);
return 0;
}
}
@@ -375,7 +372,9 @@ static void strongarm_rtc_write(void *opaque, hwaddr addr,
break;
default:
- printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad rtc register write 0x"HWADDR_FMT_plx"\n",
+ __func__, addr);
}
}
@@ -556,12 +555,12 @@ static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
case GPSR: /* GPIO Pin-Output Set registers */
qemu_log_mask(LOG_GUEST_ERROR,
- "strongarm GPIO: read from write only register GPSR\n");
+ "%s: read from write only register GPSR\n", __func__);
return 0;
case GPCR: /* GPIO Pin-Output Clear registers */
qemu_log_mask(LOG_GUEST_ERROR,
- "strongarm GPIO: read from write only register GPCR\n");
+ "%s: read from write only register GPCR\n", __func__);
return 0;
case GRER: /* GPIO Rising-Edge Detect Enable registers */
@@ -581,7 +580,9 @@ static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
return s->status;
default:
- printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad gpio read offset 0x"HWADDR_FMT_plx"\n",
+ __func__, offset);
}
return 0;
@@ -626,7 +627,9 @@ static void strongarm_gpio_write(void *opaque, hwaddr offset,
break;
default:
- printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x"HWADDR_FMT_plx"\n",
+ __func__, offset);
}
}
@@ -782,7 +785,9 @@ static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset,
return s->ppfr | ~0x7f001;
default:
- printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad ppc read offset 0x"HWADDR_FMT_plx "\n",
+ __func__, offset);
}
return 0;
@@ -817,7 +822,9 @@ static void strongarm_ppc_write(void *opaque, hwaddr offset,
break;
default:
- printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad ppc write offset 0x"HWADDR_FMT_plx"\n",
+ __func__, offset);
}
}
@@ -1029,8 +1036,13 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s)
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
- DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
- speed, parity, data_bits, stop_bits);
+ trace_strongarm_uart_update_parameters((s->chr.chr ?
+ s->chr.chr->label : "NULL") ?:
+ "NULL",
+ speed,
+ parity,
+ data_bits,
+ stop_bits);
}
static void strongarm_uart_rx_to(void *opaque)
@@ -1164,7 +1176,9 @@ static uint64_t strongarm_uart_read(void *opaque, hwaddr addr,
return s->utsr1;
default:
- printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad uart register read 0x"HWADDR_FMT_plx"\n",
+ __func__, addr);
return 0;
}
}
@@ -1221,7 +1235,9 @@ static void strongarm_uart_write(void *opaque, hwaddr addr,
break;
default:
- printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad uart register write 0x"HWADDR_FMT_plx"\n",
+ __func__, addr);
}
}
@@ -1434,7 +1450,7 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
return 0xffffffff;
}
if (s->rx_level < 1) {
- printf("%s: SSP Rx Underrun\n", __func__);
+ trace_strongarm_ssp_read_underrun();
return 0xffffffff;
}
s->rx_level--;
@@ -1443,7 +1459,9 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
strongarm_ssp_fifo_update(s);
return retval;
default:
- printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad ssp register read 0x"HWADDR_FMT_plx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -1458,8 +1476,8 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
case SSCR0:
s->sscr[0] = value & 0xffbf;
if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
- printf("%s: Wrong data size: %i bits\n", __func__,
- (int)SSCR0_DSS(value));
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Wrong data size: %i bits\n",
+ __func__, (int)SSCR0_DSS(value));
}
if (!(value & SSCR0_SSE)) {
s->sssr = 0;
@@ -1471,7 +1489,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
case SSCR1:
s->sscr[1] = value & 0x2f;
if (value & SSCR1_LBM) {
- printf("%s: Attempt to use SSP LBM mode\n", __func__);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Attempt to use SSP LBM mode\n",
+ __func__);
}
strongarm_ssp_fifo_update(s);
break;
@@ -1509,7 +1529,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
break;
default:
- printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad ssp register write 0x"HWADDR_FMT_plx"\n",
+ __func__, addr);
break;
}
}
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index cdc1ea0..fd0d927 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -55,3 +55,18 @@ smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
+# strongarm.c
+strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
+strongarm_ssp_read_underrun(void) "SSP rx underrun"
+
+# z2.c
+z2_lcd_reg_update(uint8_t cur, uint8_t i_0, uint8_t i_1, uint8_t i_2, uint32_t value) "cur_reg = 0x%x, buf = [0x%x, 0x%x, 0x%x], value = 0x%x"
+z2_lcd_enable_disable_result(const char *result) "LCD %s"
+z2_aer915_send_too_long(int8_t msg) "message too long (%i bytes)"
+z2_aer915_send(uint8_t reg, uint8_t value) "reg %d value 0x%02x"
+z2_aer915_event(int8_t event, int8_t len) "i2c event =0x%x len=%d bytes"
+
+# xen_arm.c
+xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64
+xen_init_ram(uint64_t machine_ram_size) "Initialized xen ram with size 0x%"PRIx64
+xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index e5fb3ab..aa5f3ca 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -783,22 +783,30 @@ static void vexpress_class_init(ObjectClass *oc, void *data)
static void vexpress_a9_class_init(ObjectClass *oc, void *data)
{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a9"),
+ NULL
+ };
MachineClass *mc = MACHINE_CLASS(oc);
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
mc->desc = "ARM Versatile Express for Cortex-A9";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
+ mc->valid_cpu_types = valid_cpu_types;
vmc->daughterboard = &a9_daughterboard;
}
static void vexpress_a15_class_init(ObjectClass *oc, void *data)
{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a15"),
+ NULL
+ };
MachineClass *mc = MACHINE_CLASS(oc);
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
mc->desc = "ARM Versatile Express for Cortex-A15";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
+ mc->valid_cpu_types = valid_cpu_types;
vmc->daughterboard = &a15_daughterboard;
diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c
index a563152..32776d9 100644
--- a/hw/arm/xen_arm.c
+++ b/hw/arm/xen_arm.c
@@ -34,6 +34,7 @@
#include "hw/xen/xen-hvm-common.h"
#include "sysemu/tpm.h"
#include "hw/xen/arch_hvm.h"
+#include "trace.h"
#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM)
@@ -91,8 +92,9 @@ static void xen_create_virtio_mmio_devices(XenArmState *xam)
sysbus_create_simple("virtio-mmio", base, irq);
- DPRINTF("Created virtio-mmio device %d: irq %d base 0x%lx\n",
- i, GUEST_VIRTIO_MMIO_SPI_FIRST + i, base);
+ trace_xen_create_virtio_mmio_devices(i,
+ GUEST_VIRTIO_MMIO_SPI_FIRST + i,
+ base);
}
}
@@ -101,6 +103,7 @@ static void xen_init_ram(MachineState *machine)
MemoryRegion *sysmem = get_system_memory();
ram_addr_t block_len, ram_size[GUEST_RAM_BANKS];
+ trace_xen_init_ram(machine->ram_size);
if (machine->ram_size <= GUEST_RAM0_SIZE) {
ram_size[0] = machine->ram_size;
ram_size[1] = 0;
@@ -117,15 +120,10 @@ static void xen_init_ram(MachineState *machine)
memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &ram_memory,
GUEST_RAM0_BASE, ram_size[0]);
memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo);
- DPRINTF("Initialized region xen.ram.lo: base 0x%llx size 0x%lx\n",
- GUEST_RAM0_BASE, ram_size[0]);
-
if (ram_size[1] > 0) {
memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &ram_memory,
GUEST_RAM1_BASE, ram_size[1]);
memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi);
- DPRINTF("Initialized region xen.ram.hi: base 0x%llx size 0x%lx\n",
- GUEST_RAM1_BASE, ram_size[1]);
}
}
@@ -158,7 +156,7 @@ static void xen_enable_tpm(XenArmState *xam)
TPMBackend *be = qemu_find_tpm_be("tpm0");
if (be == NULL) {
- DPRINTF("Couldn't fine the backend for tpm0\n");
+ error_report("Couldn't find tmp0 backend");
return;
}
dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
@@ -168,7 +166,7 @@ static void xen_enable_tpm(XenArmState *xam)
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr);
- DPRINTF("Connected tpmdev at address 0x%lx\n", xam->cfg.tpm_base_addr);
+ trace_xen_enable_tpm(xam->cfg.tpm_base_addr);
}
#endif
@@ -179,8 +177,9 @@ static void xen_arm_init(MachineState *machine)
xam->state = g_new0(XenIOState, 1);
if (machine->ram_size == 0) {
- DPRINTF("ram_size not specified. QEMU machine started without IOREQ"
- "(no emulated devices including Virtio)\n");
+ warn_report("%s non-zero ram size not specified. QEMU machine started"
+ " without IOREQ (no emulated devices including virtio)",
+ MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc);
return;
}
@@ -194,7 +193,7 @@ static void xen_arm_init(MachineState *machine)
if (xam->cfg.tpm_base_addr) {
xen_enable_tpm(xam);
} else {
- DPRINTF("tpm-base-addr is not provided. TPM will not be enabled\n");
+ warn_report("tpm-base-addr is not provided. TPM will not be enabled");
}
#endif
}
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 35fa804..a41a118 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -352,13 +352,17 @@ static void zynq_init(MachineState *machine)
static void zynq_machine_class_init(ObjectClass *oc, void *data)
{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a9"),
+ NULL
+ };
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
mc->init = zynq_init;
mc->max_cpus = 1;
mc->no_sdcard = 1;
mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
+ mc->valid_cpu_types = valid_cpu_types;
mc->default_ram_id = "zynq.ext_ram";
}
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index a67fba2..eb2ff8d 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -27,13 +27,7 @@
#include "exec/address-spaces.h"
#include "qom/object.h"
#include "qapi/error.h"
-
-#ifdef DEBUG_Z2
-#define DPRINTF(fmt, ...) \
- printf(fmt, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
+#include "trace.h"
static const struct keymap map[0x100] = {
[0 ... 0xff] = { -1, -1 },
@@ -119,6 +113,8 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
{
ZipitLCD *z = ZIPIT_LCD(dev);
uint16_t val;
+
+ trace_z2_lcd_reg_update(z->cur_reg, z->buf[0], z->buf[1], z->buf[2], value);
if (z->selected) {
z->buf[z->pos] = value & 0xff;
z->pos++;
@@ -126,22 +122,19 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
if (z->pos == 3) {
switch (z->buf[0]) {
case 0x74:
- DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
z->cur_reg = z->buf[2];
break;
case 0x76:
val = z->buf[1] << 8 | z->buf[2];
- DPRINTF("%s: value: 0x%.4x\n", __func__, val);
if (z->cur_reg == 0x22 && val == 0x0000) {
z->enabled = 1;
- printf("%s: LCD enabled\n", __func__);
+ trace_z2_lcd_enable_disable_result("enabled");
} else if (z->cur_reg == 0x10 && val == 0x0000) {
z->enabled = 0;
- printf("%s: LCD disabled\n", __func__);
+ trace_z2_lcd_enable_disable_result("disabled");
}
break;
default:
- DPRINTF("%s: unknown command!\n", __func__);
break;
}
z->pos = 0;
@@ -211,14 +204,12 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)
s->buf[s->len] = data;
if (s->len++ > 2) {
- DPRINTF("%s: message too long (%i bytes)\n",
- __func__, s->len);
+ trace_z2_aer915_send_too_long(s->len);
return 1;
}
if (s->len == 2) {
- DPRINTF("%s: reg %d value 0x%02x\n", __func__,
- s->buf[0], s->buf[1]);
+ trace_z2_aer915_send(s->buf[0], s->buf[1]);
}
return 0;
@@ -228,14 +219,12 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event)
{
AER915State *s = AER915(i2c);
+ trace_z2_aer915_event(s->len, event);
switch (event) {
case I2C_START_SEND:
s->len = 0;
break;
case I2C_START_RECV:
- if (s->len != 1) {
- DPRINTF("%s: short message!?\n", __func__);
- }
break;
case I2C_FINISH:
break;
diff --git a/hw/core/bus.c b/hw/core/bus.c
index c7831b5..b9d8949 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -232,57 +232,6 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev)
return g_strdup(object_get_typename(OBJECT(dev)));
}
-/**
- * bus_phases_reset:
- * Transition reset method for buses to allow moving
- * smoothly from legacy reset method to multi-phases
- */
-static void bus_phases_reset(BusState *bus)
-{
- ResettableClass *rc = RESETTABLE_GET_CLASS(bus);
-
- if (rc->phases.enter) {
- rc->phases.enter(OBJECT(bus), RESET_TYPE_COLD);
- }
- if (rc->phases.hold) {
- rc->phases.hold(OBJECT(bus));
- }
- if (rc->phases.exit) {
- rc->phases.exit(OBJECT(bus));
- }
-}
-
-static void bus_transitional_reset(Object *obj)
-{
- BusClass *bc = BUS_GET_CLASS(obj);
-
- /*
- * This will call either @bus_phases_reset (for multi-phases transitioned
- * buses) or a bus's specific method for not-yet transitioned buses.
- * In both case, it does not reset children.
- */
- if (bc->reset) {
- bc->reset(BUS(obj));
- }
-}
-
-/**
- * bus_get_transitional_reset:
- * check if the bus's class is ready for multi-phase
- */
-static ResettableTrFunction bus_get_transitional_reset(Object *obj)
-{
- BusClass *dc = BUS_GET_CLASS(obj);
- if (dc->reset != bus_phases_reset) {
- /*
- * dc->reset has been overridden by a subclass,
- * the bus is not ready for multi phase yet.
- */
- return bus_transitional_reset;
- }
- return NULL;
-}
-
static void bus_class_init(ObjectClass *class, void *data)
{
BusClass *bc = BUS_CLASS(class);
@@ -293,22 +242,6 @@ static void bus_class_init(ObjectClass *class, void *data)
rc->get_state = bus_get_reset_state;
rc->child_foreach = bus_reset_child_foreach;
-
- /*
- * @bus_phases_reset is put as the default reset method below, allowing
- * to do the multi-phase transition from base classes to leaf classes. It
- * allows a legacy-reset Bus class to extend a multi-phases-reset
- * Bus class for the following reason:
- * + If a base class B has been moved to multi-phase, then it does not
- * override this default reset method and may have defined phase methods.
- * + A child class C (extending class B) which uses
- * bus_class_set_parent_reset() (or similar means) to override the
- * reset method will still work as expected. @bus_phases_reset function
- * will be registered as the parent reset method and effectively call
- * parent reset phases.
- */
- bc->reset = bus_phases_reset;
- rc->get_transitional_function = bus_get_transitional_reset;
}
static void qbus_finalize(Object *obj)
diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
index c86d189..380239a 100644
--- a/hw/hyperv/vmbus.c
+++ b/hw/hyperv/vmbus.c
@@ -2453,9 +2453,9 @@ static void vmbus_unrealize(BusState *bus)
qemu_mutex_destroy(&vmbus->rx_queue_lock);
}
-static void vmbus_reset(BusState *bus)
+static void vmbus_reset_hold(Object *obj)
{
- vmbus_deinit(VMBUS(bus));
+ vmbus_deinit(VMBUS(obj));
}
static char *vmbus_get_dev_path(DeviceState *dev)
@@ -2476,12 +2476,13 @@ static char *vmbus_get_fw_dev_path(DeviceState *dev)
static void vmbus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
k->get_dev_path = vmbus_get_dev_path;
k->get_fw_dev_path = vmbus_get_fw_dev_path;
k->realize = vmbus_realize;
k->unrealize = vmbus_unrealize;
- k->reset = vmbus_reset;
+ rc->phases.hold = vmbus_reset_hold;
}
static int vmbus_pre_load(void *opaque)
diff --git a/hw/input/adb.c b/hw/input/adb.c
index 0f3c73d..98f39b4 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -231,9 +231,9 @@ static const VMStateDescription vmstate_adb_bus = {
}
};
-static void adb_bus_reset(BusState *qbus)
+static void adb_bus_reset_hold(Object *obj)
{
- ADBBusState *adb_bus = ADB_BUS(qbus);
+ ADBBusState *adb_bus = ADB_BUS(obj);
adb_bus->autopoll_enabled = false;
adb_bus->autopoll_mask = 0xffff;
@@ -262,10 +262,11 @@ static void adb_bus_unrealize(BusState *qbus)
static void adb_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
k->realize = adb_bus_realize;
k->unrealize = adb_bus_unrealize;
- k->reset = adb_bus_reset;
+ rc->phases.hold = adb_bus_reset_hold;
}
static const TypeInfo adb_bus_type_info = {
diff --git a/hw/net/meson.build b/hw/net/meson.build
index 2b426d3..b742687 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -38,7 +38,7 @@ system_ss.add(when: 'CONFIG_I82596_COMMON', if_true: files('i82596.c'))
system_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c'))
system_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c'))
system_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c'))
-system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c'))
+system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c', 'npcm_gmac.c'))
system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))
diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c
new file mode 100644
index 0000000..1b71e25
--- /dev/null
+++ b/hw/net/npcm_gmac.c
@@ -0,0 +1,942 @@
+/*
+ * Nuvoton NPCM7xx/8xx GMAC Module
+ *
+ * Copyright 2024 Google LLC
+ * Authors:
+ * Hao Wu <wuhaotsh@google.com>
+ * Nabih Estefan <nabihestefan@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * Unsupported/unimplemented features:
+ * - MII is not implemented, MII_ADDR.BUSY and MII_DATA always return zero
+ * - Precision timestamp (PTP) is not implemented.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/registerfields.h"
+#include "hw/net/mii.h"
+#include "hw/net/npcm_gmac.h"
+#include "migration/vmstate.h"
+#include "net/checksum.h"
+#include "net/eth.h"
+#include "net/net.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qemu/units.h"
+#include "sysemu/dma.h"
+#include "trace.h"
+
+REG32(NPCM_DMA_BUS_MODE, 0x1000)
+REG32(NPCM_DMA_XMT_POLL_DEMAND, 0x1004)
+REG32(NPCM_DMA_RCV_POLL_DEMAND, 0x1008)
+REG32(NPCM_DMA_RX_BASE_ADDR, 0x100c)
+REG32(NPCM_DMA_TX_BASE_ADDR, 0x1010)
+REG32(NPCM_DMA_STATUS, 0x1014)
+REG32(NPCM_DMA_CONTROL, 0x1018)
+REG32(NPCM_DMA_INTR_ENA, 0x101c)
+REG32(NPCM_DMA_MISSED_FRAME_CTR, 0x1020)
+REG32(NPCM_DMA_HOST_TX_DESC, 0x1048)
+REG32(NPCM_DMA_HOST_RX_DESC, 0x104c)
+REG32(NPCM_DMA_CUR_TX_BUF_ADDR, 0x1050)
+REG32(NPCM_DMA_CUR_RX_BUF_ADDR, 0x1054)
+REG32(NPCM_DMA_HW_FEATURE, 0x1058)
+
+REG32(NPCM_GMAC_MAC_CONFIG, 0x0)
+REG32(NPCM_GMAC_FRAME_FILTER, 0x4)
+REG32(NPCM_GMAC_HASH_HIGH, 0x8)
+REG32(NPCM_GMAC_HASH_LOW, 0xc)
+REG32(NPCM_GMAC_MII_ADDR, 0x10)
+REG32(NPCM_GMAC_MII_DATA, 0x14)
+REG32(NPCM_GMAC_FLOW_CTRL, 0x18)
+REG32(NPCM_GMAC_VLAN_FLAG, 0x1c)
+REG32(NPCM_GMAC_VERSION, 0x20)
+REG32(NPCM_GMAC_WAKEUP_FILTER, 0x28)
+REG32(NPCM_GMAC_PMT, 0x2c)
+REG32(NPCM_GMAC_LPI_CTRL, 0x30)
+REG32(NPCM_GMAC_TIMER_CTRL, 0x34)
+REG32(NPCM_GMAC_INT_STATUS, 0x38)
+REG32(NPCM_GMAC_INT_MASK, 0x3c)
+REG32(NPCM_GMAC_MAC0_ADDR_HI, 0x40)
+REG32(NPCM_GMAC_MAC0_ADDR_LO, 0x44)
+REG32(NPCM_GMAC_MAC1_ADDR_HI, 0x48)
+REG32(NPCM_GMAC_MAC1_ADDR_LO, 0x4c)
+REG32(NPCM_GMAC_MAC2_ADDR_HI, 0x50)
+REG32(NPCM_GMAC_MAC2_ADDR_LO, 0x54)
+REG32(NPCM_GMAC_MAC3_ADDR_HI, 0x58)
+REG32(NPCM_GMAC_MAC3_ADDR_LO, 0x5c)
+REG32(NPCM_GMAC_RGMII_STATUS, 0xd8)
+REG32(NPCM_GMAC_WATCHDOG, 0xdc)
+REG32(NPCM_GMAC_PTP_TCR, 0x700)
+REG32(NPCM_GMAC_PTP_SSIR, 0x704)
+REG32(NPCM_GMAC_PTP_STSR, 0x708)
+REG32(NPCM_GMAC_PTP_STNSR, 0x70c)
+REG32(NPCM_GMAC_PTP_STSUR, 0x710)
+REG32(NPCM_GMAC_PTP_STNSUR, 0x714)
+REG32(NPCM_GMAC_PTP_TAR, 0x718)
+REG32(NPCM_GMAC_PTP_TTSR, 0x71c)
+
+/* Register Fields */
+#define NPCM_GMAC_MII_ADDR_BUSY BIT(0)
+#define NPCM_GMAC_MII_ADDR_WRITE BIT(1)
+#define NPCM_GMAC_MII_ADDR_GR(rv) extract16((rv), 6, 5)
+#define NPCM_GMAC_MII_ADDR_PA(rv) extract16((rv), 11, 5)
+
+#define NPCM_GMAC_INT_MASK_LPIIM BIT(10)
+#define NPCM_GMAC_INT_MASK_PMTM BIT(3)
+#define NPCM_GMAC_INT_MASK_RGIM BIT(0)
+
+#define NPCM_DMA_BUS_MODE_SWR BIT(0)
+
+static const uint32_t npcm_gmac_cold_reset_values[NPCM_GMAC_NR_REGS] = {
+ /* Reduce version to 3.2 so that the kernel can enable interrupt. */
+ [R_NPCM_GMAC_VERSION] = 0x00001032,
+ [R_NPCM_GMAC_TIMER_CTRL] = 0x03e80000,
+ [R_NPCM_GMAC_MAC0_ADDR_HI] = 0x8000ffff,
+ [R_NPCM_GMAC_MAC0_ADDR_LO] = 0xffffffff,
+ [R_NPCM_GMAC_MAC1_ADDR_HI] = 0x0000ffff,
+ [R_NPCM_GMAC_MAC1_ADDR_LO] = 0xffffffff,
+ [R_NPCM_GMAC_MAC2_ADDR_HI] = 0x0000ffff,
+ [R_NPCM_GMAC_MAC2_ADDR_LO] = 0xffffffff,
+ [R_NPCM_GMAC_MAC3_ADDR_HI] = 0x0000ffff,
+ [R_NPCM_GMAC_MAC3_ADDR_LO] = 0xffffffff,
+ [R_NPCM_GMAC_PTP_TCR] = 0x00002000,
+ [R_NPCM_DMA_BUS_MODE] = 0x00020101,
+ [R_NPCM_DMA_HW_FEATURE] = 0x100d4f37,
+};
+
+static const uint16_t phy_reg_init[] = {
+ [MII_BMCR] = MII_BMCR_AUTOEN | MII_BMCR_FD | MII_BMCR_SPEED1000,
+ [MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
+ MII_BMSR_10T_HD | MII_BMSR_EXTSTAT | MII_BMSR_AUTONEG |
+ MII_BMSR_LINK_ST | MII_BMSR_EXTCAP,
+ [MII_PHYID1] = 0x0362,
+ [MII_PHYID2] = 0x5e6a,
+ [MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD |
+ MII_ANAR_10 | MII_ANAR_CSMACD,
+ [MII_ANLPAR] = MII_ANLPAR_ACK | MII_ANLPAR_PAUSE |
+ MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD |
+ MII_ANLPAR_10 | MII_ANLPAR_CSMACD,
+ [MII_ANER] = 0x64 | MII_ANER_NWAY,
+ [MII_ANNP] = 0x2001,
+ [MII_CTRL1000] = MII_CTRL1000_FULL,
+ [MII_STAT1000] = MII_STAT1000_FULL,
+ [MII_EXTSTAT] = 0x3000, /* 1000BASTE_T full-duplex capable */
+};
+
+static void npcm_gmac_soft_reset(NPCMGMACState *gmac)
+{
+ memcpy(gmac->regs, npcm_gmac_cold_reset_values,
+ NPCM_GMAC_NR_REGS * sizeof(uint32_t));
+ /* Clear reset bits */
+ gmac->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR;
+}
+
+static void gmac_phy_set_link(NPCMGMACState *gmac, bool active)
+{
+ /* Autonegotiation status mirrors link status. */
+ if (active) {
+ gmac->phy_regs[0][MII_BMSR] |= (MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
+ } else {
+ gmac->phy_regs[0][MII_BMSR] &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
+ }
+}
+
+static bool gmac_can_receive(NetClientState *nc)
+{
+ NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc));
+
+ /* If GMAC receive is disabled. */
+ if (!(gmac->regs[R_NPCM_GMAC_MAC_CONFIG] & NPCM_GMAC_MAC_CONFIG_RX_EN)) {
+ return false;
+ }
+
+ /* If GMAC DMA RX is stopped. */
+ if (!(gmac->regs[R_NPCM_DMA_CONTROL] & NPCM_DMA_CONTROL_START_STOP_RX)) {
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Function that updates the GMAC IRQ
+ * It find the logical OR of the enabled bits for NIS (if enabled)
+ * It find the logical OR of the enabled bits for AIS (if enabled)
+ */
+static void gmac_update_irq(NPCMGMACState *gmac)
+{
+ /*
+ * Check if the normal interrupts summary is enabled
+ * if so, add the bits for the summary that are enabled
+ */
+ if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
+ (NPCM_DMA_INTR_ENAB_NIE_BITS)) {
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_NIS;
+ }
+ /*
+ * Check if the abnormal interrupts summary is enabled
+ * if so, add the bits for the summary that are enabled
+ */
+ if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
+ (NPCM_DMA_INTR_ENAB_AIE_BITS)) {
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_AIS;
+ }
+
+ /* Get the logical OR of both normal and abnormal interrupts */
+ int level = !!((gmac->regs[R_NPCM_DMA_STATUS] &
+ gmac->regs[R_NPCM_DMA_INTR_ENA] &
+ NPCM_DMA_STATUS_NIS) |
+ (gmac->regs[R_NPCM_DMA_STATUS] &
+ gmac->regs[R_NPCM_DMA_INTR_ENA] &
+ NPCM_DMA_STATUS_AIS));
+
+ /* Set the IRQ */
+ trace_npcm_gmac_update_irq(DEVICE(gmac)->canonical_path,
+ gmac->regs[R_NPCM_DMA_STATUS],
+ gmac->regs[R_NPCM_DMA_INTR_ENA],
+ level);
+ qemu_set_irq(gmac->irq, level);
+}
+
+static int gmac_read_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc)
+{
+ if (dma_memory_read(&address_space_memory, addr, desc,
+ sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ desc->rdes0 = le32_to_cpu(desc->rdes0);
+ desc->rdes1 = le32_to_cpu(desc->rdes1);
+ desc->rdes2 = le32_to_cpu(desc->rdes2);
+ desc->rdes3 = le32_to_cpu(desc->rdes3);
+ return 0;
+}
+
+static int gmac_write_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc)
+{
+ struct NPCMGMACRxDesc le_desc;
+ le_desc.rdes0 = cpu_to_le32(desc->rdes0);
+ le_desc.rdes1 = cpu_to_le32(desc->rdes1);
+ le_desc.rdes2 = cpu_to_le32(desc->rdes2);
+ le_desc.rdes3 = cpu_to_le32(desc->rdes3);
+ if (dma_memory_write(&address_space_memory, addr, &le_desc,
+ sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ return 0;
+}
+
+static int gmac_read_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc)
+{
+ if (dma_memory_read(&address_space_memory, addr, desc,
+ sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ desc->tdes0 = le32_to_cpu(desc->tdes0);
+ desc->tdes1 = le32_to_cpu(desc->tdes1);
+ desc->tdes2 = le32_to_cpu(desc->tdes2);
+ desc->tdes3 = le32_to_cpu(desc->tdes3);
+ return 0;
+}
+
+static int gmac_write_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc)
+{
+ struct NPCMGMACTxDesc le_desc;
+ le_desc.tdes0 = cpu_to_le32(desc->tdes0);
+ le_desc.tdes1 = cpu_to_le32(desc->tdes1);
+ le_desc.tdes2 = cpu_to_le32(desc->tdes2);
+ le_desc.tdes3 = cpu_to_le32(desc->tdes3);
+ if (dma_memory_write(&address_space_memory, addr, &le_desc,
+ sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ return 0;
+}
+
+static int gmac_rx_transfer_frame_to_buffer(uint32_t rx_buf_len,
+ uint32_t *left_frame,
+ uint32_t rx_buf_addr,
+ bool *eof_transferred,
+ const uint8_t **frame_ptr,
+ uint16_t *transferred)
+{
+ uint32_t to_transfer;
+ /*
+ * Check that buffer is bigger than the frame being transfered
+ * If bigger then transfer only whats left of frame
+ * Else, fill frame with all the content possible
+ */
+ if (rx_buf_len >= *left_frame) {
+ to_transfer = *left_frame;
+ *eof_transferred = true;
+ } else {
+ to_transfer = rx_buf_len;
+ }
+
+ /* write frame part to memory */
+ if (dma_memory_write(&address_space_memory, (uint64_t) rx_buf_addr,
+ *frame_ptr, to_transfer, MEMTXATTRS_UNSPECIFIED)) {
+ return -1;
+ }
+
+ /* update frame pointer and size of whats left of frame */
+ *frame_ptr += to_transfer;
+ *left_frame -= to_transfer;
+ *transferred += to_transfer;
+
+ return 0;
+}
+
+static void gmac_dma_set_state(NPCMGMACState *gmac, int shift, uint32_t state)
+{
+ gmac->regs[R_NPCM_DMA_STATUS] = deposit32(gmac->regs[R_NPCM_DMA_STATUS],
+ shift, 3, state);
+}
+
+static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len)
+{
+ /*
+ * Comments have steps that relate to the
+ * receiving process steps in pg 386
+ */
+ NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc));
+ uint32_t left_frame = len;
+ const uint8_t *frame_ptr = buf;
+ uint32_t desc_addr;
+ uint32_t rx_buf_len, rx_buf_addr;
+ struct NPCMGMACRxDesc rx_desc;
+ uint16_t transferred = 0;
+ bool eof_transferred = false;
+
+ trace_npcm_gmac_packet_receive(DEVICE(gmac)->canonical_path, len);
+ if (!gmac_can_receive(nc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "GMAC Currently is not able for Rx");
+ return -1;
+ }
+ if (!gmac->regs[R_NPCM_DMA_HOST_RX_DESC]) {
+ gmac->regs[R_NPCM_DMA_HOST_RX_DESC] =
+ NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]);
+ }
+ desc_addr = NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_HOST_RX_DESC]);
+
+ /* step 1 */
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_RUNNING_FETCHING_STATE);
+ trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, desc_addr);
+ if (gmac_read_rx_desc(desc_addr, &rx_desc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "RX Descriptor @ 0x%x cant be read\n",
+ desc_addr);
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_SUSPENDED_STATE);
+ return -1;
+ }
+
+ /* step 2 */
+ if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "RX Descriptor @ 0x%x is owned by software\n",
+ desc_addr);
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU;
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI;
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_SUSPENDED_STATE);
+ gmac_update_irq(gmac);
+ return len;
+ }
+ /* step 3 */
+ /*
+ * TODO --
+ * Implement all frame filtering and processing (with its own interrupts)
+ */
+ trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc,
+ rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2,
+ rx_desc.rdes3);
+ /* Clear rdes0 for the incoming descriptor and set FS in first descriptor.*/
+ rx_desc.rdes0 = RX_DESC_RDES0_FIRST_DESC_MASK;
+
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_RUNNING_TRANSFERRING_STATE);
+
+ /* Pad the frame with FCS as the kernel driver will strip it away. */
+ left_frame += ETH_FCS_LEN;
+
+ /* repeat while we still have frame to transfer to memory */
+ while (!eof_transferred) {
+ /* Return descriptor no matter what happens */
+ rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN;
+ /* Set the frame to be an IPv4/IPv6 frame. */
+ rx_desc.rdes0 |= RX_DESC_RDES0_FRM_TYPE_MASK;
+
+ /* step 4 */
+ rx_buf_len = RX_DESC_RDES1_BFFR1_SZ_MASK(rx_desc.rdes1);
+ rx_buf_addr = rx_desc.rdes2;
+ gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr;
+ gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame, rx_buf_addr,
+ &eof_transferred, &frame_ptr,
+ &transferred);
+
+ trace_npcm_gmac_packet_receiving_buffer(DEVICE(gmac)->canonical_path,
+ rx_buf_len, rx_buf_addr);
+ /* if we still have frame left and the second buffer is not chained */
+ if (!(rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) && \
+ !eof_transferred) {
+ /* repeat process from above on buffer 2 */
+ rx_buf_len = RX_DESC_RDES1_BFFR2_SZ_MASK(rx_desc.rdes1);
+ rx_buf_addr = rx_desc.rdes3;
+ gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr;
+ gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame,
+ rx_buf_addr, &eof_transferred,
+ &frame_ptr, &transferred);
+ trace_npcm_gmac_packet_receiving_buffer( \
+ DEVICE(gmac)->canonical_path,
+ rx_buf_len, rx_buf_addr);
+ }
+ /* update address for descriptor */
+ gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = rx_buf_addr;
+ /* Return descriptor */
+ rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN;
+ /* Update frame length transferred */
+ rx_desc.rdes0 |= ((uint32_t)transferred)
+ << RX_DESC_RDES0_FRAME_LEN_SHIFT;
+ trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc,
+ rx_desc.rdes0, rx_desc.rdes1,
+ rx_desc.rdes2, rx_desc.rdes3);
+
+ /* step 5 */
+ gmac_write_rx_desc(desc_addr, &rx_desc);
+ trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path,
+ &rx_desc, rx_desc.rdes0,
+ rx_desc.rdes1, rx_desc.rdes2,
+ rx_desc.rdes3);
+ /* read new descriptor into rx_desc if needed*/
+ if (!eof_transferred) {
+ /* Get next descriptor address (chained or sequential) */
+ if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) {
+ desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR];
+ } else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) {
+ desc_addr = rx_desc.rdes3;
+ } else {
+ desc_addr += sizeof(rx_desc);
+ }
+ trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path,
+ desc_addr);
+ if (gmac_read_rx_desc(desc_addr, &rx_desc)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "RX Descriptor @ 0x%x cant be read\n",
+ desc_addr);
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU;
+ gmac_update_irq(gmac);
+ return len;
+ }
+
+ /* step 6 */
+ if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) {
+ if (!(gmac->regs[R_NPCM_DMA_CONTROL] & \
+ NPCM_DMA_CONTROL_FLUSH_MASK)) {
+ rx_desc.rdes0 |= RX_DESC_RDES0_DESC_ERR_MASK;
+ }
+ eof_transferred = true;
+ }
+ /* Clear rdes0 for the incoming descriptor */
+ rx_desc.rdes0 = 0;
+ }
+ }
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_RUNNING_CLOSING_STATE);
+
+ rx_desc.rdes0 |= RX_DESC_RDES0_LAST_DESC_MASK;
+ if (!(rx_desc.rdes1 & RX_DESC_RDES1_DIS_INTR_COMP_MASK)) {
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI;
+ gmac_update_irq(gmac);
+ }
+ trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc,
+ rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2,
+ rx_desc.rdes3);
+
+ /* step 8 */
+ gmac->regs[R_NPCM_DMA_CONTROL] |= NPCM_DMA_CONTROL_FLUSH_MASK;
+
+ /* step 9 */
+ trace_npcm_gmac_packet_received(DEVICE(gmac)->canonical_path, left_frame);
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
+ gmac_write_rx_desc(desc_addr, &rx_desc);
+
+ /* Get next descriptor address (chained or sequential) */
+ if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) {
+ desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR];
+ } else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) {
+ desc_addr = rx_desc.rdes3;
+ } else {
+ desc_addr += sizeof(rx_desc);
+ }
+ gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = desc_addr;
+ return len;
+}
+
+static int gmac_tx_get_csum(uint32_t tdes1)
+{
+ uint32_t mask = TX_DESC_TDES1_CHKSM_INS_CTRL_MASK(tdes1);
+ int csum = 0;
+
+ if (likely(mask > 0)) {
+ csum |= CSUM_IP;
+ }
+ if (likely(mask > 1)) {
+ csum |= CSUM_TCP | CSUM_UDP;
+ }
+
+ return csum;
+}
+
+static void gmac_try_send_next_packet(NPCMGMACState *gmac)
+{
+ /*
+ * Comments about steps refer to steps for
+ * transmitting in page 384 of datasheet
+ */
+ uint16_t tx_buffer_size = 2048;
+ g_autofree uint8_t *tx_send_buffer = g_malloc(tx_buffer_size);
+ uint32_t desc_addr;
+ struct NPCMGMACTxDesc tx_desc;
+ uint32_t tx_buf_addr, tx_buf_len;
+ uint16_t length = 0;
+ uint8_t *buf = tx_send_buffer;
+ uint32_t prev_buf_size = 0;
+ int csum = 0;
+
+ /* steps 1&2 */
+ if (!gmac->regs[R_NPCM_DMA_HOST_TX_DESC]) {
+ gmac->regs[R_NPCM_DMA_HOST_TX_DESC] =
+ NPCM_DMA_HOST_TX_DESC_MASK(gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]);
+ }
+ desc_addr = gmac->regs[R_NPCM_DMA_HOST_TX_DESC];
+
+ while (true) {
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_TX_RUNNING_FETCHING_STATE);
+ if (gmac_read_tx_desc(desc_addr, &tx_desc)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "TX Descriptor @ 0x%x can't be read\n",
+ desc_addr);
+ return;
+ }
+ /* step 3 */
+
+ trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path,
+ desc_addr);
+ trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &tx_desc,
+ tx_desc.tdes0, tx_desc.tdes1, tx_desc.tdes2, tx_desc.tdes3);
+
+ /* 1 = DMA Owned, 0 = Software Owned */
+ if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "TX Descriptor @ 0x%x is owned by software\n",
+ desc_addr);
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU;
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_TX_SUSPENDED_STATE);
+ gmac_update_irq(gmac);
+ return;
+ }
+
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_TX_RUNNING_READ_STATE);
+ /* Give the descriptor back regardless of what happens. */
+ tx_desc.tdes0 &= ~TX_DESC_TDES0_OWN;
+
+ if (tx_desc.tdes1 & TX_DESC_TDES1_FIRST_SEG_MASK) {
+ csum = gmac_tx_get_csum(tx_desc.tdes1);
+ }
+
+ /* step 4 */
+ tx_buf_addr = tx_desc.tdes2;
+ gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr;
+ tx_buf_len = TX_DESC_TDES1_BFFR1_SZ_MASK(tx_desc.tdes1);
+ buf = &tx_send_buffer[prev_buf_size];
+
+ if ((prev_buf_size + tx_buf_len) > sizeof(buf)) {
+ tx_buffer_size = prev_buf_size + tx_buf_len;
+ tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size);
+ buf = &tx_send_buffer[prev_buf_size];
+ }
+
+ /* step 5 */
+ if (dma_memory_read(&address_space_memory, tx_buf_addr, buf,
+ tx_buf_len, MEMTXATTRS_UNSPECIFIED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n",
+ __func__, tx_buf_addr);
+ return;
+ }
+ length += tx_buf_len;
+ prev_buf_size += tx_buf_len;
+
+ /* If not chained we'll have a second buffer. */
+ if (!(tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK)) {
+ tx_buf_addr = tx_desc.tdes3;
+ gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr;
+ tx_buf_len = TX_DESC_TDES1_BFFR2_SZ_MASK(tx_desc.tdes1);
+ buf = &tx_send_buffer[prev_buf_size];
+
+ if ((prev_buf_size + tx_buf_len) > sizeof(buf)) {
+ tx_buffer_size = prev_buf_size + tx_buf_len;
+ tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size);
+ buf = &tx_send_buffer[prev_buf_size];
+ }
+
+ if (dma_memory_read(&address_space_memory, tx_buf_addr, buf,
+ tx_buf_len, MEMTXATTRS_UNSPECIFIED)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Failed to read packet @ 0x%x\n",
+ __func__, tx_buf_addr);
+ return;
+ }
+ length += tx_buf_len;
+ prev_buf_size += tx_buf_len;
+ }
+ if (tx_desc.tdes1 & TX_DESC_TDES1_LAST_SEG_MASK) {
+ net_checksum_calculate(tx_send_buffer, length, csum);
+ qemu_send_packet(qemu_get_queue(gmac->nic), tx_send_buffer, length);
+ trace_npcm_gmac_packet_sent(DEVICE(gmac)->canonical_path, length);
+ buf = tx_send_buffer;
+ length = 0;
+ }
+
+ /* step 6 */
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_TX_RUNNING_CLOSING_STATE);
+ gmac_write_tx_desc(desc_addr, &tx_desc);
+ if (tx_desc.tdes1 & TX_DESC_TDES1_TX_END_RING_MASK) {
+ desc_addr = gmac->regs[R_NPCM_DMA_TX_BASE_ADDR];
+ } else if (tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK) {
+ desc_addr = tx_desc.tdes3;
+ } else {
+ desc_addr += sizeof(tx_desc);
+ }
+ gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = desc_addr;
+
+ /* step 7 */
+ if (tx_desc.tdes1 & TX_DESC_TDES1_INTERR_COMP_MASK) {
+ gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TI;
+ gmac_update_irq(gmac);
+ }
+ }
+}
+
+static void gmac_cleanup(NetClientState *nc)
+{
+ /* Nothing to do yet. */
+}
+
+static void gmac_set_link(NetClientState *nc)
+{
+ NPCMGMACState *gmac = qemu_get_nic_opaque(nc);
+
+ trace_npcm_gmac_set_link(!nc->link_down);
+ gmac_phy_set_link(gmac, !nc->link_down);
+}
+
+static void npcm_gmac_mdio_access(NPCMGMACState *gmac, uint16_t v)
+{
+ bool busy = v & NPCM_GMAC_MII_ADDR_BUSY;
+ uint8_t is_write;
+ uint8_t pa, gr;
+ uint16_t data;
+
+ if (busy) {
+ is_write = v & NPCM_GMAC_MII_ADDR_WRITE;
+ pa = NPCM_GMAC_MII_ADDR_PA(v);
+ gr = NPCM_GMAC_MII_ADDR_GR(v);
+ /* Both pa and gr are 5 bits, so they are less than 32. */
+ g_assert(pa < NPCM_GMAC_MAX_PHYS);
+ g_assert(gr < NPCM_GMAC_MAX_PHY_REGS);
+
+
+ if (v & NPCM_GMAC_MII_ADDR_WRITE) {
+ data = gmac->regs[R_NPCM_GMAC_MII_DATA];
+ /* Clear reset bit for BMCR register */
+ switch (gr) {
+ case MII_BMCR:
+ data &= ~MII_BMCR_RESET;
+ /* Autonegotiation is a W1C bit*/
+ if (data & MII_BMCR_ANRESTART) {
+ /* Tells autonegotiation to not restart again */
+ data &= ~MII_BMCR_ANRESTART;
+ }
+ if ((data & MII_BMCR_AUTOEN) &&
+ !(gmac->phy_regs[pa][MII_BMSR] & MII_BMSR_AN_COMP)) {
+ /* sets autonegotiation as complete */
+ gmac->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP;
+ /* Resolve AN automatically->need to set this */
+ gmac->phy_regs[0][MII_ANLPAR] = 0x0000;
+ }
+ }
+ gmac->phy_regs[pa][gr] = data;
+ } else {
+ data = gmac->phy_regs[pa][gr];
+ gmac->regs[R_NPCM_GMAC_MII_DATA] = data;
+ }
+ trace_npcm_gmac_mdio_access(DEVICE(gmac)->canonical_path, is_write, pa,
+ gr, data);
+ }
+ gmac->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY;
+}
+
+static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size)
+{
+ NPCMGMACState *gmac = opaque;
+ uint32_t v = 0;
+
+ switch (offset) {
+ /* Write only registers */
+ case A_NPCM_DMA_XMT_POLL_DEMAND:
+ case A_NPCM_DMA_RCV_POLL_DEMAND:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Read of write-only reg: offset: 0x%04" HWADDR_PRIx
+ "\n", DEVICE(gmac)->canonical_path, offset);
+ break;
+
+ default:
+ v = gmac->regs[offset / sizeof(uint32_t)];
+ }
+
+ trace_npcm_gmac_reg_read(DEVICE(gmac)->canonical_path, offset, v);
+ return v;
+}
+
+static void npcm_gmac_write(void *opaque, hwaddr offset,
+ uint64_t v, unsigned size)
+{
+ NPCMGMACState *gmac = opaque;
+
+ trace_npcm_gmac_reg_write(DEVICE(gmac)->canonical_path, offset, v);
+
+ switch (offset) {
+ /* Read only registers */
+ case A_NPCM_GMAC_VERSION:
+ case A_NPCM_GMAC_INT_STATUS:
+ case A_NPCM_GMAC_RGMII_STATUS:
+ case A_NPCM_GMAC_PTP_STSR:
+ case A_NPCM_GMAC_PTP_STNSR:
+ case A_NPCM_DMA_MISSED_FRAME_CTR:
+ case A_NPCM_DMA_HOST_TX_DESC:
+ case A_NPCM_DMA_HOST_RX_DESC:
+ case A_NPCM_DMA_CUR_TX_BUF_ADDR:
+ case A_NPCM_DMA_CUR_RX_BUF_ADDR:
+ case A_NPCM_DMA_HW_FEATURE:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Write of read-only reg: offset: 0x%04" HWADDR_PRIx
+ ", value: 0x%04" PRIx64 "\n",
+ DEVICE(gmac)->canonical_path, offset, v);
+ break;
+
+ case A_NPCM_GMAC_MAC_CONFIG:
+ gmac->regs[offset / sizeof(uint32_t)] = v;
+ break;
+
+ case A_NPCM_GMAC_MII_ADDR:
+ npcm_gmac_mdio_access(gmac, v);
+ break;
+
+ case A_NPCM_GMAC_MAC0_ADDR_HI:
+ gmac->regs[offset / sizeof(uint32_t)] = v;
+ gmac->conf.macaddr.a[0] = v >> 8;
+ gmac->conf.macaddr.a[1] = v >> 0;
+ break;
+
+ case A_NPCM_GMAC_MAC0_ADDR_LO:
+ gmac->regs[offset / sizeof(uint32_t)] = v;
+ gmac->conf.macaddr.a[2] = v >> 24;
+ gmac->conf.macaddr.a[3] = v >> 16;
+ gmac->conf.macaddr.a[4] = v >> 8;
+ gmac->conf.macaddr.a[5] = v >> 0;
+ break;
+
+ case A_NPCM_GMAC_MAC1_ADDR_HI:
+ case A_NPCM_GMAC_MAC1_ADDR_LO:
+ case A_NPCM_GMAC_MAC2_ADDR_HI:
+ case A_NPCM_GMAC_MAC2_ADDR_LO:
+ case A_NPCM_GMAC_MAC3_ADDR_HI:
+ case A_NPCM_GMAC_MAC3_ADDR_LO:
+ gmac->regs[offset / sizeof(uint32_t)] = v;
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Only MAC Address 0 is supported. This request "
+ "is ignored.\n", DEVICE(gmac)->canonical_path);
+ break;
+
+ case A_NPCM_DMA_BUS_MODE:
+ gmac->regs[offset / sizeof(uint32_t)] = v;
+ if (v & NPCM_DMA_BUS_MODE_SWR) {
+ npcm_gmac_soft_reset(gmac);
+ }
+ break;
+
+ case A_NPCM_DMA_RCV_POLL_DEMAND:
+ /* We dont actually care about the value */
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
+ break;
+
+ case A_NPCM_DMA_XMT_POLL_DEMAND:
+ /* We dont actually care about the value */
+ gmac_try_send_next_packet(gmac);
+ break;
+
+ case A_NPCM_DMA_CONTROL:
+ gmac->regs[offset / sizeof(uint32_t)] = v;
+ if (v & NPCM_DMA_CONTROL_START_STOP_TX) {
+ gmac_try_send_next_packet(gmac);
+ } else {
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_TX_STOPPED_STATE);
+ }
+ if (v & NPCM_DMA_CONTROL_START_STOP_RX) {
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
+ qemu_flush_queued_packets(qemu_get_queue(gmac->nic));
+ } else {
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_STOPPED_STATE);
+ }
+ break;
+
+ case A_NPCM_DMA_STATUS:
+ /* Check that RO bits are not written to */
+ if (NPCM_DMA_STATUS_RO_MASK(v)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Write of read-only bits of reg: offset: 0x%04"
+ HWADDR_PRIx ", value: 0x%04" PRIx64 "\n",
+ DEVICE(gmac)->canonical_path, offset, v);
+ }
+ /* for W1C bits, implement W1C */
+ gmac->regs[offset / sizeof(uint32_t)] &= ~NPCM_DMA_STATUS_W1C_MASK(v);
+ if (v & NPCM_DMA_STATUS_RU) {
+ /* Clearing RU bit indicates descriptor is owned by DMA again. */
+ gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
+ NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
+ qemu_flush_queued_packets(qemu_get_queue(gmac->nic));
+ }
+ break;
+
+ default:
+ gmac->regs[offset / sizeof(uint32_t)] = v;
+ break;
+ }
+
+ gmac_update_irq(gmac);
+}
+
+static void npcm_gmac_reset(DeviceState *dev)
+{
+ NPCMGMACState *gmac = NPCM_GMAC(dev);
+
+ npcm_gmac_soft_reset(gmac);
+ memcpy(gmac->phy_regs[0], phy_reg_init, sizeof(phy_reg_init));
+
+ trace_npcm_gmac_reset(DEVICE(gmac)->canonical_path,
+ gmac->phy_regs[0][MII_BMSR]);
+}
+
+static NetClientInfo net_npcm_gmac_info = {
+ .type = NET_CLIENT_DRIVER_NIC,
+ .size = sizeof(NICState),
+ .can_receive = gmac_can_receive,
+ .receive = gmac_receive,
+ .cleanup = gmac_cleanup,
+ .link_status_changed = gmac_set_link,
+};
+
+static const struct MemoryRegionOps npcm_gmac_ops = {
+ .read = npcm_gmac_read,
+ .write = npcm_gmac_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void npcm_gmac_realize(DeviceState *dev, Error **errp)
+{
+ NPCMGMACState *gmac = NPCM_GMAC(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&gmac->iomem, OBJECT(gmac), &npcm_gmac_ops, gmac,
+ TYPE_NPCM_GMAC, 8 * KiB);
+ sysbus_init_mmio(sbd, &gmac->iomem);
+ sysbus_init_irq(sbd, &gmac->irq);
+
+ qemu_macaddr_default_if_unset(&gmac->conf.macaddr);
+
+ gmac->nic = qemu_new_nic(&net_npcm_gmac_info, &gmac->conf, TYPE_NPCM_GMAC,
+ dev->id, &dev->mem_reentrancy_guard, gmac);
+ qemu_format_nic_info_str(qemu_get_queue(gmac->nic), gmac->conf.macaddr.a);
+ gmac->regs[R_NPCM_GMAC_MAC0_ADDR_HI] = (gmac->conf.macaddr.a[0] << 8) + \
+ gmac->conf.macaddr.a[1];
+ gmac->regs[R_NPCM_GMAC_MAC0_ADDR_LO] = (gmac->conf.macaddr.a[2] << 24) + \
+ (gmac->conf.macaddr.a[3] << 16) + \
+ (gmac->conf.macaddr.a[4] << 8) + \
+ gmac->conf.macaddr.a[5];
+}
+
+static void npcm_gmac_unrealize(DeviceState *dev)
+{
+ NPCMGMACState *gmac = NPCM_GMAC(dev);
+
+ qemu_del_nic(gmac->nic);
+}
+
+static const VMStateDescription vmstate_npcm_gmac = {
+ .name = TYPE_NPCM_GMAC,
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, NPCMGMACState, NPCM_GMAC_NR_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static Property npcm_gmac_properties[] = {
+ DEFINE_NIC_PROPERTIES(NPCMGMACState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void npcm_gmac_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+ dc->desc = "NPCM GMAC Controller";
+ dc->realize = npcm_gmac_realize;
+ dc->unrealize = npcm_gmac_unrealize;
+ dc->reset = npcm_gmac_reset;
+ dc->vmsd = &vmstate_npcm_gmac;
+ device_class_set_props(dc, npcm_gmac_properties);
+}
+
+static const TypeInfo npcm_gmac_types[] = {
+ {
+ .name = TYPE_NPCM_GMAC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMGMACState),
+ .class_init = npcm_gmac_class_init,
+ },
+};
+DEFINE_TYPES(npcm_gmac_types)
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 387e32e..78efa2e 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -467,6 +467,25 @@ npcm7xx_emc_rx_done(uint32_t crxdsa) "RX done, CRXDSA=0x%x"
npcm7xx_emc_reg_read(int emc_num, uint32_t result, const char *name, int regno) "emc%d: 0x%x = reg[%s/%d]"
npcm7xx_emc_reg_write(int emc_num, const char *name, int regno, uint32_t value) "emc%d: reg[%s/%d] = 0x%x"
+# npcm_gmac.c
+npcm_gmac_reg_read(const char *name, uint64_t offset, uint32_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx32
+npcm_gmac_reg_write(const char *name, uint64_t offset, uint32_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx32
+npcm_gmac_mdio_access(const char *name, uint8_t is_write, uint8_t pa, uint8_t gr, uint16_t val) "%s: is_write: %" PRIu8 " pa: %" PRIu8 " gr: %" PRIu8 " val: 0x%04" PRIx16
+npcm_gmac_reset(const char *name, uint16_t value) "%s: phy_regs[0][1]: 0x%04" PRIx16
+npcm_gmac_set_link(bool active) "Set link: active=%u"
+npcm_gmac_update_irq(const char *name, uint32_t status, uint32_t intr_en, int level) "%s: Status Reg: 0x%04" PRIX32 " Interrupt Enable Reg: 0x%04" PRIX32 " IRQ Set: %d"
+npcm_gmac_packet_desc_read(const char* name, uint32_t desc_addr) "%s: attempting to read descriptor @0x%04" PRIX32
+npcm_gmac_packet_receive(const char* name, uint32_t len) "%s: RX packet length: 0x%04" PRIX32
+npcm_gmac_packet_receiving_buffer(const char* name, uint32_t buf_len, uint32_t rx_buf_addr) "%s: Receiving into Buffer size: 0x%04" PRIX32 " at address 0x%04" PRIX32
+npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finished, packet left: 0x%04" PRIX32
+npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16
+npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32
+npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
+
+# npcm_pcs.c
+npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
+npcm_pcs_reg_write(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
+
# dp8398x.c
dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x"
dp8393x_lower_irq(void) "lower irq"
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
index dd9e389..c25d50f 100644
--- a/hw/pci-host/designware.c
+++ b/hw/pci-host/designware.c
@@ -340,6 +340,8 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
break;
case DESIGNWARE_PCIE_ATU_VIEWPORT:
+ val &= DESIGNWARE_PCIE_ATU_REGION_INBOUND |
+ (DESIGNWARE_PCIE_NUM_VIEWPORTS - 1);
root->atu_viewport = val;
break;
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 449abfb..6496d02 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -64,7 +64,7 @@ bool pci_available = true;
static char *pcibus_get_dev_path(DeviceState *dev);
static char *pcibus_get_fw_dev_path(DeviceState *dev);
-static void pcibus_reset(BusState *qbus);
+static void pcibus_reset_hold(Object *obj);
static bool pcie_has_upstream_port(PCIDevice *dev);
static Property pci_props[] = {
@@ -202,13 +202,15 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
PCIBusClass *pbc = PCI_BUS_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
k->print_dev = pcibus_dev_print;
k->get_dev_path = pcibus_get_dev_path;
k->get_fw_dev_path = pcibus_get_fw_dev_path;
k->realize = pci_bus_realize;
k->unrealize = pci_bus_unrealize;
- k->reset = pcibus_reset;
+
+ rc->phases.hold = pcibus_reset_hold;
pbc->bus_num = pcibus_num;
pbc->numa_node = pcibus_numa_node;
@@ -424,9 +426,9 @@ void pci_device_reset(PCIDevice *dev)
* Called via bus_cold_reset on RST# assert, after the devices
* have been reset device_cold_reset-ed already.
*/
-static void pcibus_reset(BusState *qbus)
+static void pcibus_reset_hold(Object *obj)
{
- PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
+ PCIBus *bus = PCI_BUS(obj);
int i;
for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 15d26ef..34639f2 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev,
qdev_unrealize(dev);
}
-static void virtual_css_bus_reset(BusState *qbus)
+static void virtual_css_bus_reset_hold(Object *obj)
{
/* This should actually be modelled via the generic css */
css_reset();
@@ -81,8 +81,9 @@ static char *virtual_css_bus_get_dev_path(DeviceState *dev)
static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
- k->reset = virtual_css_bus_reset;
+ rc->phases.hold = virtual_css_bus_reset_hold;
k->get_dev_path = virtual_css_bus_get_dev_path;
}
diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig
index 7d90a02..83ee53c 100644
--- a/hw/ssi/Kconfig
+++ b/hw/ssi/Kconfig
@@ -20,3 +20,7 @@ config XILINX_SPIPS
config STM32F2XX_SPI
bool
select SSI
+
+config BCM2835_SPI
+ bool
+ select SSI
diff --git a/hw/ssi/bcm2835_spi.c b/hw/ssi/bcm2835_spi.c
new file mode 100644
index 0000000..6ecb42d
--- /dev/null
+++ b/hw/ssi/bcm2835_spi.c
@@ -0,0 +1,288 @@
+/*
+ * BCM2835 SPI Master Controller
+ *
+ * Copyright (c) 2024 Rayhan Faizel <rayhan.faizel@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/fifo8.h"
+#include "hw/ssi/bcm2835_spi.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+
+static void bcm2835_spi_update_int(BCM2835SPIState *s)
+{
+ int do_interrupt = 0;
+
+ /* Interrupt on DONE */
+ if (s->cs & BCM2835_SPI_CS_INTD && s->cs & BCM2835_SPI_CS_DONE) {
+ do_interrupt = 1;
+ }
+ /* Interrupt on RXR */
+ if (s->cs & BCM2835_SPI_CS_INTR && s->cs & BCM2835_SPI_CS_RXR) {
+ do_interrupt = 1;
+ }
+ qemu_set_irq(s->irq, do_interrupt);
+}
+
+static void bcm2835_spi_update_rx_flags(BCM2835SPIState *s)
+{
+ /* Set RXD if RX FIFO is non empty */
+ if (!fifo8_is_empty(&s->rx_fifo)) {
+ s->cs |= BCM2835_SPI_CS_RXD;
+ } else {
+ s->cs &= ~BCM2835_SPI_CS_RXD;
+ }
+
+ /* Set RXF if RX FIFO is full */
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->cs |= BCM2835_SPI_CS_RXF;
+ } else {
+ s->cs &= ~BCM2835_SPI_CS_RXF;
+ }
+
+ /* Set RXR if RX FIFO is 3/4th used or above */
+ if (fifo8_num_used(&s->rx_fifo) >= FIFO_SIZE_3_4) {
+ s->cs |= BCM2835_SPI_CS_RXR;
+ } else {
+ s->cs &= ~BCM2835_SPI_CS_RXR;
+ }
+}
+
+static void bcm2835_spi_update_tx_flags(BCM2835SPIState *s)
+{
+ /* Set TXD if TX FIFO is not full */
+ if (fifo8_is_full(&s->tx_fifo)) {
+ s->cs &= ~BCM2835_SPI_CS_TXD;
+ } else {
+ s->cs |= BCM2835_SPI_CS_TXD;
+ }
+
+ /* Set DONE if in TA mode and TX FIFO is empty */
+ if (fifo8_is_empty(&s->tx_fifo) && s->cs & BCM2835_SPI_CS_TA) {
+ s->cs |= BCM2835_SPI_CS_DONE;
+ } else {
+ s->cs &= ~BCM2835_SPI_CS_DONE;
+ }
+}
+
+static void bcm2835_spi_flush_tx_fifo(BCM2835SPIState *s)
+{
+ uint8_t tx_byte, rx_byte;
+
+ while (!fifo8_is_empty(&s->tx_fifo) && !fifo8_is_full(&s->rx_fifo)) {
+ tx_byte = fifo8_pop(&s->tx_fifo);
+ rx_byte = ssi_transfer(s->bus, tx_byte);
+ fifo8_push(&s->rx_fifo, rx_byte);
+ }
+
+ bcm2835_spi_update_tx_flags(s);
+ bcm2835_spi_update_rx_flags(s);
+}
+
+static uint64_t bcm2835_spi_read(void *opaque, hwaddr addr, unsigned size)
+{
+ BCM2835SPIState *s = opaque;
+ uint32_t readval = 0;
+
+ switch (addr) {
+ case BCM2835_SPI_CS:
+ readval = s->cs & 0xffffffff;
+ break;
+ case BCM2835_SPI_FIFO:
+ bcm2835_spi_flush_tx_fifo(s);
+ if (s->cs & BCM2835_SPI_CS_RXD) {
+ readval = fifo8_pop(&s->rx_fifo);
+ bcm2835_spi_update_rx_flags(s);
+ }
+
+ bcm2835_spi_update_int(s);
+ break;
+ case BCM2835_SPI_CLK:
+ readval = s->clk & 0xffff;
+ break;
+ case BCM2835_SPI_DLEN:
+ readval = s->dlen & 0xffff;
+ break;
+ case BCM2835_SPI_LTOH:
+ readval = s->ltoh & 0xf;
+ break;
+ case BCM2835_SPI_DC:
+ readval = s->dc & 0xffffffff;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
+ }
+ return readval;
+}
+
+static void bcm2835_spi_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned int size)
+{
+ BCM2835SPIState *s = opaque;
+
+ switch (addr) {
+ case BCM2835_SPI_CS:
+ s->cs = (value & ~RO_MASK) | (s->cs & RO_MASK);
+ if (!(s->cs & BCM2835_SPI_CS_TA)) {
+ /* Clear DONE and RXR if TA is off */
+ s->cs &= ~(BCM2835_SPI_CS_DONE);
+ s->cs &= ~(BCM2835_SPI_CS_RXR);
+ }
+
+ /* Clear RX FIFO */
+ if (s->cs & BCM2835_SPI_CLEAR_RX) {
+ fifo8_reset(&s->rx_fifo);
+ bcm2835_spi_update_rx_flags(s);
+ }
+
+ /* Clear TX FIFO*/
+ if (s->cs & BCM2835_SPI_CLEAR_TX) {
+ fifo8_reset(&s->tx_fifo);
+ bcm2835_spi_update_tx_flags(s);
+ }
+
+ /* Set Transfer Active */
+ if (s->cs & BCM2835_SPI_CS_TA) {
+ bcm2835_spi_update_tx_flags(s);
+ }
+
+ if (s->cs & BCM2835_SPI_CS_DMAEN) {
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "DMA not supported\n", __func__);
+ }
+
+ if (s->cs & BCM2835_SPI_CS_LEN) {
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "LoSSI not supported\n", __func__);
+ }
+
+ bcm2835_spi_update_int(s);
+ break;
+ case BCM2835_SPI_FIFO:
+ /*
+ * According to documentation, writes to FIFO without TA controls
+ * CS and DLEN registers. This is supposed to be used in DMA mode
+ * which is currently unimplemented. Moreover, Linux does not make
+ * use of this and directly modifies the CS and DLEN registers.
+ */
+ if (s->cs & BCM2835_SPI_CS_TA) {
+ if (s->cs & BCM2835_SPI_CS_TXD) {
+ fifo8_push(&s->tx_fifo, value & 0xff);
+ bcm2835_spi_update_tx_flags(s);
+ }
+
+ bcm2835_spi_flush_tx_fifo(s);
+ bcm2835_spi_update_int(s);
+ }
+ break;
+ case BCM2835_SPI_CLK:
+ s->clk = value & 0xffff;
+ break;
+ case BCM2835_SPI_DLEN:
+ s->dlen = value & 0xffff;
+ break;
+ case BCM2835_SPI_LTOH:
+ s->ltoh = value & 0xf;
+ break;
+ case BCM2835_SPI_DC:
+ s->dc = value & 0xffffffff;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps bcm2835_spi_ops = {
+ .read = bcm2835_spi_read,
+ .write = bcm2835_spi_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void bcm2835_spi_realize(DeviceState *dev, Error **errp)
+{
+ BCM2835SPIState *s = BCM2835_SPI(dev);
+ s->bus = ssi_create_bus(dev, "spi");
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_spi_ops, s,
+ TYPE_BCM2835_SPI, 0x18);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+
+ fifo8_create(&s->tx_fifo, FIFO_SIZE);
+ fifo8_create(&s->rx_fifo, FIFO_SIZE);
+}
+static void bcm2835_spi_reset(DeviceState *dev)
+{
+ BCM2835SPIState *s = BCM2835_SPI(dev);
+
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
+
+ /* Reset values according to BCM2835 Peripheral Documentation */
+ s->cs = BCM2835_SPI_CS_TXD | BCM2835_SPI_CS_REN;
+ s->clk = 0;
+ s->dlen = 0;
+ s->ltoh = 0x1;
+ s->dc = 0x30201020;
+}
+
+static const VMStateDescription vmstate_bcm2835_spi = {
+ .name = TYPE_BCM2835_SPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_FIFO8(tx_fifo, BCM2835SPIState),
+ VMSTATE_FIFO8(rx_fifo, BCM2835SPIState),
+ VMSTATE_UINT32(cs, BCM2835SPIState),
+ VMSTATE_UINT32(clk, BCM2835SPIState),
+ VMSTATE_UINT32(dlen, BCM2835SPIState),
+ VMSTATE_UINT32(ltoh, BCM2835SPIState),
+ VMSTATE_UINT32(dc, BCM2835SPIState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void bcm2835_spi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = bcm2835_spi_reset;
+ dc->realize = bcm2835_spi_realize;
+ dc->vmsd = &vmstate_bcm2835_spi;
+}
+
+static const TypeInfo bcm2835_spi_info = {
+ .name = TYPE_BCM2835_SPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BCM2835SPIState),
+ .class_init = bcm2835_spi_class_init,
+};
+
+static void bcm2835_spi_register_types(void)
+{
+ type_register_static(&bcm2835_spi_info);
+}
+
+type_init(bcm2835_spi_register_types)
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index 0aebcdd6..b999aeb 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -11,3 +11,4 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c'))
+system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c'))
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
index 67a6c41..d1b27f6 100644
--- a/hw/xen/trace-events
+++ b/hw/xen/trace-events
@@ -42,7 +42,7 @@ xs_node_vscanf(char *path, char *value) "%s %s"
xs_node_watch(char *path) "%s"
xs_node_unwatch(char *path) "%s"
-# xen-hvm.c
+# xen-hvm-common.c
xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: 0x%lx, size 0x%lx"
xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "0x%"PRIx64" size 0x%lx, log_dirty %i"
handle_ioreq(void *req, uint32_t type, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p type=%d dir=%d df=%d ptr=%d port=0x%"PRIx64" data=0x%"PRIx64" count=%d size=%d"
@@ -55,8 +55,27 @@ cpu_ioreq_move(void *req, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint6
xen_map_resource_ioreq(uint32_t id, void *addr) "id: %u addr: %p"
cpu_ioreq_config_read(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x"
cpu_ioreq_config_write(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x"
+cpu_get_ioreq_from_shared_memory_req_not_ready(int state, int data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O request not ready: 0x%x, ptr: 0x%x, port: 0x%"PRIx64", data: 0x%"PRIx64", count: %u, size: %u"
+xen_main_loop_prepare_init_cpu(int id, void *cpu) "cpu_by_vcpu_id[%d]=%p"
+xen_map_ioreq_server_shared_page(long unsigned int ioreq_pfn) "shared page at pfn 0x%lx"
+xen_map_ioreq_server_buffered_io_page(long unsigned int ioreq_pfn) "buffered io page at pfn 0x%lx"
+xen_map_ioreq_server_buffered_io_evtchn(int bufioreq_evtchn) "buffered io evtchn is 0x%x"
+destroy_hvm_domain_cannot_acquire_handle(void) "Cannot acquire xenctrl handle"
+destroy_hvm_domain_failed_action(const char *action, int sts, char *errno_s) "xc_domain_shutdown failed to issue %s, sts %d, %s"
+destroy_hvm_domain_action(int xen_domid, const char *action) "Issued domain %d %s"
# xen-mapcache.c
xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64
xen_remap_bucket(uint64_t index) "index 0x%"PRIx64
xen_map_cache_return(void* ptr) "%p"
+xen_map_cache_init(uint64_t nr_buckets, uint64_t size) "nr_buckets = 0x%"PRIx64" size 0x%"PRIx64
+xen_replace_cache_entry_dummy(uint64_t old_phys_addr, uint64_t new_phys_addr) "Replacing a dummy mapcache entry for 0x%"PRIx64" with 0x%"PRIx64
+xen_invalidate_map_cache_entry_unlocked_not_found(void *p) "could not find %p"
+xen_invalidate_map_cache_entry_unlocked_found(uint64_t addr, void *p) " 0x%"PRIx64" -> %p is present"
+xen_invalidate_map_cache_entry_unlocked_miss(void *buffer) "Trying to unmap address %p that is not in the mapcache"
+xen_replace_cache_entry_unlocked_could_not_update_entry(uint64_t old_phys_addr) "Unable to update a mapcache entry for 0x%"PRIx64
+xen_ram_addr_from_mapcache_not_found(void *p) "could not find %p"
+xen_ram_addr_from_mapcache_found(uint64_t addr, void *p) " 0x%"PRIx64" -> %p is present"
+xen_ram_addr_from_mapcache_not_in_cache(void *p) "Trying to find address %p that is not in the mapcache"
+xen_replace_cache_entry_unlocked(uint64_t old_phys_addr) "Trying to update an entry for 0x%"PRIx64" that is not in the mapcache"
+xen_invalidate_map_cache(uint64_t paddr_index, void *vaddr_req) "Locked DMA mapping while invalidating mapcache 0x%"PRIx64" -> %p is present"
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index 47e6cb1..baa1adb 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -20,8 +20,8 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr,
if (runstate_check(RUN_STATE_INMIGRATE)) {
/* RAM already populated in Xen */
- fprintf(stderr, "%s: do not alloc "RAM_ADDR_FMT
- " bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE\n",
+ warn_report("%s: do not alloc "RAM_ADDR_FMT
+ " bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE",
__func__, size, ram_addr);
return;
}
@@ -169,11 +169,12 @@ static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu)
ioreq_t *req = xen_vcpu_ioreq(state->shared_page, vcpu);
if (req->state != STATE_IOREQ_READY) {
- DPRINTF("I/O request not ready: "
- "%x, ptr: %x, port: %"PRIx64", "
- "data: %"PRIx64", count: %u, size: %u\n",
- req->state, req->data_is_ptr, req->addr,
- req->data, req->count, req->size);
+ trace_cpu_get_ioreq_from_shared_memory_req_not_ready(req->state,
+ req->data_is_ptr,
+ req->addr,
+ req->data,
+ req->count,
+ req->size);
return NULL;
}
@@ -551,9 +552,9 @@ static void cpu_handle_ioreq(void *opaque)
req->data = copy.data;
if (req->state != STATE_IOREQ_INPROCESS) {
- fprintf(stderr, "Badness in I/O request ... not in service?!: "
+ warn_report("Badness in I/O request ... not in service?!: "
"%x, ptr: %x, port: %"PRIx64", "
- "data: %"PRIx64", count: %u, size: %u, type: %u\n",
+ "data: %"PRIx64", count: %u, size: %u, type: %u",
req->state, req->data_is_ptr, req->addr,
req->data, req->count, req->size, req->type);
destroy_hvm_domain(false);
@@ -601,10 +602,9 @@ static void xen_main_loop_prepare(XenIOState *state)
if (evtchn_fd != -1) {
CPUState *cpu_state;
- DPRINTF("%s: Init cpu_by_vcpu_id\n", __func__);
CPU_FOREACH(cpu_state) {
- DPRINTF("%s: cpu_by_vcpu_id[%d]=%p\n",
- __func__, cpu_state->cpu_index, cpu_state);
+ trace_xen_main_loop_prepare_init_cpu(cpu_state->cpu_index,
+ cpu_state);
state->cpu_by_vcpu_id[cpu_state->cpu_index] = cpu_state;
}
qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state);
@@ -681,7 +681,7 @@ static int xen_map_ioreq_server(XenIOState *state)
}
if (state->shared_page == NULL) {
- DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
+ trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
PROT_READ | PROT_WRITE,
@@ -693,7 +693,7 @@ static int xen_map_ioreq_server(XenIOState *state)
}
if (state->buffered_io_page == NULL) {
- DPRINTF("buffered io page at pfn %lx\n", bufioreq_pfn);
+ trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
PROT_READ | PROT_WRITE,
@@ -709,7 +709,7 @@ static int xen_map_ioreq_server(XenIOState *state)
return -1;
}
- DPRINTF("buffered io evtchn is %x\n", bufioreq_evtchn);
+ trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
state->bufioreq_remote_port = bufioreq_evtchn;
@@ -737,16 +737,17 @@ void destroy_hvm_domain(bool reboot)
xc_handle = xc_interface_open(0, 0, 0);
if (xc_handle == NULL) {
- fprintf(stderr, "Cannot acquire xenctrl handle\n");
+ trace_destroy_hvm_domain_cannot_acquire_handle();
} else {
sts = xc_domain_shutdown(xc_handle, xen_domid, reason);
if (sts != 0) {
- fprintf(stderr, "xc_domain_shutdown failed to issue %s, "
- "sts %d, %s\n", reboot ? "reboot" : "poweroff",
- sts, strerror(errno));
+ trace_destroy_hvm_domain_failed_action(
+ reboot ? "reboot" : "poweroff", sts, strerror(errno)
+ );
} else {
- fprintf(stderr, "Issued domain %d %s\n", xen_domid,
- reboot ? "reboot" : "poweroff");
+ trace_destroy_hvm_domain_action(
+ xen_domid, reboot ? "reboot" : "poweroff"
+ );
}
xc_interface_close(xc_handle);
}
@@ -757,9 +758,9 @@ void xen_shutdown_fatal_error(const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
+ error_vreport(fmt, ap);
va_end(ap);
- fprintf(stderr, "Will destroy the domain.\n");
+ error_report("Will destroy the domain.");
/* destroy the domain */
qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
}
diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
index f7d9746..4f956d0 100644
--- a/hw/xen/xen-mapcache.c
+++ b/hw/xen/xen-mapcache.c
@@ -22,16 +22,6 @@
#include "trace.h"
-//#define MAPCACHE_DEBUG
-
-#ifdef MAPCACHE_DEBUG
-# define DPRINTF(fmt, ...) do { \
- fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
-} while (0)
-#else
-# define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
#if HOST_LONG_BITS == 32
# define MCACHE_BUCKET_SHIFT 16
# define MCACHE_MAX_SIZE (1UL<<31) /* 2GB Cap */
@@ -145,8 +135,7 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
size = mapcache->nr_buckets * sizeof (MapCacheEntry);
size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
- DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__,
- mapcache->nr_buckets, size);
+ trace_xen_map_cache_init(mapcache->nr_buckets, size);
mapcache->entry = g_malloc0(size);
}
@@ -286,7 +275,9 @@ tryagain:
test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
mapcache->last_entry->valid_mapping)) {
- trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);
+ trace_xen_map_cache_return(
+ mapcache->last_entry->vaddr_base + address_offset
+ );
return mapcache->last_entry->vaddr_base + address_offset;
}
@@ -356,9 +347,8 @@ tryagain:
MapCacheRev *reventry = g_new0(MapCacheRev, 1);
entry->lock++;
if (entry->lock == 0) {
- fprintf(stderr,
- "mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p\n",
- entry->paddr_index, entry->vaddr_base);
+ error_report("mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p",
+ entry->paddr_index, entry->vaddr_base);
abort();
}
reventry->dma = dma;
@@ -368,7 +358,9 @@ tryagain:
QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);
}
- trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);
+ trace_xen_map_cache_return(
+ mapcache->last_entry->vaddr_base + address_offset
+ );
return mapcache->last_entry->vaddr_base + address_offset;
}
@@ -402,10 +394,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
}
}
if (!found) {
- fprintf(stderr, "%s, could not find %p\n", __func__, ptr);
+ trace_xen_ram_addr_from_mapcache_not_found(ptr);
QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
- DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index,
- reventry->vaddr_req);
+ trace_xen_ram_addr_from_mapcache_found(reventry->paddr_index,
+ reventry->vaddr_req);
}
abort();
return 0;
@@ -416,7 +408,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
entry = entry->next;
}
if (!entry) {
- DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr);
+ trace_xen_ram_addr_from_mapcache_not_in_cache(ptr);
raddr = 0;
} else {
raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
@@ -443,9 +435,12 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
}
}
if (!found) {
- DPRINTF("%s, could not find %p\n", __func__, buffer);
+ trace_xen_invalidate_map_cache_entry_unlocked_not_found(buffer);
QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
- DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+ trace_xen_invalidate_map_cache_entry_unlocked_found(
+ reventry->paddr_index,
+ reventry->vaddr_req
+ );
}
return;
}
@@ -463,7 +458,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
entry = entry->next;
}
if (!entry) {
- DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer);
+ trace_xen_invalidate_map_cache_entry_unlocked_miss(buffer);
return;
}
entry->lock--;
@@ -502,9 +497,8 @@ void xen_invalidate_map_cache(void)
if (!reventry->dma) {
continue;
}
- fprintf(stderr, "Locked DMA mapping while invalidating mapcache!"
- " "HWADDR_FMT_plx" -> %p is present\n",
- reventry->paddr_index, reventry->vaddr_req);
+ trace_xen_invalidate_map_cache(reventry->paddr_index,
+ reventry->vaddr_req);
}
for (i = 0; i < mapcache->nr_buckets; i++) {
@@ -562,24 +556,23 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr,
entry = entry->next;
}
if (!entry) {
- DPRINTF("Trying to update an entry for "HWADDR_FMT_plx \
- "that is not in the mapcache!\n", old_phys_addr);
+ trace_xen_replace_cache_entry_unlocked(old_phys_addr);
return NULL;
}
address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT;
address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1);
- fprintf(stderr, "Replacing a dummy mapcache entry for "HWADDR_FMT_plx \
- " with "HWADDR_FMT_plx"\n", old_phys_addr, new_phys_addr);
+ trace_xen_replace_cache_entry_dummy(old_phys_addr, new_phys_addr);
xen_remap_bucket(entry, entry->vaddr_base,
cache_size, address_index, false);
if (!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
- DPRINTF("Unable to update a mapcache entry for "HWADDR_FMT_plx"!\n",
- old_phys_addr);
+ trace_xen_replace_cache_entry_unlocked_could_not_update_entry(
+ old_phys_addr
+ );
return NULL;
}
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
index d724a2f..0203bb7 100644
--- a/include/hw/arm/bcm2835_peripherals.h
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -31,6 +31,7 @@
#include "hw/gpio/bcm2835_gpio.h"
#include "hw/timer/bcm2835_systmr.h"
#include "hw/usb/hcd-dwc2.h"
+#include "hw/ssi/bcm2835_spi.h"
#include "hw/misc/unimp.h"
#include "qom/object.h"
@@ -66,7 +67,7 @@ struct BCM2835PeripheralState {
BCM2835GpioState gpio;
Bcm2835ThermalState thermal;
UnimplementedDeviceState i2s;
- UnimplementedDeviceState spi[1];
+ BCM2835SPIState spi[1];
UnimplementedDeviceState i2c[3];
UnimplementedDeviceState otp;
UnimplementedDeviceState dbus;
diff --git a/include/hw/arm/msf2-soc.h b/include/hw/arm/msf2-soc.h
index ce417a6..9300664 100644
--- a/include/hw/arm/msf2-soc.h
+++ b/include/hw/arm/msf2-soc.h
@@ -47,13 +47,10 @@ OBJECT_DECLARE_SIMPLE_TYPE(MSF2State, MSF2_SOC)
#define MSF2_NUM_TIMERS 2
struct MSF2State {
- /*< private >*/
SysBusDevice parent_obj;
- /*< public >*/
ARMv7MState armv7m;
- char *cpu_type;
char *part_name;
uint64_t envm_size;
uint64_t esram_size;
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
index 72c7722..4e0d210 100644
--- a/include/hw/arm/npcm7xx.h
+++ b/include/hw/arm/npcm7xx.h
@@ -29,6 +29,7 @@
#include "hw/misc/npcm7xx_pwm.h"
#include "hw/misc/npcm7xx_rng.h"
#include "hw/net/npcm7xx_emc.h"
+#include "hw/net/npcm_gmac.h"
#include "hw/nvram/npcm7xx_otp.h"
#include "hw/timer/npcm7xx_timer.h"
#include "hw/ssi/npcm7xx_fiu.h"
@@ -104,6 +105,7 @@ struct NPCM7xxState {
OHCISysBusState ohci;
NPCM7xxFIUState fiu[2];
NPCM7xxEMCState emc[2];
+ NPCMGMACState gmac[2];
NPCM7xxSDHCIState mmc;
NPCMPSPIState pspi[2];
};
diff --git a/include/hw/net/npcm_gmac.h b/include/hw/net/npcm_gmac.h
new file mode 100644
index 0000000..f2d9f08
--- /dev/null
+++ b/include/hw/net/npcm_gmac.h
@@ -0,0 +1,343 @@
+/*
+ * Nuvoton NPCM7xx/8xx GMAC Module
+ *
+ * Copyright 2024 Google LLC
+ * Authors:
+ * Hao Wu <wuhaotsh@google.com>
+ * Nabih Estefan <nabihestefan@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef NPCM_GMAC_H
+#define NPCM_GMAC_H
+
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+
+#define NPCM_GMAC_NR_REGS (0x1060 / sizeof(uint32_t))
+
+#define NPCM_GMAC_MAX_PHYS 32
+#define NPCM_GMAC_MAX_PHY_REGS 32
+
+struct NPCMGMACRxDesc {
+ uint32_t rdes0;
+ uint32_t rdes1;
+ uint32_t rdes2;
+ uint32_t rdes3;
+};
+
+/* NPCMGMACRxDesc.flags values */
+/* RDES2 and RDES3 are buffer addresses */
+/* Owner: 0 = software, 1 = dma */
+#define RX_DESC_RDES0_OWN BIT(31)
+/* Destination Address Filter Fail */
+#define RX_DESC_RDES0_DEST_ADDR_FILT_FAIL BIT(30)
+/* Frame length */
+#define RX_DESC_RDES0_FRAME_LEN_MASK(word) extract32(word, 16, 14)
+/* Frame length Shift*/
+#define RX_DESC_RDES0_FRAME_LEN_SHIFT 16
+/* Error Summary */
+#define RX_DESC_RDES0_ERR_SUMM_MASK BIT(15)
+/* Descriptor Error */
+#define RX_DESC_RDES0_DESC_ERR_MASK BIT(14)
+/* Source Address Filter Fail */
+#define RX_DESC_RDES0_SRC_ADDR_FILT_FAIL_MASK BIT(13)
+/* Length Error */
+#define RX_DESC_RDES0_LEN_ERR_MASK BIT(12)
+/* Overflow Error */
+#define RX_DESC_RDES0_OVRFLW_ERR_MASK BIT(11)
+/* VLAN Tag */
+#define RX_DESC_RDES0_VLAN_TAG_MASK BIT(10)
+/* First Descriptor */
+#define RX_DESC_RDES0_FIRST_DESC_MASK BIT(9)
+/* Last Descriptor */
+#define RX_DESC_RDES0_LAST_DESC_MASK BIT(8)
+/* IPC Checksum Error/Giant Frame */
+#define RX_DESC_RDES0_IPC_CHKSM_ERR_GNT_FRM_MASK BIT(7)
+/* Late Collision */
+#define RX_DESC_RDES0_LT_COLL_MASK BIT(6)
+/* Frame Type */
+#define RX_DESC_RDES0_FRM_TYPE_MASK BIT(5)
+/* Receive Watchdog Timeout */
+#define RX_DESC_RDES0_REC_WTCHDG_TMT_MASK BIT(4)
+/* Receive Error */
+#define RX_DESC_RDES0_RCV_ERR_MASK BIT(3)
+/* Dribble Bit Error */
+#define RX_DESC_RDES0_DRBL_BIT_ERR_MASK BIT(2)
+/* Cyclcic Redundancy Check Error */
+#define RX_DESC_RDES0_CRC_ERR_MASK BIT(1)
+/* Rx MAC Address/Payload Checksum Error */
+#define RC_DESC_RDES0_RCE_MASK BIT(0)
+
+/* Disable Interrupt on Completion */
+#define RX_DESC_RDES1_DIS_INTR_COMP_MASK BIT(31)
+/* Recieve end of ring */
+#define RX_DESC_RDES1_RC_END_RING_MASK BIT(25)
+/* Second Address Chained */
+#define RX_DESC_RDES1_SEC_ADDR_CHND_MASK BIT(24)
+/* Receive Buffer 2 Size */
+#define RX_DESC_RDES1_BFFR2_SZ_SHIFT 11
+#define RX_DESC_RDES1_BFFR2_SZ_MASK(word) extract32(word, \
+ RX_DESC_RDES1_BFFR2_SZ_SHIFT, 11)
+/* Receive Buffer 1 Size */
+#define RX_DESC_RDES1_BFFR1_SZ_MASK(word) extract32(word, 0, 11)
+
+
+struct NPCMGMACTxDesc {
+ uint32_t tdes0;
+ uint32_t tdes1;
+ uint32_t tdes2;
+ uint32_t tdes3;
+};
+
+/* NPCMGMACTxDesc.flags values */
+/* TDES2 and TDES3 are buffer addresses */
+/* Owner: 0 = software, 1 = gmac */
+#define TX_DESC_TDES0_OWN BIT(31)
+/* Tx Time Stamp Status */
+#define TX_DESC_TDES0_TTSS_MASK BIT(17)
+/* IP Header Error */
+#define TX_DESC_TDES0_IP_HEAD_ERR_MASK BIT(16)
+/* Error Summary */
+#define TX_DESC_TDES0_ERR_SUMM_MASK BIT(15)
+/* Jabber Timeout */
+#define TX_DESC_TDES0_JBBR_TMT_MASK BIT(14)
+/* Frame Flushed */
+#define TX_DESC_TDES0_FRM_FLSHD_MASK BIT(13)
+/* Payload Checksum Error */
+#define TX_DESC_TDES0_PYLD_CHKSM_ERR_MASK BIT(12)
+/* Loss of Carrier */
+#define TX_DESC_TDES0_LSS_CARR_MASK BIT(11)
+/* No Carrier */
+#define TX_DESC_TDES0_NO_CARR_MASK BIT(10)
+/* Late Collision */
+#define TX_DESC_TDES0_LATE_COLL_MASK BIT(9)
+/* Excessive Collision */
+#define TX_DESC_TDES0_EXCS_COLL_MASK BIT(8)
+/* VLAN Frame */
+#define TX_DESC_TDES0_VLAN_FRM_MASK BIT(7)
+/* Collision Count */
+#define TX_DESC_TDES0_COLL_CNT_MASK(word) extract32(word, 3, 4)
+/* Excessive Deferral */
+#define TX_DESC_TDES0_EXCS_DEF_MASK BIT(2)
+/* Underflow Error */
+#define TX_DESC_TDES0_UNDRFLW_ERR_MASK BIT(1)
+/* Deferred Bit */
+#define TX_DESC_TDES0_DFRD_BIT_MASK BIT(0)
+
+/* Interrupt of Completion */
+#define TX_DESC_TDES1_INTERR_COMP_MASK BIT(31)
+/* Last Segment */
+#define TX_DESC_TDES1_LAST_SEG_MASK BIT(30)
+/* First Segment */
+#define TX_DESC_TDES1_FIRST_SEG_MASK BIT(29)
+/* Checksum Insertion Control */
+#define TX_DESC_TDES1_CHKSM_INS_CTRL_MASK(word) extract32(word, 27, 2)
+/* Disable Cyclic Redundancy Check */
+#define TX_DESC_TDES1_DIS_CDC_MASK BIT(26)
+/* Transmit End of Ring */
+#define TX_DESC_TDES1_TX_END_RING_MASK BIT(25)
+/* Secondary Address Chained */
+#define TX_DESC_TDES1_SEC_ADDR_CHND_MASK BIT(24)
+/* Transmit Buffer 2 Size */
+#define TX_DESC_TDES1_BFFR2_SZ_MASK(word) extract32(word, 11, 11)
+/* Transmit Buffer 1 Size */
+#define TX_DESC_TDES1_BFFR1_SZ_MASK(word) extract32(word, 0, 11)
+
+typedef struct NPCMGMACState {
+ SysBusDevice parent;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ NICState *nic;
+ NICConf conf;
+
+ uint32_t regs[NPCM_GMAC_NR_REGS];
+ uint16_t phy_regs[NPCM_GMAC_MAX_PHYS][NPCM_GMAC_MAX_PHY_REGS];
+} NPCMGMACState;
+
+#define TYPE_NPCM_GMAC "npcm-gmac"
+OBJECT_DECLARE_SIMPLE_TYPE(NPCMGMACState, NPCM_GMAC)
+
+/* Mask for RO bits in Status */
+#define NPCM_DMA_STATUS_RO_MASK(word) (word & 0xfffe0000)
+/* Mask for RO bits in Status */
+#define NPCM_DMA_STATUS_W1C_MASK(word) (word & 0x1e7ff)
+
+/* Transmit Process State */
+#define NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT 20
+/* Transmit States */
+#define NPCM_DMA_STATUS_TX_STOPPED_STATE \
+ (0b000)
+#define NPCM_DMA_STATUS_TX_RUNNING_FETCHING_STATE \
+ (0b001)
+#define NPCM_DMA_STATUS_TX_RUNNING_WAITING_STATE \
+ (0b010)
+#define NPCM_DMA_STATUS_TX_RUNNING_READ_STATE \
+ (0b011)
+#define NPCM_DMA_STATUS_TX_SUSPENDED_STATE \
+ (0b110)
+#define NPCM_DMA_STATUS_TX_RUNNING_CLOSING_STATE \
+ (0b111)
+/* Transmit Process State */
+#define NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT 17
+/* Receive States */
+#define NPCM_DMA_STATUS_RX_STOPPED_STATE \
+ (0b000)
+#define NPCM_DMA_STATUS_RX_RUNNING_FETCHING_STATE \
+ (0b001)
+#define NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE \
+ (0b011)
+#define NPCM_DMA_STATUS_RX_SUSPENDED_STATE \
+ (0b100)
+#define NPCM_DMA_STATUS_RX_RUNNING_CLOSING_STATE \
+ (0b101)
+#define NPCM_DMA_STATUS_RX_RUNNING_TRANSFERRING_STATE \
+ (0b111)
+
+
+/* Early Receive Interrupt */
+#define NPCM_DMA_STATUS_ERI BIT(14)
+/* Fatal Bus Error Interrupt */
+#define NPCM_DMA_STATUS_FBI BIT(13)
+/* Early transmit Interrupt */
+#define NPCM_DMA_STATUS_ETI BIT(10)
+/* Receive Watchdog Timout */
+#define NPCM_DMA_STATUS_RWT BIT(9)
+/* Receive Process Stopped */
+#define NPCM_DMA_STATUS_RPS BIT(8)
+/* Receive Buffer Unavailable */
+#define NPCM_DMA_STATUS_RU BIT(7)
+/* Receive Interrupt */
+#define NPCM_DMA_STATUS_RI BIT(6)
+/* Transmit Underflow */
+#define NPCM_DMA_STATUS_UNF BIT(5)
+/* Receive Overflow */
+#define NPCM_DMA_STATUS_OVF BIT(4)
+/* Transmit Jabber Timeout */
+#define NPCM_DMA_STATUS_TJT BIT(3)
+/* Transmit Buffer Unavailable */
+#define NPCM_DMA_STATUS_TU BIT(2)
+/* Transmit Process Stopped */
+#define NPCM_DMA_STATUS_TPS BIT(1)
+/* Transmit Interrupt */
+#define NPCM_DMA_STATUS_TI BIT(0)
+
+/* Normal Interrupt Summary */
+#define NPCM_DMA_STATUS_NIS BIT(16)
+/* Interrupts enabled by NIE */
+#define NPCM_DMA_STATUS_NIS_BITS (NPCM_DMA_STATUS_TI | \
+ NPCM_DMA_STATUS_TU | \
+ NPCM_DMA_STATUS_RI | \
+ NPCM_DMA_STATUS_ERI)
+/* Abnormal Interrupt Summary */
+#define NPCM_DMA_STATUS_AIS BIT(15)
+/* Interrupts enabled by AIE */
+#define NPCM_DMA_STATUS_AIS_BITS (NPCM_DMA_STATUS_TPS | \
+ NPCM_DMA_STATUS_TJT | \
+ NPCM_DMA_STATUS_OVF | \
+ NPCM_DMA_STATUS_UNF | \
+ NPCM_DMA_STATUS_RU | \
+ NPCM_DMA_STATUS_RPS | \
+ NPCM_DMA_STATUS_RWT | \
+ NPCM_DMA_STATUS_ETI | \
+ NPCM_DMA_STATUS_FBI)
+
+/* Early Receive Interrupt Enable */
+#define NPCM_DMA_INTR_ENAB_ERE BIT(14)
+/* Fatal Bus Error Interrupt Enable */
+#define NPCM_DMA_INTR_ENAB_FBE BIT(13)
+/* Early transmit Interrupt Enable */
+#define NPCM_DMA_INTR_ENAB_ETE BIT(10)
+/* Receive Watchdog Timout Enable */
+#define NPCM_DMA_INTR_ENAB_RWE BIT(9)
+/* Receive Process Stopped Enable */
+#define NPCM_DMA_INTR_ENAB_RSE BIT(8)
+/* Receive Buffer Unavailable Enable */
+#define NPCM_DMA_INTR_ENAB_RUE BIT(7)
+/* Receive Interrupt Enable */
+#define NPCM_DMA_INTR_ENAB_RIE BIT(6)
+/* Transmit Underflow Enable */
+#define NPCM_DMA_INTR_ENAB_UNE BIT(5)
+/* Receive Overflow Enable */
+#define NPCM_DMA_INTR_ENAB_OVE BIT(4)
+/* Transmit Jabber Timeout Enable */
+#define NPCM_DMA_INTR_ENAB_TJE BIT(3)
+/* Transmit Buffer Unavailable Enable */
+#define NPCM_DMA_INTR_ENAB_TUE BIT(2)
+/* Transmit Process Stopped Enable */
+#define NPCM_DMA_INTR_ENAB_TSE BIT(1)
+/* Transmit Interrupt Enable */
+#define NPCM_DMA_INTR_ENAB_TIE BIT(0)
+
+/* Normal Interrupt Summary Enable */
+#define NPCM_DMA_INTR_ENAB_NIE BIT(16)
+/* Interrupts enabled by NIE Enable */
+#define NPCM_DMA_INTR_ENAB_NIE_BITS (NPCM_DMA_INTR_ENAB_TIE | \
+ NPCM_DMA_INTR_ENAB_TUE | \
+ NPCM_DMA_INTR_ENAB_RIE | \
+ NPCM_DMA_INTR_ENAB_ERE)
+/* Abnormal Interrupt Summary Enable */
+#define NPCM_DMA_INTR_ENAB_AIE BIT(15)
+/* Interrupts enabled by AIE Enable */
+#define NPCM_DMA_INTR_ENAB_AIE_BITS (NPCM_DMA_INTR_ENAB_TSE | \
+ NPCM_DMA_INTR_ENAB_TJE | \
+ NPCM_DMA_INTR_ENAB_OVE | \
+ NPCM_DMA_INTR_ENAB_UNE | \
+ NPCM_DMA_INTR_ENAB_RUE | \
+ NPCM_DMA_INTR_ENAB_RSE | \
+ NPCM_DMA_INTR_ENAB_RWE | \
+ NPCM_DMA_INTR_ENAB_ETE | \
+ NPCM_DMA_INTR_ENAB_FBE)
+
+/* Flushing Disabled */
+#define NPCM_DMA_CONTROL_FLUSH_MASK BIT(24)
+/* Start/stop Transmit */
+#define NPCM_DMA_CONTROL_START_STOP_TX BIT(13)
+/* Start/stop Receive */
+#define NPCM_DMA_CONTROL_START_STOP_RX BIT(1)
+/* Next receive descriptor start address */
+#define NPCM_DMA_HOST_RX_DESC_MASK(word) ((uint32_t) (word) & ~3u)
+/* Next transmit descriptor start address */
+#define NPCM_DMA_HOST_TX_DESC_MASK(word) ((uint32_t) (word) & ~3u)
+
+/* Receive enable */
+#define NPCM_GMAC_MAC_CONFIG_RX_EN BIT(2)
+/* Transmit enable */
+#define NPCM_GMAC_MAC_CONFIG_TX_EN BIT(3)
+
+/* Frame Receive All */
+#define NPCM_GMAC_FRAME_FILTER_REC_ALL_MASK BIT(31)
+/* Frame HPF Filter*/
+#define NPCM_GMAC_FRAME_FILTER_HPF_MASK BIT(10)
+/* Frame SAF Filter*/
+#define NPCM_GMAC_FRAME_FILTER_SAF_MASK BIT(9)
+/* Frame SAIF Filter*/
+#define NPCM_GMAC_FRAME_FILTER_SAIF_MASK BIT(8)
+/* Frame PCF Filter*/
+#define NPCM_GMAC_FRAME_FILTER_PCF_MASK BIT(word) extract32((word), 6, 2)
+/* Frame DBF Filter*/
+#define NPCM_GMAC_FRAME_FILTER_DBF_MASK BIT(5)
+/* Frame PM Filter*/
+#define NPCM_GMAC_FRAME_FILTER_PM_MASK BIT(4)
+/* Frame DAIF Filter*/
+#define NPCM_GMAC_FRAME_FILTER_DAIF_MASK BIT(3)
+/* Frame HMC Filter*/
+#define NPCM_GMAC_FRAME_FILTER_HMC_MASK BIT(2)
+/* Frame HUC Filter*/
+#define NPCM_GMAC_FRAME_FILTER_HUC_MASK BIT(1)
+/* Frame PR Filter*/
+#define NPCM_GMAC_FRAME_FILTER_PR_MASK BIT(0)
+
+#endif /* NPCM_GMAC_H */
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 66338f4..d47536e 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -329,8 +329,6 @@ struct BusClass {
*/
char *(*get_fw_dev_path)(DeviceState *dev);
- void (*reset)(BusState *bus);
-
/*
* Return whether the device can be added to @bus,
* based on the address that was set (via device properties)
diff --git a/include/hw/ssi/bcm2835_spi.h b/include/hw/ssi/bcm2835_spi.h
new file mode 100644
index 0000000..d3f8cec
--- /dev/null
+++ b/include/hw/ssi/bcm2835_spi.h
@@ -0,0 +1,81 @@
+/*
+ * BCM2835 SPI Master Controller
+ *
+ * Copyright (c) 2024 Rayhan Faizel <rayhan.faizel@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/ssi/ssi.h"
+#include "qom/object.h"
+#include "qemu/fifo8.h"
+
+#define TYPE_BCM2835_SPI "bcm2835-spi"
+OBJECT_DECLARE_SIMPLE_TYPE(BCM2835SPIState, BCM2835_SPI)
+
+/*
+ * Though BCM2835 documentation says FIFOs have a capacity of 16,
+ * FIFOs are actually 16 words in size or effectively 64 bytes when operating
+ * in non DMA mode.
+ */
+#define FIFO_SIZE 64
+#define FIFO_SIZE_3_4 48
+
+#define RO_MASK 0x1f0000
+
+#define BCM2835_SPI_CS 0x00
+#define BCM2835_SPI_FIFO 0x04
+#define BCM2835_SPI_CLK 0x08
+#define BCM2835_SPI_DLEN 0x0c
+#define BCM2835_SPI_LTOH 0x10
+#define BCM2835_SPI_DC 0x14
+
+#define BCM2835_SPI_CS_RXF BIT(20)
+#define BCM2835_SPI_CS_RXR BIT(19)
+#define BCM2835_SPI_CS_TXD BIT(18)
+#define BCM2835_SPI_CS_RXD BIT(17)
+#define BCM2835_SPI_CS_DONE BIT(16)
+#define BCM2835_SPI_CS_LEN BIT(13)
+#define BCM2835_SPI_CS_REN BIT(12)
+#define BCM2835_SPI_CS_INTR BIT(10)
+#define BCM2835_SPI_CS_INTD BIT(9)
+#define BCM2835_SPI_CS_DMAEN BIT(8)
+#define BCM2835_SPI_CS_TA BIT(7)
+#define BCM2835_SPI_CLEAR_RX BIT(5)
+#define BCM2835_SPI_CLEAR_TX BIT(4)
+
+struct BCM2835SPIState {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ SSIBus *bus;
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ uint32_t cs;
+ uint32_t clk;
+ uint32_t dlen;
+ uint32_t ltoh;
+ uint32_t dc;
+
+ Fifo8 tx_fifo;
+ Fifo8 rx_fifo;
+};
diff --git a/qemu-options.hx b/qemu-options.hx
index 484cc21..5adbed1 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3994,7 +3994,7 @@ ERST
DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \
"-initrd file use 'file' as initial ram disk\n", QEMU_ARCH_ALL)
-SRST
+SRST(initrd)
``-initrd file``
Use file as initial ram disk.
@@ -4129,7 +4129,8 @@ SRST
This option can be used several times to simulate up to 4 serial
ports.
- Use ``-serial none`` to disable all serial ports.
+ You can use ``-serial none`` to suppress the creation of default
+ serial devices.
Available character devices are:
@@ -4151,10 +4152,17 @@ SRST
[Linux only] Pseudo TTY (a new PTY is automatically allocated)
``none``
- No device is allocated.
+ No device is allocated. Note that for machine types which
+ emulate systems where a serial device is always present in
+ real hardware, this may be equivalent to the ``null`` option,
+ in that the serial device is still present but all output
+ is discarded. For boards where the number of serial ports is
+ truly variable, this suppresses the creation of the device.
``null``
- void device
+ A guest will see the UART or serial device as present in the
+ machine, but all output is discarded, and there is no input.
+ Conceptually equivalent to redirecting the output to ``/dev/null``.
``chardev:id``
Use a named character device defined with the ``-chardev``
diff --git a/system/vl.c b/system/vl.c
index 60fd1e5..bb959cb 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -1439,18 +1439,22 @@ static void qemu_create_default_devices(void)
static int serial_parse(const char *devname)
{
int index = num_serial_hds;
- char label[32];
- if (strcmp(devname, "none") == 0)
- return 0;
- snprintf(label, sizeof(label), "serial%d", index);
serial_hds = g_renew(Chardev *, serial_hds, index + 1);
- serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
- if (!serial_hds[index]) {
- error_report("could not connect serial device"
- " to character backend '%s'", devname);
- return -1;
+ if (strcmp(devname, "none") == 0) {
+ /* Don't allocate a serial device for this index */
+ serial_hds[index] = NULL;
+ } else {
+ char label[32];
+ snprintf(label, sizeof(label), "serial%d", index);
+
+ serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
+ if (!serial_hds[index]) {
+ error_report("could not connect serial device"
+ " to character backend '%s'", devname);
+ return -1;
+ }
}
num_serial_hds++;
return 0;
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 6a96b24..1ce26e5 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1627,6 +1627,10 @@ void arm_cpu_post_init(Object *obj)
}
} else if (cpu_isar_feature(aa32_vfp, cpu)) {
cpu->has_vfp = true;
+ if (tcg_enabled() || qtest_enabled()) {
+ qdev_property_add_static(DEVICE(obj),
+ &arm_cpu_has_vfp_property);
+ }
if (cpu_isar_feature(aa32_simd_r32, cpu)) {
cpu->has_vfp_d32 = true;
/*
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 945d857..d51093a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8897,6 +8897,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
R_ID_AA64ZFR0_AES_MASK |
R_ID_AA64ZFR0_BITPERM_MASK |
R_ID_AA64ZFR0_BFLOAT16_MASK |
+ R_ID_AA64ZFR0_B16B16_MASK |
R_ID_AA64ZFR0_SHA3_MASK |
R_ID_AA64ZFR0_SM4_MASK |
R_ID_AA64ZFR0_I8MM_MASK |
@@ -11015,6 +11016,24 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
}
if (env->exception.target_el == 2) {
+ /* Debug exceptions are reported differently on AArch32 */
+ switch (syn_get_ec(env->exception.syndrome)) {
+ case EC_BREAKPOINT:
+ case EC_BREAKPOINT_SAME_EL:
+ case EC_AA32_BKPT:
+ case EC_VECTORCATCH:
+ env->exception.syndrome = syn_insn_abort(arm_current_el(env) == 2,
+ 0, 0, 0x22);
+ break;
+ case EC_WATCHPOINT:
+ env->exception.syndrome = syn_set_ec(env->exception.syndrome,
+ EC_DATAABORT);
+ break;
+ case EC_WATCHPOINT_SAME_EL:
+ env->exception.syndrome = syn_set_ec(env->exception.syndrome,
+ EC_DATAABORT_SAME_EL);
+ break;
+ }
arm_cpu_do_interrupt_aarch32_hyp(cs);
return;
}
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 1a49767..3244e07 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -25,6 +25,8 @@
#ifndef TARGET_ARM_SYNDROME_H
#define TARGET_ARM_SYNDROME_H
+#include "qemu/bitops.h"
+
/* Valid Syndrome Register EC field values */
enum arm_exception_class {
EC_UNCATEGORIZED = 0x00,
@@ -80,6 +82,7 @@ typedef enum {
SME_ET_InactiveZA,
} SMEExceptionType;
+#define ARM_EL_EC_LENGTH 6
#define ARM_EL_EC_SHIFT 26
#define ARM_EL_IL_SHIFT 25
#define ARM_EL_ISV_SHIFT 24
@@ -94,6 +97,11 @@ static inline uint32_t syn_get_ec(uint32_t syn)
return syn >> ARM_EL_EC_SHIFT;
}
+static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec)
+{
+ return deposit32(syn, ARM_EL_EC_SHIFT, ARM_EL_EC_LENGTH, ec);
+}
+
/*
* Utility functions for constructing various kinds of syndrome value.
* Note that in general we follow the AArch64 syndrome values; in a
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 663338a..39557d5 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -231,6 +231,7 @@ qtests_aarch64 = \
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
['arm-cpu-features',
'numa-test',
'boot-serial-test',
diff --git a/tests/qtest/npcm_gmac-test.c b/tests/qtest/npcm_gmac-test.c
new file mode 100644
index 0000000..9e58b15
--- /dev/null
+++ b/tests/qtest/npcm_gmac-test.c
@@ -0,0 +1,344 @@
+/*
+ * QTests for Nuvoton NPCM7xx/8xx GMAC Modules.
+ *
+ * Copyright 2024 Google LLC
+ * Authors:
+ * Hao Wu <wuhaotsh@google.com>
+ * Nabih Estefan <nabihestefan@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+#include "libqos/libqos.h"
+
+/* Name of the GMAC Device */
+#define TYPE_NPCM_GMAC "npcm-gmac"
+
+/* Address of the PCS Module */
+#define PCS_BASE_ADDRESS 0xf0780000
+#define NPCM_PCS_IND_AC_BA 0x1fe
+
+typedef struct GMACModule {
+ int irq;
+ uint64_t base_addr;
+} GMACModule;
+
+typedef struct TestData {
+ const GMACModule *module;
+} TestData;
+
+/* Values extracted from hw/arm/npcm8xx.c */
+static const GMACModule gmac_module_list[] = {
+ {
+ .irq = 14,
+ .base_addr = 0xf0802000
+ },
+ {
+ .irq = 15,
+ .base_addr = 0xf0804000
+ },
+ {
+ .irq = 16,
+ .base_addr = 0xf0806000
+ },
+ {
+ .irq = 17,
+ .base_addr = 0xf0808000
+ }
+};
+
+/* Returns the index of the GMAC module. */
+static int gmac_module_index(const GMACModule *mod)
+{
+ ptrdiff_t diff = mod - gmac_module_list;
+
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(gmac_module_list));
+
+ return diff;
+}
+
+/* 32-bit register indices. Taken from npcm_gmac.c */
+typedef enum NPCMRegister {
+ /* DMA Registers */
+ NPCM_DMA_BUS_MODE = 0x1000,
+ NPCM_DMA_XMT_POLL_DEMAND = 0x1004,
+ NPCM_DMA_RCV_POLL_DEMAND = 0x1008,
+ NPCM_DMA_RCV_BASE_ADDR = 0x100c,
+ NPCM_DMA_TX_BASE_ADDR = 0x1010,
+ NPCM_DMA_STATUS = 0x1014,
+ NPCM_DMA_CONTROL = 0x1018,
+ NPCM_DMA_INTR_ENA = 0x101c,
+ NPCM_DMA_MISSED_FRAME_CTR = 0x1020,
+ NPCM_DMA_HOST_TX_DESC = 0x1048,
+ NPCM_DMA_HOST_RX_DESC = 0x104c,
+ NPCM_DMA_CUR_TX_BUF_ADDR = 0x1050,
+ NPCM_DMA_CUR_RX_BUF_ADDR = 0x1054,
+ NPCM_DMA_HW_FEATURE = 0x1058,
+
+ /* GMAC Registers */
+ NPCM_GMAC_MAC_CONFIG = 0x0,
+ NPCM_GMAC_FRAME_FILTER = 0x4,
+ NPCM_GMAC_HASH_HIGH = 0x8,
+ NPCM_GMAC_HASH_LOW = 0xc,
+ NPCM_GMAC_MII_ADDR = 0x10,
+ NPCM_GMAC_MII_DATA = 0x14,
+ NPCM_GMAC_FLOW_CTRL = 0x18,
+ NPCM_GMAC_VLAN_FLAG = 0x1c,
+ NPCM_GMAC_VERSION = 0x20,
+ NPCM_GMAC_WAKEUP_FILTER = 0x28,
+ NPCM_GMAC_PMT = 0x2c,
+ NPCM_GMAC_LPI_CTRL = 0x30,
+ NPCM_GMAC_TIMER_CTRL = 0x34,
+ NPCM_GMAC_INT_STATUS = 0x38,
+ NPCM_GMAC_INT_MASK = 0x3c,
+ NPCM_GMAC_MAC0_ADDR_HI = 0x40,
+ NPCM_GMAC_MAC0_ADDR_LO = 0x44,
+ NPCM_GMAC_MAC1_ADDR_HI = 0x48,
+ NPCM_GMAC_MAC1_ADDR_LO = 0x4c,
+ NPCM_GMAC_MAC2_ADDR_HI = 0x50,
+ NPCM_GMAC_MAC2_ADDR_LO = 0x54,
+ NPCM_GMAC_MAC3_ADDR_HI = 0x58,
+ NPCM_GMAC_MAC3_ADDR_LO = 0x5c,
+ NPCM_GMAC_RGMII_STATUS = 0xd8,
+ NPCM_GMAC_WATCHDOG = 0xdc,
+ NPCM_GMAC_PTP_TCR = 0x700,
+ NPCM_GMAC_PTP_SSIR = 0x704,
+ NPCM_GMAC_PTP_STSR = 0x708,
+ NPCM_GMAC_PTP_STNSR = 0x70c,
+ NPCM_GMAC_PTP_STSUR = 0x710,
+ NPCM_GMAC_PTP_STNSUR = 0x714,
+ NPCM_GMAC_PTP_TAR = 0x718,
+ NPCM_GMAC_PTP_TTSR = 0x71c,
+
+ /* PCS Registers */
+ NPCM_PCS_SR_CTL_ID1 = 0x3c0008,
+ NPCM_PCS_SR_CTL_ID2 = 0x3c000a,
+ NPCM_PCS_SR_CTL_STS = 0x3c0010,
+
+ NPCM_PCS_SR_MII_CTRL = 0x3e0000,
+ NPCM_PCS_SR_MII_STS = 0x3e0002,
+ NPCM_PCS_SR_MII_DEV_ID1 = 0x3e0004,
+ NPCM_PCS_SR_MII_DEV_ID2 = 0x3e0006,
+ NPCM_PCS_SR_MII_AN_ADV = 0x3e0008,
+ NPCM_PCS_SR_MII_LP_BABL = 0x3e000a,
+ NPCM_PCS_SR_MII_AN_EXPN = 0x3e000c,
+ NPCM_PCS_SR_MII_EXT_STS = 0x3e001e,
+
+ NPCM_PCS_SR_TIM_SYNC_ABL = 0x3e0e10,
+ NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR = 0x3e0e12,
+ NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR = 0x3e0e14,
+ NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR = 0x3e0e16,
+ NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR = 0x3e0e18,
+ NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR = 0x3e0e1a,
+ NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR = 0x3e0e1c,
+ NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR = 0x3e0e1e,
+ NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR = 0x3e0e20,
+
+ NPCM_PCS_VR_MII_MMD_DIG_CTRL1 = 0x3f0000,
+ NPCM_PCS_VR_MII_AN_CTRL = 0x3f0002,
+ NPCM_PCS_VR_MII_AN_INTR_STS = 0x3f0004,
+ NPCM_PCS_VR_MII_TC = 0x3f0006,
+ NPCM_PCS_VR_MII_DBG_CTRL = 0x3f000a,
+ NPCM_PCS_VR_MII_EEE_MCTRL0 = 0x3f000c,
+ NPCM_PCS_VR_MII_EEE_TXTIMER = 0x3f0010,
+ NPCM_PCS_VR_MII_EEE_RXTIMER = 0x3f0012,
+ NPCM_PCS_VR_MII_LINK_TIMER_CTRL = 0x3f0014,
+ NPCM_PCS_VR_MII_EEE_MCTRL1 = 0x3f0016,
+ NPCM_PCS_VR_MII_DIG_STS = 0x3f0020,
+ NPCM_PCS_VR_MII_ICG_ERRCNT1 = 0x3f0022,
+ NPCM_PCS_VR_MII_MISC_STS = 0x3f0030,
+ NPCM_PCS_VR_MII_RX_LSTS = 0x3f0040,
+ NPCM_PCS_VR_MII_MP_TX_BSTCTRL0 = 0x3f0070,
+ NPCM_PCS_VR_MII_MP_TX_LVLCTRL0 = 0x3f0074,
+ NPCM_PCS_VR_MII_MP_TX_GENCTRL0 = 0x3f007a,
+ NPCM_PCS_VR_MII_MP_TX_GENCTRL1 = 0x3f007c,
+ NPCM_PCS_VR_MII_MP_TX_STS = 0x3f0090,
+ NPCM_PCS_VR_MII_MP_RX_GENCTRL0 = 0x3f00b0,
+ NPCM_PCS_VR_MII_MP_RX_GENCTRL1 = 0x3f00b2,
+ NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0 = 0x3f00ba,
+ NPCM_PCS_VR_MII_MP_MPLL_CTRL0 = 0x3f00f0,
+ NPCM_PCS_VR_MII_MP_MPLL_CTRL1 = 0x3f00f2,
+ NPCM_PCS_VR_MII_MP_MPLL_STS = 0x3f0110,
+ NPCM_PCS_VR_MII_MP_MISC_CTRL2 = 0x3f0126,
+ NPCM_PCS_VR_MII_MP_LVL_CTRL = 0x3f0130,
+ NPCM_PCS_VR_MII_MP_MISC_CTRL0 = 0x3f0132,
+ NPCM_PCS_VR_MII_MP_MISC_CTRL1 = 0x3f0134,
+ NPCM_PCS_VR_MII_DIG_CTRL2 = 0x3f01c2,
+ NPCM_PCS_VR_MII_DIG_ERRCNT_SEL = 0x3f01c4,
+} NPCMRegister;
+
+static uint32_t gmac_read(QTestState *qts, const GMACModule *mod,
+ NPCMRegister regno)
+{
+ return qtest_readl(qts, mod->base_addr + regno);
+}
+
+static uint16_t pcs_read(QTestState *qts, const GMACModule *mod,
+ NPCMRegister regno)
+{
+ uint32_t write_value = (regno & 0x3ffe00) >> 9;
+ qtest_writel(qts, PCS_BASE_ADDRESS + NPCM_PCS_IND_AC_BA, write_value);
+ uint32_t read_offset = regno & 0x1ff;
+ return qtest_readl(qts, PCS_BASE_ADDRESS + read_offset);
+}
+
+/* Check that GMAC registers are reset to default value */
+static void test_init(gconstpointer test_data)
+{
+ const TestData *td = test_data;
+ const GMACModule *mod = td->module;
+ QTestState *qts = qtest_init("-machine npcm845-evb");
+
+#define CHECK_REG32(regno, value) \
+ do { \
+ g_assert_cmphex(gmac_read(qts, mod, (regno)), ==, (value)); \
+ } while (0)
+
+#define CHECK_REG_PCS(regno, value) \
+ do { \
+ g_assert_cmphex(pcs_read(qts, mod, (regno)), ==, (value)); \
+ } while (0)
+
+ CHECK_REG32(NPCM_DMA_BUS_MODE, 0x00020100);
+ CHECK_REG32(NPCM_DMA_XMT_POLL_DEMAND, 0);
+ CHECK_REG32(NPCM_DMA_RCV_POLL_DEMAND, 0);
+ CHECK_REG32(NPCM_DMA_RCV_BASE_ADDR, 0);
+ CHECK_REG32(NPCM_DMA_TX_BASE_ADDR, 0);
+ CHECK_REG32(NPCM_DMA_STATUS, 0);
+ CHECK_REG32(NPCM_DMA_CONTROL, 0);
+ CHECK_REG32(NPCM_DMA_INTR_ENA, 0);
+ CHECK_REG32(NPCM_DMA_MISSED_FRAME_CTR, 0);
+ CHECK_REG32(NPCM_DMA_HOST_TX_DESC, 0);
+ CHECK_REG32(NPCM_DMA_HOST_RX_DESC, 0);
+ CHECK_REG32(NPCM_DMA_CUR_TX_BUF_ADDR, 0);
+ CHECK_REG32(NPCM_DMA_CUR_RX_BUF_ADDR, 0);
+ CHECK_REG32(NPCM_DMA_HW_FEATURE, 0x100d4f37);
+
+ CHECK_REG32(NPCM_GMAC_MAC_CONFIG, 0);
+ CHECK_REG32(NPCM_GMAC_FRAME_FILTER, 0);
+ CHECK_REG32(NPCM_GMAC_HASH_HIGH, 0);
+ CHECK_REG32(NPCM_GMAC_HASH_LOW, 0);
+ CHECK_REG32(NPCM_GMAC_MII_ADDR, 0);
+ CHECK_REG32(NPCM_GMAC_MII_DATA, 0);
+ CHECK_REG32(NPCM_GMAC_FLOW_CTRL, 0);
+ CHECK_REG32(NPCM_GMAC_VLAN_FLAG, 0);
+ CHECK_REG32(NPCM_GMAC_VERSION, 0x00001032);
+ CHECK_REG32(NPCM_GMAC_WAKEUP_FILTER, 0);
+ CHECK_REG32(NPCM_GMAC_PMT, 0);
+ CHECK_REG32(NPCM_GMAC_LPI_CTRL, 0);
+ CHECK_REG32(NPCM_GMAC_TIMER_CTRL, 0x03e80000);
+ CHECK_REG32(NPCM_GMAC_INT_STATUS, 0);
+ CHECK_REG32(NPCM_GMAC_INT_MASK, 0);
+ CHECK_REG32(NPCM_GMAC_MAC0_ADDR_HI, 0x8000ffff);
+ CHECK_REG32(NPCM_GMAC_MAC0_ADDR_LO, 0xffffffff);
+ CHECK_REG32(NPCM_GMAC_MAC1_ADDR_HI, 0x0000ffff);
+ CHECK_REG32(NPCM_GMAC_MAC1_ADDR_LO, 0xffffffff);
+ CHECK_REG32(NPCM_GMAC_MAC2_ADDR_HI, 0x0000ffff);
+ CHECK_REG32(NPCM_GMAC_MAC2_ADDR_LO, 0xffffffff);
+ CHECK_REG32(NPCM_GMAC_MAC3_ADDR_HI, 0x0000ffff);
+ CHECK_REG32(NPCM_GMAC_MAC3_ADDR_LO, 0xffffffff);
+ CHECK_REG32(NPCM_GMAC_RGMII_STATUS, 0);
+ CHECK_REG32(NPCM_GMAC_WATCHDOG, 0);
+ CHECK_REG32(NPCM_GMAC_PTP_TCR, 0x00002000);
+ CHECK_REG32(NPCM_GMAC_PTP_SSIR, 0);
+ CHECK_REG32(NPCM_GMAC_PTP_STSR, 0);
+ CHECK_REG32(NPCM_GMAC_PTP_STNSR, 0);
+ CHECK_REG32(NPCM_GMAC_PTP_STSUR, 0);
+ CHECK_REG32(NPCM_GMAC_PTP_STNSUR, 0);
+ CHECK_REG32(NPCM_GMAC_PTP_TAR, 0);
+ CHECK_REG32(NPCM_GMAC_PTP_TTSR, 0);
+
+ /* TODO Add registers PCS */
+ if (mod->base_addr == 0xf0802000) {
+ CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID1, 0x699e);
+ CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID2, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_CTL_STS, 0x8000);
+
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_CTRL, 0x1140);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_STS, 0x0109);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID1, 0x699e);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID2, 0x0ced0);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_ADV, 0x0020);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_LP_BABL, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_EXPN, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_MII_EXT_STS, 0xc000);
+
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_ABL, 0x0003);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR, 0x0038);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR, 0x0038);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR, 0x0058);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR, 0);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR, 0x0048);
+ CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR, 0);
+
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MMD_DIG_CTRL1, 0x2400);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_CTRL, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_INTR_STS, 0x000a);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_TC, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DBG_CTRL, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL0, 0x899c);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_TXTIMER, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_RXTIMER, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_LINK_TIMER_CTRL, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_STS, 0x0010);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_ICG_ERRCNT1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MISC_STS, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_RX_LSTS, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_BSTCTRL0, 0x00a);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_LVLCTRL0, 0x007f);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL0, 0x0001);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_STS, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL0, 0x0100);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL1, 0x1100);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0, 0x000e);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL0, 0x0100);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL1, 0x0032);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_STS, 0x0001);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL2, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_LVL_CTRL, 0x0019);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL0, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL1, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_CTRL2, 0);
+ CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_ERRCNT_SEL, 0);
+ }
+
+ qtest_quit(qts);
+}
+
+static void gmac_add_test(const char *name, const TestData* td,
+ GTestDataFunc fn)
+{
+ g_autofree char *full_name = g_strdup_printf(
+ "npcm7xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name);
+ qtest_add_data_func(full_name, td, fn);
+}
+
+int main(int argc, char **argv)
+{
+ TestData test_data_list[ARRAY_SIZE(gmac_module_list)];
+
+ g_test_init(&argc, &argv, NULL);
+
+ for (int i = 0; i < ARRAY_SIZE(gmac_module_list); ++i) {
+ TestData *td = &test_data_list[i];
+
+ td->module = &gmac_module_list[i];
+
+ gmac_add_test("init", td, test_init);
+ }
+
+ return g_test_run();
+}
diff --git a/tests/qtest/xlnx-versal-trng-test.c b/tests/qtest/xlnx-versal-trng-test.c
index cef4e57..ba86f39 100644
--- a/tests/qtest/xlnx-versal-trng-test.c
+++ b/tests/qtest/xlnx-versal-trng-test.c
@@ -298,10 +298,13 @@ static size_t trng_collect(uint32_t *rnd, size_t cnt)
return i;
}
+/* These tests all generate 512 bits of random data with the device */
+#define TEST_DATA_WORDS (512 / 32)
+
static void trng_test_autogen(void)
{
- const size_t cnt = 512 / 32;
- uint32_t rng[cnt], prng[cnt];
+ const size_t cnt = TEST_DATA_WORDS;
+ uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n;
trng_reset();
@@ -343,8 +346,8 @@ static void trng_test_autogen(void)
static void trng_test_oneshot(void)
{
- const size_t cnt = 512 / 32;
- uint32_t rng[cnt];
+ const size_t cnt = TEST_DATA_WORDS;
+ uint32_t rng[TEST_DATA_WORDS];
size_t n;
trng_reset();
@@ -370,8 +373,8 @@ static void trng_test_oneshot(void)
static void trng_test_per_str(void)
{
- const size_t cnt = 512 / 32;
- uint32_t rng[cnt], prng[cnt];
+ const size_t cnt = TEST_DATA_WORDS;
+ uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n;
trng_reset();
@@ -415,8 +418,8 @@ static void trng_test_forced_prng(void)
const char *prop = "forced-prng";
const uint64_t seed = 0xdeadbeefbad1bad0ULL;
- const size_t cnt = 512 / 32;
- uint32_t rng[cnt], prng[cnt];
+ const size_t cnt = TEST_DATA_WORDS;
+ uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n;
trng_reset();
diff --git a/tests/tcg/aarch64/sysregs.c b/tests/tcg/aarch64/sysregs.c
index f7a055f..301e61d 100644
--- a/tests/tcg/aarch64/sysregs.c
+++ b/tests/tcg/aarch64/sysregs.c
@@ -137,7 +137,7 @@ int main(void)
/* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */
get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006));
get_cpu_reg_check_zero(id_aa64dfr1_el1);
- get_cpu_reg_check_mask(SYS_ID_AA64ZFR0_EL1, _m(0ff0,ff0f,00ff,00ff));
+ get_cpu_reg_check_mask(SYS_ID_AA64ZFR0_EL1, _m(0ff0,ff0f,0fff,00ff));
get_cpu_reg_check_mask(SYS_ID_AA64SMFR0_EL1, _m(8ff1,fcff,0000,0000));
get_cpu_reg_check_zero(id_aa64afr0_el1);