target/arm: fix exception syndrome for AArch32 bkpt insn

pci, vmbus, adb, s390x/css-bridge: Switch buses to 3-phase reset
 system/vl.c: Fix handling of '-serial none -serial something'
 target/arm: Add ID_AA64ZFR0_EL1.B16B16 to the exposed-to-userspace set
 tests/qtest/xlnx-versal-trng-test.c: Drop use of variable length array
 target/arm: Reinstate "vfp" property on AArch32 CPUs
 doc/sphinx/hxtool.py: add optional label argument to SRST directive
 hw/arm: Check for CPU types in machine_run_board_init() for various boards
 pci-host: designware: Limit value range of iATU viewport register
 hw/arm: Convert some DPRINTF macros to trace events and guest errors
 hw/arm: NPCM7XX SoC: Add GMAC ethernet controller devices
 hw/arm: Implement BCM2835 SPI Controller
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmW9C84ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3qS6D/wM0/JGEYfaadpuMEOAx4PG
 AnfScbPqVhx9J31P2Ks3VrB5F108aq/SaL2BmCb3BLF/ECChlhBXIjd7ukdHstts
 F1TvqtvLGDZQz6wSVUeB0YOvAjGa3vIskn+Xvk9e6Ne6PcXgVnxAof/cPsXUiYNy
 6DJjNiLJ/a9Xgq9rjFO6vzW3AL95U6/FmD2F0pOotWXERhNhoyYVV6RtyeqKlDQP
 yFVk5h601YURk9PeNZn9zpOpZqjAM7PxyF3X50N3Sv+G0uoKSr6b+c3/fDJbJo3+
 0LXomEa8hdheQxm1dLY5OD0JX3bvYxwH41bDg9B0iEdjxUdXt6LfXI9Nvw9BAwix
 8AcGJJUaL4XU4uPfHBpRJApM15+MRb0hqfv4ZcGk8e67IIqVeDbKL2clTQGoHSg1
 KaB0POhtFx//M/uBOyk/FR2gb2eBNU8GuoCgxdDwh0K5ylcaK1YPiX4Tcglu4iS0
 Frvazphb2pO1BK6JiJwN2/9ezzDkDJqTKoSqdc4g3ETVOGnxr+tXwcds3t2iK3g2
 y+pgijDOAT3bJO5kYeGvhoEJPKqXwJ3UQ8zTJsU2XSYwBjIyv5V3oOn6elwYJaWq
 yUDTC3QEK61KfnQnfTyLfdGWX1aVzHnYLWmQdO+3cczuQU0s0MP246Z1GAgDtgvD
 jGjDBz6mryWvP2H0xSmERQ==
 =azdP
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20240202' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target/arm: fix exception syndrome for AArch32 bkpt insn
pci, vmbus, adb, s390x/css-bridge: Switch buses to 3-phase reset
system/vl.c: Fix handling of '-serial none -serial something'
target/arm: Add ID_AA64ZFR0_EL1.B16B16 to the exposed-to-userspace set
tests/qtest/xlnx-versal-trng-test.c: Drop use of variable length array
target/arm: Reinstate "vfp" property on AArch32 CPUs
doc/sphinx/hxtool.py: add optional label argument to SRST directive
hw/arm: Check for CPU types in machine_run_board_init() for various boards
pci-host: designware: Limit value range of iATU viewport register
hw/arm: Convert some DPRINTF macros to trace events and guest errors
hw/arm: NPCM7XX SoC: Add GMAC ethernet controller devices
hw/arm: Implement BCM2835 SPI Controller

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmW9C84ZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3qS6D/wM0/JGEYfaadpuMEOAx4PG
# AnfScbPqVhx9J31P2Ks3VrB5F108aq/SaL2BmCb3BLF/ECChlhBXIjd7ukdHstts
# F1TvqtvLGDZQz6wSVUeB0YOvAjGa3vIskn+Xvk9e6Ne6PcXgVnxAof/cPsXUiYNy
# 6DJjNiLJ/a9Xgq9rjFO6vzW3AL95U6/FmD2F0pOotWXERhNhoyYVV6RtyeqKlDQP
# yFVk5h601YURk9PeNZn9zpOpZqjAM7PxyF3X50N3Sv+G0uoKSr6b+c3/fDJbJo3+
# 0LXomEa8hdheQxm1dLY5OD0JX3bvYxwH41bDg9B0iEdjxUdXt6LfXI9Nvw9BAwix
# 8AcGJJUaL4XU4uPfHBpRJApM15+MRb0hqfv4ZcGk8e67IIqVeDbKL2clTQGoHSg1
# KaB0POhtFx//M/uBOyk/FR2gb2eBNU8GuoCgxdDwh0K5ylcaK1YPiX4Tcglu4iS0
# Frvazphb2pO1BK6JiJwN2/9ezzDkDJqTKoSqdc4g3ETVOGnxr+tXwcds3t2iK3g2
# y+pgijDOAT3bJO5kYeGvhoEJPKqXwJ3UQ8zTJsU2XSYwBjIyv5V3oOn6elwYJaWq
# yUDTC3QEK61KfnQnfTyLfdGWX1aVzHnYLWmQdO+3cczuQU0s0MP246Z1GAgDtgvD
# jGjDBz6mryWvP2H0xSmERQ==
# =azdP
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 02 Feb 2024 15:35:42 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20240202' of https://git.linaro.org/people/pmaydell/qemu-arm: (36 commits)
  hw/arm: Connect SPI Controller to BCM2835
  hw/ssi: Implement BCM2835 SPI Controller
  tests/qtest: Adding PCS Module test to GMAC Qtest
  hw/net: GMAC Tx Implementation
  hw/net: GMAC Rx Implementation
  tests/qtest: Creating qtest for GMAC Module
  hw/arm: Add GMAC devices to NPCM7XX SoC
  hw/net: Add NPCMXXX GMAC device
  hw/xen: convert stderr prints to error/warn reports
  hw/xen/xen-hvm-common.c: convert DPRINTF to tracepoints
  hw/xen/xen-mapcache.c: convert DPRINTF to tracepoints
  hw/arm/xen_arm.c: convert DPRINTF to trace events and error/warn reports
  hw/arm/z2: convert DPRINTF to trace events and guest errors
  hw/arm/strongarm.c: convert DPRINTF to trace events and guest errors
  pci-host: designware: Limit value range of iATU viewport register
  hw/arm/zynq: Check for CPU types in machine_run_board_init()
  hw/arm/vexpress: Check for CPU types in machine_run_board_init()
  hw/arm/npcm7xx_boards: Simplify setting MachineClass::valid_cpu_types[]
  hw/arm/musca: Simplify setting MachineClass::valid_cpu_types[]
  hw/arm/msf2: Simplify setting MachineClass::valid_cpu_types[]
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2024-02-02 18:56:32 +00:00
commit 4f2fdb10b5
50 changed files with 2388 additions and 244 deletions

View File

@ -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.

View File

@ -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')

View File

@ -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)

View File

@ -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
--------------------

View File

@ -429,6 +429,7 @@ config RASPI
select PL011 # UART
select SDHCI
select USB_DWC2
select BCM2835_SPI
config STM32F100_SOC
bool

View File

@ -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);

View File

@ -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.
*/

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
@ -690,6 +702,29 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq));
}
/*
* 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);

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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
}

View File

@ -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";
}

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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 = {

View File

@ -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'))

942
hw/net/npcm_gmac.c Normal file
View File

@ -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)

View File

@ -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"

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -20,3 +20,7 @@ config XILINX_SPIPS
config STM32F2XX_SPI
bool
select SSI
config BCM2835_SPI
bool
select SSI

288
hw/ssi/bcm2835_spi.c Normal file
View File

@ -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)

View File

@ -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'))

View File

@ -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"

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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];
};

343
include/hw/net/npcm_gmac.h Normal file
View File

@ -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 */

View File

@ -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)

View File

@ -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;
};

View File

@ -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``

View File

@ -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;

View File

@ -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;
/*

View File

@ -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;
}

View File

@ -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

View File

@ -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',

View File

@ -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();
}

View File

@ -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();

View File

@ -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);