diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2024-02-02 18:56:32 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2024-02-02 18:56:32 +0000 |
commit | 4f2fdb10b5f78ba95300648fce74c42d3e4511c7 (patch) | |
tree | e944136735b09304a5b02c79097b8bb0b763d6d2 /hw | |
parent | 29b008927ef6e3fbb70e6607b25d3fcae26a5190 (diff) | |
parent | f09c2b7ba9908714a3e2f1decd989462536cf731 (diff) | |
download | qemu-4f2fdb10b5f78ba95300648fce74c42d3e4511c7.zip qemu-4f2fdb10b5f78ba95300648fce74c42d3e4511c7.tar.gz qemu-4f2fdb10b5f78ba95300648fce74c42d3e4511c7.tar.bz2 |
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>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/Kconfig | 1 | ||||
-rw-r--r-- | hw/arm/bcm2835_peripherals.c | 17 | ||||
-rw-r--r-- | hw/arm/exynos4210.c | 1 | ||||
-rw-r--r-- | hw/arm/exynos4_boards.c | 8 | ||||
-rw-r--r-- | hw/arm/highbank.c | 11 | ||||
-rw-r--r-- | hw/arm/msf2-soc.c | 3 | ||||
-rw-r--r-- | hw/arm/msf2-som.c | 4 | ||||
-rw-r--r-- | hw/arm/musca.c | 1 | ||||
-rw-r--r-- | hw/arm/npcm7xx.c | 37 | ||||
-rw-r--r-- | hw/arm/npcm7xx_boards.c | 1 | ||||
-rw-r--r-- | hw/arm/strongarm.c | 82 | ||||
-rw-r--r-- | hw/arm/trace-events | 15 | ||||
-rw-r--r-- | hw/arm/vexpress.c | 12 | ||||
-rw-r--r-- | hw/arm/xen_arm.c | 23 | ||||
-rw-r--r-- | hw/arm/xilinx_zynq.c | 6 | ||||
-rw-r--r-- | hw/arm/z2.c | 27 | ||||
-rw-r--r-- | hw/core/bus.c | 67 | ||||
-rw-r--r-- | hw/hyperv/vmbus.c | 7 | ||||
-rw-r--r-- | hw/input/adb.c | 7 | ||||
-rw-r--r-- | hw/net/meson.build | 2 | ||||
-rw-r--r-- | hw/net/npcm_gmac.c | 942 | ||||
-rw-r--r-- | hw/net/trace-events | 19 | ||||
-rw-r--r-- | hw/pci-host/designware.c | 2 | ||||
-rw-r--r-- | hw/pci/pci.c | 10 | ||||
-rw-r--r-- | hw/s390x/css-bridge.c | 5 | ||||
-rw-r--r-- | hw/ssi/Kconfig | 4 | ||||
-rw-r--r-- | hw/ssi/bcm2835_spi.c | 288 | ||||
-rw-r--r-- | hw/ssi/meson.build | 1 | ||||
-rw-r--r-- | hw/xen/trace-events | 21 | ||||
-rw-r--r-- | hw/xen/xen-hvm-common.c | 47 | ||||
-rw-r--r-- | hw/xen/xen-mapcache.c | 59 |
31 files changed, 1518 insertions, 212 deletions
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index db08a00..980b14d 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -429,6 +429,7 @@ config RASPI select PL011 # UART select SDHCI select USB_DWC2 + select BCM2835_SPI config STM32F100_SOC bool diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 0233038..d5573fd 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -144,6 +144,10 @@ static void bcm2835_peripherals_init(Object *obj) /* Power Management */ object_initialize_child(obj, "powermgt", &s->powermgt, TYPE_BCM2835_POWERMGT); + + /* SPI */ + object_initialize_child(obj, "bcm2835-spi0", &s->spi[0], + TYPE_BCM2835_SPI); } static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) @@ -402,11 +406,22 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->peri_mr, PM_OFFSET, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->powermgt), 0)); + /* SPI */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[0]), errp)) { + return; + } + + memory_region_add_subregion(&s->peri_mr, SPI0_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->spi[0]), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[0]), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), + BCM2835_IC_GPU_IRQ, + INTERRUPT_SPI)); + create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000); create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40); create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100); create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100); - create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20); create_unimp(s, &s->bscsl, "bcm2835-spis", BSC_SL_OFFSET, 0x100); create_unimp(s, &s->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20); create_unimp(s, &s->i2c[1], "bcm2835-i2c1", BSC1_OFFSET, 0x20); diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 6c428d8..57c77b1 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -556,6 +556,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) for (n = 0; n < EXYNOS4210_NCPUS; n++) { Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9")); + object_property_add_child(OBJECT(s), "cpu[*]", cpuobj); /* By default A9 CPUs have EL3 enabled. This board does not currently * support EL3 so the CPU EL3 property is disabled before realization. */ diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 0039921..2410e2a 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -34,6 +34,7 @@ #include "hw/qdev-properties.h" #include "hw/boards.h" #include "hw/irq.h" +#include "target/arm/cpu-qom.h" #define SMDK_LAN9118_BASE_ADDR 0x05000000 @@ -148,12 +149,18 @@ static void smdkc210_init(MachineState *machine) arm_load_kernel(s->soc.cpu[0], machine, &exynos4_board_binfo); } +static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-a9"), + NULL +}; + static void nuri_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "Samsung NURI board (Exynos4210)"; mc->init = nuri_init; + mc->valid_cpu_types = valid_cpu_types; mc->max_cpus = EXYNOS4210_NCPUS; mc->min_cpus = EXYNOS4210_NCPUS; mc->default_cpus = EXYNOS4210_NCPUS; @@ -172,6 +179,7 @@ static void smdkc210_class_init(ObjectClass *oc, void *data) mc->desc = "Samsung SMDKC210 board (Exynos4210)"; mc->init = smdkc210_init; + mc->valid_cpu_types = valid_cpu_types; mc->max_cpus = EXYNOS4210_NCPUS; mc->min_cpus = EXYNOS4210_NCPUS; mc->default_cpus = EXYNOS4210_NCPUS; diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index e123747..9fdac1c 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -209,6 +209,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) cpuobj = object_new(machine->cpu_type); cpu = ARM_CPU(cpuobj); + object_property_add_child(OBJECT(machine), "cpu[*]", cpuobj); object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC, &error_abort); @@ -342,10 +343,15 @@ static void midway_init(MachineState *machine) static void highbank_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-a9"), + NULL + }; MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "Calxeda Highbank (ECX-1000)"; mc->init = highbank_init; + mc->valid_cpu_types = valid_cpu_types; mc->block_default_type = IF_IDE; mc->units_per_default_bus = 1; mc->max_cpus = 4; @@ -361,10 +367,15 @@ static const TypeInfo highbank_type = { static void midway_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-a15"), + NULL + }; MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "Calxeda Midway (ECX-2000)"; mc->init = midway_init; + mc->valid_cpu_types = valid_cpu_types; mc->block_default_type = IF_IDE; mc->units_per_default_bus = 1; mc->max_cpus = 4; diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index 35bf1d6..a94a10a 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -134,7 +134,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) armv7m = DEVICE(&s->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 81); - qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type); + qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); qdev_prop_set_bit(armv7m, "enable-bitband", true); qdev_connect_clock_in(armv7m, "cpuclk", s->m3clk); qdev_connect_clock_in(armv7m, "refclk", s->refclk); @@ -227,7 +227,6 @@ static Property m2sxxx_soc_properties[] = { * part name specifies the type of SmartFusion2 device variant(this * property is for information purpose only. */ - DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type), DEFINE_PROP_STRING("part-name", MSF2State, part_name), DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE), DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size, diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index a269cf0..5c415ab 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -47,7 +47,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) DeviceState *dev; DeviceState *spi_flash; MSF2State *soc; - MachineClass *mc = MACHINE_GET_CLASS(machine); DriveInfo *dinfo = drive_get(IF_MTD, 0, 0); qemu_irq cs_line; BusState *spi_bus; @@ -62,8 +61,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) dev = qdev_new(TYPE_MSF2_SOC); object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); qdev_prop_set_string(dev, "part-name", "M2S010"); - qdev_prop_set_string(dev, "cpu-type", mc->default_cpu_type); - qdev_prop_set_uint64(dev, "eNVM-size", M2S010_ENVM_SIZE); qdev_prop_set_uint64(dev, "eSRAM-size", M2S010_ESRAM_SIZE); @@ -108,7 +105,6 @@ static void emcraft_sf2_machine_init(MachineClass *mc) mc->desc = "SmartFusion2 SOM kit from Emcraft (M2S010)"; mc->init = emcraft_sf2_s2s010_init; - mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3"); mc->valid_cpu_types = valid_cpu_types; } diff --git a/hw/arm/musca.c b/hw/arm/musca.c index 770ec1a..e2c9d49 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -605,7 +605,6 @@ static void musca_class_init(ObjectClass *oc, void *data) mc->default_cpus = 2; mc->min_cpus = mc->default_cpus; mc->max_cpus = mc->default_cpus; - mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); mc->valid_cpu_types = valid_cpu_types; mc->init = musca_init; } diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index bdc609b..ff3ecde 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -84,8 +84,10 @@ enum NPCM7xxInterrupt { NPCM7XX_UART1_IRQ, NPCM7XX_UART2_IRQ, NPCM7XX_UART3_IRQ, + NPCM7XX_GMAC1_IRQ = 14, NPCM7XX_EMC1RX_IRQ = 15, NPCM7XX_EMC1TX_IRQ, + NPCM7XX_GMAC2_IRQ, NPCM7XX_MMC_IRQ = 26, NPCM7XX_PSPI2_IRQ = 28, NPCM7XX_PSPI1_IRQ = 31, @@ -229,6 +231,12 @@ static const hwaddr npcm7xx_pspi_addr[] = { 0xf0201000, }; +/* Register base address for each GMAC Module */ +static const hwaddr npcm7xx_gmac_addr[] = { + 0xf0802000, + 0xf0804000, +}; + static const struct { hwaddr regs_addr; uint32_t unconnected_pins; @@ -457,6 +465,10 @@ static void npcm7xx_init(Object *obj) object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI); } + for (i = 0; i < ARRAY_SIZE(s->gmac); i++) { + object_initialize_child(obj, "gmac[*]", &s->gmac[i], TYPE_NPCM_GMAC); + } + object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI); } @@ -691,6 +703,29 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) } /* + * GMAC Modules. Cannot fail. + */ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gmac_addr) != ARRAY_SIZE(s->gmac)); + QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->gmac) != 2); + for (i = 0; i < ARRAY_SIZE(s->gmac); i++) { + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->gmac[i]); + + /* + * The device exists regardless of whether it's connected to a QEMU + * netdev backend. So always instantiate it even if there is no + * backend. + */ + sysbus_realize(sbd, &error_abort); + sysbus_mmio_map(sbd, 0, npcm7xx_gmac_addr[i]); + int irq = i == 0 ? NPCM7XX_GMAC1_IRQ : NPCM7XX_GMAC2_IRQ; + /* + * N.B. The values for the second argument sysbus_connect_irq are + * chosen to match the registration order in npcm7xx_emc_realize. + */ + sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, irq)); + } + + /* * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects * specified, but this is a programming error. */ @@ -752,8 +787,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB); create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB); create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB); - create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB); - create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB); create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB); create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB); create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB); diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index 2999b8b..e229efb 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -465,7 +465,6 @@ static void npcm7xx_machine_class_init(ObjectClass *oc, void *data) mc->no_cdrom = 1; mc->no_parallel = 1; mc->default_ram_id = "ram"; - mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); mc->valid_cpu_types = valid_cpu_types; } diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index 7fd99a0..823b493 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -46,8 +46,7 @@ #include "qemu/log.h" #include "qom/object.h" #include "target/arm/cpu-qom.h" - -//#define DEBUG +#include "trace.h" /* TODO @@ -66,12 +65,6 @@ - Enhance UART with modem signals */ -#ifdef DEBUG -# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__) -#else -# define DPRINTF(format, ...) do { } while (0) -#endif - static struct { hwaddr io_base; int irq; @@ -151,8 +144,9 @@ static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset, case ICPR: return s->pending; default: - printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n", - __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad register offset 0x"HWADDR_FMT_plx"\n", + __func__, offset); return 0; } } @@ -173,8 +167,9 @@ static void strongarm_pic_mem_write(void *opaque, hwaddr offset, s->int_idle = (value & 1) ? 0 : ~0; break; default: - printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n", - __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad register offset 0x"HWADDR_FMT_plx"\n", + __func__, offset); break; } strongarm_pic_update(s); @@ -333,7 +328,9 @@ static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr, ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); default: - printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad rtc register read 0x"HWADDR_FMT_plx"\n", + __func__, addr); return 0; } } @@ -375,7 +372,9 @@ static void strongarm_rtc_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad rtc register write 0x"HWADDR_FMT_plx"\n", + __func__, addr); } } @@ -556,12 +555,12 @@ static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset, case GPSR: /* GPIO Pin-Output Set registers */ qemu_log_mask(LOG_GUEST_ERROR, - "strongarm GPIO: read from write only register GPSR\n"); + "%s: read from write only register GPSR\n", __func__); return 0; case GPCR: /* GPIO Pin-Output Clear registers */ qemu_log_mask(LOG_GUEST_ERROR, - "strongarm GPIO: read from write only register GPCR\n"); + "%s: read from write only register GPCR\n", __func__); return 0; case GRER: /* GPIO Rising-Edge Detect Enable registers */ @@ -581,7 +580,9 @@ static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset, return s->status; default: - printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad gpio read offset 0x"HWADDR_FMT_plx"\n", + __func__, offset); } return 0; @@ -626,7 +627,9 @@ static void strongarm_gpio_write(void *opaque, hwaddr offset, break; default: - printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x"HWADDR_FMT_plx"\n", + __func__, offset); } } @@ -782,7 +785,9 @@ static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset, return s->ppfr | ~0x7f001; default: - printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad ppc read offset 0x"HWADDR_FMT_plx "\n", + __func__, offset); } return 0; @@ -817,7 +822,9 @@ static void strongarm_ppc_write(void *opaque, hwaddr offset, break; default: - printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad ppc write offset 0x"HWADDR_FMT_plx"\n", + __func__, offset); } } @@ -1029,8 +1036,13 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s) s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); - DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label, - speed, parity, data_bits, stop_bits); + trace_strongarm_uart_update_parameters((s->chr.chr ? + s->chr.chr->label : "NULL") ?: + "NULL", + speed, + parity, + data_bits, + stop_bits); } static void strongarm_uart_rx_to(void *opaque) @@ -1164,7 +1176,9 @@ static uint64_t strongarm_uart_read(void *opaque, hwaddr addr, return s->utsr1; default: - printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad uart register read 0x"HWADDR_FMT_plx"\n", + __func__, addr); return 0; } } @@ -1221,7 +1235,9 @@ static void strongarm_uart_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad uart register write 0x"HWADDR_FMT_plx"\n", + __func__, addr); } } @@ -1434,7 +1450,7 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr, return 0xffffffff; } if (s->rx_level < 1) { - printf("%s: SSP Rx Underrun\n", __func__); + trace_strongarm_ssp_read_underrun(); return 0xffffffff; } s->rx_level--; @@ -1443,7 +1459,9 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr, strongarm_ssp_fifo_update(s); return retval; default: - printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad ssp register read 0x"HWADDR_FMT_plx"\n", + __func__, addr); break; } return 0; @@ -1458,8 +1476,8 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr, case SSCR0: s->sscr[0] = value & 0xffbf; if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) { - printf("%s: Wrong data size: %i bits\n", __func__, - (int)SSCR0_DSS(value)); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Wrong data size: %i bits\n", + __func__, (int)SSCR0_DSS(value)); } if (!(value & SSCR0_SSE)) { s->sssr = 0; @@ -1471,7 +1489,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr, case SSCR1: s->sscr[1] = value & 0x2f; if (value & SSCR1_LBM) { - printf("%s: Attempt to use SSP LBM mode\n", __func__); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Attempt to use SSP LBM mode\n", + __func__); } strongarm_ssp_fifo_update(s); break; @@ -1509,7 +1529,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad ssp register write 0x"HWADDR_FMT_plx"\n", + __func__, addr); break; } } diff --git a/hw/arm/trace-events b/hw/arm/trace-events index cdc1ea0..fd0d927 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -55,3 +55,18 @@ smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s" smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64 +# strongarm.c +strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d" +strongarm_ssp_read_underrun(void) "SSP rx underrun" + +# z2.c +z2_lcd_reg_update(uint8_t cur, uint8_t i_0, uint8_t i_1, uint8_t i_2, uint32_t value) "cur_reg = 0x%x, buf = [0x%x, 0x%x, 0x%x], value = 0x%x" +z2_lcd_enable_disable_result(const char *result) "LCD %s" +z2_aer915_send_too_long(int8_t msg) "message too long (%i bytes)" +z2_aer915_send(uint8_t reg, uint8_t value) "reg %d value 0x%02x" +z2_aer915_event(int8_t event, int8_t len) "i2c event =0x%x len=%d bytes" + +# xen_arm.c +xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64 +xen_init_ram(uint64_t machine_ram_size) "Initialized xen ram with size 0x%"PRIx64 +xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64 diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index e5fb3ab..aa5f3ca 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -783,22 +783,30 @@ static void vexpress_class_init(ObjectClass *oc, void *data) static void vexpress_a9_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-a9"), + NULL + }; MachineClass *mc = MACHINE_CLASS(oc); VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); mc->desc = "ARM Versatile Express for Cortex-A9"; - mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); + mc->valid_cpu_types = valid_cpu_types; vmc->daughterboard = &a9_daughterboard; } static void vexpress_a15_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-a15"), + NULL + }; MachineClass *mc = MACHINE_CLASS(oc); VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); mc->desc = "ARM Versatile Express for Cortex-A15"; - mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"); + mc->valid_cpu_types = valid_cpu_types; vmc->daughterboard = &a15_daughterboard; diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c index a563152..32776d9 100644 --- a/hw/arm/xen_arm.c +++ b/hw/arm/xen_arm.c @@ -34,6 +34,7 @@ #include "hw/xen/xen-hvm-common.h" #include "sysemu/tpm.h" #include "hw/xen/arch_hvm.h" +#include "trace.h" #define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh") OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM) @@ -91,8 +92,9 @@ static void xen_create_virtio_mmio_devices(XenArmState *xam) sysbus_create_simple("virtio-mmio", base, irq); - DPRINTF("Created virtio-mmio device %d: irq %d base 0x%lx\n", - i, GUEST_VIRTIO_MMIO_SPI_FIRST + i, base); + trace_xen_create_virtio_mmio_devices(i, + GUEST_VIRTIO_MMIO_SPI_FIRST + i, + base); } } @@ -101,6 +103,7 @@ static void xen_init_ram(MachineState *machine) MemoryRegion *sysmem = get_system_memory(); ram_addr_t block_len, ram_size[GUEST_RAM_BANKS]; + trace_xen_init_ram(machine->ram_size); if (machine->ram_size <= GUEST_RAM0_SIZE) { ram_size[0] = machine->ram_size; ram_size[1] = 0; @@ -117,15 +120,10 @@ static void xen_init_ram(MachineState *machine) memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &ram_memory, GUEST_RAM0_BASE, ram_size[0]); memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo); - DPRINTF("Initialized region xen.ram.lo: base 0x%llx size 0x%lx\n", - GUEST_RAM0_BASE, ram_size[0]); - if (ram_size[1] > 0) { memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &ram_memory, GUEST_RAM1_BASE, ram_size[1]); memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi); - DPRINTF("Initialized region xen.ram.hi: base 0x%llx size 0x%lx\n", - GUEST_RAM1_BASE, ram_size[1]); } } @@ -158,7 +156,7 @@ static void xen_enable_tpm(XenArmState *xam) TPMBackend *be = qemu_find_tpm_be("tpm0"); if (be == NULL) { - DPRINTF("Couldn't fine the backend for tpm0\n"); + error_report("Couldn't find tmp0 backend"); return; } dev = qdev_new(TYPE_TPM_TIS_SYSBUS); @@ -168,7 +166,7 @@ static void xen_enable_tpm(XenArmState *xam) sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr); - DPRINTF("Connected tpmdev at address 0x%lx\n", xam->cfg.tpm_base_addr); + trace_xen_enable_tpm(xam->cfg.tpm_base_addr); } #endif @@ -179,8 +177,9 @@ static void xen_arm_init(MachineState *machine) xam->state = g_new0(XenIOState, 1); if (machine->ram_size == 0) { - DPRINTF("ram_size not specified. QEMU machine started without IOREQ" - "(no emulated devices including Virtio)\n"); + warn_report("%s non-zero ram size not specified. QEMU machine started" + " without IOREQ (no emulated devices including virtio)", + MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc); return; } @@ -194,7 +193,7 @@ static void xen_arm_init(MachineState *machine) if (xam->cfg.tpm_base_addr) { xen_enable_tpm(xam); } else { - DPRINTF("tpm-base-addr is not provided. TPM will not be enabled\n"); + warn_report("tpm-base-addr is not provided. TPM will not be enabled"); } #endif } diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 35fa804..a41a118 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -352,13 +352,17 @@ static void zynq_init(MachineState *machine) static void zynq_machine_class_init(ObjectClass *oc, void *data) { + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-a9"), + NULL + }; MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->init = zynq_init; mc->max_cpus = 1; mc->no_sdcard = 1; mc->ignore_memory_transaction_failures = true; - mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); + mc->valid_cpu_types = valid_cpu_types; mc->default_ram_id = "zynq.ext_ram"; } diff --git a/hw/arm/z2.c b/hw/arm/z2.c index a67fba2..eb2ff8d 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -27,13 +27,7 @@ #include "exec/address-spaces.h" #include "qom/object.h" #include "qapi/error.h" - -#ifdef DEBUG_Z2 -#define DPRINTF(fmt, ...) \ - printf(fmt, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) -#endif +#include "trace.h" static const struct keymap map[0x100] = { [0 ... 0xff] = { -1, -1 }, @@ -119,6 +113,8 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value) { ZipitLCD *z = ZIPIT_LCD(dev); uint16_t val; + + trace_z2_lcd_reg_update(z->cur_reg, z->buf[0], z->buf[1], z->buf[2], value); if (z->selected) { z->buf[z->pos] = value & 0xff; z->pos++; @@ -126,22 +122,19 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value) if (z->pos == 3) { switch (z->buf[0]) { case 0x74: - DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]); z->cur_reg = z->buf[2]; break; case 0x76: val = z->buf[1] << 8 | z->buf[2]; - DPRINTF("%s: value: 0x%.4x\n", __func__, val); if (z->cur_reg == 0x22 && val == 0x0000) { z->enabled = 1; - printf("%s: LCD enabled\n", __func__); + trace_z2_lcd_enable_disable_result("enabled"); } else if (z->cur_reg == 0x10 && val == 0x0000) { z->enabled = 0; - printf("%s: LCD disabled\n", __func__); + trace_z2_lcd_enable_disable_result("disabled"); } break; default: - DPRINTF("%s: unknown command!\n", __func__); break; } z->pos = 0; @@ -211,14 +204,12 @@ static int aer915_send(I2CSlave *i2c, uint8_t data) s->buf[s->len] = data; if (s->len++ > 2) { - DPRINTF("%s: message too long (%i bytes)\n", - __func__, s->len); + trace_z2_aer915_send_too_long(s->len); return 1; } if (s->len == 2) { - DPRINTF("%s: reg %d value 0x%02x\n", __func__, - s->buf[0], s->buf[1]); + trace_z2_aer915_send(s->buf[0], s->buf[1]); } return 0; @@ -228,14 +219,12 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event) { AER915State *s = AER915(i2c); + trace_z2_aer915_event(s->len, event); switch (event) { case I2C_START_SEND: s->len = 0; break; case I2C_START_RECV: - if (s->len != 1) { - DPRINTF("%s: short message!?\n", __func__); - } break; case I2C_FINISH: break; diff --git a/hw/core/bus.c b/hw/core/bus.c index c7831b5..b9d8949 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -232,57 +232,6 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev) return g_strdup(object_get_typename(OBJECT(dev))); } -/** - * bus_phases_reset: - * Transition reset method for buses to allow moving - * smoothly from legacy reset method to multi-phases - */ -static void bus_phases_reset(BusState *bus) -{ - ResettableClass *rc = RESETTABLE_GET_CLASS(bus); - - if (rc->phases.enter) { - rc->phases.enter(OBJECT(bus), RESET_TYPE_COLD); - } - if (rc->phases.hold) { - rc->phases.hold(OBJECT(bus)); - } - if (rc->phases.exit) { - rc->phases.exit(OBJECT(bus)); - } -} - -static void bus_transitional_reset(Object *obj) -{ - BusClass *bc = BUS_GET_CLASS(obj); - - /* - * This will call either @bus_phases_reset (for multi-phases transitioned - * buses) or a bus's specific method for not-yet transitioned buses. - * In both case, it does not reset children. - */ - if (bc->reset) { - bc->reset(BUS(obj)); - } -} - -/** - * bus_get_transitional_reset: - * check if the bus's class is ready for multi-phase - */ -static ResettableTrFunction bus_get_transitional_reset(Object *obj) -{ - BusClass *dc = BUS_GET_CLASS(obj); - if (dc->reset != bus_phases_reset) { - /* - * dc->reset has been overridden by a subclass, - * the bus is not ready for multi phase yet. - */ - return bus_transitional_reset; - } - return NULL; -} - static void bus_class_init(ObjectClass *class, void *data) { BusClass *bc = BUS_CLASS(class); @@ -293,22 +242,6 @@ static void bus_class_init(ObjectClass *class, void *data) rc->get_state = bus_get_reset_state; rc->child_foreach = bus_reset_child_foreach; - - /* - * @bus_phases_reset is put as the default reset method below, allowing - * to do the multi-phase transition from base classes to leaf classes. It - * allows a legacy-reset Bus class to extend a multi-phases-reset - * Bus class for the following reason: - * + If a base class B has been moved to multi-phase, then it does not - * override this default reset method and may have defined phase methods. - * + A child class C (extending class B) which uses - * bus_class_set_parent_reset() (or similar means) to override the - * reset method will still work as expected. @bus_phases_reset function - * will be registered as the parent reset method and effectively call - * parent reset phases. - */ - bc->reset = bus_phases_reset; - rc->get_transitional_function = bus_get_transitional_reset; } static void qbus_finalize(Object *obj) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index c86d189..380239a 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -2453,9 +2453,9 @@ static void vmbus_unrealize(BusState *bus) qemu_mutex_destroy(&vmbus->rx_queue_lock); } -static void vmbus_reset(BusState *bus) +static void vmbus_reset_hold(Object *obj) { - vmbus_deinit(VMBUS(bus)); + vmbus_deinit(VMBUS(obj)); } static char *vmbus_get_dev_path(DeviceState *dev) @@ -2476,12 +2476,13 @@ static char *vmbus_get_fw_dev_path(DeviceState *dev) static void vmbus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); k->get_dev_path = vmbus_get_dev_path; k->get_fw_dev_path = vmbus_get_fw_dev_path; k->realize = vmbus_realize; k->unrealize = vmbus_unrealize; - k->reset = vmbus_reset; + rc->phases.hold = vmbus_reset_hold; } static int vmbus_pre_load(void *opaque) diff --git a/hw/input/adb.c b/hw/input/adb.c index 0f3c73d..98f39b4 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -231,9 +231,9 @@ static const VMStateDescription vmstate_adb_bus = { } }; -static void adb_bus_reset(BusState *qbus) +static void adb_bus_reset_hold(Object *obj) { - ADBBusState *adb_bus = ADB_BUS(qbus); + ADBBusState *adb_bus = ADB_BUS(obj); adb_bus->autopoll_enabled = false; adb_bus->autopoll_mask = 0xffff; @@ -262,10 +262,11 @@ static void adb_bus_unrealize(BusState *qbus) static void adb_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); k->realize = adb_bus_realize; k->unrealize = adb_bus_unrealize; - k->reset = adb_bus_reset; + rc->phases.hold = adb_bus_reset_hold; } static const TypeInfo adb_bus_type_info = { diff --git a/hw/net/meson.build b/hw/net/meson.build index 2b426d3..b742687 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -38,7 +38,7 @@ system_ss.add(when: 'CONFIG_I82596_COMMON', if_true: files('i82596.c')) system_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c')) system_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c')) system_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c')) -system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c')) +system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c', 'npcm_gmac.c')) system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c')) system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c')) diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c new file mode 100644 index 0000000..1b71e25 --- /dev/null +++ b/hw/net/npcm_gmac.c @@ -0,0 +1,942 @@ +/* + * Nuvoton NPCM7xx/8xx GMAC Module + * + * Copyright 2024 Google LLC + * Authors: + * Hao Wu <wuhaotsh@google.com> + * Nabih Estefan <nabihestefan@google.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * Unsupported/unimplemented features: + * - MII is not implemented, MII_ADDR.BUSY and MII_DATA always return zero + * - Precision timestamp (PTP) is not implemented. + */ + +#include "qemu/osdep.h" + +#include "hw/registerfields.h" +#include "hw/net/mii.h" +#include "hw/net/npcm_gmac.h" +#include "migration/vmstate.h" +#include "net/checksum.h" +#include "net/eth.h" +#include "net/net.h" +#include "qemu/cutils.h" +#include "qemu/log.h" +#include "qemu/units.h" +#include "sysemu/dma.h" +#include "trace.h" + +REG32(NPCM_DMA_BUS_MODE, 0x1000) +REG32(NPCM_DMA_XMT_POLL_DEMAND, 0x1004) +REG32(NPCM_DMA_RCV_POLL_DEMAND, 0x1008) +REG32(NPCM_DMA_RX_BASE_ADDR, 0x100c) +REG32(NPCM_DMA_TX_BASE_ADDR, 0x1010) +REG32(NPCM_DMA_STATUS, 0x1014) +REG32(NPCM_DMA_CONTROL, 0x1018) +REG32(NPCM_DMA_INTR_ENA, 0x101c) +REG32(NPCM_DMA_MISSED_FRAME_CTR, 0x1020) +REG32(NPCM_DMA_HOST_TX_DESC, 0x1048) +REG32(NPCM_DMA_HOST_RX_DESC, 0x104c) +REG32(NPCM_DMA_CUR_TX_BUF_ADDR, 0x1050) +REG32(NPCM_DMA_CUR_RX_BUF_ADDR, 0x1054) +REG32(NPCM_DMA_HW_FEATURE, 0x1058) + +REG32(NPCM_GMAC_MAC_CONFIG, 0x0) +REG32(NPCM_GMAC_FRAME_FILTER, 0x4) +REG32(NPCM_GMAC_HASH_HIGH, 0x8) +REG32(NPCM_GMAC_HASH_LOW, 0xc) +REG32(NPCM_GMAC_MII_ADDR, 0x10) +REG32(NPCM_GMAC_MII_DATA, 0x14) +REG32(NPCM_GMAC_FLOW_CTRL, 0x18) +REG32(NPCM_GMAC_VLAN_FLAG, 0x1c) +REG32(NPCM_GMAC_VERSION, 0x20) +REG32(NPCM_GMAC_WAKEUP_FILTER, 0x28) +REG32(NPCM_GMAC_PMT, 0x2c) +REG32(NPCM_GMAC_LPI_CTRL, 0x30) +REG32(NPCM_GMAC_TIMER_CTRL, 0x34) +REG32(NPCM_GMAC_INT_STATUS, 0x38) +REG32(NPCM_GMAC_INT_MASK, 0x3c) +REG32(NPCM_GMAC_MAC0_ADDR_HI, 0x40) +REG32(NPCM_GMAC_MAC0_ADDR_LO, 0x44) +REG32(NPCM_GMAC_MAC1_ADDR_HI, 0x48) +REG32(NPCM_GMAC_MAC1_ADDR_LO, 0x4c) +REG32(NPCM_GMAC_MAC2_ADDR_HI, 0x50) +REG32(NPCM_GMAC_MAC2_ADDR_LO, 0x54) +REG32(NPCM_GMAC_MAC3_ADDR_HI, 0x58) +REG32(NPCM_GMAC_MAC3_ADDR_LO, 0x5c) +REG32(NPCM_GMAC_RGMII_STATUS, 0xd8) +REG32(NPCM_GMAC_WATCHDOG, 0xdc) +REG32(NPCM_GMAC_PTP_TCR, 0x700) +REG32(NPCM_GMAC_PTP_SSIR, 0x704) +REG32(NPCM_GMAC_PTP_STSR, 0x708) +REG32(NPCM_GMAC_PTP_STNSR, 0x70c) +REG32(NPCM_GMAC_PTP_STSUR, 0x710) +REG32(NPCM_GMAC_PTP_STNSUR, 0x714) +REG32(NPCM_GMAC_PTP_TAR, 0x718) +REG32(NPCM_GMAC_PTP_TTSR, 0x71c) + +/* Register Fields */ +#define NPCM_GMAC_MII_ADDR_BUSY BIT(0) +#define NPCM_GMAC_MII_ADDR_WRITE BIT(1) +#define NPCM_GMAC_MII_ADDR_GR(rv) extract16((rv), 6, 5) +#define NPCM_GMAC_MII_ADDR_PA(rv) extract16((rv), 11, 5) + +#define NPCM_GMAC_INT_MASK_LPIIM BIT(10) +#define NPCM_GMAC_INT_MASK_PMTM BIT(3) +#define NPCM_GMAC_INT_MASK_RGIM BIT(0) + +#define NPCM_DMA_BUS_MODE_SWR BIT(0) + +static const uint32_t npcm_gmac_cold_reset_values[NPCM_GMAC_NR_REGS] = { + /* Reduce version to 3.2 so that the kernel can enable interrupt. */ + [R_NPCM_GMAC_VERSION] = 0x00001032, + [R_NPCM_GMAC_TIMER_CTRL] = 0x03e80000, + [R_NPCM_GMAC_MAC0_ADDR_HI] = 0x8000ffff, + [R_NPCM_GMAC_MAC0_ADDR_LO] = 0xffffffff, + [R_NPCM_GMAC_MAC1_ADDR_HI] = 0x0000ffff, + [R_NPCM_GMAC_MAC1_ADDR_LO] = 0xffffffff, + [R_NPCM_GMAC_MAC2_ADDR_HI] = 0x0000ffff, + [R_NPCM_GMAC_MAC2_ADDR_LO] = 0xffffffff, + [R_NPCM_GMAC_MAC3_ADDR_HI] = 0x0000ffff, + [R_NPCM_GMAC_MAC3_ADDR_LO] = 0xffffffff, + [R_NPCM_GMAC_PTP_TCR] = 0x00002000, + [R_NPCM_DMA_BUS_MODE] = 0x00020101, + [R_NPCM_DMA_HW_FEATURE] = 0x100d4f37, +}; + +static const uint16_t phy_reg_init[] = { + [MII_BMCR] = MII_BMCR_AUTOEN | MII_BMCR_FD | MII_BMCR_SPEED1000, + [MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD | + MII_BMSR_10T_HD | MII_BMSR_EXTSTAT | MII_BMSR_AUTONEG | + MII_BMSR_LINK_ST | MII_BMSR_EXTCAP, + [MII_PHYID1] = 0x0362, + [MII_PHYID2] = 0x5e6a, + [MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD | + MII_ANAR_10 | MII_ANAR_CSMACD, + [MII_ANLPAR] = MII_ANLPAR_ACK | MII_ANLPAR_PAUSE | + MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | + MII_ANLPAR_10 | MII_ANLPAR_CSMACD, + [MII_ANER] = 0x64 | MII_ANER_NWAY, + [MII_ANNP] = 0x2001, + [MII_CTRL1000] = MII_CTRL1000_FULL, + [MII_STAT1000] = MII_STAT1000_FULL, + [MII_EXTSTAT] = 0x3000, /* 1000BASTE_T full-duplex capable */ +}; + +static void npcm_gmac_soft_reset(NPCMGMACState *gmac) +{ + memcpy(gmac->regs, npcm_gmac_cold_reset_values, + NPCM_GMAC_NR_REGS * sizeof(uint32_t)); + /* Clear reset bits */ + gmac->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR; +} + +static void gmac_phy_set_link(NPCMGMACState *gmac, bool active) +{ + /* Autonegotiation status mirrors link status. */ + if (active) { + gmac->phy_regs[0][MII_BMSR] |= (MII_BMSR_LINK_ST | MII_BMSR_AN_COMP); + } else { + gmac->phy_regs[0][MII_BMSR] &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP); + } +} + +static bool gmac_can_receive(NetClientState *nc) +{ + NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc)); + + /* If GMAC receive is disabled. */ + if (!(gmac->regs[R_NPCM_GMAC_MAC_CONFIG] & NPCM_GMAC_MAC_CONFIG_RX_EN)) { + return false; + } + + /* If GMAC DMA RX is stopped. */ + if (!(gmac->regs[R_NPCM_DMA_CONTROL] & NPCM_DMA_CONTROL_START_STOP_RX)) { + return false; + } + return true; +} + +/* + * Function that updates the GMAC IRQ + * It find the logical OR of the enabled bits for NIS (if enabled) + * It find the logical OR of the enabled bits for AIS (if enabled) + */ +static void gmac_update_irq(NPCMGMACState *gmac) +{ + /* + * Check if the normal interrupts summary is enabled + * if so, add the bits for the summary that are enabled + */ + if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] & + (NPCM_DMA_INTR_ENAB_NIE_BITS)) { + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_NIS; + } + /* + * Check if the abnormal interrupts summary is enabled + * if so, add the bits for the summary that are enabled + */ + if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] & + (NPCM_DMA_INTR_ENAB_AIE_BITS)) { + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_AIS; + } + + /* Get the logical OR of both normal and abnormal interrupts */ + int level = !!((gmac->regs[R_NPCM_DMA_STATUS] & + gmac->regs[R_NPCM_DMA_INTR_ENA] & + NPCM_DMA_STATUS_NIS) | + (gmac->regs[R_NPCM_DMA_STATUS] & + gmac->regs[R_NPCM_DMA_INTR_ENA] & + NPCM_DMA_STATUS_AIS)); + + /* Set the IRQ */ + trace_npcm_gmac_update_irq(DEVICE(gmac)->canonical_path, + gmac->regs[R_NPCM_DMA_STATUS], + gmac->regs[R_NPCM_DMA_INTR_ENA], + level); + qemu_set_irq(gmac->irq, level); +} + +static int gmac_read_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc) +{ + if (dma_memory_read(&address_space_memory, addr, desc, + sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; + } + desc->rdes0 = le32_to_cpu(desc->rdes0); + desc->rdes1 = le32_to_cpu(desc->rdes1); + desc->rdes2 = le32_to_cpu(desc->rdes2); + desc->rdes3 = le32_to_cpu(desc->rdes3); + return 0; +} + +static int gmac_write_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc) +{ + struct NPCMGMACRxDesc le_desc; + le_desc.rdes0 = cpu_to_le32(desc->rdes0); + le_desc.rdes1 = cpu_to_le32(desc->rdes1); + le_desc.rdes2 = cpu_to_le32(desc->rdes2); + le_desc.rdes3 = cpu_to_le32(desc->rdes3); + if (dma_memory_write(&address_space_memory, addr, &le_desc, + sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; + } + return 0; +} + +static int gmac_read_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc) +{ + if (dma_memory_read(&address_space_memory, addr, desc, + sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; + } + desc->tdes0 = le32_to_cpu(desc->tdes0); + desc->tdes1 = le32_to_cpu(desc->tdes1); + desc->tdes2 = le32_to_cpu(desc->tdes2); + desc->tdes3 = le32_to_cpu(desc->tdes3); + return 0; +} + +static int gmac_write_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc) +{ + struct NPCMGMACTxDesc le_desc; + le_desc.tdes0 = cpu_to_le32(desc->tdes0); + le_desc.tdes1 = cpu_to_le32(desc->tdes1); + le_desc.tdes2 = cpu_to_le32(desc->tdes2); + le_desc.tdes3 = cpu_to_le32(desc->tdes3); + if (dma_memory_write(&address_space_memory, addr, &le_desc, + sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%" + HWADDR_PRIx "\n", __func__, addr); + return -1; + } + return 0; +} + +static int gmac_rx_transfer_frame_to_buffer(uint32_t rx_buf_len, + uint32_t *left_frame, + uint32_t rx_buf_addr, + bool *eof_transferred, + const uint8_t **frame_ptr, + uint16_t *transferred) +{ + uint32_t to_transfer; + /* + * Check that buffer is bigger than the frame being transfered + * If bigger then transfer only whats left of frame + * Else, fill frame with all the content possible + */ + if (rx_buf_len >= *left_frame) { + to_transfer = *left_frame; + *eof_transferred = true; + } else { + to_transfer = rx_buf_len; + } + + /* write frame part to memory */ + if (dma_memory_write(&address_space_memory, (uint64_t) rx_buf_addr, + *frame_ptr, to_transfer, MEMTXATTRS_UNSPECIFIED)) { + return -1; + } + + /* update frame pointer and size of whats left of frame */ + *frame_ptr += to_transfer; + *left_frame -= to_transfer; + *transferred += to_transfer; + + return 0; +} + +static void gmac_dma_set_state(NPCMGMACState *gmac, int shift, uint32_t state) +{ + gmac->regs[R_NPCM_DMA_STATUS] = deposit32(gmac->regs[R_NPCM_DMA_STATUS], + shift, 3, state); +} + +static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len) +{ + /* + * Comments have steps that relate to the + * receiving process steps in pg 386 + */ + NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc)); + uint32_t left_frame = len; + const uint8_t *frame_ptr = buf; + uint32_t desc_addr; + uint32_t rx_buf_len, rx_buf_addr; + struct NPCMGMACRxDesc rx_desc; + uint16_t transferred = 0; + bool eof_transferred = false; + + trace_npcm_gmac_packet_receive(DEVICE(gmac)->canonical_path, len); + if (!gmac_can_receive(nc)) { + qemu_log_mask(LOG_GUEST_ERROR, "GMAC Currently is not able for Rx"); + return -1; + } + if (!gmac->regs[R_NPCM_DMA_HOST_RX_DESC]) { + gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = + NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]); + } + desc_addr = NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_HOST_RX_DESC]); + + /* step 1 */ + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_RUNNING_FETCHING_STATE); + trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, desc_addr); + if (gmac_read_rx_desc(desc_addr, &rx_desc)) { + qemu_log_mask(LOG_GUEST_ERROR, "RX Descriptor @ 0x%x cant be read\n", + desc_addr); + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_SUSPENDED_STATE); + return -1; + } + + /* step 2 */ + if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) { + qemu_log_mask(LOG_GUEST_ERROR, + "RX Descriptor @ 0x%x is owned by software\n", + desc_addr); + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU; + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI; + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_SUSPENDED_STATE); + gmac_update_irq(gmac); + return len; + } + /* step 3 */ + /* + * TODO -- + * Implement all frame filtering and processing (with its own interrupts) + */ + trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc, + rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2, + rx_desc.rdes3); + /* Clear rdes0 for the incoming descriptor and set FS in first descriptor.*/ + rx_desc.rdes0 = RX_DESC_RDES0_FIRST_DESC_MASK; + + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_RUNNING_TRANSFERRING_STATE); + + /* Pad the frame with FCS as the kernel driver will strip it away. */ + left_frame += ETH_FCS_LEN; + + /* repeat while we still have frame to transfer to memory */ + while (!eof_transferred) { + /* Return descriptor no matter what happens */ + rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN; + /* Set the frame to be an IPv4/IPv6 frame. */ + rx_desc.rdes0 |= RX_DESC_RDES0_FRM_TYPE_MASK; + + /* step 4 */ + rx_buf_len = RX_DESC_RDES1_BFFR1_SZ_MASK(rx_desc.rdes1); + rx_buf_addr = rx_desc.rdes2; + gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr; + gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame, rx_buf_addr, + &eof_transferred, &frame_ptr, + &transferred); + + trace_npcm_gmac_packet_receiving_buffer(DEVICE(gmac)->canonical_path, + rx_buf_len, rx_buf_addr); + /* if we still have frame left and the second buffer is not chained */ + if (!(rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) && \ + !eof_transferred) { + /* repeat process from above on buffer 2 */ + rx_buf_len = RX_DESC_RDES1_BFFR2_SZ_MASK(rx_desc.rdes1); + rx_buf_addr = rx_desc.rdes3; + gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr; + gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame, + rx_buf_addr, &eof_transferred, + &frame_ptr, &transferred); + trace_npcm_gmac_packet_receiving_buffer( \ + DEVICE(gmac)->canonical_path, + rx_buf_len, rx_buf_addr); + } + /* update address for descriptor */ + gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = rx_buf_addr; + /* Return descriptor */ + rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN; + /* Update frame length transferred */ + rx_desc.rdes0 |= ((uint32_t)transferred) + << RX_DESC_RDES0_FRAME_LEN_SHIFT; + trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc, + rx_desc.rdes0, rx_desc.rdes1, + rx_desc.rdes2, rx_desc.rdes3); + + /* step 5 */ + gmac_write_rx_desc(desc_addr, &rx_desc); + trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, + &rx_desc, rx_desc.rdes0, + rx_desc.rdes1, rx_desc.rdes2, + rx_desc.rdes3); + /* read new descriptor into rx_desc if needed*/ + if (!eof_transferred) { + /* Get next descriptor address (chained or sequential) */ + if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) { + desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]; + } else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) { + desc_addr = rx_desc.rdes3; + } else { + desc_addr += sizeof(rx_desc); + } + trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, + desc_addr); + if (gmac_read_rx_desc(desc_addr, &rx_desc)) { + qemu_log_mask(LOG_GUEST_ERROR, + "RX Descriptor @ 0x%x cant be read\n", + desc_addr); + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU; + gmac_update_irq(gmac); + return len; + } + + /* step 6 */ + if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) { + if (!(gmac->regs[R_NPCM_DMA_CONTROL] & \ + NPCM_DMA_CONTROL_FLUSH_MASK)) { + rx_desc.rdes0 |= RX_DESC_RDES0_DESC_ERR_MASK; + } + eof_transferred = true; + } + /* Clear rdes0 for the incoming descriptor */ + rx_desc.rdes0 = 0; + } + } + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_RUNNING_CLOSING_STATE); + + rx_desc.rdes0 |= RX_DESC_RDES0_LAST_DESC_MASK; + if (!(rx_desc.rdes1 & RX_DESC_RDES1_DIS_INTR_COMP_MASK)) { + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI; + gmac_update_irq(gmac); + } + trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc, + rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2, + rx_desc.rdes3); + + /* step 8 */ + gmac->regs[R_NPCM_DMA_CONTROL] |= NPCM_DMA_CONTROL_FLUSH_MASK; + + /* step 9 */ + trace_npcm_gmac_packet_received(DEVICE(gmac)->canonical_path, left_frame); + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE); + gmac_write_rx_desc(desc_addr, &rx_desc); + + /* Get next descriptor address (chained or sequential) */ + if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) { + desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]; + } else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) { + desc_addr = rx_desc.rdes3; + } else { + desc_addr += sizeof(rx_desc); + } + gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = desc_addr; + return len; +} + +static int gmac_tx_get_csum(uint32_t tdes1) +{ + uint32_t mask = TX_DESC_TDES1_CHKSM_INS_CTRL_MASK(tdes1); + int csum = 0; + + if (likely(mask > 0)) { + csum |= CSUM_IP; + } + if (likely(mask > 1)) { + csum |= CSUM_TCP | CSUM_UDP; + } + + return csum; +} + +static void gmac_try_send_next_packet(NPCMGMACState *gmac) +{ + /* + * Comments about steps refer to steps for + * transmitting in page 384 of datasheet + */ + uint16_t tx_buffer_size = 2048; + g_autofree uint8_t *tx_send_buffer = g_malloc(tx_buffer_size); + uint32_t desc_addr; + struct NPCMGMACTxDesc tx_desc; + uint32_t tx_buf_addr, tx_buf_len; + uint16_t length = 0; + uint8_t *buf = tx_send_buffer; + uint32_t prev_buf_size = 0; + int csum = 0; + + /* steps 1&2 */ + if (!gmac->regs[R_NPCM_DMA_HOST_TX_DESC]) { + gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = + NPCM_DMA_HOST_TX_DESC_MASK(gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]); + } + desc_addr = gmac->regs[R_NPCM_DMA_HOST_TX_DESC]; + + while (true) { + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_RUNNING_FETCHING_STATE); + if (gmac_read_tx_desc(desc_addr, &tx_desc)) { + qemu_log_mask(LOG_GUEST_ERROR, + "TX Descriptor @ 0x%x can't be read\n", + desc_addr); + return; + } + /* step 3 */ + + trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, + desc_addr); + trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &tx_desc, + tx_desc.tdes0, tx_desc.tdes1, tx_desc.tdes2, tx_desc.tdes3); + + /* 1 = DMA Owned, 0 = Software Owned */ + if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) { + qemu_log_mask(LOG_GUEST_ERROR, + "TX Descriptor @ 0x%x is owned by software\n", + desc_addr); + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU; + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_SUSPENDED_STATE); + gmac_update_irq(gmac); + return; + } + + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_RUNNING_READ_STATE); + /* Give the descriptor back regardless of what happens. */ + tx_desc.tdes0 &= ~TX_DESC_TDES0_OWN; + + if (tx_desc.tdes1 & TX_DESC_TDES1_FIRST_SEG_MASK) { + csum = gmac_tx_get_csum(tx_desc.tdes1); + } + + /* step 4 */ + tx_buf_addr = tx_desc.tdes2; + gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr; + tx_buf_len = TX_DESC_TDES1_BFFR1_SZ_MASK(tx_desc.tdes1); + buf = &tx_send_buffer[prev_buf_size]; + + if ((prev_buf_size + tx_buf_len) > sizeof(buf)) { + tx_buffer_size = prev_buf_size + tx_buf_len; + tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size); + buf = &tx_send_buffer[prev_buf_size]; + } + + /* step 5 */ + if (dma_memory_read(&address_space_memory, tx_buf_addr, buf, + tx_buf_len, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n", + __func__, tx_buf_addr); + return; + } + length += tx_buf_len; + prev_buf_size += tx_buf_len; + + /* If not chained we'll have a second buffer. */ + if (!(tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK)) { + tx_buf_addr = tx_desc.tdes3; + gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr; + tx_buf_len = TX_DESC_TDES1_BFFR2_SZ_MASK(tx_desc.tdes1); + buf = &tx_send_buffer[prev_buf_size]; + + if ((prev_buf_size + tx_buf_len) > sizeof(buf)) { + tx_buffer_size = prev_buf_size + tx_buf_len; + tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size); + buf = &tx_send_buffer[prev_buf_size]; + } + + if (dma_memory_read(&address_space_memory, tx_buf_addr, buf, + tx_buf_len, MEMTXATTRS_UNSPECIFIED)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to read packet @ 0x%x\n", + __func__, tx_buf_addr); + return; + } + length += tx_buf_len; + prev_buf_size += tx_buf_len; + } + if (tx_desc.tdes1 & TX_DESC_TDES1_LAST_SEG_MASK) { + net_checksum_calculate(tx_send_buffer, length, csum); + qemu_send_packet(qemu_get_queue(gmac->nic), tx_send_buffer, length); + trace_npcm_gmac_packet_sent(DEVICE(gmac)->canonical_path, length); + buf = tx_send_buffer; + length = 0; + } + + /* step 6 */ + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_RUNNING_CLOSING_STATE); + gmac_write_tx_desc(desc_addr, &tx_desc); + if (tx_desc.tdes1 & TX_DESC_TDES1_TX_END_RING_MASK) { + desc_addr = gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]; + } else if (tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK) { + desc_addr = tx_desc.tdes3; + } else { + desc_addr += sizeof(tx_desc); + } + gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = desc_addr; + + /* step 7 */ + if (tx_desc.tdes1 & TX_DESC_TDES1_INTERR_COMP_MASK) { + gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TI; + gmac_update_irq(gmac); + } + } +} + +static void gmac_cleanup(NetClientState *nc) +{ + /* Nothing to do yet. */ +} + +static void gmac_set_link(NetClientState *nc) +{ + NPCMGMACState *gmac = qemu_get_nic_opaque(nc); + + trace_npcm_gmac_set_link(!nc->link_down); + gmac_phy_set_link(gmac, !nc->link_down); +} + +static void npcm_gmac_mdio_access(NPCMGMACState *gmac, uint16_t v) +{ + bool busy = v & NPCM_GMAC_MII_ADDR_BUSY; + uint8_t is_write; + uint8_t pa, gr; + uint16_t data; + + if (busy) { + is_write = v & NPCM_GMAC_MII_ADDR_WRITE; + pa = NPCM_GMAC_MII_ADDR_PA(v); + gr = NPCM_GMAC_MII_ADDR_GR(v); + /* Both pa and gr are 5 bits, so they are less than 32. */ + g_assert(pa < NPCM_GMAC_MAX_PHYS); + g_assert(gr < NPCM_GMAC_MAX_PHY_REGS); + + + if (v & NPCM_GMAC_MII_ADDR_WRITE) { + data = gmac->regs[R_NPCM_GMAC_MII_DATA]; + /* Clear reset bit for BMCR register */ + switch (gr) { + case MII_BMCR: + data &= ~MII_BMCR_RESET; + /* Autonegotiation is a W1C bit*/ + if (data & MII_BMCR_ANRESTART) { + /* Tells autonegotiation to not restart again */ + data &= ~MII_BMCR_ANRESTART; + } + if ((data & MII_BMCR_AUTOEN) && + !(gmac->phy_regs[pa][MII_BMSR] & MII_BMSR_AN_COMP)) { + /* sets autonegotiation as complete */ + gmac->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP; + /* Resolve AN automatically->need to set this */ + gmac->phy_regs[0][MII_ANLPAR] = 0x0000; + } + } + gmac->phy_regs[pa][gr] = data; + } else { + data = gmac->phy_regs[pa][gr]; + gmac->regs[R_NPCM_GMAC_MII_DATA] = data; + } + trace_npcm_gmac_mdio_access(DEVICE(gmac)->canonical_path, is_write, pa, + gr, data); + } + gmac->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY; +} + +static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size) +{ + NPCMGMACState *gmac = opaque; + uint32_t v = 0; + + switch (offset) { + /* Write only registers */ + case A_NPCM_DMA_XMT_POLL_DEMAND: + case A_NPCM_DMA_RCV_POLL_DEMAND: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Read of write-only reg: offset: 0x%04" HWADDR_PRIx + "\n", DEVICE(gmac)->canonical_path, offset); + break; + + default: + v = gmac->regs[offset / sizeof(uint32_t)]; + } + + trace_npcm_gmac_reg_read(DEVICE(gmac)->canonical_path, offset, v); + return v; +} + +static void npcm_gmac_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ + NPCMGMACState *gmac = opaque; + + trace_npcm_gmac_reg_write(DEVICE(gmac)->canonical_path, offset, v); + + switch (offset) { + /* Read only registers */ + case A_NPCM_GMAC_VERSION: + case A_NPCM_GMAC_INT_STATUS: + case A_NPCM_GMAC_RGMII_STATUS: + case A_NPCM_GMAC_PTP_STSR: + case A_NPCM_GMAC_PTP_STNSR: + case A_NPCM_DMA_MISSED_FRAME_CTR: + case A_NPCM_DMA_HOST_TX_DESC: + case A_NPCM_DMA_HOST_RX_DESC: + case A_NPCM_DMA_CUR_TX_BUF_ADDR: + case A_NPCM_DMA_CUR_RX_BUF_ADDR: + case A_NPCM_DMA_HW_FEATURE: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Write of read-only reg: offset: 0x%04" HWADDR_PRIx + ", value: 0x%04" PRIx64 "\n", + DEVICE(gmac)->canonical_path, offset, v); + break; + + case A_NPCM_GMAC_MAC_CONFIG: + gmac->regs[offset / sizeof(uint32_t)] = v; + break; + + case A_NPCM_GMAC_MII_ADDR: + npcm_gmac_mdio_access(gmac, v); + break; + + case A_NPCM_GMAC_MAC0_ADDR_HI: + gmac->regs[offset / sizeof(uint32_t)] = v; + gmac->conf.macaddr.a[0] = v >> 8; + gmac->conf.macaddr.a[1] = v >> 0; + break; + + case A_NPCM_GMAC_MAC0_ADDR_LO: + gmac->regs[offset / sizeof(uint32_t)] = v; + gmac->conf.macaddr.a[2] = v >> 24; + gmac->conf.macaddr.a[3] = v >> 16; + gmac->conf.macaddr.a[4] = v >> 8; + gmac->conf.macaddr.a[5] = v >> 0; + break; + + case A_NPCM_GMAC_MAC1_ADDR_HI: + case A_NPCM_GMAC_MAC1_ADDR_LO: + case A_NPCM_GMAC_MAC2_ADDR_HI: + case A_NPCM_GMAC_MAC2_ADDR_LO: + case A_NPCM_GMAC_MAC3_ADDR_HI: + case A_NPCM_GMAC_MAC3_ADDR_LO: + gmac->regs[offset / sizeof(uint32_t)] = v; + qemu_log_mask(LOG_UNIMP, + "%s: Only MAC Address 0 is supported. This request " + "is ignored.\n", DEVICE(gmac)->canonical_path); + break; + + case A_NPCM_DMA_BUS_MODE: + gmac->regs[offset / sizeof(uint32_t)] = v; + if (v & NPCM_DMA_BUS_MODE_SWR) { + npcm_gmac_soft_reset(gmac); + } + break; + + case A_NPCM_DMA_RCV_POLL_DEMAND: + /* We dont actually care about the value */ + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE); + break; + + case A_NPCM_DMA_XMT_POLL_DEMAND: + /* We dont actually care about the value */ + gmac_try_send_next_packet(gmac); + break; + + case A_NPCM_DMA_CONTROL: + gmac->regs[offset / sizeof(uint32_t)] = v; + if (v & NPCM_DMA_CONTROL_START_STOP_TX) { + gmac_try_send_next_packet(gmac); + } else { + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_TX_STOPPED_STATE); + } + if (v & NPCM_DMA_CONTROL_START_STOP_RX) { + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE); + qemu_flush_queued_packets(qemu_get_queue(gmac->nic)); + } else { + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_STOPPED_STATE); + } + break; + + case A_NPCM_DMA_STATUS: + /* Check that RO bits are not written to */ + if (NPCM_DMA_STATUS_RO_MASK(v)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Write of read-only bits of reg: offset: 0x%04" + HWADDR_PRIx ", value: 0x%04" PRIx64 "\n", + DEVICE(gmac)->canonical_path, offset, v); + } + /* for W1C bits, implement W1C */ + gmac->regs[offset / sizeof(uint32_t)] &= ~NPCM_DMA_STATUS_W1C_MASK(v); + if (v & NPCM_DMA_STATUS_RU) { + /* Clearing RU bit indicates descriptor is owned by DMA again. */ + gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, + NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE); + qemu_flush_queued_packets(qemu_get_queue(gmac->nic)); + } + break; + + default: + gmac->regs[offset / sizeof(uint32_t)] = v; + break; + } + + gmac_update_irq(gmac); +} + +static void npcm_gmac_reset(DeviceState *dev) +{ + NPCMGMACState *gmac = NPCM_GMAC(dev); + + npcm_gmac_soft_reset(gmac); + memcpy(gmac->phy_regs[0], phy_reg_init, sizeof(phy_reg_init)); + + trace_npcm_gmac_reset(DEVICE(gmac)->canonical_path, + gmac->phy_regs[0][MII_BMSR]); +} + +static NetClientInfo net_npcm_gmac_info = { + .type = NET_CLIENT_DRIVER_NIC, + .size = sizeof(NICState), + .can_receive = gmac_can_receive, + .receive = gmac_receive, + .cleanup = gmac_cleanup, + .link_status_changed = gmac_set_link, +}; + +static const struct MemoryRegionOps npcm_gmac_ops = { + .read = npcm_gmac_read, + .write = npcm_gmac_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void npcm_gmac_realize(DeviceState *dev, Error **errp) +{ + NPCMGMACState *gmac = NPCM_GMAC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&gmac->iomem, OBJECT(gmac), &npcm_gmac_ops, gmac, + TYPE_NPCM_GMAC, 8 * KiB); + sysbus_init_mmio(sbd, &gmac->iomem); + sysbus_init_irq(sbd, &gmac->irq); + + qemu_macaddr_default_if_unset(&gmac->conf.macaddr); + + gmac->nic = qemu_new_nic(&net_npcm_gmac_info, &gmac->conf, TYPE_NPCM_GMAC, + dev->id, &dev->mem_reentrancy_guard, gmac); + qemu_format_nic_info_str(qemu_get_queue(gmac->nic), gmac->conf.macaddr.a); + gmac->regs[R_NPCM_GMAC_MAC0_ADDR_HI] = (gmac->conf.macaddr.a[0] << 8) + \ + gmac->conf.macaddr.a[1]; + gmac->regs[R_NPCM_GMAC_MAC0_ADDR_LO] = (gmac->conf.macaddr.a[2] << 24) + \ + (gmac->conf.macaddr.a[3] << 16) + \ + (gmac->conf.macaddr.a[4] << 8) + \ + gmac->conf.macaddr.a[5]; +} + +static void npcm_gmac_unrealize(DeviceState *dev) +{ + NPCMGMACState *gmac = NPCM_GMAC(dev); + + qemu_del_nic(gmac->nic); +} + +static const VMStateDescription vmstate_npcm_gmac = { + .name = TYPE_NPCM_GMAC, + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, NPCMGMACState, NPCM_GMAC_NR_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + +static Property npcm_gmac_properties[] = { + DEFINE_NIC_PROPERTIES(NPCMGMACState, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void npcm_gmac_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->desc = "NPCM GMAC Controller"; + dc->realize = npcm_gmac_realize; + dc->unrealize = npcm_gmac_unrealize; + dc->reset = npcm_gmac_reset; + dc->vmsd = &vmstate_npcm_gmac; + device_class_set_props(dc, npcm_gmac_properties); +} + +static const TypeInfo npcm_gmac_types[] = { + { + .name = TYPE_NPCM_GMAC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCMGMACState), + .class_init = npcm_gmac_class_init, + }, +}; +DEFINE_TYPES(npcm_gmac_types) diff --git a/hw/net/trace-events b/hw/net/trace-events index 387e32e..78efa2e 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -467,6 +467,25 @@ npcm7xx_emc_rx_done(uint32_t crxdsa) "RX done, CRXDSA=0x%x" npcm7xx_emc_reg_read(int emc_num, uint32_t result, const char *name, int regno) "emc%d: 0x%x = reg[%s/%d]" npcm7xx_emc_reg_write(int emc_num, const char *name, int regno, uint32_t value) "emc%d: reg[%s/%d] = 0x%x" +# npcm_gmac.c +npcm_gmac_reg_read(const char *name, uint64_t offset, uint32_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx32 +npcm_gmac_reg_write(const char *name, uint64_t offset, uint32_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx32 +npcm_gmac_mdio_access(const char *name, uint8_t is_write, uint8_t pa, uint8_t gr, uint16_t val) "%s: is_write: %" PRIu8 " pa: %" PRIu8 " gr: %" PRIu8 " val: 0x%04" PRIx16 +npcm_gmac_reset(const char *name, uint16_t value) "%s: phy_regs[0][1]: 0x%04" PRIx16 +npcm_gmac_set_link(bool active) "Set link: active=%u" +npcm_gmac_update_irq(const char *name, uint32_t status, uint32_t intr_en, int level) "%s: Status Reg: 0x%04" PRIX32 " Interrupt Enable Reg: 0x%04" PRIX32 " IRQ Set: %d" +npcm_gmac_packet_desc_read(const char* name, uint32_t desc_addr) "%s: attempting to read descriptor @0x%04" PRIX32 +npcm_gmac_packet_receive(const char* name, uint32_t len) "%s: RX packet length: 0x%04" PRIX32 +npcm_gmac_packet_receiving_buffer(const char* name, uint32_t buf_len, uint32_t rx_buf_addr) "%s: Receiving into Buffer size: 0x%04" PRIX32 " at address 0x%04" PRIX32 +npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finished, packet left: 0x%04" PRIX32 +npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16 +npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32 +npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32 + +# npcm_pcs.c +npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 +npcm_pcs_reg_write(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 + # dp8398x.c dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x" dp8393x_lower_irq(void) "lower irq" diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index dd9e389..c25d50f 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -340,6 +340,8 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, break; case DESIGNWARE_PCIE_ATU_VIEWPORT: + val &= DESIGNWARE_PCIE_ATU_REGION_INBOUND | + (DESIGNWARE_PCIE_NUM_VIEWPORTS - 1); root->atu_viewport = val; break; diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 449abfb..6496d02 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -64,7 +64,7 @@ bool pci_available = true; static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); -static void pcibus_reset(BusState *qbus); +static void pcibus_reset_hold(Object *obj); static bool pcie_has_upstream_port(PCIDevice *dev); static Property pci_props[] = { @@ -202,13 +202,15 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); PCIBusClass *pbc = PCI_BUS_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); k->print_dev = pcibus_dev_print; k->get_dev_path = pcibus_get_dev_path; k->get_fw_dev_path = pcibus_get_fw_dev_path; k->realize = pci_bus_realize; k->unrealize = pci_bus_unrealize; - k->reset = pcibus_reset; + + rc->phases.hold = pcibus_reset_hold; pbc->bus_num = pcibus_num; pbc->numa_node = pcibus_numa_node; @@ -424,9 +426,9 @@ void pci_device_reset(PCIDevice *dev) * Called via bus_cold_reset on RST# assert, after the devices * have been reset device_cold_reset-ed already. */ -static void pcibus_reset(BusState *qbus) +static void pcibus_reset_hold(Object *obj) { - PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus); + PCIBus *bus = PCI_BUS(obj); int i; for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 15d26ef..34639f2 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev, qdev_unrealize(dev); } -static void virtual_css_bus_reset(BusState *qbus) +static void virtual_css_bus_reset_hold(Object *obj) { /* This should actually be modelled via the generic css */ css_reset(); @@ -81,8 +81,9 @@ static char *virtual_css_bus_get_dev_path(DeviceState *dev) static void virtual_css_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - k->reset = virtual_css_bus_reset; + rc->phases.hold = virtual_css_bus_reset_hold; k->get_dev_path = virtual_css_bus_get_dev_path; } diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 7d90a02..83ee53c 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -20,3 +20,7 @@ config XILINX_SPIPS config STM32F2XX_SPI bool select SSI + +config BCM2835_SPI + bool + select SSI diff --git a/hw/ssi/bcm2835_spi.c b/hw/ssi/bcm2835_spi.c new file mode 100644 index 0000000..6ecb42d --- /dev/null +++ b/hw/ssi/bcm2835_spi.c @@ -0,0 +1,288 @@ +/* + * BCM2835 SPI Master Controller + * + * Copyright (c) 2024 Rayhan Faizel <rayhan.faizel@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/fifo8.h" +#include "hw/ssi/bcm2835_spi.h" +#include "hw/irq.h" +#include "migration/vmstate.h" + +static void bcm2835_spi_update_int(BCM2835SPIState *s) +{ + int do_interrupt = 0; + + /* Interrupt on DONE */ + if (s->cs & BCM2835_SPI_CS_INTD && s->cs & BCM2835_SPI_CS_DONE) { + do_interrupt = 1; + } + /* Interrupt on RXR */ + if (s->cs & BCM2835_SPI_CS_INTR && s->cs & BCM2835_SPI_CS_RXR) { + do_interrupt = 1; + } + qemu_set_irq(s->irq, do_interrupt); +} + +static void bcm2835_spi_update_rx_flags(BCM2835SPIState *s) +{ + /* Set RXD if RX FIFO is non empty */ + if (!fifo8_is_empty(&s->rx_fifo)) { + s->cs |= BCM2835_SPI_CS_RXD; + } else { + s->cs &= ~BCM2835_SPI_CS_RXD; + } + + /* Set RXF if RX FIFO is full */ + if (fifo8_is_full(&s->rx_fifo)) { + s->cs |= BCM2835_SPI_CS_RXF; + } else { + s->cs &= ~BCM2835_SPI_CS_RXF; + } + + /* Set RXR if RX FIFO is 3/4th used or above */ + if (fifo8_num_used(&s->rx_fifo) >= FIFO_SIZE_3_4) { + s->cs |= BCM2835_SPI_CS_RXR; + } else { + s->cs &= ~BCM2835_SPI_CS_RXR; + } +} + +static void bcm2835_spi_update_tx_flags(BCM2835SPIState *s) +{ + /* Set TXD if TX FIFO is not full */ + if (fifo8_is_full(&s->tx_fifo)) { + s->cs &= ~BCM2835_SPI_CS_TXD; + } else { + s->cs |= BCM2835_SPI_CS_TXD; + } + + /* Set DONE if in TA mode and TX FIFO is empty */ + if (fifo8_is_empty(&s->tx_fifo) && s->cs & BCM2835_SPI_CS_TA) { + s->cs |= BCM2835_SPI_CS_DONE; + } else { + s->cs &= ~BCM2835_SPI_CS_DONE; + } +} + +static void bcm2835_spi_flush_tx_fifo(BCM2835SPIState *s) +{ + uint8_t tx_byte, rx_byte; + + while (!fifo8_is_empty(&s->tx_fifo) && !fifo8_is_full(&s->rx_fifo)) { + tx_byte = fifo8_pop(&s->tx_fifo); + rx_byte = ssi_transfer(s->bus, tx_byte); + fifo8_push(&s->rx_fifo, rx_byte); + } + + bcm2835_spi_update_tx_flags(s); + bcm2835_spi_update_rx_flags(s); +} + +static uint64_t bcm2835_spi_read(void *opaque, hwaddr addr, unsigned size) +{ + BCM2835SPIState *s = opaque; + uint32_t readval = 0; + + switch (addr) { + case BCM2835_SPI_CS: + readval = s->cs & 0xffffffff; + break; + case BCM2835_SPI_FIFO: + bcm2835_spi_flush_tx_fifo(s); + if (s->cs & BCM2835_SPI_CS_RXD) { + readval = fifo8_pop(&s->rx_fifo); + bcm2835_spi_update_rx_flags(s); + } + + bcm2835_spi_update_int(s); + break; + case BCM2835_SPI_CLK: + readval = s->clk & 0xffff; + break; + case BCM2835_SPI_DLEN: + readval = s->dlen & 0xffff; + break; + case BCM2835_SPI_LTOH: + readval = s->ltoh & 0xf; + break; + case BCM2835_SPI_DC: + readval = s->dc & 0xffffffff; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr); + } + return readval; +} + +static void bcm2835_spi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + BCM2835SPIState *s = opaque; + + switch (addr) { + case BCM2835_SPI_CS: + s->cs = (value & ~RO_MASK) | (s->cs & RO_MASK); + if (!(s->cs & BCM2835_SPI_CS_TA)) { + /* Clear DONE and RXR if TA is off */ + s->cs &= ~(BCM2835_SPI_CS_DONE); + s->cs &= ~(BCM2835_SPI_CS_RXR); + } + + /* Clear RX FIFO */ + if (s->cs & BCM2835_SPI_CLEAR_RX) { + fifo8_reset(&s->rx_fifo); + bcm2835_spi_update_rx_flags(s); + } + + /* Clear TX FIFO*/ + if (s->cs & BCM2835_SPI_CLEAR_TX) { + fifo8_reset(&s->tx_fifo); + bcm2835_spi_update_tx_flags(s); + } + + /* Set Transfer Active */ + if (s->cs & BCM2835_SPI_CS_TA) { + bcm2835_spi_update_tx_flags(s); + } + + if (s->cs & BCM2835_SPI_CS_DMAEN) { + qemu_log_mask(LOG_UNIMP, "%s: " \ + "DMA not supported\n", __func__); + } + + if (s->cs & BCM2835_SPI_CS_LEN) { + qemu_log_mask(LOG_UNIMP, "%s: " \ + "LoSSI not supported\n", __func__); + } + + bcm2835_spi_update_int(s); + break; + case BCM2835_SPI_FIFO: + /* + * According to documentation, writes to FIFO without TA controls + * CS and DLEN registers. This is supposed to be used in DMA mode + * which is currently unimplemented. Moreover, Linux does not make + * use of this and directly modifies the CS and DLEN registers. + */ + if (s->cs & BCM2835_SPI_CS_TA) { + if (s->cs & BCM2835_SPI_CS_TXD) { + fifo8_push(&s->tx_fifo, value & 0xff); + bcm2835_spi_update_tx_flags(s); + } + + bcm2835_spi_flush_tx_fifo(s); + bcm2835_spi_update_int(s); + } + break; + case BCM2835_SPI_CLK: + s->clk = value & 0xffff; + break; + case BCM2835_SPI_DLEN: + s->dlen = value & 0xffff; + break; + case BCM2835_SPI_LTOH: + s->ltoh = value & 0xf; + break; + case BCM2835_SPI_DC: + s->dc = value & 0xffffffff; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr); + } +} + +static const MemoryRegionOps bcm2835_spi_ops = { + .read = bcm2835_spi_read, + .write = bcm2835_spi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void bcm2835_spi_realize(DeviceState *dev, Error **errp) +{ + BCM2835SPIState *s = BCM2835_SPI(dev); + s->bus = ssi_create_bus(dev, "spi"); + + memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_spi_ops, s, + TYPE_BCM2835_SPI, 0x18); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + + fifo8_create(&s->tx_fifo, FIFO_SIZE); + fifo8_create(&s->rx_fifo, FIFO_SIZE); +} +static void bcm2835_spi_reset(DeviceState *dev) +{ + BCM2835SPIState *s = BCM2835_SPI(dev); + + fifo8_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); + + /* Reset values according to BCM2835 Peripheral Documentation */ + s->cs = BCM2835_SPI_CS_TXD | BCM2835_SPI_CS_REN; + s->clk = 0; + s->dlen = 0; + s->ltoh = 0x1; + s->dc = 0x30201020; +} + +static const VMStateDescription vmstate_bcm2835_spi = { + .name = TYPE_BCM2835_SPI, + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_FIFO8(tx_fifo, BCM2835SPIState), + VMSTATE_FIFO8(rx_fifo, BCM2835SPIState), + VMSTATE_UINT32(cs, BCM2835SPIState), + VMSTATE_UINT32(clk, BCM2835SPIState), + VMSTATE_UINT32(dlen, BCM2835SPIState), + VMSTATE_UINT32(ltoh, BCM2835SPIState), + VMSTATE_UINT32(dc, BCM2835SPIState), + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = bcm2835_spi_reset; + dc->realize = bcm2835_spi_realize; + dc->vmsd = &vmstate_bcm2835_spi; +} + +static const TypeInfo bcm2835_spi_info = { + .name = TYPE_BCM2835_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835SPIState), + .class_init = bcm2835_spi_class_init, +}; + +static void bcm2835_spi_register_types(void) +{ + type_register_static(&bcm2835_spi_info); +} + +type_init(bcm2835_spi_register_types) diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 0aebcdd6..b999aeb 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -11,3 +11,4 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c')) system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c')) system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c')) system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c')) +system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c')) diff --git a/hw/xen/trace-events b/hw/xen/trace-events index 67a6c41..d1b27f6 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -42,7 +42,7 @@ xs_node_vscanf(char *path, char *value) "%s %s" xs_node_watch(char *path) "%s" xs_node_unwatch(char *path) "%s" -# xen-hvm.c +# xen-hvm-common.c xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: 0x%lx, size 0x%lx" xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "0x%"PRIx64" size 0x%lx, log_dirty %i" handle_ioreq(void *req, uint32_t type, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p type=%d dir=%d df=%d ptr=%d port=0x%"PRIx64" data=0x%"PRIx64" count=%d size=%d" @@ -55,8 +55,27 @@ cpu_ioreq_move(void *req, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint6 xen_map_resource_ioreq(uint32_t id, void *addr) "id: %u addr: %p" cpu_ioreq_config_read(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x" cpu_ioreq_config_write(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x" +cpu_get_ioreq_from_shared_memory_req_not_ready(int state, int data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O request not ready: 0x%x, ptr: 0x%x, port: 0x%"PRIx64", data: 0x%"PRIx64", count: %u, size: %u" +xen_main_loop_prepare_init_cpu(int id, void *cpu) "cpu_by_vcpu_id[%d]=%p" +xen_map_ioreq_server_shared_page(long unsigned int ioreq_pfn) "shared page at pfn 0x%lx" +xen_map_ioreq_server_buffered_io_page(long unsigned int ioreq_pfn) "buffered io page at pfn 0x%lx" +xen_map_ioreq_server_buffered_io_evtchn(int bufioreq_evtchn) "buffered io evtchn is 0x%x" +destroy_hvm_domain_cannot_acquire_handle(void) "Cannot acquire xenctrl handle" +destroy_hvm_domain_failed_action(const char *action, int sts, char *errno_s) "xc_domain_shutdown failed to issue %s, sts %d, %s" +destroy_hvm_domain_action(int xen_domid, const char *action) "Issued domain %d %s" # xen-mapcache.c xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64 xen_remap_bucket(uint64_t index) "index 0x%"PRIx64 xen_map_cache_return(void* ptr) "%p" +xen_map_cache_init(uint64_t nr_buckets, uint64_t size) "nr_buckets = 0x%"PRIx64" size 0x%"PRIx64 +xen_replace_cache_entry_dummy(uint64_t old_phys_addr, uint64_t new_phys_addr) "Replacing a dummy mapcache entry for 0x%"PRIx64" with 0x%"PRIx64 +xen_invalidate_map_cache_entry_unlocked_not_found(void *p) "could not find %p" +xen_invalidate_map_cache_entry_unlocked_found(uint64_t addr, void *p) " 0x%"PRIx64" -> %p is present" +xen_invalidate_map_cache_entry_unlocked_miss(void *buffer) "Trying to unmap address %p that is not in the mapcache" +xen_replace_cache_entry_unlocked_could_not_update_entry(uint64_t old_phys_addr) "Unable to update a mapcache entry for 0x%"PRIx64 +xen_ram_addr_from_mapcache_not_found(void *p) "could not find %p" +xen_ram_addr_from_mapcache_found(uint64_t addr, void *p) " 0x%"PRIx64" -> %p is present" +xen_ram_addr_from_mapcache_not_in_cache(void *p) "Trying to find address %p that is not in the mapcache" +xen_replace_cache_entry_unlocked(uint64_t old_phys_addr) "Trying to update an entry for 0x%"PRIx64" that is not in the mapcache" +xen_invalidate_map_cache(uint64_t paddr_index, void *vaddr_req) "Locked DMA mapping while invalidating mapcache 0x%"PRIx64" -> %p is present" diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c index 47e6cb1..baa1adb 100644 --- a/hw/xen/xen-hvm-common.c +++ b/hw/xen/xen-hvm-common.c @@ -20,8 +20,8 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr, if (runstate_check(RUN_STATE_INMIGRATE)) { /* RAM already populated in Xen */ - fprintf(stderr, "%s: do not alloc "RAM_ADDR_FMT - " bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE\n", + warn_report("%s: do not alloc "RAM_ADDR_FMT + " bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE", __func__, size, ram_addr); return; } @@ -169,11 +169,12 @@ static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu) ioreq_t *req = xen_vcpu_ioreq(state->shared_page, vcpu); if (req->state != STATE_IOREQ_READY) { - DPRINTF("I/O request not ready: " - "%x, ptr: %x, port: %"PRIx64", " - "data: %"PRIx64", count: %u, size: %u\n", - req->state, req->data_is_ptr, req->addr, - req->data, req->count, req->size); + trace_cpu_get_ioreq_from_shared_memory_req_not_ready(req->state, + req->data_is_ptr, + req->addr, + req->data, + req->count, + req->size); return NULL; } @@ -551,9 +552,9 @@ static void cpu_handle_ioreq(void *opaque) req->data = copy.data; if (req->state != STATE_IOREQ_INPROCESS) { - fprintf(stderr, "Badness in I/O request ... not in service?!: " + warn_report("Badness in I/O request ... not in service?!: " "%x, ptr: %x, port: %"PRIx64", " - "data: %"PRIx64", count: %u, size: %u, type: %u\n", + "data: %"PRIx64", count: %u, size: %u, type: %u", req->state, req->data_is_ptr, req->addr, req->data, req->count, req->size, req->type); destroy_hvm_domain(false); @@ -601,10 +602,9 @@ static void xen_main_loop_prepare(XenIOState *state) if (evtchn_fd != -1) { CPUState *cpu_state; - DPRINTF("%s: Init cpu_by_vcpu_id\n", __func__); CPU_FOREACH(cpu_state) { - DPRINTF("%s: cpu_by_vcpu_id[%d]=%p\n", - __func__, cpu_state->cpu_index, cpu_state); + trace_xen_main_loop_prepare_init_cpu(cpu_state->cpu_index, + cpu_state); state->cpu_by_vcpu_id[cpu_state->cpu_index] = cpu_state; } qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state); @@ -681,7 +681,7 @@ static int xen_map_ioreq_server(XenIOState *state) } if (state->shared_page == NULL) { - DPRINTF("shared page at pfn %lx\n", ioreq_pfn); + trace_xen_map_ioreq_server_shared_page(ioreq_pfn); state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid, PROT_READ | PROT_WRITE, @@ -693,7 +693,7 @@ static int xen_map_ioreq_server(XenIOState *state) } if (state->buffered_io_page == NULL) { - DPRINTF("buffered io page at pfn %lx\n", bufioreq_pfn); + trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn); state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid, PROT_READ | PROT_WRITE, @@ -709,7 +709,7 @@ static int xen_map_ioreq_server(XenIOState *state) return -1; } - DPRINTF("buffered io evtchn is %x\n", bufioreq_evtchn); + trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn); state->bufioreq_remote_port = bufioreq_evtchn; @@ -737,16 +737,17 @@ void destroy_hvm_domain(bool reboot) xc_handle = xc_interface_open(0, 0, 0); if (xc_handle == NULL) { - fprintf(stderr, "Cannot acquire xenctrl handle\n"); + trace_destroy_hvm_domain_cannot_acquire_handle(); } else { sts = xc_domain_shutdown(xc_handle, xen_domid, reason); if (sts != 0) { - fprintf(stderr, "xc_domain_shutdown failed to issue %s, " - "sts %d, %s\n", reboot ? "reboot" : "poweroff", - sts, strerror(errno)); + trace_destroy_hvm_domain_failed_action( + reboot ? "reboot" : "poweroff", sts, strerror(errno) + ); } else { - fprintf(stderr, "Issued domain %d %s\n", xen_domid, - reboot ? "reboot" : "poweroff"); + trace_destroy_hvm_domain_action( + xen_domid, reboot ? "reboot" : "poweroff" + ); } xc_interface_close(xc_handle); } @@ -757,9 +758,9 @@ void xen_shutdown_fatal_error(const char *fmt, ...) va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + error_vreport(fmt, ap); va_end(ap); - fprintf(stderr, "Will destroy the domain.\n"); + error_report("Will destroy the domain."); /* destroy the domain */ qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR); } diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c index f7d9746..4f956d0 100644 --- a/hw/xen/xen-mapcache.c +++ b/hw/xen/xen-mapcache.c @@ -22,16 +22,6 @@ #include "trace.h" -//#define MAPCACHE_DEBUG - -#ifdef MAPCACHE_DEBUG -# define DPRINTF(fmt, ...) do { \ - fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \ -} while (0) -#else -# define DPRINTF(fmt, ...) do { } while (0) -#endif - #if HOST_LONG_BITS == 32 # define MCACHE_BUCKET_SHIFT 16 # define MCACHE_MAX_SIZE (1UL<<31) /* 2GB Cap */ @@ -145,8 +135,7 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque) size = mapcache->nr_buckets * sizeof (MapCacheEntry); size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1); - DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__, - mapcache->nr_buckets, size); + trace_xen_map_cache_init(mapcache->nr_buckets, size); mapcache->entry = g_malloc0(size); } @@ -286,7 +275,9 @@ tryagain: test_bits(address_offset >> XC_PAGE_SHIFT, test_bit_size >> XC_PAGE_SHIFT, mapcache->last_entry->valid_mapping)) { - trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset); + trace_xen_map_cache_return( + mapcache->last_entry->vaddr_base + address_offset + ); return mapcache->last_entry->vaddr_base + address_offset; } @@ -356,9 +347,8 @@ tryagain: MapCacheRev *reventry = g_new0(MapCacheRev, 1); entry->lock++; if (entry->lock == 0) { - fprintf(stderr, - "mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p\n", - entry->paddr_index, entry->vaddr_base); + error_report("mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p", + entry->paddr_index, entry->vaddr_base); abort(); } reventry->dma = dma; @@ -368,7 +358,9 @@ tryagain: QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next); } - trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset); + trace_xen_map_cache_return( + mapcache->last_entry->vaddr_base + address_offset + ); return mapcache->last_entry->vaddr_base + address_offset; } @@ -402,10 +394,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr) } } if (!found) { - fprintf(stderr, "%s, could not find %p\n", __func__, ptr); + trace_xen_ram_addr_from_mapcache_not_found(ptr); QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { - DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, - reventry->vaddr_req); + trace_xen_ram_addr_from_mapcache_found(reventry->paddr_index, + reventry->vaddr_req); } abort(); return 0; @@ -416,7 +408,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr) entry = entry->next; } if (!entry) { - DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr); + trace_xen_ram_addr_from_mapcache_not_in_cache(ptr); raddr = 0; } else { raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) + @@ -443,9 +435,12 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer) } } if (!found) { - DPRINTF("%s, could not find %p\n", __func__, buffer); + trace_xen_invalidate_map_cache_entry_unlocked_not_found(buffer); QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { - DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); + trace_xen_invalidate_map_cache_entry_unlocked_found( + reventry->paddr_index, + reventry->vaddr_req + ); } return; } @@ -463,7 +458,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer) entry = entry->next; } if (!entry) { - DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer); + trace_xen_invalidate_map_cache_entry_unlocked_miss(buffer); return; } entry->lock--; @@ -502,9 +497,8 @@ void xen_invalidate_map_cache(void) if (!reventry->dma) { continue; } - fprintf(stderr, "Locked DMA mapping while invalidating mapcache!" - " "HWADDR_FMT_plx" -> %p is present\n", - reventry->paddr_index, reventry->vaddr_req); + trace_xen_invalidate_map_cache(reventry->paddr_index, + reventry->vaddr_req); } for (i = 0; i < mapcache->nr_buckets; i++) { @@ -562,24 +556,23 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr, entry = entry->next; } if (!entry) { - DPRINTF("Trying to update an entry for "HWADDR_FMT_plx \ - "that is not in the mapcache!\n", old_phys_addr); + trace_xen_replace_cache_entry_unlocked(old_phys_addr); return NULL; } address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT; address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1); - fprintf(stderr, "Replacing a dummy mapcache entry for "HWADDR_FMT_plx \ - " with "HWADDR_FMT_plx"\n", old_phys_addr, new_phys_addr); + trace_xen_replace_cache_entry_dummy(old_phys_addr, new_phys_addr); xen_remap_bucket(entry, entry->vaddr_base, cache_size, address_index, false); if (!test_bits(address_offset >> XC_PAGE_SHIFT, test_bit_size >> XC_PAGE_SHIFT, entry->valid_mapping)) { - DPRINTF("Unable to update a mapcache entry for "HWADDR_FMT_plx"!\n", - old_phys_addr); + trace_xen_replace_cache_entry_unlocked_could_not_update_entry( + old_phys_addr + ); return NULL; } |