Re: [PATCH 2/5] hw/arm: ast2600: Wire up the eMMC controller
On Fri, 10 Jan 2020, at 22:26, Cédric Le Goater wrote: > >> + > >> + sysbus_init_child_obj(obj, "emmc", OBJECT(>emmc), sizeof(s->emmc), > >> + TYPE_ASPEED_SDHCI); > >> + > >> + object_property_set_int(OBJECT(>emmc), 1, "num-slots", > >> _abort); > >> + > >> + sysbus_init_child_obj(obj, "emmc[*]", OBJECT(>emmc.slots[0]), > > > > Single block, so use "emmc" instead. > > Andrew, how should we call the objects in the slots ? "sdhci" ? I think that's the right way to go, but maybe we need to rethink the naming at the controller level. Andrew
Re: [PATCH v3 0/4] Expose GT CNTFRQ as a CPU property to support AST2600
On Wed, 18 Dec 2019, at 01:55, Peter Maydell wrote: > On Fri, 13 Dec 2019 at 05:48, Andrew Jeffery wrote: > > > > Hello, > > > > This is a v3 of the belated follow-up from a few of my earlier attempts to > > fix > > up the ARM generic timer for correct behaviour on the ASPEED AST2600 SoC. > > The > > AST2600 clocks the generic timer at the rate of HPLL, which is configured to > > 1125MHz. This is significantly quicker than the currently hard-coded > > generic > > timer rate of 62.5MHz and so we see "sticky" behaviour in the guest. > > > > v2 can be found here: > > > > https://patchwork.ozlabs.org/cover/1203474/ > > > > Changes since v2: > > > > * Address some minor review comments from Philippe and add tags > > > > Changes since v1: > > > > * Fix a user mode build failure from partial renaming of > > gt_cntfrq_period_ns() > > * Add tags from Cedric and Richard > > > > Please review. > > > > Andrew > > > > Andrew Jeffery (4): > > target/arm: Remove redundant scaling of nexttick > > target/arm: Abstract the generic timer frequency > > target/arm: Prepare generic timer for per-platform CNTFRQ > > ast2600: Configure CNTFRQ at 1125MHz > > > > > Applied to target-arm.next, thanks. Thanks for your feedback throughout. Andrew
Re: [PATCH v2 0/2] hw/arm: ast2600: Wire up eMMC controller
On Fri, 13 Dec 2019, at 18:03, Cédric Le Goater wrote: > On 13/12/2019 05:28, Andrew Jeffery wrote: > > Hello, > > > > The AST2600 has an additional SDHCI intended for use as an eMMC boot source. > > These two patches rework the existing ASPEED SDHCI model to accommodate the > > single-slot nature of the eMMC controller and wire it into the AST2600 SoC. > > > > v2 contains some minor refactorings in response to issues pointed out by > > Cedric. > > > I think these patches are based on mainline. I fixed them locally on > my aspeed 5.0 branch and I plan to send them along with other aspeed > changes in the 5.0 timeframe. Yeah, they're based on Peter's tree. I'll base future patches on yours. Andrew
[PATCH v3 4/4] ast2600: Configure CNTFRQ at 1125MHz
This matches the configuration set by u-boot on the AST2600. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/aspeed_ast2600.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 931887ac681f..5aecc3b3caec 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -259,6 +259,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(>cpu[i]), aspeed_calc_affinity(i), "mp-affinity", _abort); +object_property_set_int(OBJECT(>cpu[i]), 112500, "cntfrq", +_abort); + /* * TODO: the secondary CPUs are started and a boot helper * is needed when using -kernel -- git-series 0.9.1
[PATCH v3 3/4] target/arm: Prepare generic timer for per-platform CNTFRQ
The ASPEED AST2600 clocks the generic timer at the rate of HPLL. On recent firmwares this is at 1125MHz, which is considerably quicker than the assumed 62.5MHz of the current generic timer implementation. The delta between the value as read from CNTFRQ and the true rate of the underlying QEMUTimer leads to sticky behaviour in AST2600 guests. Add a feature-gated property exposing CNTFRQ for ARM CPUs providing the generic timer. This allows platforms to configure CNTFRQ (and the associated QEMUTimer) to the appropriate frequency prior to starting the guest. As the platform can now determine the rate of CNTFRQ we're exposed to limitations of QEMUTimer that didn't previously materialise: In the course of emulation we need to arbitrarily and accurately convert between guest ticks and time, but we're constrained by QEMUTimer's use of an integer scaling factor. The effect is QEMUTimer cannot exactly capture the period of frequencies that do not cleanly divide NANOSECONDS_PER_SECOND for scaling ticks to time. As such, provide an equally inaccurate scaling factor for scaling time to ticks so at least a self-consistent inverse relationship holds. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson --- v3: * Relocate comment as a consequence of uninlining gt_cntfrq_period_ns() in 2/4. Philippe - I haven't moved it to the previous patch based on my reasoning on the list. I'm not sure whether you're satisfied by that, so I haven't added your Reviewed-by tag. target/arm/cpu.c| 61 ++ target/arm/helper.c | 9 ++- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index cd0dbe005d9f..7b21eb544eae 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -974,10 +974,12 @@ static void arm_cpu_initfn(Object *obj) if (tcg_enabled()) { cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ } - -cpu->gt_cntfrq_hz = NANOSECONDS_PER_SECOND / GTIMER_SCALE; } +static Property arm_cpu_gt_cntfrq_property = +DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq_hz, + NANOSECONDS_PER_SECOND / GTIMER_SCALE); + static Property arm_cpu_reset_cbar_property = DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0); @@ -1059,6 +1061,24 @@ static void arm_set_init_svtor(Object *obj, Visitor *v, const char *name, unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) { +/* + * The exact approach to calculating guest ticks is: + * + * muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), cpu->gt_cntfrq_hz, + * NANOSECONDS_PER_SECOND); + * + * We don't do that. Rather we intentionally use integer division + * truncation below and in the caller for the conversion of host monotonic + * time to guest ticks to provide the exact inverse for the semantics of + * the QEMUTimer scale factor. QEMUTimer's scale facter is an integer, so + * it loses precision when representing frequencies where + * `(NANOSECONDS_PER_SECOND % cpu->gt_cntfrq) > 0` holds. Failing to + * provide an exact inverse leads to scheduling timers with negative + * periods, which in turn leads to sticky behaviour in the guest. + * + * Finally, CNTFRQ is effectively capped at 1GHz to ensure our scale factor + * cannot become zero. + */ return NANOSECONDS_PER_SECOND > cpu->gt_cntfrq_hz ? NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1; } @@ -1180,6 +1200,11 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), _cpu_cfgend_property, _abort); + +if (arm_feature(>env, ARM_FEATURE_GENERIC_TIMER)) { +qdev_property_add_static(DEVICE(cpu), _cpu_gt_cntfrq_property, + _abort); +} } static void arm_cpu_finalizefn(Object *obj) @@ -1259,14 +1284,30 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } -cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_ptimer_cb, cpu); -cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_vtimer_cb, cpu); -cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_htimer_cb, cpu); -cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_stimer_cb, cpu); + +{ +uint64_t scale; + +if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { +if (!cpu->gt_cntfrq_hz) { +error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", + cpu->gt_cntfrq_hz); +return; +} +scale = gt_cntfrq_period_ns
[PATCH v3 1/4] target/arm: Remove redundant scaling of nexttick
The corner-case codepath was adjusting nexttick such that overflow wouldn't occur when timer_mod() scaled the value back up. Remove a use of GTIMER_SCALE and avoid unnecessary operations by calling timer_mod_ns() directly. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson Reviewed-by: Cédric Le Goater --- target/arm/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a089fb5a6909..65c4441a3896 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2446,9 +2446,10 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * timer expires we will reset the timer for any remaining period. */ if (nexttick > INT64_MAX / GTIMER_SCALE) { -nexttick = INT64_MAX / GTIMER_SCALE; +timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX); +} else { +timer_mod(cpu->gt_timer[timeridx], nexttick); } -timer_mod(cpu->gt_timer[timeridx], nexttick); trace_arm_gt_recalc(timeridx, irqstate, nexttick); } else { /* Timer disabled: ISTATUS and timer output always clear */ -- git-series 0.9.1
[PATCH v3 0/4] Expose GT CNTFRQ as a CPU property to support AST2600
Hello, This is a v3 of the belated follow-up from a few of my earlier attempts to fix up the ARM generic timer for correct behaviour on the ASPEED AST2600 SoC. The AST2600 clocks the generic timer at the rate of HPLL, which is configured to 1125MHz. This is significantly quicker than the currently hard-coded generic timer rate of 62.5MHz and so we see "sticky" behaviour in the guest. v2 can be found here: https://patchwork.ozlabs.org/cover/1203474/ Changes since v2: * Address some minor review comments from Philippe and add tags Changes since v1: * Fix a user mode build failure from partial renaming of gt_cntfrq_period_ns() * Add tags from Cedric and Richard Please review. Andrew Andrew Jeffery (4): target/arm: Remove redundant scaling of nexttick target/arm: Abstract the generic timer frequency target/arm: Prepare generic timer for per-platform CNTFRQ ast2600: Configure CNTFRQ at 1125MHz hw/arm/aspeed_ast2600.c | 3 ++- target/arm/cpu.c| 65 -- target/arm/cpu.h| 5 +++- target/arm/helper.c | 24 4 files changed, 83 insertions(+), 14 deletions(-) base-commit: 04c9c81b8fa2ee33f59a26265700fae6fc646062 -- git-series 0.9.1
[PATCH v3 2/4] target/arm: Abstract the generic timer frequency
Prepare for SoCs such as the ASPEED AST2600 whose firmware configures CNTFRQ to values significantly larger than the static 62.5MHz value currently derived from GTIMER_SCALE. As the OS potentially derives its timer periods from the CNTFRQ value the lack of support for running QEMUTimers at the appropriate rate leads to sticky behaviour in the guest. Substitute the GTIMER_SCALE constant with use of a helper to derive the period from gt_cntfrq_hz stored in struct ARMCPU. Initially set gt_cntfrq_hz to the frequency associated with GTIMER_SCALE so current behaviour is maintained. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé --- v3: * Uninline gt_cntfrq_period_ns() * Rename gt_cntfrq to gt_cntfrq_hz target/arm/cpu.c| 8 target/arm/cpu.h| 5 + target/arm/helper.c | 10 +++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7a4ac9339bf9..cd0dbe005d9f 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -974,6 +974,8 @@ static void arm_cpu_initfn(Object *obj) if (tcg_enabled()) { cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ } + +cpu->gt_cntfrq_hz = NANOSECONDS_PER_SECOND / GTIMER_SCALE; } static Property arm_cpu_reset_cbar_property = @@ -1055,6 +1057,12 @@ static void arm_set_init_svtor(Object *obj, Visitor *v, const char *name, visit_type_uint32(v, name, >init_svtor, errp); } +unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) +{ +return NANOSECONDS_PER_SECOND > cpu->gt_cntfrq_hz ? + NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1; +} + void arm_cpu_post_init(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 83a809d4bac4..ff17ec0df545 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -932,8 +932,13 @@ struct ARMCPU { */ DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); + +/* Generic timer counter frequency, in Hz */ +uint64_t gt_cntfrq_hz; }; +unsigned int gt_cntfrq_period_ns(ARMCPU *cpu); + void arm_cpu_post_init(Object *obj); uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz); diff --git a/target/arm/helper.c b/target/arm/helper.c index 65c4441a3896..2622a9a8d02f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2409,7 +2409,9 @@ static CPAccessResult gt_stimer_access(CPUARMState *env, static uint64_t gt_get_countervalue(CPUARMState *env) { -return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; +ARMCPU *cpu = env_archcpu(env); + +return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu); } static void gt_recalc_timer(ARMCPU *cpu, int timeridx) @@ -2445,7 +2447,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * set the timer for as far in the future as possible. When the * timer expires we will reset the timer for any remaining period. */ -if (nexttick > INT64_MAX / GTIMER_SCALE) { +if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) { timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX); } else { timer_mod(cpu->gt_timer[timeridx], nexttick); @@ -2874,11 +2876,13 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) { +ARMCPU *cpu = env_archcpu(env); + /* Currently we have no support for QEMUTimer in linux-user so we * can't call gt_get_countervalue(env), instead we directly * call the lower level functions. */ -return cpu_get_clock() / GTIMER_SCALE; +return cpu_get_clock() / gt_cntfrq_period_ns(cpu); } static const ARMCPRegInfo generic_timer_cp_reginfo[] = { -- git-series 0.9.1
[PATCH v2 0/2] hw/arm: ast2600: Wire up eMMC controller
Hello, The AST2600 has an additional SDHCI intended for use as an eMMC boot source. These two patches rework the existing ASPEED SDHCI model to accommodate the single-slot nature of the eMMC controller and wire it into the AST2600 SoC. v2 contains some minor refactorings in response to issues pointed out by Cedric. v1 can be found here: https://patchwork.ozlabs.org/cover/1206845/ Please review! Andrew Andrew Jeffery (2): hw/sd: Configure number of slots exposed by the ASPEED SDHCI model hw/arm: ast2600: Wire up the eMMC controller hw/arm/aspeed.c | 27 +-- hw/arm/aspeed_ast2600.c | 23 +++ hw/arm/aspeed_soc.c | 2 ++ hw/sd/aspeed_sdhci.c | 11 +-- include/hw/arm/aspeed_soc.h | 2 ++ include/hw/sd/aspeed_sdhci.h | 1 + 6 files changed, 54 insertions(+), 12 deletions(-) base-commit: 6a4ef4e5d1084ce41fafa7d470a644b0fd3d9317 -- git-series 0.9.1
[PATCH v2 2/2] hw/arm: ast2600: Wire up the eMMC controller
Initialise another SDHCI model instance for the AST2600's eMMC controller and use the SDHCI's num_slots value introduced previously to determine whether we should create an SD card instance for the new slot. Signed-off-by: Andrew Jeffery --- v2: * Extract instantiation of SD cards to helper function hw/arm/aspeed.c | 25 - hw/arm/aspeed_ast2600.c | 21 + include/hw/arm/aspeed_soc.h | 2 ++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 862549b1f3a9..87baac0ea46c 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -167,6 +167,18 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, } } +static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo) +{ +BlockBackend *blk; +DeviceState *card; + +blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; +card = qdev_create(qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), + TYPE_SD_CARD); +qdev_prop_set_drive(card, "drive", blk, _fatal); +object_property_set_bool(OBJECT(card), true, "realized", _fatal); +} + static void aspeed_board_init(MachineState *machine, const AspeedBoardConfig *cfg) { @@ -260,16 +272,11 @@ static void aspeed_board_init(MachineState *machine, } for (i = 0; i < bmc->soc.sdhci.num_slots; i++) { -SDHCIState *sdhci = >soc.sdhci.slots[i]; -DriveInfo *dinfo = drive_get_next(IF_SD); -BlockBackend *blk; -DeviceState *card; +sdhci_attach_drive(>soc.sdhci.slots[i], drive_get_next(IF_SD)); +} -blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; -card = qdev_create(qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), - TYPE_SD_CARD); -qdev_prop_set_drive(card, "drive", blk, _fatal); -object_property_set_bool(OBJECT(card), true, "realized", _fatal); +if (bmc->soc.emmc.num_slots) { +sdhci_attach_drive(>soc.emmc.slots[0], drive_get_next(IF_SD)); } arm_load_kernel(ARM_CPU(first_cpu), machine, _board_binfo); diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 931ee5aae183..723c8196c8a5 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -46,6 +46,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_ADC] = 0x1E6E9000, [ASPEED_VIDEO] = 0x1E70, [ASPEED_SDHCI] = 0x1E74, +[ASPEED_EMMC] = 0x1E75, [ASPEED_GPIO] = 0x1E78, [ASPEED_GPIO_1_8V] = 0x1E780800, [ASPEED_RTC] = 0x1E781000, @@ -64,6 +65,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { #define ASPEED_SOC_AST2600_MAX_IRQ 128 +/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_UART1] = 47, [ASPEED_UART2] = 48, @@ -77,6 +79,7 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_ADC] = 78, [ASPEED_XDMA] = 6, [ASPEED_SDHCI] = 43, +[ASPEED_EMMC] = 15, [ASPEED_GPIO] = 40, [ASPEED_GPIO_1_8V] = 11, [ASPEED_RTC] = 13, @@ -215,6 +218,14 @@ static void aspeed_soc_ast2600_init(Object *obj) sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(>sdhci.slots[i]), sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); } + +sysbus_init_child_obj(obj, "emmc", OBJECT(>emmc), sizeof(s->emmc), + TYPE_ASPEED_SDHCI); + +object_property_set_int(OBJECT(>emmc), 1, "num-slots", _abort); + +sysbus_init_child_obj(obj, "emmc[*]", OBJECT(>emmc.slots[0]), +sizeof(s->emmc.slots[0]), TYPE_SYSBUS_SDHCI); } /* @@ -487,6 +498,16 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SDHCI]); sysbus_connect_irq(SYS_BUS_DEVICE(>sdhci), 0, aspeed_soc_get_irq(s, ASPEED_SDHCI)); + +/* eMMC */ +object_property_set_bool(OBJECT(>emmc), true, "realized", ); +if (err) { +error_propagate(errp, err); +return; +} +sysbus_mmio_map(SYS_BUS_DEVICE(>emmc), 0, sc->memmap[ASPEED_EMMC]); +sysbus_connect_irq(SYS_BUS_DEVICE(>emmc), 0, + aspeed_soc_get_irq(s, ASPEED_EMMC)); } static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 495c08be1b84..911443f4c071 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -56,6 +56,7 @@ typedef struct AspeedSoCState { AspeedGPIOState gpio; AspeedGPIOState gpio_1_8v; AspeedSDHCIState sdhci; +AspeedSDHCISt
[PATCH v2 1/2] hw/sd: Configure number of slots exposed by the ASPEED SDHCI model
The AST2600 includes a second cut-down version of the SD/MMC controller found in the AST2500, named the eMMC controller. It's cut down in the sense that it only supports one slot rather than two, but it brings the total number of slots supported by the AST2600 to three. The existing code assumed that the SD controller always provided two slots. Rework the SDHCI object to expose the number of slots as a property to be set by the SoC configuration. Signed-off-by: Andrew Jeffery Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/aspeed.c | 2 +- hw/arm/aspeed_ast2600.c | 2 ++ hw/arm/aspeed_soc.c | 2 ++ hw/sd/aspeed_sdhci.c | 11 +-- include/hw/sd/aspeed_sdhci.h | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 028191ff36fc..862549b1f3a9 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -259,7 +259,7 @@ static void aspeed_board_init(MachineState *machine, cfg->i2c_init(bmc); } -for (i = 0; i < ARRAY_SIZE(bmc->soc.sdhci.slots); i++) { +for (i = 0; i < bmc->soc.sdhci.num_slots; i++) { SDHCIState *sdhci = >soc.sdhci.slots[i]; DriveInfo *dinfo = drive_get_next(IF_SD); BlockBackend *blk; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 931887ac681f..931ee5aae183 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -208,6 +208,8 @@ static void aspeed_soc_ast2600_init(Object *obj) sysbus_init_child_obj(obj, "sdc", OBJECT(>sdhci), sizeof(s->sdhci), TYPE_ASPEED_SDHCI); +object_property_set_int(OBJECT(>sdhci), 2, "num-slots", _abort); + /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(>sdhci.slots[i]), diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index f4fe243458fd..c39a42f914d4 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -215,6 +215,8 @@ static void aspeed_soc_init(Object *obj) sysbus_init_child_obj(obj, "sdc", OBJECT(>sdhci), sizeof(s->sdhci), TYPE_ASPEED_SDHCI); +object_property_set_int(OBJECT(>sdhci), 2, "num-slots", _abort); + /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(>sdhci.slots[i]), diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index cff3eb7dd21e..939d1510dedb 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -13,6 +13,7 @@ #include "qapi/error.h" #include "hw/irq.h" #include "migration/vmstate.h" +#include "hw/qdev-properties.h" #define ASPEED_SDHCI_INFO0x00 #define ASPEED_SDHCI_INFO_RESET 0x0003 @@ -120,14 +121,14 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) /* Create input irqs for the slots */ qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq, -sdhci, NULL, ASPEED_SDHCI_NUM_SLOTS); +sdhci, NULL, sdhci->num_slots); sysbus_init_irq(sbd, >irq); memory_region_init_io(>iomem, OBJECT(sdhci), _sdhci_ops, sdhci, TYPE_ASPEED_SDHCI, 0x1000); sysbus_init_mmio(sbd, >iomem); -for (int i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { +for (int i = 0; i < sdhci->num_slots; ++i) { Object *sdhci_slot = OBJECT(>slots[i]); SysBusDevice *sbd_slot = SYS_BUS_DEVICE(>slots[i]); @@ -174,6 +175,11 @@ static const VMStateDescription vmstate_aspeed_sdhci = { }, }; +static Property aspeed_sdhci_properties[] = { +DEFINE_PROP_UINT8("num-slots", AspeedSDHCIState, num_slots, 0), +DEFINE_PROP_END_OF_LIST(), +}; + static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) { DeviceClass *dc = DEVICE_CLASS(classp); @@ -181,6 +187,7 @@ static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) dc->realize = aspeed_sdhci_realize; dc->reset = aspeed_sdhci_reset; dc->vmsd = _aspeed_sdhci; +dc->props = aspeed_sdhci_properties; } static TypeInfo aspeed_sdhci_info = { diff --git a/include/hw/sd/aspeed_sdhci.h b/include/hw/sd/aspeed_sdhci.h index dfdab4379021..dffbb46946b9 100644 --- a/include/hw/sd/aspeed_sdhci.h +++ b/include/hw/sd/aspeed_sdhci.h @@ -24,6 +24,7 @@ typedef struct AspeedSDHCIState { SysBusDevice parent; SDHCIState slots[ASPEED_SDHCI_NUM_SLOTS]; +uint8_t num_slots; MemoryRegion iomem; qemu_irq irq; -- git-series 0.9.1
Re: [PATCH 0/2] hw/arm: ast2600: Wire up eMMC controller
On Tue, 10 Dec 2019, at 19:23, Cédric Le Goater wrote: > On 10/12/2019 01:52, Andrew Jeffery wrote: > > Hello, > > > > The AST2600 has an additional SDHCI intended for use as an eMMC boot source. > > Have you also considered booting the QEMU Aspeed AST2600 machine > from the eMMC device ? > I hadn't got that far. I was surprised we hadn't yet wired up the eMMC controller at all, so I solved that problem first :) Andrew
Re: [PATCH 1/2] hw/sd: Configure number of slots exposed by the ASPEED SDHCI model
On Tue, 10 Dec 2019, at 19:26, Cédric Le Goater wrote: > On 10/12/2019 01:52, Andrew Jeffery wrote: > > The AST2600 includes a second cut-down version of the SD/MMC controller > > found in the AST2500, named the eMMC controller. It's cut down in the > > sense that it only supports one slot rather than two, but it brings the > > total number of slots supported by the AST2600 to three. > > > > The existing code assumed that the SD controller always provided two > > slots. Rework the SDHCI object to expose the number of slots as a > > property to be set by the SoC configuration. > > > > Signed-off-by: Andrew Jeffery > > Reviewed-by: Cédric Le Goater > > One minor question below. > > > > --- > > hw/arm/aspeed.c | 2 +- > > hw/arm/aspeed_ast2600.c | 2 ++ > > hw/arm/aspeed_soc.c | 3 +++ > > hw/sd/aspeed_sdhci.c | 11 +-- > > include/hw/sd/aspeed_sdhci.h | 1 + > > 5 files changed, 16 insertions(+), 3 deletions(-) > > > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > > index 028191ff36fc..862549b1f3a9 100644 > > --- a/hw/arm/aspeed.c > > +++ b/hw/arm/aspeed.c > > @@ -259,7 +259,7 @@ static void aspeed_board_init(MachineState *machine, > > cfg->i2c_init(bmc); > > } > > > > -for (i = 0; i < ARRAY_SIZE(bmc->soc.sdhci.slots); i++) { > > +for (i = 0; i < bmc->soc.sdhci.num_slots; i++) { > > SDHCIState *sdhci = >soc.sdhci.slots[i]; > > DriveInfo *dinfo = drive_get_next(IF_SD); > > BlockBackend *blk; > > diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c > > index 931887ac681f..931ee5aae183 100644 > > --- a/hw/arm/aspeed_ast2600.c > > +++ b/hw/arm/aspeed_ast2600.c > > @@ -208,6 +208,8 @@ static void aspeed_soc_ast2600_init(Object *obj) > > sysbus_init_child_obj(obj, "sdc", OBJECT(>sdhci), sizeof(s->sdhci), > >TYPE_ASPEED_SDHCI); > > > > +object_property_set_int(OBJECT(>sdhci), 2, "num-slots", > > _abort); > > OK. This defines 2 SDHCI slots for the ast2600 SoC, but > > > + > > /* Init sd card slot class here so that they're under the correct > > parent */ > > for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { > > sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(>sdhci.slots[i]), > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > > index f4fe243458fd..3498f55603f2 100644 > > --- a/hw/arm/aspeed_soc.c > > +++ b/hw/arm/aspeed_soc.c > > @@ -215,6 +215,9 @@ static void aspeed_soc_init(Object *obj) > > sysbus_init_child_obj(obj, "sdc", OBJECT(>sdhci), sizeof(s->sdhci), > >TYPE_ASPEED_SDHCI); > > > > +object_property_set_int(OBJECT(>sdhci), ASPEED_SDHCI_NUM_SLOTS, > > +"num-slots", _abort); > > > why use ASPEED_SDHCI_NUM_SLOTS here ? No good reason. I'll just switch it to '2' like in the 2600. Andrew
Re: [PATCH 2/2] hw/arm: ast2600: Wire up the eMMC controller
On Tue, 10 Dec 2019, at 23:22, Cédric Le Goater wrote: > On 10/12/2019 01:52, Andrew Jeffery wrote: > > Initialise another SDHCI model instance for the AST2600's eMMC > > controller and use the SDHCI's num_slots value introduced previously to > > determine whether we should create an SD card instance for the new slot. > > > > Signed-off-by: Andrew Jeffery > > LGTM. One comment. > > > --- > > hw/arm/aspeed.c | 13 + > > hw/arm/aspeed_ast2600.c | 21 + > > include/hw/arm/aspeed_soc.h | 2 ++ > > 3 files changed, 36 insertions(+) > > > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > > index 862549b1f3a9..0e08d62e9ff3 100644 > > --- a/hw/arm/aspeed.c > > +++ b/hw/arm/aspeed.c > > @@ -272,6 +272,19 @@ static void aspeed_board_init(MachineState *machine, > > object_property_set_bool(OBJECT(card), true, "realized", > > _fatal); > > } > > > > +if (bmc->soc.emmc.num_slots) { > > +SDHCIState *emmc = >soc.emmc.slots[0]; > > +DriveInfo *dinfo = drive_get_next(IF_SD); > > +BlockBackend *blk; > > +DeviceState *card; > > + > > +blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; > > +card = qdev_create(qdev_get_child_bus(DEVICE(emmc), "sd-bus"), > > + TYPE_SD_CARD); > > +qdev_prop_set_drive(card, "drive", blk, _fatal); > > +object_property_set_bool(OBJECT(card), true, "realized", > > _fatal); > > +} > > I think we could use a function for the above ^ Yep, I'll refactor that. Andrew
[PATCH 2/2] hw/arm: ast2600: Wire up the eMMC controller
Initialise another SDHCI model instance for the AST2600's eMMC controller and use the SDHCI's num_slots value introduced previously to determine whether we should create an SD card instance for the new slot. Signed-off-by: Andrew Jeffery --- hw/arm/aspeed.c | 13 + hw/arm/aspeed_ast2600.c | 21 + include/hw/arm/aspeed_soc.h | 2 ++ 3 files changed, 36 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 862549b1f3a9..0e08d62e9ff3 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -272,6 +272,19 @@ static void aspeed_board_init(MachineState *machine, object_property_set_bool(OBJECT(card), true, "realized", _fatal); } +if (bmc->soc.emmc.num_slots) { +SDHCIState *emmc = >soc.emmc.slots[0]; +DriveInfo *dinfo = drive_get_next(IF_SD); +BlockBackend *blk; +DeviceState *card; + +blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; +card = qdev_create(qdev_get_child_bus(DEVICE(emmc), "sd-bus"), + TYPE_SD_CARD); +qdev_prop_set_drive(card, "drive", blk, _fatal); +object_property_set_bool(OBJECT(card), true, "realized", _fatal); +} + arm_load_kernel(ARM_CPU(first_cpu), machine, _board_binfo); } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 931ee5aae183..723c8196c8a5 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -46,6 +46,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_ADC] = 0x1E6E9000, [ASPEED_VIDEO] = 0x1E70, [ASPEED_SDHCI] = 0x1E74, +[ASPEED_EMMC] = 0x1E75, [ASPEED_GPIO] = 0x1E78, [ASPEED_GPIO_1_8V] = 0x1E780800, [ASPEED_RTC] = 0x1E781000, @@ -64,6 +65,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { #define ASPEED_SOC_AST2600_MAX_IRQ 128 +/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_UART1] = 47, [ASPEED_UART2] = 48, @@ -77,6 +79,7 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_ADC] = 78, [ASPEED_XDMA] = 6, [ASPEED_SDHCI] = 43, +[ASPEED_EMMC] = 15, [ASPEED_GPIO] = 40, [ASPEED_GPIO_1_8V] = 11, [ASPEED_RTC] = 13, @@ -215,6 +218,14 @@ static void aspeed_soc_ast2600_init(Object *obj) sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(>sdhci.slots[i]), sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); } + +sysbus_init_child_obj(obj, "emmc", OBJECT(>emmc), sizeof(s->emmc), + TYPE_ASPEED_SDHCI); + +object_property_set_int(OBJECT(>emmc), 1, "num-slots", _abort); + +sysbus_init_child_obj(obj, "emmc[*]", OBJECT(>emmc.slots[0]), +sizeof(s->emmc.slots[0]), TYPE_SYSBUS_SDHCI); } /* @@ -487,6 +498,16 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SDHCI]); sysbus_connect_irq(SYS_BUS_DEVICE(>sdhci), 0, aspeed_soc_get_irq(s, ASPEED_SDHCI)); + +/* eMMC */ +object_property_set_bool(OBJECT(>emmc), true, "realized", ); +if (err) { +error_propagate(errp, err); +return; +} +sysbus_mmio_map(SYS_BUS_DEVICE(>emmc), 0, sc->memmap[ASPEED_EMMC]); +sysbus_connect_irq(SYS_BUS_DEVICE(>emmc), 0, + aspeed_soc_get_irq(s, ASPEED_EMMC)); } static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 495c08be1b84..911443f4c071 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -56,6 +56,7 @@ typedef struct AspeedSoCState { AspeedGPIOState gpio; AspeedGPIOState gpio_1_8v; AspeedSDHCIState sdhci; +AspeedSDHCIState emmc; } AspeedSoCState; #define TYPE_ASPEED_SOC "aspeed-soc" @@ -125,6 +126,7 @@ enum { ASPEED_MII4, ASPEED_SDRAM, ASPEED_XDMA, +ASPEED_EMMC, }; #endif /* ASPEED_SOC_H */ -- git-series 0.9.1
[PATCH 1/2] hw/sd: Configure number of slots exposed by the ASPEED SDHCI model
The AST2600 includes a second cut-down version of the SD/MMC controller found in the AST2500, named the eMMC controller. It's cut down in the sense that it only supports one slot rather than two, but it brings the total number of slots supported by the AST2600 to three. The existing code assumed that the SD controller always provided two slots. Rework the SDHCI object to expose the number of slots as a property to be set by the SoC configuration. Signed-off-by: Andrew Jeffery --- hw/arm/aspeed.c | 2 +- hw/arm/aspeed_ast2600.c | 2 ++ hw/arm/aspeed_soc.c | 3 +++ hw/sd/aspeed_sdhci.c | 11 +-- include/hw/sd/aspeed_sdhci.h | 1 + 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 028191ff36fc..862549b1f3a9 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -259,7 +259,7 @@ static void aspeed_board_init(MachineState *machine, cfg->i2c_init(bmc); } -for (i = 0; i < ARRAY_SIZE(bmc->soc.sdhci.slots); i++) { +for (i = 0; i < bmc->soc.sdhci.num_slots; i++) { SDHCIState *sdhci = >soc.sdhci.slots[i]; DriveInfo *dinfo = drive_get_next(IF_SD); BlockBackend *blk; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 931887ac681f..931ee5aae183 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -208,6 +208,8 @@ static void aspeed_soc_ast2600_init(Object *obj) sysbus_init_child_obj(obj, "sdc", OBJECT(>sdhci), sizeof(s->sdhci), TYPE_ASPEED_SDHCI); +object_property_set_int(OBJECT(>sdhci), 2, "num-slots", _abort); + /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(>sdhci.slots[i]), diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index f4fe243458fd..3498f55603f2 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -215,6 +215,9 @@ static void aspeed_soc_init(Object *obj) sysbus_init_child_obj(obj, "sdc", OBJECT(>sdhci), sizeof(s->sdhci), TYPE_ASPEED_SDHCI); +object_property_set_int(OBJECT(>sdhci), ASPEED_SDHCI_NUM_SLOTS, +"num-slots", _abort); + /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(>sdhci.slots[i]), diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index cff3eb7dd21e..939d1510dedb 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -13,6 +13,7 @@ #include "qapi/error.h" #include "hw/irq.h" #include "migration/vmstate.h" +#include "hw/qdev-properties.h" #define ASPEED_SDHCI_INFO0x00 #define ASPEED_SDHCI_INFO_RESET 0x0003 @@ -120,14 +121,14 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) /* Create input irqs for the slots */ qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq, -sdhci, NULL, ASPEED_SDHCI_NUM_SLOTS); +sdhci, NULL, sdhci->num_slots); sysbus_init_irq(sbd, >irq); memory_region_init_io(>iomem, OBJECT(sdhci), _sdhci_ops, sdhci, TYPE_ASPEED_SDHCI, 0x1000); sysbus_init_mmio(sbd, >iomem); -for (int i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { +for (int i = 0; i < sdhci->num_slots; ++i) { Object *sdhci_slot = OBJECT(>slots[i]); SysBusDevice *sbd_slot = SYS_BUS_DEVICE(>slots[i]); @@ -174,6 +175,11 @@ static const VMStateDescription vmstate_aspeed_sdhci = { }, }; +static Property aspeed_sdhci_properties[] = { +DEFINE_PROP_UINT8("num-slots", AspeedSDHCIState, num_slots, 0), +DEFINE_PROP_END_OF_LIST(), +}; + static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) { DeviceClass *dc = DEVICE_CLASS(classp); @@ -181,6 +187,7 @@ static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) dc->realize = aspeed_sdhci_realize; dc->reset = aspeed_sdhci_reset; dc->vmsd = _aspeed_sdhci; +dc->props = aspeed_sdhci_properties; } static TypeInfo aspeed_sdhci_info = { diff --git a/include/hw/sd/aspeed_sdhci.h b/include/hw/sd/aspeed_sdhci.h index dfdab4379021..dffbb46946b9 100644 --- a/include/hw/sd/aspeed_sdhci.h +++ b/include/hw/sd/aspeed_sdhci.h @@ -24,6 +24,7 @@ typedef struct AspeedSDHCIState { SysBusDevice parent; SDHCIState slots[ASPEED_SDHCI_NUM_SLOTS]; +uint8_t num_slots; MemoryRegion iomem; qemu_irq irq; -- git-series 0.9.1
[PATCH 0/2] hw/arm: ast2600: Wire up eMMC controller
Hello, The AST2600 has an additional SDHCI intended for use as an eMMC boot source. These two patches rework the existing ASPEED SDHCI model to accommodate the single-slot nature of the eMMC controller and wire it into the AST2600 SoC. Please review! Andrew Andrew Jeffery (2): hw/sd: Configure number of slots exposed by the ASPEED SDHCI model hw/arm: ast2600: Wire up the eMMC controller hw/arm/aspeed.c | 15 ++- hw/arm/aspeed_ast2600.c | 23 +++ hw/arm/aspeed_soc.c | 3 +++ hw/sd/aspeed_sdhci.c | 11 +-- include/hw/arm/aspeed_soc.h | 2 ++ include/hw/sd/aspeed_sdhci.h | 1 + 6 files changed, 52 insertions(+), 3 deletions(-) base-commit: 6a4ef4e5d1084ce41fafa7d470a644b0fd3d9317 -- git-series 0.9.1
Re: [PATCH v2 2/4] target/arm: Abstract the generic timer frequency
On Wed, 4 Dec 2019, at 03:57, Philippe Mathieu-Daudé wrote: > On 12/3/19 1:48 PM, Andrew Jeffery wrote: > > On Tue, 3 Dec 2019, at 16:39, Philippe Mathieu-Daudé wrote: > >> On 12/3/19 5:14 AM, Andrew Jeffery wrote: > >>> Prepare for SoCs such as the ASPEED AST2600 whose firmware configures > >>> CNTFRQ to values significantly larger than the static 62.5MHz value > >>> currently derived from GTIMER_SCALE. As the OS potentially derives its > >>> timer periods from the CNTFRQ value the lack of support for running > >>> QEMUTimers at the appropriate rate leads to sticky behaviour in the > >>> guest. > >>> > >>> Substitute the GTIMER_SCALE constant with use of a helper to derive the > >>> period from gt_cntfrq stored in struct ARMCPU. Initially set gt_cntfrq > >>> to the frequency associated with GTIMER_SCALE so current behaviour is > >>> maintained. > >>> > >>> Signed-off-by: Andrew Jeffery > >>> Reviewed-by: Richard Henderson > >>> --- > >>>target/arm/cpu.c| 2 ++ > >>>target/arm/cpu.h| 10 ++ > >>>target/arm/helper.c | 10 +++--- > >>>3 files changed, 19 insertions(+), 3 deletions(-) > >>> > >>> diff --git a/target/arm/cpu.c b/target/arm/cpu.c > >>> index 7a4ac9339bf9..5698a74061bb 100644 > >>> --- a/target/arm/cpu.c > >>> +++ b/target/arm/cpu.c > >>> @@ -974,6 +974,8 @@ static void arm_cpu_initfn(Object *obj) > >>>if (tcg_enabled()) { > >>>cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ > >>>} > >>> + > >>> +cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; > >>>} > >>> > >>>static Property arm_cpu_reset_cbar_property = > >>> diff --git a/target/arm/cpu.h b/target/arm/cpu.h > >>> index 83a809d4bac4..666c03871fdf 100644 > >>> --- a/target/arm/cpu.h > >>> +++ b/target/arm/cpu.h > >>> @@ -932,8 +932,18 @@ struct ARMCPU { > >>> */ > >>>DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); > >>>DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); > >>> + > >>> +/* Generic timer counter frequency, in Hz */ > >>> +uint64_t gt_cntfrq; > >> > >> You can also explicit the unit by calling it 'gt_cntfrq_hz'. > > > > Fair call, I'll fix that. > > > >> > >>>}; > >>> > >>> +static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) > >>> +{ > >>> +/* XXX: Could include qemu/timer.h to get NANOSECONDS_PER_SECOND? */ > >> > >> Why inline this call? I doubt there is a significant performance gain. > > > > It wasn't so much performance. It started out as a macro for a simple > > calculation > > because I didn't want to duplicate it across a number of places, then I > > wanted type > > safety for the pointer so I switched the macro in the header to an inline > > function. So > > it is an evolution of the patch rather than something that came from an > > explicit goal > > of e.g. performance. > > OK. Eventually NANOSECONDS_PER_SECOND will move to "qemu/units.h". > > Should the XXX comment stay? I'm not sure, it is confusing. I'll remove that. > > Reviewed-by: Philippe Mathieu-Daudé Thanks. However, did you still want your comment on 4/4 addressed (move the comment to this patch)? Andrew
Re: [PATCH v2 3/4] target/arm: Prepare generic timer for per-platform CNTFRQ
On Tue, 3 Dec 2019, at 16:49, Philippe Mathieu-Daudé wrote: > On 12/3/19 5:14 AM, Andrew Jeffery wrote: > > The ASPEED AST2600 clocks the generic timer at the rate of HPLL. On > > recent firmwares this is at 1125MHz, which is considerably quicker than > > the assumed 62.5MHz of the current generic timer implementation. The > > delta between the value as read from CNTFRQ and the true rate of the > > underlying QEMUTimer leads to sticky behaviour in AST2600 guests. > > > > Add a feature-gated property exposing CNTFRQ for ARM CPUs providing the > > generic timer. This allows platforms to configure CNTFRQ (and the > > associated QEMUTimer) to the appropriate frequency prior to starting the > > guest. > > > > As the platform can now determine the rate of CNTFRQ we're exposed to > > limitations of QEMUTimer that didn't previously materialise: In the > > course of emulation we need to arbitrarily and accurately convert > > between guest ticks and time, but we're constrained by QEMUTimer's use > > of an integer scaling factor. The effect is QEMUTimer cannot exactly > > capture the period of frequencies that do not cleanly divide > > NANOSECONDS_PER_SECOND for scaling ticks to time. As such, provide an > > equally inaccurate scaling factor for scaling time to ticks so at least > > a self-consistent inverse relationship holds. > > > > Signed-off-by: Andrew Jeffery > > Reviewed-by: Richard Henderson > > --- > > target/arm/cpu.c| 43 +-- > > target/arm/cpu.h| 18 ++ > > target/arm/helper.c | 9 - > > 3 files changed, 59 insertions(+), 11 deletions(-) > > > > diff --git a/target/arm/cpu.c b/target/arm/cpu.c > > index 5698a74061bb..f186019a77fd 100644 > > --- a/target/arm/cpu.c > > +++ b/target/arm/cpu.c > > @@ -974,10 +974,12 @@ static void arm_cpu_initfn(Object *obj) > > if (tcg_enabled()) { > > cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ > > } > > - > > -cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; > > } > > > > +static Property arm_cpu_gt_cntfrq_property = > > +DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq, > > + NANOSECONDS_PER_SECOND / GTIMER_SCALE); > > + > > static Property arm_cpu_reset_cbar_property = > > DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0); > > > > @@ -1174,6 +1176,11 @@ void arm_cpu_post_init(Object *obj) > > > > qdev_property_add_static(DEVICE(obj), _cpu_cfgend_property, > >_abort); > > + > > +if (arm_feature(>env, ARM_FEATURE_GENERIC_TIMER)) { > > +qdev_property_add_static(DEVICE(cpu), _cpu_gt_cntfrq_property, > > + _abort); > > +} > > } > > > > static void arm_cpu_finalizefn(Object *obj) > > @@ -1253,14 +1260,30 @@ static void arm_cpu_realizefn(DeviceState *dev, > > Error **errp) > > } > > } > > > > -cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, > > GTIMER_SCALE, > > - arm_gt_ptimer_cb, cpu); > > -cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, > > GTIMER_SCALE, > > - arm_gt_vtimer_cb, cpu); > > -cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, > > - arm_gt_htimer_cb, cpu); > > -cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, > > - arm_gt_stimer_cb, cpu); > > + > > +{ > > +uint64_t scale; > > Apparently you have to use this odd indent due to the '#ifndef > CONFIG_USER_ONLY'. Well, acceptable. It's the indent associated with the block scope for the scale variable to limit its lifetime to where I needed it. > > > + > > +if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { > > +if (!cpu->gt_cntfrq) { > > +error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", > > + cpu->gt_cntfrq); > > +return; > > +} > > +scale = gt_cntfrq_period_ns(cpu); > > +} else { > > +scale = GTIMER_SCALE; > > +} > > + > > +cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
Re: [PATCH v2 2/4] target/arm: Abstract the generic timer frequency
On Tue, 3 Dec 2019, at 16:39, Philippe Mathieu-Daudé wrote: > On 12/3/19 5:14 AM, Andrew Jeffery wrote: > > Prepare for SoCs such as the ASPEED AST2600 whose firmware configures > > CNTFRQ to values significantly larger than the static 62.5MHz value > > currently derived from GTIMER_SCALE. As the OS potentially derives its > > timer periods from the CNTFRQ value the lack of support for running > > QEMUTimers at the appropriate rate leads to sticky behaviour in the > > guest. > > > > Substitute the GTIMER_SCALE constant with use of a helper to derive the > > period from gt_cntfrq stored in struct ARMCPU. Initially set gt_cntfrq > > to the frequency associated with GTIMER_SCALE so current behaviour is > > maintained. > > > > Signed-off-by: Andrew Jeffery > > Reviewed-by: Richard Henderson > > --- > > target/arm/cpu.c| 2 ++ > > target/arm/cpu.h| 10 ++ > > target/arm/helper.c | 10 +++--- > > 3 files changed, 19 insertions(+), 3 deletions(-) > > > > diff --git a/target/arm/cpu.c b/target/arm/cpu.c > > index 7a4ac9339bf9..5698a74061bb 100644 > > --- a/target/arm/cpu.c > > +++ b/target/arm/cpu.c > > @@ -974,6 +974,8 @@ static void arm_cpu_initfn(Object *obj) > > if (tcg_enabled()) { > > cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ > > } > > + > > +cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; > > } > > > > static Property arm_cpu_reset_cbar_property = > > diff --git a/target/arm/cpu.h b/target/arm/cpu.h > > index 83a809d4bac4..666c03871fdf 100644 > > --- a/target/arm/cpu.h > > +++ b/target/arm/cpu.h > > @@ -932,8 +932,18 @@ struct ARMCPU { > >*/ > > DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); > > DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); > > + > > +/* Generic timer counter frequency, in Hz */ > > +uint64_t gt_cntfrq; > > You can also explicit the unit by calling it 'gt_cntfrq_hz'. Fair call, I'll fix that. > > > }; > > > > +static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) > > +{ > > +/* XXX: Could include qemu/timer.h to get NANOSECONDS_PER_SECOND? */ > > Why inline this call? I doubt there is a significant performance gain. It wasn't so much performance. It started out as a macro for a simple calculation because I didn't want to duplicate it across a number of places, then I wanted type safety for the pointer so I switched the macro in the header to an inline function. So it is an evolution of the patch rather than something that came from an explicit goal of e.g. performance. Andrew
[PATCH v2 2/4] target/arm: Abstract the generic timer frequency
Prepare for SoCs such as the ASPEED AST2600 whose firmware configures CNTFRQ to values significantly larger than the static 62.5MHz value currently derived from GTIMER_SCALE. As the OS potentially derives its timer periods from the CNTFRQ value the lack of support for running QEMUTimers at the appropriate rate leads to sticky behaviour in the guest. Substitute the GTIMER_SCALE constant with use of a helper to derive the period from gt_cntfrq stored in struct ARMCPU. Initially set gt_cntfrq to the frequency associated with GTIMER_SCALE so current behaviour is maintained. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson --- target/arm/cpu.c| 2 ++ target/arm/cpu.h| 10 ++ target/arm/helper.c | 10 +++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7a4ac9339bf9..5698a74061bb 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -974,6 +974,8 @@ static void arm_cpu_initfn(Object *obj) if (tcg_enabled()) { cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ } + +cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; } static Property arm_cpu_reset_cbar_property = diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 83a809d4bac4..666c03871fdf 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -932,8 +932,18 @@ struct ARMCPU { */ DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); + +/* Generic timer counter frequency, in Hz */ +uint64_t gt_cntfrq; }; +static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) +{ +/* XXX: Could include qemu/timer.h to get NANOSECONDS_PER_SECOND? */ +const unsigned int ns_per_s = 1000 * 1000 * 1000; +return ns_per_s > cpu->gt_cntfrq ? ns_per_s / cpu->gt_cntfrq : 1; +} + void arm_cpu_post_init(Object *obj); uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz); diff --git a/target/arm/helper.c b/target/arm/helper.c index 65c4441a3896..2622a9a8d02f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2409,7 +2409,9 @@ static CPAccessResult gt_stimer_access(CPUARMState *env, static uint64_t gt_get_countervalue(CPUARMState *env) { -return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; +ARMCPU *cpu = env_archcpu(env); + +return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu); } static void gt_recalc_timer(ARMCPU *cpu, int timeridx) @@ -2445,7 +2447,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * set the timer for as far in the future as possible. When the * timer expires we will reset the timer for any remaining period. */ -if (nexttick > INT64_MAX / GTIMER_SCALE) { +if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) { timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX); } else { timer_mod(cpu->gt_timer[timeridx], nexttick); @@ -2874,11 +2876,13 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) { +ARMCPU *cpu = env_archcpu(env); + /* Currently we have no support for QEMUTimer in linux-user so we * can't call gt_get_countervalue(env), instead we directly * call the lower level functions. */ -return cpu_get_clock() / GTIMER_SCALE; +return cpu_get_clock() / gt_cntfrq_period_ns(cpu); } static const ARMCPRegInfo generic_timer_cp_reginfo[] = { -- 2.20.1
[PATCH v2 3/4] target/arm: Prepare generic timer for per-platform CNTFRQ
The ASPEED AST2600 clocks the generic timer at the rate of HPLL. On recent firmwares this is at 1125MHz, which is considerably quicker than the assumed 62.5MHz of the current generic timer implementation. The delta between the value as read from CNTFRQ and the true rate of the underlying QEMUTimer leads to sticky behaviour in AST2600 guests. Add a feature-gated property exposing CNTFRQ for ARM CPUs providing the generic timer. This allows platforms to configure CNTFRQ (and the associated QEMUTimer) to the appropriate frequency prior to starting the guest. As the platform can now determine the rate of CNTFRQ we're exposed to limitations of QEMUTimer that didn't previously materialise: In the course of emulation we need to arbitrarily and accurately convert between guest ticks and time, but we're constrained by QEMUTimer's use of an integer scaling factor. The effect is QEMUTimer cannot exactly capture the period of frequencies that do not cleanly divide NANOSECONDS_PER_SECOND for scaling ticks to time. As such, provide an equally inaccurate scaling factor for scaling time to ticks so at least a self-consistent inverse relationship holds. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson --- target/arm/cpu.c| 43 +-- target/arm/cpu.h| 18 ++ target/arm/helper.c | 9 - 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5698a74061bb..f186019a77fd 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -974,10 +974,12 @@ static void arm_cpu_initfn(Object *obj) if (tcg_enabled()) { cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ } - -cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; } +static Property arm_cpu_gt_cntfrq_property = +DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq, + NANOSECONDS_PER_SECOND / GTIMER_SCALE); + static Property arm_cpu_reset_cbar_property = DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0); @@ -1174,6 +1176,11 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), _cpu_cfgend_property, _abort); + +if (arm_feature(>env, ARM_FEATURE_GENERIC_TIMER)) { +qdev_property_add_static(DEVICE(cpu), _cpu_gt_cntfrq_property, + _abort); +} } static void arm_cpu_finalizefn(Object *obj) @@ -1253,14 +1260,30 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } -cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_ptimer_cb, cpu); -cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_vtimer_cb, cpu); -cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_htimer_cb, cpu); -cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_stimer_cb, cpu); + +{ +uint64_t scale; + +if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { +if (!cpu->gt_cntfrq) { +error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", + cpu->gt_cntfrq); +return; +} +scale = gt_cntfrq_period_ns(cpu); +} else { +scale = GTIMER_SCALE; +} + +cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_ptimer_cb, cpu); +cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_vtimer_cb, cpu); +cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_htimer_cb, cpu); +cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_stimer_cb, cpu); +} #endif cpu_exec_realizefn(cs, _err); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 666c03871fdf..0bcd13dcac81 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -939,6 +939,24 @@ struct ARMCPU { static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) { +/* + * The exact approach to calculating guest ticks is: + * + * muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), cpu->gt_cntfrq, + * NANOSECONDS_PER_SECOND); + * + * We don't do that. Rather we intentionally use integer division + * truncation below and in the caller for the conversion of host monotonic + * time to guest ticks to provide the exact inverse for the semantics of + * the QEMUTimer scale factor. QEMUT
[PATCH v2 4/4] ast2600: Configure CNTFRQ at 1125MHz
This matches the configuration set by u-boot on the AST2600. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson Reviewed-by: Cédric Le Goater --- hw/arm/aspeed_ast2600.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 931887ac681f..5aecc3b3caec 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -259,6 +259,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(>cpu[i]), aspeed_calc_affinity(i), "mp-affinity", _abort); +object_property_set_int(OBJECT(>cpu[i]), 112500, "cntfrq", +_abort); + /* * TODO: the secondary CPUs are started and a boot helper * is needed when using -kernel -- 2.20.1
[PATCH v2 0/4] Expose GT CNTFRQ as a CPU property to support AST2600
Hello, This is a v2 of the belated follow-up from a few of my earlier attempts to fix up the ARM generic timer for correct behaviour on the ASPEED AST2600 SoC. The AST2600 clocks the generic timer at the rate of HPLL, which is configured to 1125MHz. This is significantly quicker than the currently hard-coded generic timer rate of 62.5MHz and so we see "sticky" behaviour in the guest. v1 can be found here: https://patchwork.ozlabs.org/cover/1201887/ Changes since v1: * Fix a user mode build failure from partial renaming of gt_cntfrq_period_ns() * Add tags from Cedric and Richard Please review. Andrew Andrew Jeffery (4): target/arm: Remove redundant scaling of nexttick target/arm: Abstract the generic timer frequency target/arm: Prepare generic timer for per-platform CNTFRQ ast2600: Configure CNTFRQ at 1125MHz hw/arm/aspeed_ast2600.c | 3 +++ target/arm/cpu.c| 41 + target/arm/cpu.h| 28 target/arm/helper.c | 24 ++-- 4 files changed, 82 insertions(+), 14 deletions(-) -- 2.20.1
[PATCH v2 1/4] target/arm: Remove redundant scaling of nexttick
The corner-case codepath was adjusting nexttick such that overflow wouldn't occur when timer_mod() scaled the value back up. Remove a use of GTIMER_SCALE and avoid unnecessary operations by calling timer_mod_ns() directly. Signed-off-by: Andrew Jeffery Reviewed-by: Richard Henderson Reviewed-by: Cédric Le Goater --- target/arm/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a089fb5a6909..65c4441a3896 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2446,9 +2446,10 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * timer expires we will reset the timer for any remaining period. */ if (nexttick > INT64_MAX / GTIMER_SCALE) { -nexttick = INT64_MAX / GTIMER_SCALE; +timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX); +} else { +timer_mod(cpu->gt_timer[timeridx], nexttick); } -timer_mod(cpu->gt_timer[timeridx], nexttick); trace_arm_gt_recalc(timeridx, irqstate, nexttick); } else { /* Timer disabled: ISTATUS and timer output always clear */ -- 2.20.1
Re: [PATCH 2/4] target/arm: Abstract the generic timer frequency
On Tue, 3 Dec 2019, at 04:42, Peter Maydell wrote: > On Thu, 28 Nov 2019 at 05:44, Andrew Jeffery wrote: > > > > Prepare for SoCs such as the ASPEED AST2600 whose firmware configures > > CNTFRQ to values significantly larger than the static 62.5MHz value > > currently derived from GTIMER_SCALE. As the OS potentially derives its > > timer periods from the CNTFRQ value the lack of support for running > > QEMUTimers at the appropriate rate leads to sticky behaviour in the > > guest. > > > > Substitute the GTIMER_SCALE constant with use of a helper to derive the > > period from gt_cntfrq stored in struct ARMCPU. Initially set gt_cntfrq > > to the frequency associated with GTIMER_SCALE so current behaviour is > > maintained. > > > > Signed-off-by: Andrew Jeffery > > > +static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) > > +{ > > +/* XXX: Could include qemu/timer.h to get NANOSECONDS_PER_SECOND? */ > > +const unsigned int ns_per_s = 1000 * 1000 * 1000; > > +return ns_per_s > cpu->gt_cntfrq ? ns_per_s / cpu->gt_cntfrq : 1; > > +} > > This function is named gt_cntfrq_period_ns()... > > > static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) > > { > > +ARMCPU *cpu = env_archcpu(env); > > + > > /* Currently we have no support for QEMUTimer in linux-user so we > > * can't call gt_get_countervalue(env), instead we directly > > * call the lower level functions. > > */ > > -return cpu_get_clock() / GTIMER_SCALE; > > +return cpu_get_clock() / gt_cntfrq_period(cpu); > > } > > ...but here we call gt_cntfrq_period(), which doesn't exist, > and indeed at least one of the patchew build systems reported > it as a compile failure. > Ah yep, I failed to test user mode after renaming the function and missed this. I haven't seen an alert from patchew though, I wonder where that got to? Andrew
Re: [PATCH 2/4] target/arm: Abstract the generic timer frequency
On Thu, 28 Nov 2019, at 19:16, Cédric Le Goater wrote: > On 28/11/2019 06:45, Andrew Jeffery wrote: > > Prepare for SoCs such as the ASPEED AST2600 whose firmware configures > > CNTFRQ to values significantly larger than the static 62.5MHz value > > currently derived from GTIMER_SCALE. As the OS potentially derives its > > timer periods from the CNTFRQ value the lack of support for running > > QEMUTimers at the appropriate rate leads to sticky behaviour in the > > guest. > > > > Substitute the GTIMER_SCALE constant with use of a helper to derive the > > period from gt_cntfrq stored in struct ARMCPU. Initially set gt_cntfrq > > to the frequency associated with GTIMER_SCALE so current behaviour is > > maintained. > > > > Signed-off-by: Andrew Jeffery > > --- > > target/arm/cpu.c| 2 ++ > > target/arm/cpu.h| 10 ++ > > target/arm/helper.c | 10 +++--- > > 3 files changed, 19 insertions(+), 3 deletions(-) > > > > diff --git a/target/arm/cpu.c b/target/arm/cpu.c > > index 7a4ac9339bf9..5698a74061bb 100644 > > --- a/target/arm/cpu.c > > +++ b/target/arm/cpu.c > > @@ -974,6 +974,8 @@ static void arm_cpu_initfn(Object *obj) > > if (tcg_enabled()) { > > cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ > > } > > + > > +cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; > > } > > > > static Property arm_cpu_reset_cbar_property = > > diff --git a/target/arm/cpu.h b/target/arm/cpu.h > > index 83a809d4bac4..666c03871fdf 100644 > > --- a/target/arm/cpu.h > > +++ b/target/arm/cpu.h > > @@ -932,8 +932,18 @@ struct ARMCPU { > > */ > > DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); > > DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); > > + > > +/* Generic timer counter frequency, in Hz */ > > +uint64_t gt_cntfrq; > > }; > > > > +static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) > > +{ > > +/* XXX: Could include qemu/timer.h to get NANOSECONDS_PER_SECOND? */ > > +const unsigned int ns_per_s = 1000 * 1000 * 1000; > > +return ns_per_s > cpu->gt_cntfrq ? ns_per_s / cpu->gt_cntfrq : 1; > > +} > > Are you inlining this helper for performance reasons ? Originally I was going to do it as a macro in order to avoid redundantly scattering the calculation around. My thought was to use a macro as it's a simple calculation, but then figured it was a bit nicer as a function for type safety. I already had it as a macro in the header, so it was the least effort to switch it to a static inline and leave it where it was :) So that's the justification, mostly just evolution of thought process. Performance was also a consideration but I've done no measurements. Andrew
[PATCH 3/4] target/arm: Prepare generic timer for per-platform CNTFRQ
The ASPEED AST2600 clocks the generic timer at the rate of HPLL. On recent firmwares this is at 1125MHz, which is considerably quicker than the assumed 62.5MHz of the current generic timer implementation. The delta between the value as read from CNTFRQ and the true rate of the underlying QEMUTimer leads to sticky behaviour in AST2600 guests. Add a feature-gated property exposing CNTFRQ for ARM CPUs providing the generic timer. This allows platforms to configure CNTFRQ (and the associated QEMUTimer) to the appropriate frequency prior to starting the guest. As the platform can now determine the rate of CNTFRQ we're exposed to limitations of QEMUTimer that didn't previously materialise: In the course of emulation we need to arbitrarily and accurately convert between guest ticks and time, but we're constrained by QEMUTimer's use of an integer scaling factor. Its effect is QEMUTimer cannot exactly capture the period of frequencies that do not cleanly divide NANOSECONDS_PER_SECOND for scaling ticks to time. As such, provide an equally inaccurate scaling factor for scaling time to ticks so at least an self-consistent inverse relationship holds. Signed-off-by: Andrew Jeffery --- target/arm/cpu.c| 43 +-- target/arm/cpu.h| 18 ++ target/arm/helper.c | 9 - 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5698a74061bb..f186019a77fd 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -974,10 +974,12 @@ static void arm_cpu_initfn(Object *obj) if (tcg_enabled()) { cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ } - -cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; } +static Property arm_cpu_gt_cntfrq_property = +DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq, + NANOSECONDS_PER_SECOND / GTIMER_SCALE); + static Property arm_cpu_reset_cbar_property = DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0); @@ -1174,6 +1176,11 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), _cpu_cfgend_property, _abort); + +if (arm_feature(>env, ARM_FEATURE_GENERIC_TIMER)) { +qdev_property_add_static(DEVICE(cpu), _cpu_gt_cntfrq_property, + _abort); +} } static void arm_cpu_finalizefn(Object *obj) @@ -1253,14 +1260,30 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } -cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_ptimer_cb, cpu); -cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_vtimer_cb, cpu); -cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_htimer_cb, cpu); -cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_stimer_cb, cpu); + +{ +uint64_t scale; + +if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { +if (!cpu->gt_cntfrq) { +error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", + cpu->gt_cntfrq); +return; +} +scale = gt_cntfrq_period_ns(cpu); +} else { +scale = GTIMER_SCALE; +} + +cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_ptimer_cb, cpu); +cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_vtimer_cb, cpu); +cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_htimer_cb, cpu); +cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_stimer_cb, cpu); +} #endif cpu_exec_realizefn(cs, _err); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 666c03871fdf..0bcd13dcac81 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -939,6 +939,24 @@ struct ARMCPU { static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) { +/* + * The exact approach to calculating guest ticks is: + * + * muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), cpu->gt_cntfrq, + * NANOSECONDS_PER_SECOND); + * + * We don't do that. Rather we intentionally use integer division + * truncation below and in the caller for the conversion of host monotonic + * time to guest ticks to provide the exact inverse for the semantics of + * the QEMUTimer scale factor. QEMUTimer's scale facte
[PATCH 0/4] Expose GT CNTFRQ as a CPU property to support AST2600
Hello, This is a belated follow-up from a few of my earlier attempts to fix up the ARM generic timer for correct behaviour on the ASPEED AST2600 SoC. The AST2600 clocks the generic timer at the rate of HPLL, which is configured to 1125MHz. This is significantly quicker than the currently hard-coded generic timer rate of 62.5MHz and so we see "sticky" behaviour in the guest. Please review. Andrew Andrew Jeffery (4): target/arm: Remove redundant scaling of nexttick target/arm: Abstract the generic timer frequency target/arm: Prepare generic timer for per-platform CNTFRQ ast2600: Configure CNTFRQ at 1125MHz hw/arm/aspeed_ast2600.c | 3 +++ target/arm/cpu.c| 41 + target/arm/cpu.h| 28 target/arm/helper.c | 24 ++-- 4 files changed, 82 insertions(+), 14 deletions(-) -- 2.20.1
[PATCH 2/4] target/arm: Abstract the generic timer frequency
Prepare for SoCs such as the ASPEED AST2600 whose firmware configures CNTFRQ to values significantly larger than the static 62.5MHz value currently derived from GTIMER_SCALE. As the OS potentially derives its timer periods from the CNTFRQ value the lack of support for running QEMUTimers at the appropriate rate leads to sticky behaviour in the guest. Substitute the GTIMER_SCALE constant with use of a helper to derive the period from gt_cntfrq stored in struct ARMCPU. Initially set gt_cntfrq to the frequency associated with GTIMER_SCALE so current behaviour is maintained. Signed-off-by: Andrew Jeffery --- target/arm/cpu.c| 2 ++ target/arm/cpu.h| 10 ++ target/arm/helper.c | 10 +++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7a4ac9339bf9..5698a74061bb 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -974,6 +974,8 @@ static void arm_cpu_initfn(Object *obj) if (tcg_enabled()) { cpu->psci_version = 2; /* TCG implements PSCI 0.2 */ } + +cpu->gt_cntfrq = NANOSECONDS_PER_SECOND / GTIMER_SCALE; } static Property arm_cpu_reset_cbar_property = diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 83a809d4bac4..666c03871fdf 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -932,8 +932,18 @@ struct ARMCPU { */ DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); + +/* Generic timer counter frequency, in Hz */ +uint64_t gt_cntfrq; }; +static inline unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) +{ +/* XXX: Could include qemu/timer.h to get NANOSECONDS_PER_SECOND? */ +const unsigned int ns_per_s = 1000 * 1000 * 1000; +return ns_per_s > cpu->gt_cntfrq ? ns_per_s / cpu->gt_cntfrq : 1; +} + void arm_cpu_post_init(Object *obj); uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz); diff --git a/target/arm/helper.c b/target/arm/helper.c index 65c4441a3896..1cc0551081a0 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2409,7 +2409,9 @@ static CPAccessResult gt_stimer_access(CPUARMState *env, static uint64_t gt_get_countervalue(CPUARMState *env) { -return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; +ARMCPU *cpu = env_archcpu(env); + +return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu); } static void gt_recalc_timer(ARMCPU *cpu, int timeridx) @@ -2445,7 +2447,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * set the timer for as far in the future as possible. When the * timer expires we will reset the timer for any remaining period. */ -if (nexttick > INT64_MAX / GTIMER_SCALE) { +if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) { timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX); } else { timer_mod(cpu->gt_timer[timeridx], nexttick); @@ -2874,11 +2876,13 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) { +ARMCPU *cpu = env_archcpu(env); + /* Currently we have no support for QEMUTimer in linux-user so we * can't call gt_get_countervalue(env), instead we directly * call the lower level functions. */ -return cpu_get_clock() / GTIMER_SCALE; +return cpu_get_clock() / gt_cntfrq_period(cpu); } static const ARMCPRegInfo generic_timer_cp_reginfo[] = { -- 2.20.1
[PATCH 4/4] ast2600: Configure CNTFRQ at 1125MHz
This matches the configuration set by u-boot on the AST2600. Signed-off-by: Andrew Jeffery --- hw/arm/aspeed_ast2600.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 931887ac681f..5aecc3b3caec 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -259,6 +259,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(>cpu[i]), aspeed_calc_affinity(i), "mp-affinity", _abort); +object_property_set_int(OBJECT(>cpu[i]), 112500, "cntfrq", +_abort); + /* * TODO: the secondary CPUs are started and a boot helper * is needed when using -kernel -- 2.20.1
[PATCH 1/4] target/arm: Remove redundant scaling of nexttick
The corner-case codepath was adjusting nexttick such that overflow wouldn't occur when timer_mod() scaled the value back up. Remove a use of GTIMER_SCALE and avoid unnecessary operations by calling timer_mod_ns() directly. Signed-off-by: Andrew Jeffery --- target/arm/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a089fb5a6909..65c4441a3896 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2446,9 +2446,10 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * timer expires we will reset the timer for any remaining period. */ if (nexttick > INT64_MAX / GTIMER_SCALE) { -nexttick = INT64_MAX / GTIMER_SCALE; +timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX); +} else { +timer_mod(cpu->gt_timer[timeridx], nexttick); } -timer_mod(cpu->gt_timer[timeridx], nexttick); trace_arm_gt_recalc(timeridx, irqstate, nexttick); } else { /* Timer disabled: ISTATUS and timer output always clear */ -- 2.20.1
Re: [Qemu-devel] [PATCH v5] target-arm: Make the counter tick relative to cntfrq
On Wed, 18 Sep 2019, at 04:55, Richard Henderson wrote: > On 9/17/19 12:14 PM, Peter Maydell wrote: > >> +static Property arm_cpu_gt_cntfrq_property = > >> +DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq, > >> + (1000 * 1000 * 1000) / GTIMER_SCALE); > > I think it would be helpful to have a comment saynig what units > > this property is in. > > > > Should this be NANOSECONDS_PER_SECOND? > It's certainly a suspicious use of 1e9 otherwise. You're right that it should be NANOSECONDS_PER_SECOND but this was just code motion of the definition of the reset value for CNTFRQ_EL0 in target/arm/helper.c. Andrew
Re: [PATCH v5] target-arm: Make the counter tick relative to cntfrq
On Wed, 18 Sep 2019, at 01:44, Peter Maydell wrote: > On Thu, 12 Sep 2019 at 07:56, Andrew Jeffery wrote: > > diff --git a/target/arm/helper.c b/target/arm/helper.c > > index 507026c9154b..09975704d47f 100644 > > --- a/target/arm/helper.c > > +++ b/target/arm/helper.c > > @@ -2409,7 +2409,21 @@ static CPAccessResult gt_stimer_access(CPUARMState > > *env, > > > > static uint64_t gt_get_countervalue(CPUARMState *env) > > { > > -return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; > > +uint64_t effective; > > + > > +/* > > + * Deal with quantized clock scaling by calculating the effective > > frequency > > + * in terms of the timer scale. > > + */ > > +if (env->cp15.c14_cntfrq <= NANOSECONDS_PER_SECOND) { > > +uint32_t scale = NANOSECONDS_PER_SECOND / env->cp15.c14_cntfrq; > > +effective = NANOSECONDS_PER_SECOND / scale; > > +} else { > > +effective = NANOSECONDS_PER_SECOND; > > +} > > What is this doing, and why didn't we need to do it before? I'll fix all of your other comments, but I think this question in particular is best answered by turning the patch into a short series. It's a bit of a complex story. I'll try to split what's going on into smaller steps so what I've done above is better documented. The short story is there's asymmetry between converting time to ticks and ticks to time that leads us to schedule timers in the past for most CNTFRQ values if we don't do something like the above. Andrew
Re: [PATCH 03/21] hw: aspeed_scu: Add AST2600 support
On Thu, 19 Sep 2019, at 15:19, Cédric Le Goater wrote: > From: Joel Stanley > > The SCU controller on the AST2600 SoC has extra registers. Increase > the number of regs of the model and introduce a new field in the class > to customize the MemoryRegion operations depending on the SoC model. > > Signed-off-by: Joel Stanley > [clg: - improved commit log > - changed vmstate version > - reworked model integration into new objet class ] > Signed-off-by: Cédric Le Goater > --- > include/hw/misc/aspeed_scu.h | 7 +- > hw/misc/aspeed_scu.c | 190 +-- > 2 files changed, 189 insertions(+), 8 deletions(-) ... > +static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, > uint64_t data, > + unsigned size) > +{ > +AspeedSCUState *s = ASPEED_SCU(opaque); > +int reg = TO_REG(offset); > + > +if (reg >= ASPEED_AST2600_SCU_NR_REGS) { > +qemu_log_mask(LOG_GUEST_ERROR, > + "%s: Out-of-bounds write at offset 0x%" > HWADDR_PRIx "\n", > + __func__, offset); > +return; > +} > + > +if (reg > PROT_KEY && !s->regs[PROT_KEY]) { > +qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", > __func__); > +} > + > +trace_aspeed_scu_write(offset, size, data); > + > +switch (reg) { > +case AST2600_PROT_KEY: > +s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; > +return; > +case AST2600_HW_STRAP1: > +case AST2600_HW_STRAP2: > +if (s->regs[reg + 2]) { > +return; > +} > +/* fall through */ > +case AST2600_SYS_RST_CTRL: > +case AST2600_SYS_RST_CTRL2: > +/* W1S (Write 1 to set) registers */ > +s->regs[reg] |= data; > +return; > +case AST2600_SYS_RST_CTRL_CLR: > +case AST2600_SYS_RST_CTRL2_CLR: > +case AST2600_HW_STRAP1_CLR: > +case AST2600_HW_STRAP2_CLR: > +/* W1C (Write 1 to clear) registers */ > +s->regs[reg] &= ~data; This clear should respect the protection register for each strap case. Andrew
Re: [Qemu-devel] [PATCH 00/21] aspeed: Add support for the AST2600 SoC
On Fri, 20 Sep 2019, at 06:26, no-re...@patchew.org wrote: > Patchew URL: https://patchew.org/QEMU/20190919055002.6729-1-...@kaod.org/ > > > > Hi, > > This series failed the docker-quick@centos7 build test. Please find the > testing commands and > their output below. If you have Docker installed, you can probably > reproduce it > locally. > > === TEST SCRIPT BEGIN === > #!/bin/bash > make docker-image-centos7 V=1 NETWORK=1 > time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1 > === TEST SCRIPT END === > > libudev no > default devices yes > > warning: Python 2 support is deprecated > warning: Python 3 will be required for building future versions of QEMU > cross containers no > > NOTE: guest cross-compilers enabled: cc > --- > Property '.cntfrq' not found Ah, we should drop the patch introducing the CNTFRQ configuration for the 2600 as well given the patch adding support to configure it isn't part of the series. Andrew
[Qemu-devel] [PATCH v5] target-arm: Make the counter tick relative to cntfrq
Allow machines to configure CNTFRQ via a property if the ARM core supports the generic timer. This is necessary on e.g. the ASPEED AST2600 SoC where the generic timer clock is run at 800MHz or above. The default value for CNTFRQ remains at 62.50MHz (based on GTIMER_SCALE). CNTFRQ is a read-as-written co-processor register; the property sets the register's initial value which is used during realize() to configure the QEMUTimers that back the generic timers. Beyond that the firmware can to do whatever it sees fit with the CNTFRQ register though changes to the value will not be reflected in the timers' rate. I've tested this using an out-of-tree AST2600 SoC model (Cortex-A7) with the SDK u-boot that sets CNTFRQ as appropriate, and by starting/running machines with assorted ARM CPUs (palmetto-bmc with the ARM926EJ-S, romulus-bmc with the ARM1176 and raspi2 with the Cortex-A53). Signed-off-by: Andrew Jeffery --- v5: Remove unrelated submodule updates that snuck into v4 v4: https://patchwork.ozlabs.org/patch/1161340/ Fix configuration for cores without a generic timer v3: https://patchwork.ozlabs.org/patch/1160634/ Peter - I think this addresses most of your feedback. I still reach into the QEMUTimer to fetch out scale when adjusting the nexttick calculation, but we no longer need to update the scale member and force a recalculation of the period. v2: https://patchwork.ozlabs.org/patch/1144389/ Signed-off-by: Andrew Jeffery --- target/arm/cpu.c| 43 +++ target/arm/cpu.h| 3 +++ target/arm/helper.c | 30 ++ 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 2399c144718d..8b63a27761bb 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -40,6 +40,8 @@ #include "disas/capstone.h" #include "fpu/softfloat.h" +#include + static void arm_cpu_set_pc(CPUState *cs, vaddr value) { ARMCPU *cpu = ARM_CPU(cs); @@ -976,6 +978,10 @@ static void arm_cpu_initfn(Object *obj) } } +static Property arm_cpu_gt_cntfrq_property = +DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq, + (1000 * 1000 * 1000) / GTIMER_SCALE); + static Property arm_cpu_reset_cbar_property = DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0); @@ -1172,6 +1178,11 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), _cpu_cfgend_property, _abort); + +if (arm_feature(>env, ARM_FEATURE_GENERIC_TIMER)) { +qdev_property_add_static(DEVICE(cpu), _cpu_gt_cntfrq_property, + _abort); +} } static void arm_cpu_finalizefn(Object *obj) @@ -1238,14 +1249,30 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } -cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_ptimer_cb, cpu); -cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_vtimer_cb, cpu); -cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_htimer_cb, cpu); -cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_stimer_cb, cpu); + +{ +uint64_t scale; + +if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { +if (!cpu->gt_cntfrq) { +error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", + cpu->gt_cntfrq); +return; +} +scale = MAX(1, NANOSECONDS_PER_SECOND / cpu->gt_cntfrq); +} else { +scale = GTIMER_SCALE; +} + +cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_ptimer_cb, cpu); +cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_vtimer_cb, cpu); +cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_htimer_cb, cpu); +cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_stimer_cb, cpu); +} #endif cpu_exec_realizefn(cs, _err); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 297ad5e47ad8..8bd576f834ba 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -915,6 +915,9 @@ struct ARMCPU { /* Used to set the maximum vector length the cpu will support. */ uint32_t sve_max_vq; + +/* Used to configure the generic timer input clock */ +uint64_t gt_cntfrq; }; void arm_cpu_post_init(Object *obj); diff --git
Re: [Qemu-devel] [PATCH v4] target-arm: Make the counter tick relative to cntfrq
On Thu, 12 Sep 2019, at 15:52, Cédric Le Goater wrote: > On 12/09/2019 05:25, Andrew Jeffery wrote: > > Allow machines to configure CNTFRQ via a property if the ARM core > > supports the generic timer. This is necessary on e.g. the ASPEED AST2600 > > SoC where the generic timer clock is run at 800MHz or above. The default > > value for CNTFRQ remains at 62.50MHz (based on GTIMER_SCALE). > > > > CNTFRQ is a read-as-written co-processor register; the property sets the > > register's initial value which is used during realize() to configure the > > QEMUTimers that back the generic timers. Beyond that the firmware can to > > do whatever it sees fit with the CNTFRQ register though changes to the > > value will not be reflected in the timers' rate. > > > > I've tested this using an out-of-tree AST2600 SoC model (Cortex-A7) with > > the SDK u-boot that sets CNTFRQ as appropriate, and by starting/running > > machines with assorted ARM CPUs (palmetto-bmc with the ARM926EJ-S, > > romulus-bmc with the ARM1176 and raspi2 with the Cortex-A53). > > > > Signed-off-by: Andrew Jeffery > > --- > > v4: Fix configuration for cores without a generic timer > > > > v3: https://patchwork.ozlabs.org/patch/1160634/ > > Peter - I think this addresses most of your feedback. I still reach into > > the QEMUTimer to fetch out scale when adjusting the nexttick > > calculation, but we no longer need to update the scale member and force > > a recalculation of the period. > > > > v2: https://patchwork.ozlabs.org/patch/1144389/ > > --- > > roms/SLOF | 2 +- > > roms/skiboot| 2 +- > > target/arm/cpu.c| 43 +++ > > target/arm/cpu.h| 3 +++ > > target/arm/helper.c | 30 ++ > > 5 files changed, 66 insertions(+), 14 deletions(-) > > > > diff --git a/roms/SLOF b/roms/SLOF > > index 7bfe584e3219..ea221600a116 16 > > --- a/roms/SLOF > > +++ b/roms/SLOF > > @@ -1 +1 @@ > > -Subproject commit 7bfe584e321946771692711ff83ad2b5850daca7 > > +Subproject commit ea221600a116883137ef90b2b7ab7d2472bc4f10 > > diff --git a/roms/skiboot b/roms/skiboot > > index 261ca8e779e5..3a6fdede6ce1 16 > > --- a/roms/skiboot > > +++ b/roms/skiboot > > @@ -1 +1 @@ > > -Subproject commit 261ca8e779e5138869a45f174caa49be6a274501 > > +Subproject commit 3a6fdede6ce117facec0108afe716cf5d0472c3f > > > The changes above seem not related. How did they get in there? :eyeroll: Thanks. v5 I guess. Andrew
[Qemu-devel] [PATCH v4] target-arm: Make the counter tick relative to cntfrq
Allow machines to configure CNTFRQ via a property if the ARM core supports the generic timer. This is necessary on e.g. the ASPEED AST2600 SoC where the generic timer clock is run at 800MHz or above. The default value for CNTFRQ remains at 62.50MHz (based on GTIMER_SCALE). CNTFRQ is a read-as-written co-processor register; the property sets the register's initial value which is used during realize() to configure the QEMUTimers that back the generic timers. Beyond that the firmware can to do whatever it sees fit with the CNTFRQ register though changes to the value will not be reflected in the timers' rate. I've tested this using an out-of-tree AST2600 SoC model (Cortex-A7) with the SDK u-boot that sets CNTFRQ as appropriate, and by starting/running machines with assorted ARM CPUs (palmetto-bmc with the ARM926EJ-S, romulus-bmc with the ARM1176 and raspi2 with the Cortex-A53). Signed-off-by: Andrew Jeffery --- v4: Fix configuration for cores without a generic timer v3: https://patchwork.ozlabs.org/patch/1160634/ Peter - I think this addresses most of your feedback. I still reach into the QEMUTimer to fetch out scale when adjusting the nexttick calculation, but we no longer need to update the scale member and force a recalculation of the period. v2: https://patchwork.ozlabs.org/patch/1144389/ --- roms/SLOF | 2 +- roms/skiboot| 2 +- target/arm/cpu.c| 43 +++ target/arm/cpu.h| 3 +++ target/arm/helper.c | 30 ++ 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/roms/SLOF b/roms/SLOF index 7bfe584e3219..ea221600a116 16 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit 7bfe584e321946771692711ff83ad2b5850daca7 +Subproject commit ea221600a116883137ef90b2b7ab7d2472bc4f10 diff --git a/roms/skiboot b/roms/skiboot index 261ca8e779e5..3a6fdede6ce1 16 --- a/roms/skiboot +++ b/roms/skiboot @@ -1 +1 @@ -Subproject commit 261ca8e779e5138869a45f174caa49be6a274501 +Subproject commit 3a6fdede6ce117facec0108afe716cf5d0472c3f diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 2399c144718d..8b63a27761bb 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -40,6 +40,8 @@ #include "disas/capstone.h" #include "fpu/softfloat.h" +#include + static void arm_cpu_set_pc(CPUState *cs, vaddr value) { ARMCPU *cpu = ARM_CPU(cs); @@ -976,6 +978,10 @@ static void arm_cpu_initfn(Object *obj) } } +static Property arm_cpu_gt_cntfrq_property = +DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq, + (1000 * 1000 * 1000) / GTIMER_SCALE); + static Property arm_cpu_reset_cbar_property = DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0); @@ -1172,6 +1178,11 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), _cpu_cfgend_property, _abort); + +if (arm_feature(>env, ARM_FEATURE_GENERIC_TIMER)) { +qdev_property_add_static(DEVICE(cpu), _cpu_gt_cntfrq_property, + _abort); +} } static void arm_cpu_finalizefn(Object *obj) @@ -1238,14 +1249,30 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } -cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_ptimer_cb, cpu); -cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_vtimer_cb, cpu); -cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_htimer_cb, cpu); -cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_stimer_cb, cpu); + +{ +uint64_t scale; + +if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { +if (!cpu->gt_cntfrq) { +error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", + cpu->gt_cntfrq); +return; +} +scale = MAX(1, NANOSECONDS_PER_SECOND / cpu->gt_cntfrq); +} else { +scale = GTIMER_SCALE; +} + +cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_ptimer_cb, cpu); +cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_vtimer_cb, cpu); +cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_htimer_cb, cpu); +cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_stimer_cb, cpu); +} #endif cpu_exec_realizefn(cs,
Re: [Qemu-devel] [PATCH v3] target-arm: Make the counter tick relative to cntfrq
On Wed, 11 Sep 2019, at 15:40, no-re...@patchew.org wrote: > Patchew URL: https://patchew.org/QEMU/20190911034302.29108-1-and...@aj.id.au/ > > > > Hi, > > This series failed the docker-quick@centos7 build test. Please find the > testing commands and > their output below. If you have Docker installed, you can probably > reproduce it > locally. Disregard v3, I got distracted by some updates to the way ASPEED's u-boot configures CNTFRQ and didn't test some relevant cases. Sorry for the noise. Andrew
[Qemu-devel] [PATCH v3] target-arm: Make the counter tick relative to cntfrq
Allow machines to configure CNTFRQ via a property if the ARM core supports the generic timer. This is necessary on e.g. the ASPEED AST2600 SoC where the generic timer clock is run at 800MHz or above. CNTFRQ is a read-as-written co-processor register; the property sets the register's initial value which is used during realize() to configure the QEMUTimers that back the generic timers. Beyond that the firmware can to do whatever it sees fit with the CNTFRQ register though changes to the value will not be reflected in the timers' rate. Signed-off-by: Andrew Jeffery --- Peter - I think this addresses most of your feedback. I still reach into the QEMUTimer to fetch out scale when adjusting the nexttick calculation, but we no longer need to update the scale member and force a recalculation of the period. --- target/arm/cpu.c| 36 target/arm/helper.c | 20 +--- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 2399c144718d..7ac422729608 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -40,6 +40,8 @@ #include "disas/capstone.h" #include "fpu/softfloat.h" +#include + static void arm_cpu_set_pc(CPUState *cs, vaddr value) { ARMCPU *cpu = ARM_CPU(cs); @@ -976,6 +978,10 @@ static void arm_cpu_initfn(Object *obj) } } +static Property arm_cpu_cp_cntfrq_property = +DEFINE_PROP_UINT64("cntfrq", ARMCPU, env.cp15.c14_cntfrq, + (1000 * 1000 * 1000) / GTIMER_SCALE); + static Property arm_cpu_reset_cbar_property = DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0); @@ -1172,6 +1178,11 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), _cpu_cfgend_property, _abort); + +if (arm_feature(>env, ARM_FEATURE_GENERIC_TIMER)) { +qdev_property_add_static(DEVICE(cpu), _cpu_cp_cntfrq_property, + _abort); +} } static void arm_cpu_finalizefn(Object *obj) @@ -1238,14 +1249,23 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } -cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_ptimer_cb, cpu); -cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_vtimer_cb, cpu); -cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_htimer_cb, cpu); -cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, - arm_gt_stimer_cb, cpu); +if (!env->cp15.c14_cntfrq) { +error_setg(errp, "Invalid CNTFRQ: %"PRIx64"Hz", env->cp15.c14_cntfrq); +return; +} + +{ +uint64_t scale = MAX(1, NANOSECONDS_PER_SECOND / env->cp15.c14_cntfrq); + +cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_ptimer_cb, cpu); +cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_vtimer_cb, cpu); +cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_htimer_cb, cpu); +cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, scale, + arm_gt_stimer_cb, cpu); +} #endif cpu_exec_realizefn(cs, _err); diff --git a/target/arm/helper.c b/target/arm/helper.c index 507026c9154b..8783f92c718c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2409,7 +2409,21 @@ static CPAccessResult gt_stimer_access(CPUARMState *env, static uint64_t gt_get_countervalue(CPUARMState *env) { -return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; +uint64_t effective; + +/* + * Deal with quantized clock scaling by calculating the effective frequency + * in terms of the timer scale. + */ +if (env->cp15.c14_cntfrq <= NANOSECONDS_PER_SECOND) { +uint32_t scale = NANOSECONDS_PER_SECOND / env->cp15.c14_cntfrq; +effective = NANOSECONDS_PER_SECOND / scale; +} else { +effective = NANOSECONDS_PER_SECOND; +} + +return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), effective, +NANOSECONDS_PER_SECOND); } static void gt_recalc_timer(ARMCPU *cpu, int timeridx) @@ -2445,8 +2459,8 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * set the timer for as far in the future as possible. When the * timer expires we will reset the timer for any remaining period. */ -if (nexttick > INT64_MAX / GTIMER_SCALE) { -
Re: [Qemu-devel] [PATCH v2] target-arm: Make the counter tick relative to cntfrq
On Thu, 29 Aug 2019, at 11:08, Andrew Jeffery wrote: > > > On Wed, 28 Aug 2019, at 01:39, Peter Maydell wrote: > > On Fri, 9 Aug 2019 at 06:43, Andrew Jeffery wrote: > > > > > > The use of GTIMER_SCALE assumes the clock feeding the generic timer is > > > 62.5MHz for all platforms. This is untrue in general, for example the > > > ASPEED AST2600 feeds the counter with either an 800 or 1200MHz clock, > > > and CNTFRQ is configured appropriately by u-boot. > > > > > > To cope with these values we need to take care of the quantization > > > caused by the clock scaling in terms of nanoseconds per clock by > > > calculating an effective frequency such that NANOSECONDS_PER_SECOND is > > > an integer multiple of the effective frequency. Failing to account for > > > the quantisation leads to sticky behaviour in the VM as the guest timer > > > subsystems account for the difference between delay time and the counter > > > value. > > > > > > Signed-off-by: Andrew Jeffery > > > --- > > > v2: > > > 1. Removed the user-mode change that broke v1 > > > 2. Rearranged the implementation as a consequence of 1. > > > > > > target/arm/helper.c | 51 ++--- > > > 1 file changed, 48 insertions(+), 3 deletions(-) > > > > > > diff --git a/target/arm/helper.c b/target/arm/helper.c > > > index b74c23a9bc08..166a54daf278 100644 > > > --- a/target/arm/helper.c > > > +++ b/target/arm/helper.c > > > @@ -2277,6 +2277,34 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { > > > > > > #ifndef CONFIG_USER_ONLY > > > > > > +static void gt_recalc_timer(ARMCPU *cpu, int timeridx); > > > +static void gt_cntfrq_write(CPUARMState *env, const ARMCPRegInfo *ri, > > > +uint64_t value) > > > +{ > > > +uint64_t scale; > > > +ARMCPU *cpu; > > > +int i; > > > + > > > +raw_write(env, ri, value); > > > + > > > +/* Fix up the timer scaling */ > > > +cpu = env_archcpu(env); > > > +scale = MAX(1, NANOSECONDS_PER_SECOND / value); > > > +for (i = 0; i < NUM_GTIMERS; i++) { > > > +if (!cpu->gt_timer[i]) { > > > +continue; > > > +} > > > + > > > +cpu->gt_timer[i]->scale = scale; > > > > Reaching into the internals of a QEMUTimer and changing > > the 'scale' value seems like a bad idea. If QEMUTimer doesn't > > have a facility for changing the frequency and we need one > > then we should add one at that API layer. > > Yeah, fair point. It is an RFC patch Ugh, I just looked at the subject and realised I hadn't added "RFC". Too many things going on :/ Andrew
Re: [Qemu-devel] [PATCH v2] target-arm: Make the counter tick relative to cntfrq
On Wed, 28 Aug 2019, at 01:39, Peter Maydell wrote: > On Fri, 9 Aug 2019 at 06:43, Andrew Jeffery wrote: > > > > The use of GTIMER_SCALE assumes the clock feeding the generic timer is > > 62.5MHz for all platforms. This is untrue in general, for example the > > ASPEED AST2600 feeds the counter with either an 800 or 1200MHz clock, > > and CNTFRQ is configured appropriately by u-boot. > > > > To cope with these values we need to take care of the quantization > > caused by the clock scaling in terms of nanoseconds per clock by > > calculating an effective frequency such that NANOSECONDS_PER_SECOND is > > an integer multiple of the effective frequency. Failing to account for > > the quantisation leads to sticky behaviour in the VM as the guest timer > > subsystems account for the difference between delay time and the counter > > value. > > > > Signed-off-by: Andrew Jeffery > > --- > > v2: > > 1. Removed the user-mode change that broke v1 > > 2. Rearranged the implementation as a consequence of 1. > > > > target/arm/helper.c | 51 ++--- > > 1 file changed, 48 insertions(+), 3 deletions(-) > > > > diff --git a/target/arm/helper.c b/target/arm/helper.c > > index b74c23a9bc08..166a54daf278 100644 > > --- a/target/arm/helper.c > > +++ b/target/arm/helper.c > > @@ -2277,6 +2277,34 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { > > > > #ifndef CONFIG_USER_ONLY > > > > +static void gt_recalc_timer(ARMCPU *cpu, int timeridx); > > +static void gt_cntfrq_write(CPUARMState *env, const ARMCPRegInfo *ri, > > +uint64_t value) > > +{ > > +uint64_t scale; > > +ARMCPU *cpu; > > +int i; > > + > > +raw_write(env, ri, value); > > + > > +/* Fix up the timer scaling */ > > +cpu = env_archcpu(env); > > +scale = MAX(1, NANOSECONDS_PER_SECOND / value); > > +for (i = 0; i < NUM_GTIMERS; i++) { > > +if (!cpu->gt_timer[i]) { > > +continue; > > +} > > + > > +cpu->gt_timer[i]->scale = scale; > > Reaching into the internals of a QEMUTimer and changing > the 'scale' value seems like a bad idea. If QEMUTimer doesn't > have a facility for changing the frequency and we need one > then we should add one at that API layer. Yeah, fair point. It is an RFC patch for these kinds of reasons - I solved the problem but wasn't at all convinced about the shape of the solution. > > Also, this isn't how the hardware works, I'm pretty sure. > In hardware the timers tick at whatever frequency they're > set up to tick, and CNTFRQ is just a reads-as-written register > that firmware can fill in with an appropriate value that it's > determined from somewhere for the benefit of other software. Yes, I think you're right. Again, as above this got rid of the problem, but needed some massaging. The write just was a handy hook point to inject the change of frequency. > > If on ASPEED SoCs the timer frequency is different, then we > should model that by having CPU properties for timer frequency > and having the SoC set those properties, I think. Sounds good, I'll work on that approach. Thanks for the feedback. Andrew
Re: [Qemu-devel] [PATCH v9 01/11] hw/arm: simplify arm_load_dtb
On Wed, 14 Aug 2019, at 07:30, Alistair Francis wrote: > On Fri, Aug 9, 2019 at 12:01 AM Tao wrote: > > > > From: Tao Xu > > > > In struct arm_boot_info, kernel_filename, initrd_filename and > > kernel_cmdline are copied from from MachineState. This patch add > > MachineState as a parameter into arm_load_dtb() and move the copy chunk > > of kernel_filename, initrd_filename and kernel_cmdline into > > arm_load_kernel(). > > > > Reviewed-by: Igor Mammedov > > Reviewed-by: Liu Jingqi > > Suggested-by: Igor Mammedov > > Signed-off-by: Tao Xu > > Reviewed-by: Alistair Francis > > Alistair > > > --- > > > > No changes in v9 > > --- > > hw/arm/aspeed.c | 5 + For the ASPEED machines: Acked-by: Andrew Jeffery
[Qemu-devel] [PATCH v2] target-arm: Make the counter tick relative to cntfrq
The use of GTIMER_SCALE assumes the clock feeding the generic timer is 62.5MHz for all platforms. This is untrue in general, for example the ASPEED AST2600 feeds the counter with either an 800 or 1200MHz clock, and CNTFRQ is configured appropriately by u-boot. To cope with these values we need to take care of the quantization caused by the clock scaling in terms of nanoseconds per clock by calculating an effective frequency such that NANOSECONDS_PER_SECOND is an integer multiple of the effective frequency. Failing to account for the quantisation leads to sticky behaviour in the VM as the guest timer subsystems account for the difference between delay time and the counter value. Signed-off-by: Andrew Jeffery --- v2: 1. Removed the user-mode change that broke v1 2. Rearranged the implementation as a consequence of 1. target/arm/helper.c | 51 ++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index b74c23a9bc08..166a54daf278 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2277,6 +2277,34 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { #ifndef CONFIG_USER_ONLY +static void gt_recalc_timer(ARMCPU *cpu, int timeridx); +static void gt_cntfrq_write(CPUARMState *env, const ARMCPRegInfo *ri, +uint64_t value) +{ +uint64_t scale; +ARMCPU *cpu; +int i; + +raw_write(env, ri, value); + +/* Fix up the timer scaling */ +cpu = env_archcpu(env); +scale = MAX(1, NANOSECONDS_PER_SECOND / value); +for (i = 0; i < NUM_GTIMERS; i++) { +if (!cpu->gt_timer[i]) { +continue; +} + +cpu->gt_timer[i]->scale = scale; +gt_recalc_timer(cpu, i); +} +} + +static void gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque) +{ +gt_cntfrq_write(env, opaque, opaque->resetvalue); +} + static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { @@ -2407,7 +2435,21 @@ static CPAccessResult gt_stimer_access(CPUARMState *env, static uint64_t gt_get_countervalue(CPUARMState *env) { -return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; +uint64_t effective; + +/* + * Deal with quantized clock scaling by calculating the effective frequency + * in terms of the timer scale. + */ +if (env->cp15.c14_cntfrq <= NANOSECONDS_PER_SECOND) { +uint32_t scale = NANOSECONDS_PER_SECOND / env->cp15.c14_cntfrq; +effective = NANOSECONDS_PER_SECOND / scale; +} else { +effective = NANOSECONDS_PER_SECOND; +} + +return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), effective, +NANOSECONDS_PER_SECOND); } static void gt_recalc_timer(ARMCPU *cpu, int timeridx) @@ -2443,8 +2485,8 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * set the timer for as far in the future as possible. When the * timer expires we will reset the timer for any remaining period. */ -if (nexttick > INT64_MAX / GTIMER_SCALE) { -nexttick = INT64_MAX / GTIMER_SCALE; +if (nexttick > INT64_MAX / cpu->gt_timer[timeridx]->scale) { +nexttick = INT64_MAX / cpu->gt_timer[timeridx]->scale; } timer_mod(cpu->gt_timer[timeridx], nexttick); trace_arm_gt_recalc(timeridx, irqstate, nexttick); @@ -2686,13 +2728,16 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0, .type = ARM_CP_ALIAS, .access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access, + .writefn = gt_cntfrq_write, .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_cntfrq), }, { .name = "CNTFRQ_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0, .access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access, + .writefn = gt_cntfrq_write, .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq), .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE, + .resetfn = gt_cntfrq_reset, }, /* overall control: mostly access permissions */ { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH, -- 2.20.1
Re: [Qemu-devel] [PATCH] target-arm: Make the counter tick relative to cntfrq
On Fri, 9 Aug 2019, at 13:36, no-re...@patchew.org wrote: > Patchew URL: https://patchew.org/QEMU/20190809031321.14760-1-and...@aj.id.au/ > > > > Hi, > > This series failed build test on s390x host. Please find the details below. > > === TEST SCRIPT BEGIN === > #!/bin/bash > # Testing script will be invoked under the git checkout with > # HEAD pointing to a commit that has the patches applied on top of "base" > # branch > set -e > > echo > echo "=== ENV ===" > env > > echo > echo "=== PACKAGES ===" > rpm -qa > > echo > echo "=== UNAME ===" > uname -a > > CC=$HOME/bin/cc > INSTALL=$PWD/install > BUILD=$PWD/build > mkdir -p $BUILD $INSTALL > SRC=$PWD > cd $BUILD > $SRC/configure --cc=$CC --prefix=$INSTALL > make -j4 > # XXX: we need reliable clean up > # make check -j4 V=1 > make install > === TEST SCRIPT END === > > CC aarch64_be-linux-user/target/arm/arm-semi.o > CC aarch64_be-linux-user/target/arm/helper.o > /var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c: In > function ‘gt_virt_cnt_read’: > /var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c:2921:12: > error: implicit declaration of function ‘gt_calc_tick’ > [-Werror=implicit-function-declaration] > 2921 | return gt_calc_tick(env, cpu_get_clock()); > |^~~~ > /var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c:2921:12: > error: nested extern declaration of ‘gt_calc_tick’ > [-Werror=nested-externs] > cc1: all warnings being treated as errors > make[1]: *** [/var/tmp/patchew-tester-tmp-hkd7ua1n/src/rules.mak:69: > target/arm/helper.o] Error 1 > make: *** [Makefile:472: aarch64_be-linux-user/all] Error 2 > Ah, I missed that I put the implementation inside the #ifndef CONFIG_USER_ONLY` block. Maybe we can just not do the scaling for userspace anyway? Andrew
[Qemu-devel] [PATCH] target-arm: Make the counter tick relative to cntfrq
The use of GTIMER_SCALE assumes the clock feeding the generic timer is 62.5MHz for all platforms. This is untrue in general, for example the ASPEED AST2600 feeds the counter with either an 800 or 1200MHz clock, and CNTFRQ is configured appropriately by u-boot. To cope with these values we need to take care of the quantization caused by the clock scaling in terms of nanoseconds per clock by calculating an effective frequency such that NANOSECONDS_PER_SECOND is an integer multiple of the effective frequency. Failing to account for the quantisation leads to sticky behaviour in the VM as the guest timer subsystems account for the difference between delay time and the counter value. Signed-off-by: Andrew Jeffery --- The timer rate assumptions seemed unusual, so I'm not sure if this patch is way off-base or not. However it does make the AST2600 u-boot and kernel behave correctly. target/arm/helper.c | 51 + 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index b74c23a9bc08..35d14c183630 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2277,6 +2277,34 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { #ifndef CONFIG_USER_ONLY +static void gt_recalc_timer(ARMCPU *cpu, int timeridx); +static void gt_cntfrq_write(CPUARMState *env, const ARMCPRegInfo *ri, +uint64_t value) +{ +uint64_t scale; +ARMCPU *cpu; +int i; + +raw_write(env, ri, value); + +/* Fix up the timer scaling */ +cpu = env_archcpu(env); +scale = MAX(1, NANOSECONDS_PER_SECOND / value); +for (i = 0; i < NUM_GTIMERS; i++) { +if (!cpu->gt_timer[i]) { +continue; +} + +cpu->gt_timer[i]->scale = scale; +gt_recalc_timer(cpu, i); +} +} + +static void gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque) +{ +gt_cntfrq_write(env, opaque, opaque->resetvalue); +} + static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { @@ -2405,9 +2433,21 @@ static CPAccessResult gt_stimer_access(CPUARMState *env, } } +static uint64_t gt_calc_tick(CPUARMState *env, uint64_t ns) +{ +/* + * Deal with quantized clock scaling by calculating the effective frequency + * in terms of the timer scale. + */ +uint32_t scale = MAX(1, NANOSECONDS_PER_SECOND / env->cp15.c14_cntfrq); +uint64_t effective = NANOSECONDS_PER_SECOND / scale; + +return muldiv64(ns, effective, NANOSECONDS_PER_SECOND); +} + static uint64_t gt_get_countervalue(CPUARMState *env) { -return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; +return gt_calc_tick(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } static void gt_recalc_timer(ARMCPU *cpu, int timeridx) @@ -2443,8 +2483,8 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) * set the timer for as far in the future as possible. When the * timer expires we will reset the timer for any remaining period. */ -if (nexttick > INT64_MAX / GTIMER_SCALE) { -nexttick = INT64_MAX / GTIMER_SCALE; +if (nexttick > INT64_MAX / cpu->gt_timer[timeridx]->scale) { +nexttick = INT64_MAX / cpu->gt_timer[timeridx]->scale; } timer_mod(cpu->gt_timer[timeridx], nexttick); trace_arm_gt_recalc(timeridx, irqstate, nexttick); @@ -2686,13 +2726,16 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0, .type = ARM_CP_ALIAS, .access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access, + .writefn = gt_cntfrq_write, .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_cntfrq), }, { .name = "CNTFRQ_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0, .access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access, + .writefn = gt_cntfrq_write, .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq), .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE, + .resetfn = gt_cntfrq_reset, }, /* overall control: mostly access permissions */ { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH, @@ -2875,7 +2918,7 @@ static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) * can't call gt_get_countervalue(env), instead we directly * call the lower level functions. */ -return cpu_get_clock() / GTIMER_SCALE; +return gt_calc_tick(env, cpu_get_clock()); } static const ARMCPRegInfo generic_timer_cp_reginfo[] = { -- 2.20.1
Re: [Qemu-devel] [PATCH 1/2] hw/gpio: Add basic Aspeed GPIO model
On Mon, 15 Jul 2019, at 12:06, Rashmica Gupta wrote: > Sorry for the late reply! I agree with most of your feedback and will > send out > a v2 shortly with those changes. I have a few replies below > > [snip] > > > > +static const struct AspeedGPIO gpios[0x1f0] = { > > > +/* Set ABCD */ > > > +[GPIO_ABCD_DATA_VALUE] = {0, read_data_value, > > > _write_data_value}, > > > > Maybe there would be less tedium (and risk of minor bugs) here if we > > add > > a table for looking up the read/write callbacks from a type, and just > > stash > > the type in struct AspeedGPIO (or a pointer to the corresponding type > > ops), > > e.g: > > > > enum gpio_property { gpio_direction = 0, gpio_int_enable, ... }; > > > > struct aspeed_gpio_reg_ops { > > int (*read)(...); > > int (*write)(...); > > }; > > > > struct aspeed_gpio_reg_ops gpio_reg_ops[] = { > > [gpio_direction] = { .read = read_direction, .write = > > write_direction }; > > ... > > }; > > > > Then we have: > > > > static const struct AspeedGPIO gpios[...] = { > > [GPIO_ABCD_DIRECTION] = { .set = 0, .type = gpio_direction }, > > ... > > }; > > > > Not wedded to the idea, just thinking out loud. What do you think? > > > > I'm not a huge fan of the extra indirection. It is less error prone but > is this a place that is likely to be updated regularly? Right - if you've written correctly already then there's not much benefit. > > > > > +[GPIO_ABCD_DIRECTION] = {0, read_direction, _write_direction}, > > > +[GPIO_ABCD_INT_ENABLE] = {0, read_int_enable, > > > _write_int_enable}, > > > +[GPIO_ABCD_INT_SENS_0] = {0, read_int_sens_0, > > > _write_int_sens_0}, > > > +[GPIO_ABCD_INT_SENS_1] = {0, read_int_sens_1, > > > _write_int_sens_1}, > > > +[GPIO_ABCD_INT_SENS_2] = {0, read_int_sens_2, > > > _write_int_sens_2}, > > > +[GPIO_ABCD_INT_STATUS] = {0, read_int_status, > > > _write_int_status}, > > > +[GPIO_ABCD_RESET_TOLERANT] = {0, read_reset_tol, > > > _write_reset_tol}, > > > +[GPIO_ABCD_DEBOUNCE_1] = {0, read_debounce_1, > > > _write_debounce_1}, > > > +[GPIO_ABCD_DEBOUNCE_2] = {0, read_debounce_2, > > > _write_debounce_2}, > > > +[GPIO_ABCD_COMMAND_SRC_0] = {0, read_cmd_source_0, > > > _write_cmd_source_0}, > > > +[GPIO_ABCD_COMMAND_SRC_1] = {0, read_cmd_source_1, > > > _write_cmd_source_1}, > > > +[GPIO_ABCD_DATA_READ] = {0, read_data, NULL}, > > > +[GPIO_ABCD_INPUT_MASK] = {0, read_input_mask, > > > _write_input_mask}, > > > +/* Set EFGH */ > > > +[GPIO_EFGH_DATA_VALUE] = {1, read_data_value, > > > _write_data_value}, > > > +[GPIO_EFGH_DIRECTION] = {1, read_direction, _write_direction > > > }, > > > +[GPIO_EFGH_INT_ENABLE] = {1, read_int_enable, > > > _write_int_enable}, > > > +[GPIO_EFGH_INT_SENS_0] = {1, read_int_sens_0, > > > _write_int_sens_0}, > > > +[GPIO_EFGH_INT_SENS_1] = {1, read_int_sens_1, > > > _write_int_sens_1}, > > > +[GPIO_EFGH_INT_SENS_2] = {1, read_int_sens_2, > > > _write_int_sens_2}, > > > +[GPIO_EFGH_INT_STATUS] = {1, read_int_status, > > > _write_int_status}, > > > +[GPIO_EFGH_RESET_TOL] = {1, > > > read_reset_tol, _write_reset_tol}, > > > +[GPIO_EFGH_DEBOUNCE_1] = {1, > > > read_debounce_1, _write_debounce_1}, > > > +[GPIO_EFGH_DEBOUNCE_2] = {1, > > > read_debounce_2, _write_debounce_2}, > > > +[GPIO_EFGH_COMMAND_SRC_0] = {1, read_cmd_source_0, > > > _write_cmd_source_0}, > > > +[GPIO_EFGH_COMMAND_SRC_1] = {1, read_cmd_source_1, > > > _write_cmd_source_1}, > > > +[GPIO_EFGH_DATA_READ] = {1, read_data, NULL}, > > > +[GPIO_EFGH_INPUT_MASK] = {1, > > > read_input_mask, _write_input_mask}, > > > +/* Set IJKL */ > > > +[GPIO_IJKL_DATA_VALUE] = {2, read_data_value, > > > _write_data_value}, > > > +[GPIO_IJKL_DIRECTION] = {2, read_direction, _write_direction}, > > > +[GPIO_IJKL_INT_ENABLE] = {2, read_int_enable, > > > _write_int_enable}, > > > +[GPIO_IJKL_INT_SENS_0] = {2, read_int_sens_0, > > > _write_int_sens_0}, > > > +[GPIO_IJKL_INT_SENS_1] = {2, read_int_sens_1, > > > _write_int_sens_1}, > > > +[GPIO_IJKL_INT_SENS_2] = {2, read_int_sens_2, > > > _write_int_sens_2}, > > > +[GPIO_IJKL_INT_STATUS] = {2, read_int_status, > > > _write_int_status}, > > > +[GPIO_IJKL_RESET_TOLERANT] = {2, read_reset_tol, > > > _write_reset_tol}, > > > +[GPIO_IJKL_DEBOUNCE_1] = {2, read_debounce_1, > > > _write_debounce_1}, > > > +[GPIO_IJKL_DEBOUNCE_2] = {2, read_debounce_2, > > > _write_debounce_2}, > > > +[GPIO_IJKL_COMMAND_SRC_0] = {2, read_cmd_source_0, > > > _write_cmd_source_0}, > > > +[GPIO_IJKL_COMMAND_SRC_1] = {2, read_cmd_source_1, > > > _write_cmd_source_1}, > > > +[GPIO_IJKL_DATA_READ] = {2, read_data, NULL}, > > > +[GPIO_IJKL_INPUT_MASK] = {2, read_input_mask, > > > _write_input_mask}, > > > +/* Set MNOP */ > > > +[GPIO_MNOP_DATA_VALUE] = {3, read_data_value, > > > _write_data_value}, > > > +[GPIO_MNOP_DIRECTION]
Re: [Qemu-devel] [PATCH 1/2] hw/gpio: Add basic Aspeed GPIO model
On Tue, 18 Jun 2019, at 18:52, Rashmica Gupta wrote: > Add in details for GPIO controller for AST 2400 and 2500 > > Signed-off-by: Rashmica Gupta > --- > hw/gpio/Makefile.objs | 1 + > hw/gpio/aspeed_gpio.c | 869 ++ > include/hw/gpio/aspeed_gpio.h | 76 +++ > 3 files changed, 946 insertions(+) > create mode 100644 hw/gpio/aspeed_gpio.c > create mode 100644 include/hw/gpio/aspeed_gpio.h > > diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs > index e5da0cb54f..d305b3b24b 100644 > --- a/hw/gpio/Makefile.objs > +++ b/hw/gpio/Makefile.objs > @@ -9,3 +9,4 @@ obj-$(CONFIG_OMAP) += omap_gpio.o > obj-$(CONFIG_IMX) += imx_gpio.o > obj-$(CONFIG_RASPI) += bcm2835_gpio.o > obj-$(CONFIG_NRF51_SOC) += nrf51_gpio.o > +obj-$(CONFIG_ASPEED_SOC) += aspeed_gpio.o > diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c > new file mode 100644 > index 00..d84dd69255 > --- /dev/null > +++ b/hw/gpio/aspeed_gpio.c > @@ -0,0 +1,869 @@ > +/* > + * ASPEED GPIO Controller > + * > + * Copyright (C) 2017-2019 IBM Corp. > + * > + * This code is licensed under the GPL version 2 or later. See > + * the COPYING file in the top-level directory. > + * I'd use a SPDX license marker here instead. > + * > + * This models the ast2400 and ast2500 GPIO controllers. > + * > + * GPIO pins are arranged in groups of 8 pins labeled > A,B,..,Y,Z,AA,AB,AC. > + * (Note that the ast2400 controller only goes up to group AB). > + * A set has four groups (except set AC which only has one) and is > + * referred to by the groups it is composed of (eg > ABCD,EFGH,...,YZAAAB). > + * Each set is accessed and controlled by a bank of 14 registers. > + * > + * These registers operate on a per pin level where each bit in the > register > + * corresponds to a pin, except for the command source registers. The > command > + * source registers operate on a per group level where bits 24, 16, 8 > and 0 > + * correspond to each group in the set. > + * > + * eg. registers for set ABCD: > + * |D7...D0|C7...C0|B7...B0|A7...A0| <- GPIOs > + * |31...24|23...16|158|7.0| <- bit position > + * > + * Note that there are a couple of groups that only have 4 pins. > + > + * There are three ways that this model deviates from the behaviour of > the > + * actual controller: > + * (1) There are three debounce registers which aren't modeled and so > the per > + * set debounce setting registers don't affect anything. > + * > + * (2) The only control source driving the GPIO pins in the model is > the ARM > + * model (as there currently aren't models for the LPC or Coprocessor > [TODO]). > + * > + * (3) None of the registers in the model are reset tolerant. [TODO] > + * > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "hw/gpio/aspeed_gpio.h" > +#include "include/hw/misc/aspeed_scu.h" > +#include "qapi/error.h" > +#include "qapi/visitor.h" > + > +#define ASPEED_GPIOS_PER_REG 32 > + > +/* GPIO Source Types */ > +#define ASPEED_CMD_SRC_MASK 0x01010101 > +#define ASPEED_SOURCE_ARM 0 > +#define ASPEED_SOURCE_LPC 1 > +#define ASPEED_SOURCE_COPROCESSOR 2 > +#define ASPEED_SOURCE_RESERVED 3 > + > +/* GPIO Interrupt Triggers */ > +#define ASPEED_FALLING_EDGE 0 > +#define ASPEED_RISING_EDGE 1 > +#define ASPEED_LEVEL_LOW2 > +#define ASPEED_LEVEL_HIGH 3 > +#define ASPEED_DUAL_EDGE4 > + > +/* GPIO Register Address Offsets */ > +#define GPIO_ABCD_DATA_VALUE 0x000 > +#define GPIO_ABCD_DIRECTION 0x004 > +#define GPIO_ABCD_INT_ENABLE 0x008 > +#define GPIO_ABCD_INT_SENS_0 0x00C > +#define GPIO_ABCD_INT_SENS_1 0x010 > +#define GPIO_ABCD_INT_SENS_2 0x014 > +#define GPIO_ABCD_INT_STATUS 0x018 > +#define GPIO_ABCD_RESET_TOLERANT 0x01C > +#define GPIO_EFGH_DATA_VALUE 0x020 > +#define GPIO_EFGH_DIRECTION 0x024 > +#define GPIO_EFGH_INT_ENABLE 0x028 > +#define GPIO_EFGH_INT_SENS_0 0x02C > +#define GPIO_EFGH_INT_SENS_1 0x030 > +#define GPIO_EFGH_INT_SENS_2 0x034 > +#define GPIO_EFGH_INT_STATUS 0x038 > +#define GPIO_EFGH_RESET_TOL 0x03C > +#define GPIO_ABCD_DEBOUNCE_1 0x040 > +#define GPIO_ABCD_DEBOUNCE_2 0x044 > +#define GPIO_EFGH_DEBOUNCE_1 0x048 > +#define GPIO_EFGH_DEBOUNCE_2 0x04C > +#define GPIO_DEBOUNCE_TIME_1 0x050 > +#define GPIO_DEBOUNCE_TIME_2 0x054 > +#define GPIO_DEBOUNCE_TIME_3 0x058 > +#define GPIO_ABCD_COMMAND_SRC_0 0x060 > +#define GPIO_ABCD_COMMAND_SRC_1 0x064 > +#define GPIO_EFGH_COMMAND_SRC_0 0x068 > +#define GPIO_EFGH_COMMAND_SRC_1 0x06C > +#define GPIO_IJKL_DATA_VALUE 0x070 > +#define GPIO_IJKL_DIRECTION 0x074 > +#define GPIO_MNOP_DATA_VALUE 0x078 > +#define GPIO_MNOP_DIRECTION 0x07C > +#define GPIO_QRST_DATA_VALUE 0x080 > +#define GPIO_QRST_DIRECTION 0x084 > +#define GPIO_UVWX_DATA_VALUE 0x088 > +#define GPIO_UWVX_DIRECTION 0x08C > +#define GPIO_IJKL_COMMAND_SRC_0 0x090 > +#define
Re: [Qemu-devel] [PATCH v2 11/21] aspeed/timer: Ensure positive muldiv delta
On Wed, 19 Jun 2019, at 02:24, Cédric Le Goater wrote: > From: Christian Svensson > > If the host decrements the counter register that results in a negative > delta. This is then passed to muldiv64 which only handles unsigned > numbers resulting in bogus results. > > This fix ensures the delta being operated on is positive. > > Test case: kexec a kernel using aspeed_timer and it will freeze on the > second bootup when the kernel initializes the timer. With this patch > that no longer happens and the timer appears to run OK. > > Signed-off-by: Christian Svensson > Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery > --- > hw/timer/aspeed_timer.c | 6 +- > 1 file changed, 5 insertions(+), 1 deletion(-) > > diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c > index 6501fa0768e7..1f0f1886fb2a 100644 > --- a/hw/timer/aspeed_timer.c > +++ b/hw/timer/aspeed_timer.c > @@ -275,7 +275,11 @@ static void > aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, > int64_t delta = (int64_t) value - (int64_t) > calculate_ticks(t, now); > uint32_t rate = calculate_rate(t); > > -t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate); > +if (delta >= 0) { > +t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate); > +} else { > +t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate); > +} > aspeed_timer_mod(t); > } > break; > -- > 2.21.0 > >
Re: [Qemu-devel] [PATCH qemu] aspeed: Add support for the swift-bmc board
On Tue, 4 Jun 2019, at 09:07, Joel Stanley wrote: > On Mon, 3 Jun 2019 at 19:11, Adriana Kobylak wrote: > > > > From: Adriana Kobylak > > > > The Swift board is an OpenPOWER system hosting POWER processors. > > Add support for their BMC including the I2C devices as found on HW. > > > > Signed-off-by: Adriana Kobylak > > Reviewed-by: Cédric Le Goater > > --- > > hw/arm/aspeed.c | 42 ++ > > 1 file changed, 42 insertions(+) > > > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > > index 33070a6..cd95b3c 100644 > > --- a/hw/arm/aspeed.c > > +++ b/hw/arm/aspeed.c > > @@ -73,6 +73,9 @@ struct AspeedBoardState { > > SCU_AST2500_HW_STRAP_ACPI_ENABLE | \ > > SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER)) > > > > +/* TODO: Swift hardware value: ? (use romulus definition for now) */ > > +#define SWIFT_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 > > I got this from hardware: 0xF11AD206 There are two differences from the value noted in the comment below: 1. Bit 4 is clear in your value 2. Bit 20 is set in your value Bit 4 is reserved, so not sure if we should care about the difference. Bit 20 is the SuperIO decode disable bit. I don't think we care much about it at the moment, but we may as we model more of the LPC interface in the future. Andrew > > The rest looks okay. > > Reviewed-by: Joel Stanley > > > + > > /* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */ > > #define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 > > > > @@ -287,6 +290,35 @@ static void romulus_bmc_i2c_init(AspeedBoardState *bmc) > > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 11), "ds1338", > > 0x32); > > } > > > > +static void swift_bmc_i2c_init(AspeedBoardState *bmc) > > +{ > > +AspeedSoCState *soc = >soc; > > + > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 3), "pca9552", > > 0x60); > > + > > +/* The swift board expects a TMP275 but a TMP105 is compatible */ > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 7), "tmp105", > > 0x48); > > +/* The swift board expects a pca9551 but a pca9552 is compatible */ > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 7), "pca9552", > > 0x60); > > + > > +/* The swift board expects an Epson RX8900 RTC but a ds1338 is > > compatible */ > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 8), "ds1338", > > 0x32); > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 8), "pca9552", > > 0x60); > > + > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 9), "tmp423", > > 0x4c); > > +/* The swift board expects a pca9539 but a pca9552 is compatible */ > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 9), "pca9552", > > 0x74); > > + > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 10), "tmp423", > > 0x4c); > > +/* The swift board expects a pca9539 but a pca9552 is compatible */ > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 10), "pca9552", > > + 0x74); > > + > > +/* The swift board expects a TMP275 but a TMP105 is compatible */ > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 12), "tmp105", > > 0x48); > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 12), "tmp105", > > 0x4a); > > +} > > + > > static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) > > { > > AspeedSoCState *soc = >soc; > > @@ -378,6 +410,16 @@ static const AspeedBoardConfig aspeed_boards[] = { > > .i2c_init = romulus_bmc_i2c_init, > > .ram = 512 * MiB, > > }, { > > +.name = MACHINE_TYPE_NAME("swift-bmc"), > > +.desc = "OpenPOWER Swift BMC (ARM1176)", > > +.soc_name = "ast2500-a1", > > +.hw_strap1 = SWIFT_BMC_HW_STRAP1, > > +.fmc_model = "mx66l1g45g", > > +.spi_model = "mx66l1g45g", > > +.num_cs= 2, > > +.i2c_init = swift_bmc_i2c_init, > > +.ram = 512 * MiB, > > +}, { > > .name = MACHINE_TYPE_NAME("witherspoon-bmc"), > > .desc = "OpenPOWER Witherspoon BMC (ARM1176)", > > .soc_name = "ast2500-a1", > > -- > > 1.8.3.1 > > >
Re: [Qemu-devel] [PATCH] arm: aspeed: Set SDRAM size
On Wed, 1 May 2019, at 15:48, Joel Stanley wrote: > We currently use Qemu's default of 128MB. As we know how much ram each > machine ships with, make it easier on users by setting a default. > > It can still be overridden with -m on the command line. > > Signed-off-by: Joel Stanley Reviewed-by: Andrew Jeffery > --- > hw/arm/aspeed.c | 6 ++ > include/hw/arm/aspeed.h | 1 + > 2 files changed, 7 insertions(+) > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > index 1c23ebd99252..3f3d4162b3c5 100644 > --- a/hw/arm/aspeed.c > +++ b/hw/arm/aspeed.c > @@ -331,6 +331,8 @@ static void aspeed_machine_class_init(ObjectClass > *oc, void *data) > mc->no_floppy = 1; > mc->no_cdrom = 1; > mc->no_parallel = 1; > +if (board->ram) > +mc->default_ram_size = board->ram; > amc->board = board; > } > > @@ -352,6 +354,7 @@ static const AspeedBoardConfig aspeed_boards[] = { > .spi_model = "mx25l25635e", > .num_cs= 1, > .i2c_init = palmetto_bmc_i2c_init, > +.ram = 256 << 20, > }, { > .name = MACHINE_TYPE_NAME("ast2500-evb"), > .desc = "Aspeed AST2500 EVB (ARM1176)", > @@ -361,6 +364,7 @@ static const AspeedBoardConfig aspeed_boards[] = { > .spi_model = "mx25l25635e", > .num_cs= 1, > .i2c_init = ast2500_evb_i2c_init, > +.ram = 512 << 20, > }, { > .name = MACHINE_TYPE_NAME("romulus-bmc"), > .desc = "OpenPOWER Romulus BMC (ARM1176)", > @@ -370,6 +374,7 @@ static const AspeedBoardConfig aspeed_boards[] = { > .spi_model = "mx66l1g45g", > .num_cs= 2, > .i2c_init = romulus_bmc_i2c_init, > +.ram = 512 << 20, > }, { > .name = MACHINE_TYPE_NAME("witherspoon-bmc"), > .desc = "OpenPOWER Witherspoon BMC (ARM1176)", > @@ -379,6 +384,7 @@ static const AspeedBoardConfig aspeed_boards[] = { > .spi_model = "mx66l1g45g", > .num_cs= 2, > .i2c_init = witherspoon_bmc_i2c_init, > +.ram = 512 << 20, > }, > }; > > diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h > index 325c091d09e4..02073a6b4d61 100644 > --- a/include/hw/arm/aspeed.h > +++ b/include/hw/arm/aspeed.h > @@ -22,6 +22,7 @@ typedef struct AspeedBoardConfig { > const char *spi_model; > uint32_t num_cs; > void (*i2c_init)(AspeedBoardState *bmc); > +uint32_t ram; > } AspeedBoardConfig; > > #define TYPE_ASPEED_MACHINE MACHINE_TYPE_NAME("aspeed") > -- > 2.20.1 > >
Re: [Qemu-devel] [PATCH 2/3] aspeed: add a per SoC mapping for the memory space
On Fri, 12 Apr 2019, at 11:48, Joel Stanley wrote: > On Thu, 11 Apr 2019 at 16:10, Cédric Le Goater wrote: > > > > This will simplify the definition of new SoCs, like the AST2600 which > > should use a slightly different address space and have a different set > > of controllers. > > > > Signed-off-by: Cédric Le Goater > > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > > index 5bbd1fb87d18..9b601709e93c 100644 > > --- a/hw/arm/aspeed_soc.c > > +++ b/hw/arm/aspeed_soc.c > > > +static const hwaddr aspeed_soc_ast2400_memmap[] = { > > > +static const hwaddr aspeed_soc_ast2500_memmap[] = { > > Most of these arrays is common. And some of it will stay common in the > 2600. Any ideas how we could avoid duplication? I dunno, I feel that any attempt to create some "common" layout concept is more distracting than having soc-specific, complete layouts described. There's no reason why they're common beyond coincidence (i.e. it's at ASPEED's whim). I think this is fine. Reviewed-by: Andrew Jeffery > > This is fine for now. > > Reviewed-by: Joel Stanley >
Re: [Qemu-devel] [PATCH 3/3] aspeed: use sysbus_init_child_obj() to initialize children
On Fri, 12 Apr 2019, at 01:40, Cédric Le Goater wrote: > Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery > --- > hw/arm/aspeed_soc.c | 50 ++--- > 1 file changed, 20 insertions(+), 30 deletions(-) > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index 9b601709e93c..110956828c44 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -212,12 +212,11 @@ static void aspeed_soc_init(Object *obj) > AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); > int i; > > -object_initialize(>cpu, sizeof(s->cpu), sc->info->cpu_type); > -object_property_add_child(obj, "cpu", OBJECT(>cpu), NULL); > +object_initialize_child(obj, "cpu", OBJECT(>cpu), sizeof(s->cpu), > +sc->info->cpu_type, _abort, NULL); > > -object_initialize(>scu, sizeof(s->scu), TYPE_ASPEED_SCU); > -object_property_add_child(obj, "scu", OBJECT(>scu), NULL); > -qdev_set_parent_bus(DEVICE(>scu), sysbus_get_default()); > +sysbus_init_child_obj(obj, "scu", OBJECT(>scu), sizeof(s->scu), > + TYPE_ASPEED_SCU); > qdev_prop_set_uint32(DEVICE(>scu), "silicon-rev", > sc->info->silicon_rev); > object_property_add_alias(obj, "hw-strap1", OBJECT(>scu), > @@ -227,36 +226,29 @@ static void aspeed_soc_init(Object *obj) > object_property_add_alias(obj, "hw-prot-key", OBJECT(>scu), >"hw-prot-key", _abort); > > -object_initialize(>vic, sizeof(s->vic), TYPE_ASPEED_VIC); > -object_property_add_child(obj, "vic", OBJECT(>vic), NULL); > -qdev_set_parent_bus(DEVICE(>vic), sysbus_get_default()); > +sysbus_init_child_obj(obj, "vic", OBJECT(>vic), sizeof(s->vic), > + TYPE_ASPEED_VIC); > > -object_initialize(>timerctrl, sizeof(s->timerctrl), > TYPE_ASPEED_TIMER); > -object_property_add_child(obj, "timerctrl", OBJECT(>timerctrl), NULL); > +sysbus_init_child_obj(obj, "timerctrl", OBJECT(>timerctrl), > + sizeof(s->timerctrl), TYPE_ASPEED_TIMER); > object_property_add_const_link(OBJECT(>timerctrl), "scu", > OBJECT(>scu), _abort); > -qdev_set_parent_bus(DEVICE(>timerctrl), sysbus_get_default()); > > -object_initialize(>i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); > -object_property_add_child(obj, "i2c", OBJECT(>i2c), NULL); > -qdev_set_parent_bus(DEVICE(>i2c), sysbus_get_default()); > +sysbus_init_child_obj(obj, "i2c", OBJECT(>i2c), sizeof(s->i2c), > + TYPE_ASPEED_I2C); > > -object_initialize(>fmc, sizeof(s->fmc), sc->info->fmc_typename); > -object_property_add_child(obj, "fmc", OBJECT(>fmc), NULL); > -qdev_set_parent_bus(DEVICE(>fmc), sysbus_get_default()); > +sysbus_init_child_obj(obj, "fmc", OBJECT(>fmc), sizeof(s->fmc), > + sc->info->fmc_typename); > object_property_add_alias(obj, "num-cs", OBJECT(>fmc), "num-cs", >_abort); > > for (i = 0; i < sc->info->spis_num; i++) { > -object_initialize(>spi[i], sizeof(s->spi[i]), > - sc->info->spi_typename[i]); > -object_property_add_child(obj, "spi[*]", OBJECT(>spi[i]), NULL); > -qdev_set_parent_bus(DEVICE(>spi[i]), sysbus_get_default()); > +sysbus_init_child_obj(obj, "spi[*]", OBJECT(>spi[i]), > + sizeof(s->spi[i]), sc->info->spi_typename[i]); > } > > -object_initialize(>sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC); > -object_property_add_child(obj, "sdmc", OBJECT(>sdmc), NULL); > -qdev_set_parent_bus(DEVICE(>sdmc), sysbus_get_default()); > +sysbus_init_child_obj(obj, "sdmc", OBJECT(>sdmc), sizeof(s->sdmc), > + TYPE_ASPEED_SDMC); > qdev_prop_set_uint32(DEVICE(>sdmc), "silicon-rev", > sc->info->silicon_rev); > object_property_add_alias(obj, "ram-size", OBJECT(>sdmc), > @@ -265,16 +257,14 @@ static void aspeed_soc_init(Object *obj) >"max-ram-size", _abort); > > for (i = 0; i < sc->info->wdts_num; i++) { > -object_initialize(&g
Re: [Qemu-devel] [PATCH 1/3] aspeed: add a per SoC mapping for the interrupt space
On Fri, 12 Apr 2019, at 02:13, Philippe Mathieu-Daudé wrote: > Hi Cédric, > > On 4/11/19 6:10 PM, Cédric Le Goater wrote: > > This will simplify the definition of new SoCs, like the AST2600 which > > should use a different CPU and a different IRQ number layout. > > > > Signed-off-by: Cédric Le Goater > > --- > > include/hw/arm/aspeed_soc.h | 1 + > > hw/arm/aspeed_soc.c | 93 + > > 2 files changed, 86 insertions(+), 8 deletions(-) > > > > diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h > > index 11ec0179db50..b0d266434288 100644 > > --- a/include/hw/arm/aspeed_soc.h > > +++ b/include/hw/arm/aspeed_soc.h > > @@ -57,6 +57,7 @@ typedef struct AspeedSoCInfo { > > const char *fmc_typename; > > const char **spi_typename; > > int wdts_num; > > +const int *irqmap; > > } AspeedSoCInfo; > > > > typedef struct AspeedSoCClass { > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > > index a27233d4876b..5bbd1fb87d18 100644 > > --- a/hw/arm/aspeed_soc.c > > +++ b/hw/arm/aspeed_soc.c > > @@ -22,6 +22,42 @@ > > #include "hw/i2c/aspeed_i2c.h" > > #include "net/net.h" > > > > +enum { > > +ASPEED_IOMEM, > > +ASPEED_UART1, > > +ASPEED_UART2, > > +ASPEED_UART3, > > +ASPEED_UART4, > > +ASPEED_UART5, > > +ASPEED_VUART, > > +ASPEED_FMC, > > +ASPEED_SPI1, > > +ASPEED_SPI2, > > +ASPEED_VIC, > > +ASPEED_SDMC, > > +ASPEED_SCU, > > +ASPEED_ADC, > > +ASPEED_SRAM, > > +ASPEED_GPIO, > > +ASPEED_RTC, > > +ASPEED_TIMER1, > > +ASPEED_TIMER2, > > +ASPEED_TIMER3, > > +ASPEED_TIMER4, > > +ASPEED_TIMER5, > > +ASPEED_TIMER6, > > +ASPEED_TIMER7, > > +ASPEED_TIMER8, > > You use an enum to define const values. It is recommended to also define > the value, to avoid problems if someone add/remove a value in the list > (unlikely, but we never know... imagine someone wants to try this SoC > with 9 timers and add ASPEED_TIMER9) ;) The enum's not used outside of aspeed_soc.c though, so it should all be self-consistent? Adding ASPEED_TIMER9 would just adjust the designated initialiser index values in aspeed_soc_ast2400_irqmap declaration below. Am I missing something? Specifying enum values seems tedious in this case. Andrew > > > +ASPEED_WDT, > > +ASPEED_PWM, > > +ASPEED_LPC, > > +ASPEED_IBT, > > +ASPEED_I2C, > > +ASPEED_ETH1, > > +ASPEED_ETH2, > > +ASPEED_SDRAM, > > +}; > > + > > #define ASPEED_SOC_UART_5_BASE 0x00184000 > > #define ASPEED_SOC_IOMEM_SIZE 0x0020 > > #define ASPEED_SOC_IOMEM_BASE 0x1E60 > > @@ -38,12 +74,42 @@ > > #define ASPEED_SOC_ETH1_BASE0x1E66 > > #define ASPEED_SOC_ETH2_BASE0x1E68 > > > > -static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; > > -static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; > > +static const int aspeed_soc_ast2400_irqmap[] = { > > +[ASPEED_UART1] = 9, > > +[ASPEED_UART2] = 32, > > +[ASPEED_UART3] = 33, > > +[ASPEED_UART4] = 34, > > +[ASPEED_UART5] = 10, > > +[ASPEED_VUART] = 8, > > +[ASPEED_FMC]= 19, > > +[ASPEED_SDMC] = 0, > > +[ASPEED_SCU]= 21, > > +[ASPEED_ADC]= 31, > > +[ASPEED_GPIO] = 20, > > +[ASPEED_RTC]= 22, > > +[ASPEED_TIMER1] = 16, > > +[ASPEED_TIMER2] = 17, > > +[ASPEED_TIMER3] = 18, > > +[ASPEED_TIMER4] = 35, > > +[ASPEED_TIMER5] = 36, > > +[ASPEED_TIMER6] = 37, > > +[ASPEED_TIMER7] = 38, > > +[ASPEED_TIMER8] = 39, > > +[ASPEED_WDT]= 27, > > +[ASPEED_PWM]= 28, > > +[ASPEED_LPC]= 8, > > +[ASPEED_IBT]= 8, /* LPC */ > > +[ASPEED_I2C]= 12, > > +[ASPEED_ETH1] = 2, > > +[ASPEED_ETH2] = 3, > > +}; > > > > #define AST2400_SDRAM_BASE 0x4000 > > #define AST2500_SDRAM_BASE 0x8000 > > > > +/* AST2500 uses the same IRQs as the AST2400 */ > > +#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap > > + > > static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE > > }; > > static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" }; > > > > @@ -64,6 +130,7 @@ static const AspeedSoCInfo aspeed_socs[] = { > > .fmc_typename = "aspeed.smc.fmc", > > .spi_typename = aspeed_soc_ast2400_typenames, > > .wdts_num = 2, > > +.irqmap = aspeed_soc_ast2400_irqmap, > > }, { > > .name = "ast2400-a1", > > .cpu_type = ARM_CPU_TYPE_NAME("arm926"), > > @@ -75,6 +142,7 @@ static const AspeedSoCInfo aspeed_socs[] = { > > .fmc_typename = "aspeed.smc.fmc", > > .spi_typename = aspeed_soc_ast2400_typenames, > > .wdts_num = 2, > > +.irqmap = aspeed_soc_ast2400_irqmap, > > }, { > > .name = "ast2400", > > .cpu_type =
Re: [Qemu-devel] Maintainers, please tell us how to boot your machines!
On Wed, 13 Mar 2019, at 07:07, Cédric Le Goater wrote: > On 3/12/19 6:36 PM, Markus Armbruster wrote: > > Dear board code maintainers, > > > > This is a (rather late) follow-up to the last QEMU summit. Minutes[*]: > > > > * Deprecating unmaintained features (devices, targets, backends) in QEMU > > > >QEMU has a mechanism to deprecate features but there remains a lot of > >old unmaintained code. Refactoring is hindered by untested legacy > >code, so there is a desire to deprecate unmaintained features more > >often. > > > >[...] > > > >We should require at least a minimal test for each board; if nobody > >cares enough to come up with one, that board should be deprecated. > > > >[...] > > > >Also see the qemu-devel discussion about deprecating code: > >https://lists.nongnu.org/archive/html/qemu-devel/2018-10/msg05828.html. > > > > That's a link to "Minutes of KVM Forum BoF on deprecating stuff". > > Quote: > > > > * One obvious class of candidates for removal is machines we don't know > >how to boot, or can't boot, say because we lack required firmware > >and/or OS. > > > >Of course, "can boot" should be an automated test. As a first step > >towards that, we should at least document how to boot each machine. > >We're going to ask machine maintainers to do that. > > > > Let's get going on this. > > > > I gathered the machine types, mapped them to source files, which I fed > > to get_maintainer.pl. Results are appended. If you're cc'ed, > > MAINTAINERS fingers you for at least one machine type's source file. > > Please tell us for all of them how to to a "meaningful" boot test. > > > > For now, what's "meaningful" is entirely up to you. Booting Linux > > certainly is. > > > > Make sure to include a complete QEMU command line. If your QEMU command > > line requires resources beyond the QEMU source tree and what we build > > from it, please detail them, and provide download URLs as far as > > possible. > > > > Goals for this exercise: > > > > * Gather information we need to cover more machines in our automated > > testing. > > > > Related work: > > [PATCH v4 00/19] Acceptance Tests: target architecture support > > Message-Id: <20190312121150.8638-1-cr...@redhat.com> > > https://lists.gnu.org/archive/html/qemu-devel/2019-03/msg03881.html > > > > * Maybe identify a few machines we don't know how to boot anymore. > > > > Thanks in advance for your help! > > > > > > > > Machines with at least one maintainer: > > > > = hw/alpha/dp264.c = > > Richard Henderson (maintainer:Alpha Machines) > > > > = hw/arm/aspeed.c = > > "Cédric Le Goater" (maintainer:ASPEED BMCs) > > Peter Maydell (maintainer:ASPEED BMCs) > > Andrew Jeffery (reviewer:ASPEED BMCs) > > Joel Stanley (reviewer:ASPEED BMCs) > > qemu-...@nongnu.org (open list:ASPEED BMCs) > > I have checked the URLs but they could change in the future : > > * palmetto-bmc > > > https://openpower.xyz/job/openbmc-build/lastSuccessfulBuild/distro=ubuntu,label=builder,target=palmetto/artifact/deploy/images/palmetto/flash-palmetto > > qemu-system-arm -m 512 -M palmetto-bmc -net > nic,macaddr=C0:FF:EE:00:00:01,model=ftgmac100 -net > user,id=netdev0,hostfwd=::-:22,hostname=ast1 -drive > file=flash-palmetto,format=raw,if=mtd -nographic > > * romulus-bmc > > > https://openpower.xyz/job/openbmc-build/lastSuccessfulBuild/distro=ubuntu,label=builder,target=romulus/artifact/deploy/images/romulus/flash-romulus > > qemu-system-arm -m 512 -M romulus-bmc -net > nic,macaddr=C0:FF:EE:00:00:01,model=ftgmac100 -net > user,id=netdev0,hostfwd=::-:22,hostname=ast1 -drive > file=flash-romulus,format=raw,if=mtd -nographic > > * ast2500-evb > > > https://openpower.xyz/job/openbmc-build/lastSuccessfulBuild/distro=ubuntu,label=builder,target=evb-ast2500/artifact/deploy/images/evb-ast2500/flash-evb-ast2500 > > qemu-system-arm -m 512 -M ast2500-evb -net > nic,macaddr=C0:FF:EE:00:00:01,model=ftgmac100 -net > user,id=netdev0,hostfwd=::-:22,hostname=ast1 -drive > file=flash-evb-ast2500,format=raw,if=mtd -nographic > > * witherspoon-bmc > > > https://openpower.xyz/job/openbmc-build/lastSuccessfulBuild/distro=ubuntu,label=builder,target=witherspoon/artifact/deploy/images/witherspoon/obmc-phosphor-image-witherspoon
Re: [Qemu-devel] [PATCH] ftgmac100: implement the new MDIO interface on Aspeed SoC
On Fri, 11 Jan 2019, at 23:27, Cédric Le Goater wrote: > The PHY behind the MAC of an Aspeed SoC can be controlled using two > different MDC/MDIO interfaces. The same registers PHYCR (MAC60) and > PHYDATA (MAC64) are involved but they have a different layout. > > BIT31 of the Feature Register (MAC40) controls which MDC/MDIO > interface is active. > > Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery > --- > hw/net/ftgmac100.c | 80 +++--- > 1 file changed, 68 insertions(+), 12 deletions(-) > > diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c > index 909c1182eebe..790430346b51 100644 > --- a/hw/net/ftgmac100.c > +++ b/hw/net/ftgmac100.c > @@ -89,6 +89,18 @@ > #define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0x) > #define FTGMAC100_PHYDATA_MIIRDATA(x) (((x) >> 16) & 0x) > > +/* > + * PHY control register - New MDC/MDIO interface > + */ > +#define FTGMAC100_PHYCR_NEW_DATA(x) (((x) >> 16) & 0x) > +#define FTGMAC100_PHYCR_NEW_FIRE(1 << 15) > +#define FTGMAC100_PHYCR_NEW_ST_22 (1 << 12) > +#define FTGMAC100_PHYCR_NEW_OP(x) (((x) >> 10) & 3) > +#define FTGMAC100_PHYCR_NEW_OP_WRITE0x1 > +#define FTGMAC100_PHYCR_NEW_OP_READ 0x2 > +#define FTGMAC100_PHYCR_NEW_DEV(x) (((x) >> 5) & 0x1f) > +#define FTGMAC100_PHYCR_NEW_REG(x) ((x) & 0x1f) > + > /* > * Feature Register > */ > @@ -269,9 +281,9 @@ static void phy_reset(FTGMAC100State *s) > s->phy_int = 0; > } > > -static uint32_t do_phy_read(FTGMAC100State *s, int reg) > +static uint16_t do_phy_read(FTGMAC100State *s, uint8_t reg) > { > -uint32_t val; > +uint16_t val; > > switch (reg) { > case MII_BMCR: /* Basic Control */ > @@ -336,7 +348,7 @@ static uint32_t do_phy_read(FTGMAC100State *s, int reg) > MII_BMCR_FD | MII_BMCR_CTST) > #define MII_ANAR_MASK 0x2d7f > > -static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val) > +static void do_phy_write(FTGMAC100State *s, uint8_t reg, uint16_t val) > { > switch (reg) { > case MII_BMCR: /* Basic Control */ > @@ -373,6 +385,55 @@ static void do_phy_write(FTGMAC100State *s, int > reg, uint32_t val) > } > } > > +static void do_phy_new_ctl(FTGMAC100State *s) > +{ > +uint8_t reg; > +uint16_t data; > + > +if (!(s->phycr & FTGMAC100_PHYCR_NEW_ST_22)) { > +qemu_log_mask(LOG_UNIMP, "%s: unsupported ST code\n", __func__); > +return; > +} > + > +/* Nothing to do */ > +if (!(s->phycr & FTGMAC100_PHYCR_NEW_FIRE)) { > +return; > +} > + > +reg = FTGMAC100_PHYCR_NEW_REG(s->phycr); > +data = FTGMAC100_PHYCR_NEW_DATA(s->phycr); > + > +switch (FTGMAC100_PHYCR_NEW_OP(s->phycr)) { > +case FTGMAC100_PHYCR_NEW_OP_WRITE: > +do_phy_write(s, reg, data); > +break; > +case FTGMAC100_PHYCR_NEW_OP_READ: > +s->phydata = do_phy_read(s, reg) & 0x; > +break; > +default: > +qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid OP code %08x\n", > + __func__, s->phycr); > +} > + > +s->phycr &= ~FTGMAC100_PHYCR_NEW_FIRE; > +} > + > +static void do_phy_ctl(FTGMAC100State *s) > +{ > +uint8_t reg = FTGMAC100_PHYCR_REG(s->phycr); > + > +if (s->phycr & FTGMAC100_PHYCR_MIIWR) { > +do_phy_write(s, reg, s->phydata & 0x); > +s->phycr &= ~FTGMAC100_PHYCR_MIIWR; > +} else if (s->phycr & FTGMAC100_PHYCR_MIIRD) { > +s->phydata = do_phy_read(s, reg) << 16; > +s->phycr &= ~FTGMAC100_PHYCR_MIIRD; > +} else { > +qemu_log_mask(LOG_GUEST_ERROR, "%s: no OP code %08x\n", > + __func__, s->phycr); > +} > +} > + > static int ftgmac100_read_bd(FTGMAC100Desc *bd, dma_addr_t addr) > { > if (dma_memory_read(_space_memory, addr, bd, sizeof(*bd))) { > @@ -628,7 +689,6 @@ static void ftgmac100_write(void *opaque, hwaddr addr, >uint64_t value, unsigned size) > { > FTGMAC100State *s = FTGMAC100(opaque); > -int reg; > > switch (addr & 0xff) { > case FTGMAC100_ISR: /* Interrupt status */ > @@ -711,14 +771,11 @@ static void ftgmac100_write(void *opaque, hwaddr addr, > break; > > case FTGMAC100_PHYCR: /* PHY Device control */ > -reg = FTGMAC100_PHYCR_REG(value); > s->phycr = value; > -if (valu
Re: [Qemu-devel] [PATCH] gitdm: Add other IBMers
On Wed, 2 Jan 2019, at 21:36, Joel Stanley wrote: > Here are some IBMers who use their personal addresses when submitting > patches. > > Signed-off-by: Joel Stanley For the addition of my address: Acked-by: Andrew Jeffery > --- > contrib/gitdm/group-map-ibm | 5 + > 1 file changed, 5 insertions(+) > > diff --git a/contrib/gitdm/group-map-ibm b/contrib/gitdm/group-map-ibm > index b66db5f4a825..6c0570107d65 100644 > --- a/contrib/gitdm/group-map-ibm > +++ b/contrib/gitdm/group-map-ibm > @@ -2,5 +2,10 @@ > # Some IBM contributors submit via another domain > # > > +a...@ozlabs.ru > +and...@aj.id.au > +b...@kernel.crashing.org > c...@kaod.org > gr...@kaod.org > +j...@jms.id.au > +sjitindarsi...@gmail.com > -- > 2.19.1 >
Re: [Qemu-devel] [RFC PATCH 1/1] memory: Support unaligned accesses on aligned-only models
On Thu, 20 Sep 2018, at 21:43, Cédric Le Goater wrote: > Andrew, > > On 07/14/2017 08:20 AM, Andrew Jeffery wrote: > > Hi Paolo, > > > > Thanks for taking a look! > > > > On Thu, 2017-07-13 at 14:05 +0200, Paolo Bonzini wrote: > >> On 30/06/2017 05:00, Andrew Jeffery wrote: > >>> This RFC patch stems from a discussion on a patch for an ADC model[1] > >>> where it > >>> was pointed out that I should be able to use the .impl member of > >>> MemoryRegionOps to constrain how my read() and write() callbacks where > >>> invoked. > >>> > >>> I tried Phil's suggested approach and found I got reads of size 4, but > >>> with an > >>> address that was not 4-byte aligned. > >>> > >>> Looking at the source for access_with_adjusted_size() lead to the comment > >>> > >>> /* FIXME: support unaligned access? */ > >>> > >>> which at least suggests that the implementation isn't complete. > >>> > >>> So, this patch is a quick and incomplete attempt at resolving the issue > >>> to see > >>> whether I'm on the right track or way off in the weeds. > >>> > >>> I've lightly tested it with the ADC model mentioned above, and it appears > >>> to do > >>> the right thing (I changed the values generated by the ADC to distinguish > >>> between the lower and upper 16 bits). > >> > >> I think the idea is okay. > >> > >>> +access_addr[0] = align_down(addr, access_size); > >>> +access_addr[1] = align_up(addr + size, access_size); > >>> + > >>> +for (cur = access_addr[0]; cur < access_addr[1]; cur += > >>> access_size) { > >>> +uint64_t mask_bounds[2]; > >>> +mask_bounds[0] = MAX(addr, cur) - cur; > >>> +mask_bounds[1] = > >>> +MIN(addr + size, align_up(cur + 1, access_size)) - cur; > >>> + > >>> +access_mask = (-1ULL << mask_bounds[0] * 8) & > >>> +(-1ULL >> (64 - mask_bounds[1] * 8)); > >> > >> Please use MAKE_64BIT_MASK. > > > > Okay. > > > >> > >>> +r |= access(mr, cur, _value, access_size, > >>> + (MAX(addr, cur) - addr), access_mask, attrs); > >>> + > >>> +/* XXX: Can't do this hack for writes */ > >>> +access_value >>= mask_bounds[0] * 8; > >>> +} > >> > >> Can you subtract access_addr[0] from mask_bounds[0] and mask_bounds[1] > >> (instead of cur) to remove the need for this right shift? > > > > I haven't looked at the patch since I sent it. Given you think the idea > > of the patch is okay I'll get back to working on it and think about > > this. > > We have been using successfully this patch for over a year now and it > would be nice to get it merged along with the ADC model. Do you have > a new version addressing Paolo's remarks ? Aggh, no :( I've been meaning to get to it, but have been significantly distracted for quite some time now. I'm not sure when I'll be able to look at it. I'm happy for someone else to have a crack at fixing it in the mean time :) Thanks for the reminder. Andrew
Re: [Qemu-devel] [PATCH] aspeed: Implement write-1-{set, clear} for AST2500 strapping
On Fri, 13 Jul 2018, at 01:28, Peter Maydell wrote: > On 9 July 2018 at 15:35, Andrew Jeffery wrote: > > The AST2500 SoC family changes the runtime behaviour of the hardware > > strapping register (SCU70) to write-1-set/write-1-clear, with > > write-1-clear implemented on the "read-only" SoC revision register > > (SCU7C). For the the AST2400, the hardware strapping is > > runtime-configured with read-modify-write semantics. > > > > Signed-off-by: Andrew Jeffery > > --- > > Hi -- is this a bugfix suitable for 3.0, or something you'd > like to wait until 3.1 ? The commit message sounds like a bugfix... If we could get it into 3.0 that would be great. I ran into a case where the distinction was important so it would be good to have it resolved sooner rather than later. Cheers, Andrew
[Qemu-devel] [PATCH] aspeed: Implement write-1-{set, clear} for AST2500 strapping
The AST2500 SoC family changes the runtime behaviour of the hardware strapping register (SCU70) to write-1-set/write-1-clear, with write-1-clear implemented on the "read-only" SoC revision register (SCU7C). For the the AST2400, the hardware strapping is runtime-configured with read-modify-write semantics. Signed-off-by: Andrew Jeffery --- hw/misc/aspeed_scu.c | 19 +-- include/hw/misc/aspeed_scu.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index 5e6d5744eeca..9051767cbbcd 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -202,11 +202,26 @@ static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data, case PROT_KEY: s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; return; - +case HW_STRAP1: +if (ASPEED_IS_AST2500(s->regs[SILICON_REV])) { +s->regs[HW_STRAP1] |= data; +return; +} +/* Jump to assignment below */ +break; +case SILICON_REV: +if (ASPEED_IS_AST2500(s->regs[SILICON_REV])) { +s->regs[HW_STRAP1] &= ~data; +} else { +qemu_log_mask(LOG_GUEST_ERROR, + "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", + __func__, offset); +} +/* Avoid assignment below, we've handled everything */ +return; case FREQ_CNTR_EVAL: case VGA_SCRATCH1 ... VGA_SCRATCH8: case RNG_DATA: -case SILICON_REV: case FREE_CNTR4: case FREE_CNTR4_EXT: qemu_log_mask(LOG_GUEST_ERROR, diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index d70cc0aeca61..169611a211bb 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -37,6 +37,8 @@ typedef struct AspeedSCUState { #define AST2500_A0_SILICON_REV 0x04000303U #define AST2500_A1_SILICON_REV 0x04010303U +#define ASPEED_IS_AST2500(si_rev) si_rev) >> 24) & 0xff) == 0x04) + extern bool is_supported_silicon_rev(uint32_t silicon_rev); #define ASPEED_SCU_PROT_KEY 0x1688A8A8 -- 2.17.1
Re: [Qemu-devel] [PATCH] MAINTAINERS: Add ASPEED BMCs
On Mon, 25 Jun 2018, at 20:43, Philippe Mathieu-Daudé wrote: > Hi Joel, > > On 06/25/2018 08:07 AM, Joel Stanley wrote: > > This adds Cedric as the maintainer, with Andrew and I as reviewers, for > > the ASPEED boards and the peripherals we use. > > Good idea, this should speed up ASPEED reviews. > > > > > Signed-off-by: Joel Stanley > > --- > > MAINTAINERS | 11 +++ > > 1 file changed, 11 insertions(+) > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 2874ddce6097..14bcf2ed3e3d 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -644,6 +644,17 @@ M: Subbaraya Sundeep > > S: Maintained > > F: hw/arm/msf2-som.c > > > > +ASPEED BMCs > > +M: Cédric Le Goater > > +R: Andrew Jeffery > > +R: Joel Stanley > > +L: qemu-...@nongnu.org > > +S: Maintained > > +F: hw/*/*aspeed* > > +F: include/*/*aspeed* > > This line does not match, however include/hw/*/*aspeed* does. > > With that fixed: > Reviewed-by: Philippe Mathieu-Daudé Similarly: Reviewed-by: Andrew Jeffery > > > +F: hw/net/ftgmac100.c > > +F: include/hw/net/ftgmac100.h > > + > > CRIS Machines > > - > > Axis Dev88 > >
Re: [Qemu-devel] [PATCH 3/3] aspeed/smc: rename aspeed_smc_flash_send_addr() to aspeed_smc_flash_setup()
On Tue, 12 Jun 2018, at 16:27, Cédric Le Goater wrote: > Also handle the fake transfers for dummy bytes in this setup > routine. It will be useful when we activate MMIO execution. > > Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery > --- > hw/ssi/aspeed_smc.c | 31 --- > 1 file changed, 16 insertions(+), 15 deletions(-) > > diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c > index b15370893583..b29bfd3124a9 100644 > --- a/hw/ssi/aspeed_smc.c > +++ b/hw/ssi/aspeed_smc.c > @@ -503,10 +503,11 @@ static int aspeed_smc_flash_dummies(const > AspeedSMCFlash *fl) > return dummies; > } > > -static void aspeed_smc_flash_send_addr(AspeedSMCFlash *fl, uint32_t addr) > +static void aspeed_smc_flash_setup(AspeedSMCFlash *fl, uint32_t addr) > { > const AspeedSMCState *s = fl->controller; > uint8_t cmd = aspeed_smc_flash_cmd(fl); > +int i; > > /* Flash access can not exceed CS segment */ > addr = aspeed_smc_check_segment_addr(fl, addr); > @@ -519,6 +520,18 @@ static void > aspeed_smc_flash_send_addr(AspeedSMCFlash *fl, uint32_t addr) > ssi_transfer(s->spi, (addr >> 16) & 0xff); > ssi_transfer(s->spi, (addr >> 8) & 0xff); > ssi_transfer(s->spi, (addr & 0xff)); > + > +/* > + * Use fake transfers to model dummy bytes. The value should > + * be configured to some non-zero value in fast read mode and > + * zero in read mode. But, as the HW allows inconsistent > + * settings, let's check for fast read mode. > + */ > +if (aspeed_smc_flash_mode(fl) == CTRL_FREADMODE) { > +for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) { > +ssi_transfer(fl->controller->spi, 0xFF); > +} > +} > } > > static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, > unsigned size) > @@ -537,19 +550,7 @@ static uint64_t aspeed_smc_flash_read(void *opaque, > hwaddr addr, unsigned size) > case CTRL_READMODE: > case CTRL_FREADMODE: > aspeed_smc_flash_select(fl); > -aspeed_smc_flash_send_addr(fl, addr); > - > -/* > - * Use fake transfers to model dummy bytes. The value should > - * be configured to some non-zero value in fast read mode and > - * zero in read mode. But, as the HW allows inconsistent > - * settings, let's check for fast read mode. > - */ > -if (aspeed_smc_flash_mode(fl) == CTRL_FREADMODE) { > -for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) { > -ssi_transfer(fl->controller->spi, 0xFF); > -} > -} > +aspeed_smc_flash_setup(fl, addr); > > for (i = 0; i < size; i++) { > ret |= ssi_transfer(s->spi, 0x0) << (8 * i); > @@ -586,7 +587,7 @@ static void aspeed_smc_flash_write(void *opaque, > hwaddr addr, uint64_t data, > break; > case CTRL_WRITEMODE: > aspeed_smc_flash_select(fl); > -aspeed_smc_flash_send_addr(fl, addr); > +aspeed_smc_flash_setup(fl, addr); > > for (i = 0; i < size; i++) { > ssi_transfer(s->spi, (data >> (8 * i)) & 0xff); > -- > 2.13.6 > >
Re: [Qemu-devel] [PATCH 2/3] aspeed/smc: fix HW strapping
On Tue, 12 Jun 2018, at 16:27, Cédric Le Goater wrote: > Only the flash type is strapped by HW. The 4BYTE mode is set by > firmware when the flash device is detected. > > Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery > --- > hw/ssi/aspeed_smc.c | 8 +--- > 1 file changed, 1 insertion(+), 7 deletions(-) > > diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c > index fce126e6ee92..b15370893583 100644 > --- a/hw/ssi/aspeed_smc.c > +++ b/hw/ssi/aspeed_smc.c > @@ -639,23 +639,17 @@ static void aspeed_smc_reset(DeviceState *d) > aspeed_smc_segment_to_reg(>ctrl->segments[i]); > } > > -/* HW strapping for AST2500 FMC controllers */ > +/* HW strapping flash type for FMC controllers */ > if (s->ctrl->segments == aspeed_segments_ast2500_fmc) { > /* flash type is fixed to SPI for CE0 and CE1 */ > s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); > s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1); > - > -/* 4BYTE mode is autodetected for CE0. Let's force it to 1 for > - * now */ > -s->regs[s->r_ce_ctrl] |= (1 << (CTRL_EXTENDED0)); > } > > /* HW strapping for AST2400 FMC controllers (SCU70). Let's use the > * configuration of the palmetto-bmc machine */ > if (s->ctrl->segments == aspeed_segments_fmc) { > s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); > - > -s->regs[s->r_ce_ctrl] |= (1 << (CTRL_EXTENDED0)); > } > } > > -- > 2.13.6 > >
Re: [Qemu-devel] [Qemu-arm] [PATCH 1/3] aspeed/smc: fix dummy cycles count when in dual IO mode
On Tue, 12 Jun 2018, at 16:27, Cédric Le Goater wrote: > When configured in dual I/O mode, address and data are sent in dual > mode, including the dummy byte cycles in between. Adapt the count to > the IO setting. > > Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery > --- > hw/ssi/aspeed_smc.c | 9 - > 1 file changed, 8 insertions(+), 1 deletion(-) > > diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c > index 5059396bc623..fce126e6ee92 100644 > --- a/hw/ssi/aspeed_smc.c > +++ b/hw/ssi/aspeed_smc.c > @@ -66,6 +66,8 @@ > > /* CEx Control Register */ > #define R_CTRL0 (0x10 / 4) > +#define CTRL_IO_DUAL_DATA(1 << 29) > +#define CTRL_IO_DUAL_ADDR_DATA (1 << 28) /* Includes dummies */ > #define CTRL_CMD_SHIFT 16 > #define CTRL_CMD_MASK0xff > #define CTRL_DUMMY_HIGH_SHIFT14 > @@ -492,8 +494,13 @@ static int aspeed_smc_flash_dummies(const > AspeedSMCFlash *fl) > uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->id]; > uint32_t dummy_high = (r_ctrl0 >> CTRL_DUMMY_HIGH_SHIFT) & 0x1; > uint32_t dummy_low = (r_ctrl0 >> CTRL_DUMMY_LOW_SHIFT) & 0x3; > +uint32_t dummies = ((dummy_high << 2) | dummy_low) * 8; > > -return ((dummy_high << 2) | dummy_low) * 8; > +if (r_ctrl0 & CTRL_IO_DUAL_ADDR_DATA) { > +dummies /= 2; > +} > + > +return dummies; > } > > static void aspeed_smc_flash_send_addr(AspeedSMCFlash *fl, uint32_t addr) > -- > 2.13.6 > >
Re: [Qemu-devel] [PATCH v2 3/3] aspeed/timer: use the APB frequency from the SCU
On Fri, 22 Jun 2018, at 17:27, Cédric Le Goater wrote: > The timer controller can be driven by either an external 1MHz clock or > by the APB clock. Today, the model makes the assumption that the APB > frequency is always set to 24MHz but this is incorrect. > > The AST2400 SoC on the palmetto machines uses a 48MHz input clock > source and the APB can be set to 48MHz. The consequence is a general > system slowdown. The QEMU machines using the AST2500 SoC do not seem > impacted today because the APB frequency is still set to 24MHz. > > We fix the timer frequency for all SoCs by linking the Timer model to > the SCU model. The APB frequency driving the timers is now the one > configured for the SoC. > > Signed-off-by: Cédric Le Goater > Reviewed-by: Joel Stanley Reviewed-by: Andrew Jeffery > --- > include/hw/timer/aspeed_timer.h | 4 > hw/arm/aspeed_soc.c | 2 ++ > hw/timer/aspeed_timer.c | 19 +++ > 3 files changed, 21 insertions(+), 4 deletions(-) > > diff --git a/include/hw/timer/aspeed_timer.h b/include/hw/timer/aspeed_timer.h > index bd6c1a7f9609..040a08873432 100644 > --- a/include/hw/timer/aspeed_timer.h > +++ b/include/hw/timer/aspeed_timer.h > @@ -24,6 +24,8 @@ > > #include "qemu/timer.h" > > +typedef struct AspeedSCUState AspeedSCUState; > + > #define ASPEED_TIMER(obj) \ > OBJECT_CHECK(AspeedTimerCtrlState, (obj), TYPE_ASPEED_TIMER); > #define TYPE_ASPEED_TIMER "aspeed.timer" > @@ -55,6 +57,8 @@ typedef struct AspeedTimerCtrlState { > uint32_t ctrl; > uint32_t ctrl2; > AspeedTimer timers[ASPEED_TIMER_NR_TIMERS]; > + > +AspeedSCUState *scu; > } AspeedTimerCtrlState; > > #endif /* ASPEED_TIMER_H */ > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index 7cc05ee27ea4..e68911af0f90 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -127,6 +127,8 @@ static void aspeed_soc_init(Object *obj) > > object_initialize(>timerctrl, sizeof(s->timerctrl), > TYPE_ASPEED_TIMER); > object_property_add_child(obj, "timerctrl", OBJECT(>timerctrl), NULL); > +object_property_add_const_link(OBJECT(>timerctrl), "scu", > + OBJECT(>scu), _abort); > qdev_set_parent_bus(DEVICE(>timerctrl), sysbus_get_default()); > > object_initialize(>i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); > diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c > index 1e31e22b6f1f..5e3f51b66b43 100644 > --- a/hw/timer/aspeed_timer.c > +++ b/hw/timer/aspeed_timer.c > @@ -10,8 +10,10 @@ > */ > > #include "qemu/osdep.h" > +#include "qapi/error.h" > #include "hw/sysbus.h" > #include "hw/timer/aspeed_timer.h" > +#include "hw/misc/aspeed_scu.h" > #include "qemu-common.h" > #include "qemu/bitops.h" > #include "qemu/timer.h" > @@ -26,7 +28,6 @@ > #define TIMER_CLOCK_USE_EXT true > #define TIMER_CLOCK_EXT_HZ 100 > #define TIMER_CLOCK_USE_APB false > -#define TIMER_CLOCK_APB_HZ 2400 > > #define TIMER_REG_STATUS 0 > #define TIMER_REG_RELOAD 1 > @@ -80,11 +81,11 @@ static inline bool timer_external_clock(AspeedTimer *t) > return timer_ctrl_status(t, op_external_clock); > } > > -static uint32_t clock_rates[] = { TIMER_CLOCK_APB_HZ, TIMER_CLOCK_EXT_HZ }; > - > static inline uint32_t calculate_rate(struct AspeedTimer *t) > { > -return clock_rates[timer_external_clock(t)]; > +AspeedTimerCtrlState *s = timer_to_ctrl(t); > + > +return timer_external_clock(t) ? TIMER_CLOCK_EXT_HZ : s->scu->apb_freq; > } > > static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t > now_ns) > @@ -449,6 +450,16 @@ static void aspeed_timer_realize(DeviceState *dev, > Error **errp) > int i; > SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > AspeedTimerCtrlState *s = ASPEED_TIMER(dev); > +Object *obj; > +Error *err = NULL; > + > +obj = object_property_get_link(OBJECT(dev), "scu", ); > +if (!obj) { > +error_propagate(errp, err); > +error_prepend(errp, "required link 'scu' not found: "); > +return; > +} > +s->scu = ASPEED_SCU(obj); > > for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { > aspeed_init_one_timer(s, i); > -- > 2.13.6 >
Re: [Qemu-devel] [PATCH v2 2/3] aspeed: initialize the SCU controller first
On Fri, 22 Jun 2018, at 17:26, Cédric Le Goater wrote: > The System Control Unit should be initialized first as it drives all > the configuration of the SoC and other device models. > > Signed-off-by: Cédric Le Goater > Reviewed-by: Joel Stanley Acked-by: Andrew Jeffery > --- > hw/arm/aspeed_soc.c | 40 > 1 file changed, 20 insertions(+), 20 deletions(-) > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index 1955a892f4a4..7cc05ee27ea4 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -109,18 +109,6 @@ static void aspeed_soc_init(Object *obj) > object_initialize(>cpu, sizeof(s->cpu), sc->info->cpu_type); > object_property_add_child(obj, "cpu", OBJECT(>cpu), NULL); > > -object_initialize(>vic, sizeof(s->vic), TYPE_ASPEED_VIC); > -object_property_add_child(obj, "vic", OBJECT(>vic), NULL); > -qdev_set_parent_bus(DEVICE(>vic), sysbus_get_default()); > - > -object_initialize(>timerctrl, sizeof(s->timerctrl), > TYPE_ASPEED_TIMER); > -object_property_add_child(obj, "timerctrl", OBJECT(>timerctrl), NULL); > -qdev_set_parent_bus(DEVICE(>timerctrl), sysbus_get_default()); > - > -object_initialize(>i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); > -object_property_add_child(obj, "i2c", OBJECT(>i2c), NULL); > -qdev_set_parent_bus(DEVICE(>i2c), sysbus_get_default()); > - > object_initialize(>scu, sizeof(s->scu), TYPE_ASPEED_SCU); > object_property_add_child(obj, "scu", OBJECT(>scu), NULL); > qdev_set_parent_bus(DEVICE(>scu), sysbus_get_default()); > @@ -133,6 +121,18 @@ static void aspeed_soc_init(Object *obj) > object_property_add_alias(obj, "hw-prot-key", OBJECT(>scu), >"hw-prot-key", _abort); > > +object_initialize(>vic, sizeof(s->vic), TYPE_ASPEED_VIC); > +object_property_add_child(obj, "vic", OBJECT(>vic), NULL); > +qdev_set_parent_bus(DEVICE(>vic), sysbus_get_default()); > + > +object_initialize(>timerctrl, sizeof(s->timerctrl), > TYPE_ASPEED_TIMER); > +object_property_add_child(obj, "timerctrl", OBJECT(>timerctrl), > NULL); > +qdev_set_parent_bus(DEVICE(>timerctrl), sysbus_get_default()); > + > +object_initialize(>i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); > +object_property_add_child(obj, "i2c", OBJECT(>i2c), NULL); > +qdev_set_parent_bus(DEVICE(>i2c), sysbus_get_default()); > + > object_initialize(>fmc, sizeof(s->fmc), sc->info->fmc_typename); > object_property_add_child(obj, "fmc", OBJECT(>fmc), NULL); > qdev_set_parent_bus(DEVICE(>fmc), sysbus_get_default()); > @@ -195,6 +195,14 @@ static void aspeed_soc_realize(DeviceState *dev, > Error **errp) > memory_region_add_subregion(get_system_memory(), > ASPEED_SOC_SRAM_BASE, > >sram); > > +/* SCU */ > +object_property_set_bool(OBJECT(>scu), true, "realized", ); > +if (err) { > +error_propagate(errp, err); > +return; > +} > +sysbus_mmio_map(SYS_BUS_DEVICE(>scu), 0, ASPEED_SOC_SCU_BASE); > + > /* VIC */ > object_property_set_bool(OBJECT(>vic), true, "realized", ); > if (err) { > @@ -219,14 +227,6 @@ static void aspeed_soc_realize(DeviceState *dev, > Error **errp) > sysbus_connect_irq(SYS_BUS_DEVICE(>timerctrl), i, irq); > } > > -/* SCU */ > -object_property_set_bool(OBJECT(>scu), true, "realized", ); > -if (err) { > -error_propagate(errp, err); > -return; > -} > -sysbus_mmio_map(SYS_BUS_DEVICE(>scu), 0, ASPEED_SOC_SCU_BASE); > - > /* UART - attach an 8250 to the IO space as our UART5 */ > if (serial_hd(0)) { > qemu_irq uart5 = qdev_get_gpio_in(DEVICE(>vic), uart_irqs[4]); > -- > 2.13.6 >
Re: [Qemu-devel] [PATCH v2 1/3] aspeed/scu: introduce clock frequencies
On Fri, 22 Jun 2018, at 17:26, Cédric Le Goater wrote: > All Aspeed SoC clocks are driven by an input source clock which can > have different frequencies : 24MHz or 25MHz, and also, on the Aspeed > AST2400 SoC, 48MHz. The H-PLL (CPU) clock is defined from a > calculation using parameters in the H-PLL Parameter register or from a > predefined set of frequencies if the setting is strapped by hardware > (Aspeed AST2400 SoC). The other clocks of the SoC are then defined > from the H-PLL using dividers. > > We introduce first the APB clock because it should be used to drive > the Aspeed timer model. > > Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery > --- > include/hw/misc/aspeed_scu.h | 70 ++-- > hw/misc/aspeed_scu.c | 106 > +++ > 2 files changed, 172 insertions(+), 4 deletions(-) > > diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h > index d70cc0aeca61..f662c38188f4 100644 > --- a/include/hw/misc/aspeed_scu.h > +++ b/include/hw/misc/aspeed_scu.h > @@ -30,6 +30,10 @@ typedef struct AspeedSCUState { > uint32_t hw_strap1; > uint32_t hw_strap2; > uint32_t hw_prot_key; > + > +uint32_t clkin; > +uint32_t hpll; > +uint32_t apb_freq; > } AspeedSCUState; > > #define AST2400_A0_SILICON_REV 0x02000303U > @@ -58,7 +62,64 @@ extern bool is_supported_silicon_rev(uint32_t silicon_rev); > * 1. 2012/12/29 Ryan Chen Create > */ > > -/* Hardware Strapping Register definition (for Aspeed AST2400 SOC) > +/* SCU08 Clock Selection Register > + * > + * 31 Enable Video Engine clock dynamic slow down > + * 30:28 Video Engine clock slow down setting > + * 27 2D Engine GCLK clock source selection > + * 26 2D Engine GCLK clock throttling enable > + * 25:23 APB PCLK divider selection > + * 22:20 LPC Host LHCLK divider selection > + * 19 LPC Host LHCLK clock generation/output enable control > + * 18:16 MAC AHB bus clock divider selection > + * 15 SD/SDIO clock running enable > + * 14:12 SD/SDIO divider selection > + * 11 Reserved > + * 10:8 Video port output clock delay control bit > + * 7 ARM CPU/AHB clock slow down enable > + * 6:4ARM CPU/AHB clock slow down setting > + * 3:2ECLK clock source selection > + * 1 CPU/AHB clock slow down idle timer > + * 0 CPU/AHB clock dynamic slow down enable (defined in bit[6:4]) > + */ > +#define SCU_CLK_GET_PCLK_DIV(x)(((x) >> 23) & 0x7) > + > +/* SCU24 H-PLL Parameter Register (for Aspeed AST2400 SOC) > + * > + * 18 H-PLL parameter selection > + * 0: Select H-PLL by strapping resistors > + * 1: Select H-PLL by the programmed registers (SCU24[17:0]) > + * 17 Enable H-PLL bypass mode > + * 16 Turn off H-PLL > + * 10:5 H-PLL Numerator > + * 4 H-PLL Output Divider > + * 3:0H-PLL Denumerator > + * > + * (Output frequency) = 24MHz * (2-OD) * [(Numerator+2) / (Denumerator > +1)] > + */ > + > +#define SCU_AST2400_H_PLL_PROGRAMMED (0x1 << 18) > +#define SCU_AST2400_H_PLL_BYPASS_EN(0x1 << 17) > +#define SCU_AST2400_H_PLL_OFF (0x1 << 16) > + > +/* SCU24 H-PLL Parameter Register (for Aspeed AST2500 SOC) > + * > + * 21 Enable H-PLL reset > + * 20 Enable H-PLL bypass mode > + * 19 Turn off H-PLL > + * 18:13 H-PLL Post Divider > + * 12:5 H-PLL Numerator (M) > + * 4:0H-PLL Denumerator (N) > + * > + * (Output frequency) = CLKIN(24MHz) * [(M+1) / (N+1)] / (P+1) > + * > + * The default frequency is 792Mhz when CLKIN = 24MHz > + */ > + > +#define SCU_H_PLL_BYPASS_EN(0x1 << 20) > +#define SCU_H_PLL_OFF (0x1 << 19) > + > +/* SCU70 Hardware Strapping Register definition (for Aspeed AST2400 > SOC) > * > * 31:29 Software defined strapping registers > * 28:27 DRAM size setting (for VGA driver use) > @@ -107,12 +168,13 @@ extern bool is_supported_silicon_rev(uint32_t > silicon_rev); > #define SCU_AST2400_HW_STRAP_GET_CLK_SOURCE(x) (x) >> 23) & > 0x1) << 1) \ > | (((x) >> 18) & > 0x1)) > #define SCU_AST2400_HW_STRAP_CLK_SOURCE_MASK ((0x1 << 23) | (0x1 > << 18)) > -#define AST2400_CLK_25M_IN (0x1 << 23) > +#define SCU_HW_STRAP_CLK_25M_IN(0x1 << 23) > #define AST2400_CLK_24M_IN 0 > #define AST2400_CLK_48M_IN
Re: [Qemu-devel] [PATCH] Fix ast2500 protection register emulation
On Tue, 20 Feb 2018, at 23:56, Hugo Landau wrote: > Some register blocks of the ast2500 are protected by protection key > registers which require the right magic value to be written to those > registers to allow those registers to be mutated. > > Register manuals indicate that writing the correct magic value to these > registers should cause subsequent reads from those values to return 1, > and writing any other value should cause subsequent reads to return 0. > > Previously, qemu implemented these registers incorrectly: the registers > were handled as simple memory, meaning that writing some value x to a > protection key register would result in subsequent reads from that > register returning the same value x. The protection was implemented by > ensuring that the current value of that register equaled the magic > value. > > This modifies qemu to have the correct behaviour: attempts to write to a > ast2500 protection register results in a transition to 1 or 0 depending > on whether the written value is the correct magic. The protection logic > is updated to ensure that the value of the register is nonzero. > > This bug caused deadlocks with u-boot HEAD: when u-boot is done with a > protectable register block, it attempts to lock it by writing the > bitwise inverse of the correct magic value, and then spinning forever > until the register reads as zero. Since qemu implemented writes to these > registers as ordinary memory writes, writing the inverse of the magic > value resulted in subsequent reads returning that value, leading to > u-boot spinning forever. > > Signed-off-by: Hugo Landau <hlan...@devever.net> Acked-by: Andrew Jeffery <and...@aj.id.au> > --- > hw/misc/aspeed_scu.c | 6 +- > hw/misc/aspeed_sdmc.c | 8 +++- > 2 files changed, 12 insertions(+), 2 deletions(-) > > diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c > index 74537ce975..5e6d5744ee 100644 > --- a/hw/misc/aspeed_scu.c > +++ b/hw/misc/aspeed_scu.c > @@ -191,7 +191,7 @@ static void aspeed_scu_write(void *opaque, hwaddr > offset, uint64_t data, > } > > if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && > -s->regs[PROT_KEY] != ASPEED_SCU_PROT_KEY) { > +!s->regs[PROT_KEY]) { > qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", > __func__); > return; > } > @@ -199,6 +199,10 @@ static void aspeed_scu_write(void *opaque, hwaddr > offset, uint64_t data, > trace_aspeed_scu_write(offset, size, data); > > switch (reg) { > +case PROT_KEY: > +s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; > +return; > + > case FREQ_CNTR_EVAL: > case VGA_SCRATCH1 ... VGA_SCRATCH8: > case RNG_DATA: > diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c > index f0b3053fae..265171ee42 100644 > --- a/hw/misc/aspeed_sdmc.c > +++ b/hw/misc/aspeed_sdmc.c > @@ -110,7 +110,12 @@ static void aspeed_sdmc_write(void *opaque, hwaddr > addr, uint64_t data, > return; > } > > -if (addr != R_PROT && s->regs[R_PROT] != PROT_KEY_UNLOCK) { > +if (addr == R_PROT) { > + s->regs[addr] = (data == PROT_KEY_UNLOCK) ? 1 : 0; > + return; > +} > + > +if (!s->regs[R_PROT]) { > qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked!\n", > __func__); > return; > } > @@ -123,6 +128,7 @@ static void aspeed_sdmc_write(void *opaque, hwaddr > addr, uint64_t data, > data &= ~ASPEED_SDMC_READONLY_MASK; > break; > case AST2500_A0_SILICON_REV: > +case AST2500_A1_SILICON_REV: > data &= ~ASPEED_SDMC_AST2500_READONLY_MASK; > break; > default: > -- > 2.15.0 > >
Re: [Qemu-devel] [PATCH v2 2/2] hw/arm/aspeed: simplify using the 'unimplemented device' for aspeed_soc.io
On Fri, 2018-02-09 at 05:57 -0300, Philippe Mathieu-Daudé wrote: > (qemu) info mtree > address-space: cpu-memory-0 >- (prio 0, i/o): system > -07ff (prio 0, rom): aspeed.boot_rom > -1e60-1e7f (prio -1, i/o): aspeed_soc.io > +1e60-1e7f (prio -1000, i/o): aspeed_soc.io > 1e62-1e6200ff (prio 0, i/o): aspeed.smc.ast2500-fmc > 1e63-1e6300ff (prio 0, i/o): aspeed.smc.ast2500-spi1 > 1e631000-1e6310ff (prio 0, i/o): aspeed.smc.ast2500-spi2 > > Signed-off-by: Philippe Mathieu-Daudé <f4...@amsat.org> > Reviewed-by: Cédric Le Goater <c...@kaod.org> Reviewed-by: Andrew Jeffery <and...@aj.id.au> > --- > include/hw/arm/aspeed_soc.h | 1 - > hw/arm/aspeed_soc.c | 32 +++- > 2 files changed, 3 insertions(+), 30 deletions(-) > > diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h > index f26914a2b9..11ec0179db 100644 > --- a/include/hw/arm/aspeed_soc.h > +++ b/include/hw/arm/aspeed_soc.h > @@ -31,7 +31,6 @@ typedef struct AspeedSoCState { > > /*< public >*/ > ARMCPU cpu; > -MemoryRegion iomem; > MemoryRegion sram; > AspeedVICState vic; > AspeedTimerCtrlState timerctrl; > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index 2a5d041b3b..30d25f8b06 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -15,6 +15,7 @@ > #include "qemu-common.h" > #include "cpu.h" > #include "exec/address-spaces.h" > +#include "hw/misc/unimp.h" > #include "hw/arm/aspeed_soc.h" > #include "hw/char/serial.h" > #include "qemu/log.h" > @@ -99,31 +100,6 @@ static const AspeedSoCInfo aspeed_socs[] = { > }, > }; > > -/* > - * IO handlers: simply catch any reads/writes to IO addresses that aren't > - * handled by a device mapping. > - */ > - > -static uint64_t aspeed_soc_io_read(void *p, hwaddr offset, unsigned size) > -{ > -qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", > - __func__, offset, size); > -return 0; > -} > - > -static void aspeed_soc_io_write(void *opaque, hwaddr offset, uint64_t value, > -unsigned size) > -{ > -qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " > [%u]\n", > - __func__, offset, value, size); > -} > - > -static const MemoryRegionOps aspeed_soc_io_ops = { > -.read = aspeed_soc_io_read, > -.write = aspeed_soc_io_write, > -.endianness = DEVICE_LITTLE_ENDIAN, > -}; > - > static void aspeed_soc_init(Object *obj) > { > AspeedSoCState *s = ASPEED_SOC(obj); > @@ -199,10 +175,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error > **errp) > Error *err = NULL, *local_err = NULL; > > /* IO space */ > -memory_region_init_io(>iomem, NULL, _soc_io_ops, NULL, > -"aspeed_soc.io", ASPEED_SOC_IOMEM_SIZE); > -memory_region_add_subregion_overlap(get_system_memory(), > -ASPEED_SOC_IOMEM_BASE, >iomem, > -1); > +create_unimplemented_device("aspeed_soc.io", > +ASPEED_SOC_IOMEM_BASE, > ASPEED_SOC_IOMEM_SIZE); > > /* CPU */ > object_property_set_bool(OBJECT(>cpu), true, "realized", ); signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2 1/2] hw/arm/aspeed: directly map the serial device to the system address space
On Fri, 2018-02-09 at 05:57 -0300, Philippe Mathieu-Daudé wrote: > (qemu) info mtree > address-space: cpu-memory-0 >- (prio 0, i/o): system > -07ff (prio 0, rom): aspeed.boot_rom > 1e60-1e7f (prio -1, i/o): aspeed_soc.io > - 1e784000-1e78401f (prio 0, i/o): serial > 1e62-1e6200ff (prio 0, i/o): > aspeed.smc.ast2500-fmc > 1e63-1e6300ff (prio 0, i/o): > aspeed.smc.ast2500-spi1 > [...] > 1e72-1e728fff (prio 0, ram): aspeed.sram > 1e782000-1e782fff (prio 0, i/o): aspeed.timer > +1e784000-1e78401f (prio 0, i/o): serial > 1e785000-1e78501f (prio 0, i/o): aspeed.wdt > 1e785020-1e78503f (prio 0, i/o): aspeed.wdt > > Signed-off-by: Philippe Mathieu-Daudé <f4...@amsat.org> Reviewed-by: Andrew Jeffery <and...@aj.id.au> > --- > hw/arm/aspeed_soc.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index c83b7e207b..2a5d041b3b 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -257,7 +257,8 @@ static void aspeed_soc_realize(DeviceState *dev, > Error **errp) > /* UART - attach an 8250 to the IO space as our UART5 */ > if (serial_hds[0]) { > qemu_irq uart5 = qdev_get_gpio_in(DEVICE(>vic), > uart_irqs[4]); > -serial_mm_init(>iomem, ASPEED_SOC_UART_5_BASE, 2, > +serial_mm_init(get_system_memory(), > + ASPEED_SOC_IOMEM_BASE + > ASPEED_SOC_UART_5_BASE, 2, > uart5, 38400, serial_hds[0], > DEVICE_LITTLE_ENDIAN); > } > signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH 1/2] hw/arm/aspeed: directly map the serial device to the system address space
On Thu, 2018-02-08 at 14:40 -0300, Philippe Mathieu-Daudé wrote: > On 02/08/2018 02:30 PM, Peter Maydell wrote: > > On 8 February 2018 at 17:22, Philippe Mathieu-Daudéwrote: > > > Signed-off-by: Philippe Mathieu-Daudé > > > --- > > > hw/arm/aspeed_soc.c | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > > > index c83b7e207b..a786750e14 100644 > > > --- a/hw/arm/aspeed_soc.c > > > +++ b/hw/arm/aspeed_soc.c > > > @@ -257,7 +257,7 @@ static void aspeed_soc_realize(DeviceState *dev, > > > Error **errp) > > > /* UART - attach an 8250 to the IO space as our UART5 */ > > > if (serial_hds[0]) { > > > qemu_irq uart5 = qdev_get_gpio_in(DEVICE(>vic), uart_irqs[4]); > > > -serial_mm_init(>iomem, ASPEED_SOC_UART_5_BASE, 2, > > > +serial_mm_init(get_system_memory(), ASPEED_SOC_UART_5_BASE, 2, > > > uart5, 38400, serial_hds[0], > > > DEVICE_LITTLE_ENDIAN); > > > } > > > > Is this a bug fix? It certainly changes behaviour, which > > suggests that a fuller commit message would be useful. > > This patch is buggy indeed, using system_memory the serial address > should be ASPEED_SOC_IOMEM_BASE + ASPEED_SOC_UART_5_BASE. > If you'd like to test, you can grab images from here: https://openpower.xyz/job/openbmc-build/distro=ubuntu,target=romulus/ For example (without the patch): $ wget https://openpower.xyz/job/openbmc-build/1240/distro=ubuntu,target=romulus/artifact/deploy/images/romulus/image-bmc ... $ qemu-system-arm -M romulus-bmc -m 512 -drive file=image-bmc,if=mtd,format=raw -nographic U-Boot 2016.07 (Jan 25 2018 - 16:31:27 +) Watchdog enabled DRAM: 496 MiB Flash: 32 MiB *** Warning - bad CRC, using default environment In:serial Out: serial Err: serial Net: aspeednic#0 Error: aspeednic#0 address not set. Hit any key to stop autoboot: 0 ## Loading kernel from FIT Image at 2008 ... ... And yeah, this patch breaks output. Thanks for the cleanup though. Andrew signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2] hw/arm/aspeed: Unlock SCU when running kernel
On Mon, 2017-11-13 at 23:58 +1030, Joel Stanley wrote: > The ASPEED hardware contains a lock register for the SCU that disables > any writes to the SCU when it is locked. The machine comes up with the > lock enabled, but on all known hardware u-boot will unlock it and leave > it unlocked when loading the kernel. > > This means the kernel expects the SCU to be unlocked. When booting from > an emulated ROM the normal u-boot unlock path is executed. Things don't > go well when booting using the -kernel command line, as u-boot does not > run first. > > Change behaviour so that when a kernel is passed to the machine, set the > reset value of the SCU to be unlocked. > > Signed-off-by: Joel Stanley> --- > v2: > - use the correct value for the key > - rename it ASPEED_SCU_PROT_KEY > --- > hw/arm/aspeed.c | 10 ++ > hw/arm/aspeed_soc.c | 2 ++ > hw/misc/aspeed_scu.c | 5 +++-- > include/hw/misc/aspeed_scu.h | 3 +++ > 4 files changed, 18 insertions(+), 2 deletions(-) > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > index ab895ad490af..754df8403273 100644 > --- a/hw/arm/aspeed.c > +++ b/hw/arm/aspeed.c > @@ -36,6 +36,7 @@ typedef struct AspeedBoardState { > typedef struct AspeedBoardConfig { > const char *soc_name; > uint32_t hw_strap1; > +uint32_t hw_prot_key; It doesn't seem like this member is used? With respect to the patch as a whole, I was planning to implement a small kernel driver for the SCU to unlock it on probe but never got around to it. However, this seems reasonable; I always worked around it locally in a much more hacky fashion. It would be handy to have an upstream solution. Andrew > const char *fmc_model; > const char *spi_model; > uint32_t num_cs; > @@ -186,6 +187,15 @@ static void aspeed_board_init(MachineState *machine, > _abort); > object_property_set_int(OBJECT(>soc), cfg->num_cs, "num-cs", > _abort); > +if (machine->kernel_filename) { > +/* > + * When booting with a -kernel command line there is no u-boot > + * that runs to unlock the SCU. In this case set the default to > + * be unlocked as the kernel expects > + */ > +object_property_set_int(OBJECT(>soc), ASPEED_SCU_PROT_KEY, > +"hw-prot-key", _abort); > +} > object_property_set_bool(OBJECT(>soc), true, "realized", > _abort); > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index 5aa3d2ddd9cd..c83b7e207b86 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -154,6 +154,8 @@ static void aspeed_soc_init(Object *obj) >"hw-strap1", _abort); > object_property_add_alias(obj, "hw-strap2", OBJECT(>scu), >"hw-strap2", _abort); > +object_property_add_alias(obj, "hw-prot-key", OBJECT(>scu), > + "hw-prot-key", _abort); > > object_initialize(>fmc, sizeof(s->fmc), sc->info->fmc_typename); > object_property_add_child(obj, "fmc", OBJECT(>fmc), NULL); > diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c > index 95022d3607ad..74537ce9755d 100644 > --- a/hw/misc/aspeed_scu.c > +++ b/hw/misc/aspeed_scu.c > @@ -85,7 +85,6 @@ > #define BMC_REV TO_REG(0x19C) > #define BMC_DEV_ID TO_REG(0x1A4) > > -#define PROT_KEY_UNLOCK 0x1688A8A8 > #define SCU_IO_REGION_SIZE 0x1000 > > static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { > @@ -192,7 +191,7 @@ static void aspeed_scu_write(void *opaque, hwaddr offset, > uint64_t data, > } > > if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && > -s->regs[PROT_KEY] != PROT_KEY_UNLOCK) { > +s->regs[PROT_KEY] != ASPEED_SCU_PROT_KEY) { > qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); > return; > } > @@ -246,6 +245,7 @@ static void aspeed_scu_reset(DeviceState *dev) > s->regs[SILICON_REV] = s->silicon_rev; > s->regs[HW_STRAP1] = s->hw_strap1; > s->regs[HW_STRAP2] = s->hw_strap2; > +s->regs[PROT_KEY] = s->hw_prot_key; > } > > static uint32_t aspeed_silicon_revs[] = { > @@ -299,6 +299,7 @@ static Property aspeed_scu_properties[] = { > DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0), > DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0), > DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0), > +DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0), > DEFINE_PROP_END_OF_LIST(), > }; > > diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h > index bd4ac013f997..d70cc0aeca61 100644 > --- a/include/hw/misc/aspeed_scu.h > +++ b/include/hw/misc/aspeed_scu.h > @@ -29,6 +29,7 @@ typedef struct AspeedSCUState { > uint32_t silicon_rev; > uint32_t hw_strap1; > uint32_t
Re: [Qemu-devel] [PATCH v2 1/6] aspeed: add support for the witherspoon-bmc board
On Wed, 2017-10-11 at 09:28 +0200, Cédric Le Goater wrote: > On 10/11/2017 05:49 AM, Andrew Jeffery wrote: > > On Tue, 2017-10-10 at 15:30 +0200, Cédric Le Goater wrote: > > > On 10/09/2017 02:04 AM, Andrew Jeffery wrote: > > > > On Wed, 2017-09-20 at 09:01 +0200, Cédric Le Goater wrote: > > > > > The Witherspoon boards are OpenPOWER system hosting POWER9 Processors. > > > > > Let's add support for their BMC including a couple of I2C devices as > > > > > found on real HW. > > > > > > > > > > > > > Signed-off-by: Cédric Le Goater <c...@kaod.org> > > > > > > > > > > --- > > > > > hw/arm/aspeed.c | 49 > > > > > + > > > > > 1 file changed, 49 insertions(+) > > > > > > > > > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > > > > > index ab895ad490af..81f522f711ae 100644 > > > > > --- a/hw/arm/aspeed.c > > > > > +++ b/hw/arm/aspeed.c > > > > > @@ -46,6 +46,7 @@ enum { > > > > > PALMETTO_BMC, > > > > > AST2500_EVB, > > > > > ROMULUS_BMC, > > > > > +WITHERSPOON_BMC, > > > > > }; > > > > > > > > > > /* Palmetto hardware value: 0x120CE416 */ > > > > > @@ -83,8 +84,12 @@ enum { > > > > > SCU_AST2500_HW_STRAP_ACPI_ENABLE | > > > > > \ > > > > > SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER)) > > > > > > > > > > +/* Witherspoon hardware value: 0xF10AD216 (but use romulus > > > > > definition) */ > > > > > +#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 > > > > > + > > > > > static void palmetto_bmc_i2c_init(AspeedBoardState *bmc); > > > > > static void ast2500_evb_i2c_init(AspeedBoardState *bmc); > > > > > +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc); > > > > > > > > > > static const AspeedBoardConfig aspeed_boards[] = { > > > > > [PALMETTO_BMC] = { > > > > > @@ -110,6 +115,14 @@ static const AspeedBoardConfig aspeed_boards[] = > > > > > { > > > > > .spi_model = "mx66l1g45g", > > > > > .num_cs= 2, > > > > > }, > > > > > +[WITHERSPOON_BMC] = { > > > > > +.soc_name = "ast2500-a1", > > > > > +.hw_strap1 = WITHERSPOON_BMC_HW_STRAP1, > > > > > +.fmc_model = "mx25l25635e", > > > > > +.spi_model = "mx66l1g45g", > > > > > +.num_cs= 2, > > > > > +.i2c_init = witherspoon_bmc_i2c_init, > > > > > +}, > > > > > }; > > > > > > > > > > #define FIRMWARE_ADDR 0x0 > > > > > @@ -337,11 +350,47 @@ static const TypeInfo romulus_bmc_type = { > > > > > .class_init = romulus_bmc_class_init, > > > > > }; > > > > > > > > > > +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) > > > > > +{ > > > > > +AspeedSoCState *soc = >soc; > > > > > + > > > > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 4), > > > > > "tmp423", 0x4c); > > > > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 5), > > > > > "tmp423", 0x4c); > > > > > + > > > > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 9), > > > > > "tmp105", 0x4a); > > > > > > > > Looks like I need to track down newer versions of the schematics I have. > > > > > > the device on the board is a tmp275 but the tmp105 model is compatible. > > > > It neither device is listed in the version I have :) > > Here is my source : > > > https://github.com/openbmc/linux/blob/dev-4.10/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts#L504 > Yeah, I ended up jumping on a machine and verifying the device was on the bus. Cheers, Andrew signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2 1/6] aspeed: add support for the witherspoon-bmc board
On Tue, 2017-10-10 at 15:30 +0200, Cédric Le Goater wrote: > On 10/09/2017 02:04 AM, Andrew Jeffery wrote: > > On Wed, 2017-09-20 at 09:01 +0200, Cédric Le Goater wrote: > > > The Witherspoon boards are OpenPOWER system hosting POWER9 Processors. > > > Let's add support for their BMC including a couple of I2C devices as > > > found on real HW. > > > > > > > > > Signed-off-by: Cédric Le Goater <c...@kaod.org> > > > --- > > > hw/arm/aspeed.c | 49 + > > > 1 file changed, 49 insertions(+) > > > > > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > > > index ab895ad490af..81f522f711ae 100644 > > > --- a/hw/arm/aspeed.c > > > +++ b/hw/arm/aspeed.c > > > @@ -46,6 +46,7 @@ enum { > > > PALMETTO_BMC, > > > AST2500_EVB, > > > ROMULUS_BMC, > > > +WITHERSPOON_BMC, > > > }; > > > > > > /* Palmetto hardware value: 0x120CE416 */ > > > @@ -83,8 +84,12 @@ enum { > > > SCU_AST2500_HW_STRAP_ACPI_ENABLE | \ > > > SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER)) > > > > > > +/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */ > > > +#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 > > > + > > > static void palmetto_bmc_i2c_init(AspeedBoardState *bmc); > > > static void ast2500_evb_i2c_init(AspeedBoardState *bmc); > > > +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc); > > > > > > static const AspeedBoardConfig aspeed_boards[] = { > > > [PALMETTO_BMC] = { > > > @@ -110,6 +115,14 @@ static const AspeedBoardConfig aspeed_boards[] = { > > > .spi_model = "mx66l1g45g", > > > .num_cs= 2, > > > }, > > > +[WITHERSPOON_BMC] = { > > > +.soc_name = "ast2500-a1", > > > +.hw_strap1 = WITHERSPOON_BMC_HW_STRAP1, > > > +.fmc_model = "mx25l25635e", > > > +.spi_model = "mx66l1g45g", > > > +.num_cs= 2, > > > +.i2c_init = witherspoon_bmc_i2c_init, > > > +}, > > > }; > > > > > > #define FIRMWARE_ADDR 0x0 > > > @@ -337,11 +350,47 @@ static const TypeInfo romulus_bmc_type = { > > > .class_init = romulus_bmc_class_init, > > > }; > > > > > > +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) > > > +{ > > > +AspeedSoCState *soc = >soc; > > > + > > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 4), "tmp423", > > > 0x4c); > > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 5), "tmp423", > > > 0x4c); > > > + > > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 9), "tmp105", > > > 0x4a); > > > > Looks like I need to track down newer versions of the schematics I have. > > the device on the board is a tmp275 but the tmp105 model is compatible. It neither device is listed in the version I have :) Andrew signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2 6/6] aspeed: add the pc9552 chips to the witherspoon machine
On Wed, 2017-09-20 at 09:01 +0200, Cédric Le Goater wrote: > The pca9552 LED blinkers on the Witherspoon machine are used for leds > but also as GPIOs to control fans and GPUs. > > Signed-off-by: Cédric Le Goater <c...@kaod.org> Reviewed-by: Andrew Jeffery <and...@aj.id.au> > --- > hw/arm/aspeed.c | 4 > 1 file changed, 4 insertions(+) > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > index 462f8008cff5..2ae46d71bff7 100644 > --- a/hw/arm/aspeed.c > +++ b/hw/arm/aspeed.c > @@ -379,6 +379,8 @@ static void witherspoon_bmc_i2c_init(AspeedBoardState > *bmc) > AspeedSoCState *soc = >soc; > uint8_t *eeprom_buf = g_malloc0(8 * 1024); > > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 3), "pca9552", > 0x60); > + > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 4), "tmp423", > 0x4c); > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 5), "tmp423", > 0x4c); > > @@ -390,6 +392,8 @@ static void witherspoon_bmc_i2c_init(AspeedBoardState > *bmc) > > smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(>i2c), 11), 0x51, > eeprom_buf); > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 11), "pca9552", > + 0x60); > } > > static void witherspoon_bmc_init(MachineState *machine) signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2 4/6] aspeed: Add EEPROM I2C devices
On Wed, 2017-09-20 at 09:01 +0200, Cédric Le Goater wrote: > The Aspeed boards have at least one EEPROM to hold the Vital Product > Data (VPD). > > Signed-off-by: Cédric Le Goater <c...@kaod.org> Reviewed-by: Andrew Jeffery <and...@aj.id.au> > --- > > Changes since v1: > > - fixed palmetto EEPROM size > - used smbus_eeprom_init_one() > > hw/arm/aspeed.c | 13 + > 1 file changed, 13 insertions(+) > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > index 362b683e9021..462f8008cff5 100644 > --- a/hw/arm/aspeed.c > +++ b/hw/arm/aspeed.c > @@ -17,6 +17,7 @@ > #include "hw/arm/arm.h" > #include "hw/arm/aspeed_soc.h" > #include "hw/boards.h" > +#include "hw/i2c/smbus.h" > #include "qemu/log.h" > #include "sysemu/block-backend.h" > #include "sysemu/blockdev.h" > @@ -255,11 +256,15 @@ static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) > { > AspeedSoCState *soc = >soc; > DeviceState *dev; > +uint8_t *eeprom_buf = g_malloc0(32 * 1024); > > /* The palmetto platform expects a ds3231 RTC but a ds1338 is > * enough to provide basic RTC features. Alarms will be missing */ > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 0), "ds1338", > 0x68); > > +smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(>i2c), 0), 0x50, > + eeprom_buf); > + > /* add a TMP423 temperature sensor */ > dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 2), > "tmp423", 0x4c); > @@ -297,6 +302,10 @@ static const TypeInfo palmetto_bmc_type = { > static void ast2500_evb_i2c_init(AspeedBoardState *bmc) > { > AspeedSoCState *soc = >soc; > +uint8_t *eeprom_buf = g_malloc0(8 * 1024); > + > +smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(>i2c), 3), 0x50, > + eeprom_buf); > > /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */ > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 7), "tmp105", > 0x4d); > @@ -368,6 +377,7 @@ static const TypeInfo romulus_bmc_type = { > static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) > { > AspeedSoCState *soc = >soc; > +uint8_t *eeprom_buf = g_malloc0(8 * 1024); > > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 4), "tmp423", > 0x4c); > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 5), "tmp423", > 0x4c); > @@ -377,6 +387,9 @@ static void witherspoon_bmc_i2c_init(AspeedBoardState > *bmc) > /* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is > * good enough */ > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 11), "ds1338", > 0x32); > + > +smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(>i2c), 11), 0x51, > + eeprom_buf); > } > > static void witherspoon_bmc_init(MachineState *machine) signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2 2/6] aspeed: add an I2C RTC device to all machines
On Wed, 2017-09-20 at 09:01 +0200, Cédric Le Goater wrote: > The AST2500 EVB does not have an RTC but we can pretend that one is > plugged on the I2C bus header. > > The romulus and witherspoon boards expects an Epson RX8900 I2C RTC but > a ds1338 is good enough for the basic features we need. > > Signed-off-by: Cédric Le Goater <c...@kaod.org> Reviewed-by: Andrew Jeffery <and...@aj.id.au> > --- > hw/arm/aspeed.c | 19 +++ > 1 file changed, 19 insertions(+) > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > index 81f522f711ae..362b683e9021 100644 > --- a/hw/arm/aspeed.c > +++ b/hw/arm/aspeed.c > @@ -89,6 +89,7 @@ enum { > > static void palmetto_bmc_i2c_init(AspeedBoardState *bmc); > static void ast2500_evb_i2c_init(AspeedBoardState *bmc); > +static void romulus_bmc_i2c_init(AspeedBoardState *bmc); > static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc); > > static const AspeedBoardConfig aspeed_boards[] = { > @@ -114,6 +115,7 @@ static const AspeedBoardConfig aspeed_boards[] = { > .fmc_model = "n25q256a", > .spi_model = "mx66l1g45g", > .num_cs= 2, > +.i2c_init = romulus_bmc_i2c_init, > }, > [WITHERSPOON_BMC] = { > .soc_name = "ast2500-a1", > @@ -298,6 +300,10 @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc) > > /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */ > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 7), "tmp105", > 0x4d); > + > +/* The AST2500 EVB does not have an RTC. Let's pretend that one is > + * plugged on the I2C bus header */ > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 11), "ds1338", > 0x32); > } > > static void ast2500_evb_init(MachineState *machine) > @@ -325,6 +331,15 @@ static const TypeInfo ast2500_evb_type = { > .class_init = ast2500_evb_class_init, > }; > > +static void romulus_bmc_i2c_init(AspeedBoardState *bmc) > +{ > +AspeedSoCState *soc = >soc; > + > +/* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is > + * good enough */ > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 11), "ds1338", > 0x32); > +} > + > static void romulus_bmc_init(MachineState *machine) > { > aspeed_board_init(machine, _boards[ROMULUS_BMC]); > @@ -358,6 +373,10 @@ static void witherspoon_bmc_i2c_init(AspeedBoardState > *bmc) > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 5), "tmp423", > 0x4c); > > i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 9), "tmp105", > 0x4a); > + > +/* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is > + * good enough */ > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 11), "ds1338", > 0x32); > } > > static void witherspoon_bmc_init(MachineState *machine) signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2 1/6] aspeed: add support for the witherspoon-bmc board
On Wed, 2017-09-20 at 09:01 +0200, Cédric Le Goater wrote: > The Witherspoon boards are OpenPOWER system hosting POWER9 Processors. > Let's add support for their BMC including a couple of I2C devices as > found on real HW. > > Signed-off-by: Cédric Le Goater <c...@kaod.org> > --- > hw/arm/aspeed.c | 49 + > 1 file changed, 49 insertions(+) > > diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c > index ab895ad490af..81f522f711ae 100644 > --- a/hw/arm/aspeed.c > +++ b/hw/arm/aspeed.c > @@ -46,6 +46,7 @@ enum { > PALMETTO_BMC, > AST2500_EVB, > ROMULUS_BMC, > +WITHERSPOON_BMC, > }; > > /* Palmetto hardware value: 0x120CE416 */ > @@ -83,8 +84,12 @@ enum { > SCU_AST2500_HW_STRAP_ACPI_ENABLE | \ > SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER)) > > +/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */ > +#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 > + > static void palmetto_bmc_i2c_init(AspeedBoardState *bmc); > static void ast2500_evb_i2c_init(AspeedBoardState *bmc); > +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc); > > static const AspeedBoardConfig aspeed_boards[] = { > [PALMETTO_BMC] = { > @@ -110,6 +115,14 @@ static const AspeedBoardConfig aspeed_boards[] = { > .spi_model = "mx66l1g45g", > .num_cs= 2, > }, > +[WITHERSPOON_BMC] = { > +.soc_name = "ast2500-a1", > +.hw_strap1 = WITHERSPOON_BMC_HW_STRAP1, > +.fmc_model = "mx25l25635e", > +.spi_model = "mx66l1g45g", > +.num_cs= 2, > +.i2c_init = witherspoon_bmc_i2c_init, > +}, > }; > > #define FIRMWARE_ADDR 0x0 > @@ -337,11 +350,47 @@ static const TypeInfo romulus_bmc_type = { > .class_init = romulus_bmc_class_init, > }; > > +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) > +{ > +AspeedSoCState *soc = >soc; > + > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 4), "tmp423", > 0x4c); > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 5), "tmp423", > 0x4c); > + > +i2c_create_slave(aspeed_i2c_get_bus(DEVICE(>i2c), 9), "tmp105", > 0x4a); Looks like I need to track down newer versions of the schematics I have. > +} > + > +static void witherspoon_bmc_init(MachineState *machine) > +{ > +aspeed_board_init(machine, _boards[WITHERSPOON_BMC]); > +} > + > +static void witherspoon_bmc_class_init(ObjectClass *oc, void *data) > +{ > +MachineClass *mc = MACHINE_CLASS(oc); > + > +mc->desc = "OpenPOWER Witherspoon BMC (ARM1176)"; > +mc->init = witherspoon_bmc_init; > +mc->max_cpus = 1; > +mc->no_sdcard = 1; > +mc->no_floppy = 1; > +mc->no_cdrom = 1; > +mc->no_parallel = 1; > +mc->ignore_memory_transaction_failures = true; Aside from the issue with the above as pointed out by Peter, Reviewed-by: Andrew Jeffery <and...@aj.id.au> > +} > + > +static const TypeInfo witherspoon_bmc_type = { > +.name = MACHINE_TYPE_NAME("witherspoon-bmc"), > +.parent = TYPE_MACHINE, > +.class_init = witherspoon_bmc_class_init, > +}; > + > static void aspeed_machine_init(void) > { > type_register_static(_bmc_type); > type_register_static(_evb_type); > type_register_static(_bmc_type); > +type_register_static(_bmc_type); > } > > type_init(aspeed_machine_init) signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH v2] watchdog/aspeed: fix variable type to store reload value
On Wed, 2017-09-20 at 08:49 +0200, Cédric Le Goater wrote: > Initially from Anton D. Kachalov" <mo...@yandex-team.ru> but the SoB was > missing. > > Signed-off-by: Cédric Le Goater <c...@kaod.org> > [clg: change commit log and subject > replace UL suffix by ULL ] > Signed-off-by: Cédric Le Goater <c...@kaod.org> Acked-by: Andrew Jeffery <and...@aj.id.au> > --- > hw/watchdog/wdt_aspeed.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > index 22bce364d7b5..95f6ad186d72 100644 > --- a/hw/watchdog/wdt_aspeed.c > +++ b/hw/watchdog/wdt_aspeed.c > @@ -100,13 +100,13 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr > offset, unsigned size) > > static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk) > { > -uint32_t reload; > +uint64_t reload; > > if (pclk) { > reload = muldiv64(s->regs[WDT_RELOAD_VALUE], NANOSECONDS_PER_SECOND, > s->pclk_freq); > } else { > -reload = s->regs[WDT_RELOAD_VALUE] * 1000; > +reload = s->regs[WDT_RELOAD_VALUE] * 1000ULL; > } > > if (aspeed_wdt_is_enabled(s)) { signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH for 2.11 v2 1/2] watchdog: wdt_aspeed: Add support for the reset width register
On Wed, Aug 9, 2017, at 18:28, Cédric Le Goater wrote: > On 08/09/2017 08:28 AM, Andrew Jeffery wrote: > > The reset width register controls how the pulse on the SoC's WDTRST{1,2} > > pins behaves. A pulse is emitted if the external reset bit is set in > > WDT_CTRL. On the AST2500 WDT_RESET_WIDTH can consume magic bit patterns > > to configure push-pull/open-drain and active-high/active-low > > behaviours and thus needs some special handling in the write path. > > > > As some of the capabilities depend on the SoC version a silicon-rev > > property is introduced, which is used to guard version-specific > > behaviour. > > > > Signed-off-by: Andrew Jeffery <and...@aj.id.au> > > One minor comment below. Nevertheless : > > Reviewed-by: Cédric Le Goater <c...@kaod.org> > > > --- > > hw/watchdog/wdt_aspeed.c | 93 > > +++- > > include/hw/watchdog/wdt_aspeed.h | 2 + > > 2 files changed, 84 insertions(+), 11 deletions(-) > > > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > > index 8bbe579b6b66..22bce364d7b5 100644 > > --- a/hw/watchdog/wdt_aspeed.c > > +++ b/hw/watchdog/wdt_aspeed.c > > @@ -8,16 +8,19 @@ > > */ > > > > #include "qemu/osdep.h" > > + > > +#include "qapi/error.h" > > #include "qemu/log.h" > > +#include "qemu/timer.h" > > #include "sysemu/watchdog.h" > > +#include "hw/misc/aspeed_scu.h" > > #include "hw/sysbus.h" > > -#include "qemu/timer.h" > > #include "hw/watchdog/wdt_aspeed.h" > > > > -#define WDT_STATUS (0x00 / 4) > > -#define WDT_RELOAD_VALUE(0x04 / 4) > > -#define WDT_RESTART (0x08 / 4) > > -#define WDT_CTRL(0x0C / 4) > > +#define WDT_STATUS (0x00 / 4) > > +#define WDT_RELOAD_VALUE(0x04 / 4) > > +#define WDT_RESTART (0x08 / 4) > > +#define WDT_CTRL(0x0C / 4) > > #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) > > #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) > > #define WDT_CTRL_1MHZ_CLK BIT(4) > > @@ -25,18 +28,41 @@ > > #define WDT_CTRL_WDT_INTR BIT(2) > > #define WDT_CTRL_RESET_SYSTEM BIT(1) > > #define WDT_CTRL_ENABLE BIT(0) > > +#define WDT_RESET_WIDTH (0x18 / 4) > > +#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) > > +#define WDT_POLARITY_MASK (0xFF << 24) > > +#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) > > +#define WDT_ACTIVE_LOW_MAGIC(0x5A << 24) > > +#define WDT_RESET_WIDTH_PUSH_PULL BIT(30) > > +#define WDT_DRIVE_TYPE_MASK (0xFF << 24) > > +#define WDT_PUSH_PULL_MAGIC (0xA8 << 24) > > +#define WDT_OPEN_DRAIN_MAGIC(0x8A << 24) > > > > -#define WDT_TIMEOUT_STATUS (0x10 / 4) > > -#define WDT_TIMEOUT_CLEAR (0x14 / 4) > > -#define WDT_RESET_WDITH (0x18 / 4) > > +#define WDT_TIMEOUT_STATUS (0x10 / 4) > > +#define WDT_TIMEOUT_CLEAR (0x14 / 4) > > > > -#define WDT_RESTART_MAGIC 0x4755 > > +#define WDT_RESTART_MAGIC 0x4755 > > > > static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) > > { > > return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE; > > } > > > > +static bool is_ast2500(const AspeedWDTState *s) > > I think we could use this routine in other controllers (scu, sdmc). > So may be, in a follow-up patch, we could move it in aspeed_scu.h Right, I figured we would move it when we came to need it elsewhere. Thanks for the review. Cheers, Andrew > > Thanks, > > C. > > > +{ > > +switch (s->silicon_rev) { > > +case AST2500_A0_SILICON_REV: > > +case AST2500_A1_SILICON_REV: > > +return true; > > +case AST2400_A0_SILICON_REV: > > +case AST2400_A1_SILICON_REV: > > +default: > > +break; > > +} > > + > > +return false; > > +} > > + > > static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) > > { > > AspeedWDTState *s = ASPEED_WDT(opaque); > > @@ -55,9 +81,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr > > offset, unsigned size) > > return 0; > > case WDT
Re: [Qemu-devel] [PATCH for 2.11 v2 2/2] ARM: aspeed_soc: Propagate silicon-rev to watchdog
Ugh, disregard this one; I changed the subject and reissued `git format-patch`, which naturally doesn't overwrite any existing patch in the output directory and so the old one got sent as well. Andrew On Wed, 2017-08-09 at 15:58 +0930, Andrew Jeffery wrote: > This is required to configure differences in behaviour between the > AST2400 and AST2500 watchdog IPs. > > Signed-off-by: Andrew Jeffery <and...@aj.id.au> > --- > hw/arm/aspeed_soc.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index 3034849c80bf..79804e1ee652 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -183,6 +183,8 @@ static void aspeed_soc_init(Object *obj) > object_initialize(>wdt[i], sizeof(s->wdt[i]), > TYPE_ASPEED_WDT); > object_property_add_child(obj, "wdt[*]", OBJECT(>wdt[i]), > NULL); > qdev_set_parent_bus(DEVICE(>wdt[i]), > sysbus_get_default()); > +qdev_prop_set_uint32(DEVICE(>wdt[i]), "silicon-rev", > +sc->info->silicon_rev); > } > > object_initialize(>ftgmac100, sizeof(s->ftgmac100), > TYPE_FTGMAC100); signature.asc Description: This is a digitally signed message part
[Qemu-devel] [PATCH for 2.11 v2 2/2] aspeed_soc: Propagate silicon-rev to watchdog
This is required to configure differences in behaviour between the AST2400 and AST2500 watchdog IPs. Signed-off-by: Andrew Jeffery <and...@aj.id.au> --- hw/arm/aspeed_soc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 3034849c80bf..79804e1ee652 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -183,6 +183,8 @@ static void aspeed_soc_init(Object *obj) object_initialize(>wdt[i], sizeof(s->wdt[i]), TYPE_ASPEED_WDT); object_property_add_child(obj, "wdt[*]", OBJECT(>wdt[i]), NULL); qdev_set_parent_bus(DEVICE(>wdt[i]), sysbus_get_default()); +qdev_prop_set_uint32(DEVICE(>wdt[i]), "silicon-rev", +sc->info->silicon_rev); } object_initialize(>ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100); -- 2.11.0
[Qemu-devel] [PATCH for 2.11 v2 1/2] watchdog: wdt_aspeed: Add support for the reset width register
The reset width register controls how the pulse on the SoC's WDTRST{1,2} pins behaves. A pulse is emitted if the external reset bit is set in WDT_CTRL. On the AST2500 WDT_RESET_WIDTH can consume magic bit patterns to configure push-pull/open-drain and active-high/active-low behaviours and thus needs some special handling in the write path. As some of the capabilities depend on the SoC version a silicon-rev property is introduced, which is used to guard version-specific behaviour. Signed-off-by: Andrew Jeffery <and...@aj.id.au> --- hw/watchdog/wdt_aspeed.c | 93 +++- include/hw/watchdog/wdt_aspeed.h | 2 + 2 files changed, 84 insertions(+), 11 deletions(-) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 8bbe579b6b66..22bce364d7b5 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -8,16 +8,19 @@ */ #include "qemu/osdep.h" + +#include "qapi/error.h" #include "qemu/log.h" +#include "qemu/timer.h" #include "sysemu/watchdog.h" +#include "hw/misc/aspeed_scu.h" #include "hw/sysbus.h" -#include "qemu/timer.h" #include "hw/watchdog/wdt_aspeed.h" -#define WDT_STATUS (0x00 / 4) -#define WDT_RELOAD_VALUE(0x04 / 4) -#define WDT_RESTART (0x08 / 4) -#define WDT_CTRL(0x0C / 4) +#define WDT_STATUS (0x00 / 4) +#define WDT_RELOAD_VALUE(0x04 / 4) +#define WDT_RESTART (0x08 / 4) +#define WDT_CTRL(0x0C / 4) #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) #define WDT_CTRL_1MHZ_CLK BIT(4) @@ -25,18 +28,41 @@ #define WDT_CTRL_WDT_INTR BIT(2) #define WDT_CTRL_RESET_SYSTEM BIT(1) #define WDT_CTRL_ENABLE BIT(0) +#define WDT_RESET_WIDTH (0x18 / 4) +#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) +#define WDT_POLARITY_MASK (0xFF << 24) +#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) +#define WDT_ACTIVE_LOW_MAGIC(0x5A << 24) +#define WDT_RESET_WIDTH_PUSH_PULL BIT(30) +#define WDT_DRIVE_TYPE_MASK (0xFF << 24) +#define WDT_PUSH_PULL_MAGIC (0xA8 << 24) +#define WDT_OPEN_DRAIN_MAGIC(0x8A << 24) -#define WDT_TIMEOUT_STATUS (0x10 / 4) -#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESET_WDITH (0x18 / 4) +#define WDT_TIMEOUT_STATUS (0x10 / 4) +#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESTART_MAGIC 0x4755 +#define WDT_RESTART_MAGIC 0x4755 static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) { return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE; } +static bool is_ast2500(const AspeedWDTState *s) +{ +switch (s->silicon_rev) { +case AST2500_A0_SILICON_REV: +case AST2500_A1_SILICON_REV: +return true; +case AST2400_A0_SILICON_REV: +case AST2400_A1_SILICON_REV: +default: +break; +} + +return false; +} + static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) { AspeedWDTState *s = ASPEED_WDT(opaque); @@ -55,9 +81,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) return 0; case WDT_CTRL: return s->regs[WDT_CTRL]; +case WDT_RESET_WIDTH: +return s->regs[WDT_RESET_WIDTH]; case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: -case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -119,9 +146,27 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, timer_del(s->timer); } break; +case WDT_RESET_WIDTH: +{ +uint32_t property = data & WDT_POLARITY_MASK; + +if (property && is_ast2500(s)) { +if (property == WDT_ACTIVE_HIGH_MAGIC) { +s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH; +} else if (property == WDT_ACTIVE_LOW_MAGIC) { +s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH; +} else if (property == WDT_PUSH_PULL_MAGIC) { +s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL; +} else if (property == WDT_OPEN_DRAIN_MAGIC) { +s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL; +} +} +s->regs[WDT_RESET_WIDTH] &= ~s->ext_pulse_width_mask; +s->regs[WDT_RESET_WIDTH] |= data & s->ext_pulse_width_mask; +break; +} case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: -case WDT_RE
[Qemu-devel] [PATCH for 2.11 v2 2/2] ARM: aspeed_soc: Propagate silicon-rev to watchdog
This is required to configure differences in behaviour between the AST2400 and AST2500 watchdog IPs. Signed-off-by: Andrew Jeffery <and...@aj.id.au> --- hw/arm/aspeed_soc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 3034849c80bf..79804e1ee652 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -183,6 +183,8 @@ static void aspeed_soc_init(Object *obj) object_initialize(>wdt[i], sizeof(s->wdt[i]), TYPE_ASPEED_WDT); object_property_add_child(obj, "wdt[*]", OBJECT(>wdt[i]), NULL); qdev_set_parent_bus(DEVICE(>wdt[i]), sysbus_get_default()); +qdev_prop_set_uint32(DEVICE(>wdt[i]), "silicon-rev", +sc->info->silicon_rev); } object_initialize(>ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100); -- 2.11.0
[Qemu-devel] [PATCH for 2.11 v2 0/2] wdt_aspeed: Support reset width patterns
Hello, These two patches add support for the reset width configuration register in the Aspeed watchdog. Initially this was just one patch[1], but I've reworked it as two to explicitly support the varying capabilities between Aspeed SoC versions. Andrew [1] http://patchwork.ozlabs.org/patch/796039/ Andrew Jeffery (2): watchdog: wdt_aspeed: Add support for the reset width register aspeed_soc: Propagate silicon-rev to watchdog hw/arm/aspeed_soc.c | 2 + hw/watchdog/wdt_aspeed.c | 93 +++- include/hw/watchdog/wdt_aspeed.h | 2 + 3 files changed, 86 insertions(+), 11 deletions(-) -- 2.11.0
Re: [Qemu-devel] [PATCH] watchdog: wdt_aspeed: Add support for the reset width register
On Tue, 2017-08-01 at 09:21 +0200, Cédric Le Goater wrote: > On 08/01/2017 03:04 AM, Andrew Jeffery wrote: > > The reset width register controls how the pulse on the SoC's WDTRST{1,2} > > pins behaves. A pulse is emitted if the external reset bit is set in > > WDT_CTRL. WDT_RESET_WIDTH requires magic bit patterns to configure both > > push-pull/open-drain and active-high/active-low behaviours and thus > > needs some special handling in the write path. > > > > > > Signed-off-by: Andrew Jeffery <and...@aj.id.au> > > --- > > I understand that we're in stabilisation mode, but I thought I'd send this > > out > > to provoke any feedback. Happy to resend after the 2.10 release if required. > > > > hw/watchdog/wdt_aspeed.c | 47 > > +-- > > 1 file changed, 37 insertions(+), 10 deletions(-) > > > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > > index 8bbe579b6b66..4ef1412e99fc 100644 > > --- a/hw/watchdog/wdt_aspeed.c > > +++ b/hw/watchdog/wdt_aspeed.c > > @@ -14,10 +14,10 @@ > > #include "qemu/timer.h" > > #include "hw/watchdog/wdt_aspeed.h" > > > > -#define WDT_STATUS (0x00 / 4) > > -#define WDT_RELOAD_VALUE(0x04 / 4) > > -#define WDT_RESTART (0x08 / 4) > > -#define WDT_CTRL(0x0C / 4) > > +#define WDT_STATUS (0x00 / 4) > > +#define WDT_RELOAD_VALUE(0x04 / 4) > > +#define WDT_RESTART (0x08 / 4) > > +#define WDT_CTRL(0x0C / 4) > > #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) > > #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) > > #define WDT_CTRL_1MHZ_CLK BIT(4) > > @@ -25,12 +25,21 @@ > > #define WDT_CTRL_WDT_INTR BIT(2) > > #define WDT_CTRL_RESET_SYSTEM BIT(1) > > #define WDT_CTRL_ENABLE BIT(0) > > +#define WDT_RESET_WIDTH (0x18 / 4) > > +#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) > > +#define WDT_POLARITY_MASK (0xFF << 24) > > +#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) > > +#define WDT_ACTIVE_LOW_MAGIC(0x5A << 24) > > +#define WDT_RESET_WIDTH_PUSH_PULL BIT(30) > > +#define WDT_DRIVE_TYPE_MASK (0xFF << 24) > > +#define WDT_PUSH_PULL_MAGIC (0xA8 << 24) > > +#define WDT_OPEN_DRAIN_MAGIC(0x8A << 24) > > +#define WDT_RESET_WIDTH_DURATION 0xFFF; > > I would call this define WDT_RESET_WIDTH_DEFAULT (0xFF) and > use it also in the aspeed_wdt_reset() This WDT_RESET_WIDTH_DURATION is intended as a mask. It's probably poorly named. As I found when replying to Phil, the width actually varies between the AST2400 and AST2500, and on the AST2500 is actually 20 bits wide, not 12 (and is 8 bits on the AST2400). I'll need to respin to fix that. On the otherhand, 0xFF is the default value for the field on both the AST2400 and AST2500. > > I have checked the specs and the bits definitions are correct. > What else could we model ? Would the pulse be interesting ? Hrm, we could. In Witherspoon (and Romulus?) systems the pulse is being used to drive the FAULT pin on the MAX31785 fan controller. I've got some very hacky patches lying around adding PMBus support and a basic MAX31785 model to QEMU - with a bit of extra work we could hook up the external watchdog signal to the FAULT pin and drive our virtual fans to 100% PWM duty as per the hardware. It's not high on my todo list though :) Andrew > > C. > > > > > > -#define WDT_TIMEOUT_STATUS (0x10 / 4) > > -#define WDT_TIMEOUT_CLEAR (0x14 / 4) > > -#define WDT_RESET_WDITH (0x18 / 4) > > +#define WDT_TIMEOUT_STATUS (0x10 / 4) > > +#define WDT_TIMEOUT_CLEAR (0x14 / 4) > > > > -#define WDT_RESTART_MAGIC 0x4755 > > +#define WDT_RESTART_MAGIC 0x4755 > > > > static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) > > { > > @@ -55,9 +64,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr > > offset, unsigned size) > > return 0; > > case WDT_CTRL: > > return s->regs[WDT_CTRL]; > > +case WDT_RESET_WIDTH: > > +return s->regs[WDT_RESET_WIDTH]; > > case WDT_TIMEOUT_STATUS: > > case WDT_TIMEOUT_CLEAR: > > -case WDT_RESET_WDITH: > > qemu_log_mask(LOG_UNIMP, > > "%s: uninmplemented read at offset 0
Re: [Qemu-devel] [Qemu-arm] [PATCH] watchdog: wdt_aspeed: Add support for the reset width register
Hi Phil, On Tue, 2017-08-01 at 00:23 -0300, Philippe Mathieu-Daudé wrote: > Hi Andrew, > > On 07/31/2017 10:04 PM, Andrew Jeffery wrote: > > The reset width register controls how the pulse on the SoC's WDTRST{1,2} > > pins behaves. A pulse is emitted if the external reset bit is set in > > WDT_CTRL. WDT_RESET_WIDTH requires magic bit patterns to configure both > > push-pull/open-drain and active-high/active-low behaviours and thus > > needs some special handling in the write path. > > I wanted to verify the datashit but it seems to unavailable, looking there: > https://www.verical.com/datasheet/aspeed-technology-inc-interface-misc-ast2050a3-gp-4078885.pdf > > Can you point out which cpu model you are modeling and where to get this > watchdog datashit please? You might also add this to the header, for the > next one looking at this file :) The watchdog model is common to at least the Aspeed AST2400- and AST2500- SoC families, which I have datasheets for. However, they are not available to the public and therefore (unfortunately) I can't point you to them. You may be able to access them if you have appropriate arrangements with Aspeed. Regarding the features exposed by the patch, configuration of the electrical properties of the external reset signal is only provided in the AST2500's watchdog IP, but the bits used in the reset width register are marked as reserved on the AST2400. Therefore I thought it was reasonable not to guard them behind some kind of revision test. > > > > > > > Signed-off-by: Andrew Jeffery <and...@aj.id.au> > > --- > > I understand that we're in stabilisation mode, but I thought I'd send this > > out > > to provoke any feedback. Happy to resend after the 2.10 release if required. > > you can subject it "PATCH for 2.11" so ppl testing/closing 2.10 can keep > focused but still queue your mail for when 2.10 release is out. Thanks for the tip. > > > > > hw/watchdog/wdt_aspeed.c | 47 > > +-- > > 1 file changed, 37 insertions(+), 10 deletions(-) > > > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > > index 8bbe579b6b66..4ef1412e99fc 100644 > > --- a/hw/watchdog/wdt_aspeed.c > > +++ b/hw/watchdog/wdt_aspeed.c > > @@ -14,10 +14,10 @@ > > #include "qemu/timer.h" > > #include "hw/watchdog/wdt_aspeed.h" > > > > -#define WDT_STATUS (0x00 / 4) > > -#define WDT_RELOAD_VALUE(0x04 / 4) > > -#define WDT_RESTART (0x08 / 4) > > -#define WDT_CTRL(0x0C / 4) > > +#define WDT_STATUS (0x00 / 4) > > +#define WDT_RELOAD_VALUE(0x04 / 4) > > +#define WDT_RESTART (0x08 / 4) > > +#define WDT_CTRL(0x0C / 4) > > #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) > > #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) > > #define WDT_CTRL_1MHZ_CLK BIT(4) > > @@ -25,12 +25,21 @@ > > #define WDT_CTRL_WDT_INTR BIT(2) > > #define WDT_CTRL_RESET_SYSTEM BIT(1) > > #define WDT_CTRL_ENABLE BIT(0) > > +#define WDT_RESET_WIDTH (0x18 / 4) > > +#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) > > +#define WDT_POLARITY_MASK (0xFF << 24) > > +#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) > > +#define WDT_ACTIVE_LOW_MAGIC(0x5A << 24) > > +#define WDT_RESET_WIDTH_PUSH_PULL BIT(30) > > +#define WDT_DRIVE_TYPE_MASK (0xFF << 24) > > +#define WDT_PUSH_PULL_MAGIC (0xA8 << 24) > > +#define WDT_OPEN_DRAIN_MAGIC(0x8A << 24) > > +#define WDT_RESET_WIDTH_DURATION 0xFFF; > > Which model? the AST2050 seems to be 0xff. Ah, good catch, this is also the case in the AST2400. The AST2500 extends this field. Host code for the AST2400 and AST2050 *shouldn't* set any greater values; is it worth enforcing? > > > > > -#define WDT_TIMEOUT_STATUS (0x10 / 4) > > -#define WDT_TIMEOUT_CLEAR (0x14 / 4) > > -#define WDT_RESET_WDITH (0x18 / 4) > > +#define WDT_TIMEOUT_STATUS (0x10 / 4) > > +#define WDT_TIMEOUT_CLEAR (0x14 / 4) > > > > -#define WDT_RESTART_MAGIC 0x4755 > > +#define WDT_RESTART_MAGIC 0x4755 > > > > static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) > > { > > @@ -55,9 +64,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr > > offset, unsigned s
[Qemu-devel] [PATCH] watchdog: wdt_aspeed: Add support for the reset width register
The reset width register controls how the pulse on the SoC's WDTRST{1,2} pins behaves. A pulse is emitted if the external reset bit is set in WDT_CTRL. WDT_RESET_WIDTH requires magic bit patterns to configure both push-pull/open-drain and active-high/active-low behaviours and thus needs some special handling in the write path. Signed-off-by: Andrew Jeffery <and...@aj.id.au> --- I understand that we're in stabilisation mode, but I thought I'd send this out to provoke any feedback. Happy to resend after the 2.10 release if required. hw/watchdog/wdt_aspeed.c | 47 +-- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 8bbe579b6b66..4ef1412e99fc 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -14,10 +14,10 @@ #include "qemu/timer.h" #include "hw/watchdog/wdt_aspeed.h" -#define WDT_STATUS (0x00 / 4) -#define WDT_RELOAD_VALUE(0x04 / 4) -#define WDT_RESTART (0x08 / 4) -#define WDT_CTRL(0x0C / 4) +#define WDT_STATUS (0x00 / 4) +#define WDT_RELOAD_VALUE(0x04 / 4) +#define WDT_RESTART (0x08 / 4) +#define WDT_CTRL(0x0C / 4) #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) #define WDT_CTRL_1MHZ_CLK BIT(4) @@ -25,12 +25,21 @@ #define WDT_CTRL_WDT_INTR BIT(2) #define WDT_CTRL_RESET_SYSTEM BIT(1) #define WDT_CTRL_ENABLE BIT(0) +#define WDT_RESET_WIDTH (0x18 / 4) +#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) +#define WDT_POLARITY_MASK (0xFF << 24) +#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) +#define WDT_ACTIVE_LOW_MAGIC(0x5A << 24) +#define WDT_RESET_WIDTH_PUSH_PULL BIT(30) +#define WDT_DRIVE_TYPE_MASK (0xFF << 24) +#define WDT_PUSH_PULL_MAGIC (0xA8 << 24) +#define WDT_OPEN_DRAIN_MAGIC(0x8A << 24) +#define WDT_RESET_WIDTH_DURATION 0xFFF; -#define WDT_TIMEOUT_STATUS (0x10 / 4) -#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESET_WDITH (0x18 / 4) +#define WDT_TIMEOUT_STATUS (0x10 / 4) +#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESTART_MAGIC 0x4755 +#define WDT_RESTART_MAGIC 0x4755 static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) { @@ -55,9 +64,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) return 0; case WDT_CTRL: return s->regs[WDT_CTRL]; +case WDT_RESET_WIDTH: +return s->regs[WDT_RESET_WIDTH]; case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: -case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -119,9 +129,25 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, timer_del(s->timer); } break; +case WDT_RESET_WIDTH: +{ +uint32_t property = data & WDT_POLARITY_MASK; + +if (property == WDT_ACTIVE_HIGH_MAGIC) { +s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH; +} else if (property == WDT_ACTIVE_LOW_MAGIC) { +s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH; +} else if (property == WDT_PUSH_PULL_MAGIC) { +s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL; +} else if (property == WDT_OPEN_DRAIN_MAGIC) { +s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL; +} +s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_DURATION; +s->regs[WDT_RESET_WIDTH] |= data & WDT_RESET_WIDTH_DURATION; +break; +} case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: -case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -167,6 +193,7 @@ static void aspeed_wdt_reset(DeviceState *dev) s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; s->regs[WDT_RESTART] = 0; s->regs[WDT_CTRL] = 0; +s->regs[WDT_RESET_WIDTH] = 0XFF; timer_del(s->timer); } -- 2.11.0
Re: [Qemu-devel] [RFC PATCH 1/1] memory: Support unaligned accesses on aligned-only models
Hi Paolo, Thanks for taking a look! On Thu, 2017-07-13 at 14:05 +0200, Paolo Bonzini wrote: > On 30/06/2017 05:00, Andrew Jeffery wrote: > > This RFC patch stems from a discussion on a patch for an ADC model[1] where > > it > > was pointed out that I should be able to use the .impl member of > > MemoryRegionOps to constrain how my read() and write() callbacks where > > invoked. > > > > I tried Phil's suggested approach and found I got reads of size 4, but with > > an > > address that was not 4-byte aligned. > > > > Looking at the source for access_with_adjusted_size() lead to the comment > > > > /* FIXME: support unaligned access? */ > > > > which at least suggests that the implementation isn't complete. > > > > So, this patch is a quick and incomplete attempt at resolving the issue to > > see > > whether I'm on the right track or way off in the weeds. > > > > I've lightly tested it with the ADC model mentioned above, and it appears > > to do > > the right thing (I changed the values generated by the ADC to distinguish > > between the lower and upper 16 bits). > > I think the idea is okay. > > > +access_addr[0] = align_down(addr, access_size); > > +access_addr[1] = align_up(addr + size, access_size); > > + > > +for (cur = access_addr[0]; cur < access_addr[1]; cur += > > access_size) { > > +uint64_t mask_bounds[2]; > > +mask_bounds[0] = MAX(addr, cur) - cur; > > +mask_bounds[1] = > > +MIN(addr + size, align_up(cur + 1, access_size)) - cur; > > + > > +access_mask = (-1ULL << mask_bounds[0] * 8) & > > +(-1ULL >> (64 - mask_bounds[1] * 8)); > > Please use MAKE_64BIT_MASK. Okay. > > > +r |= access(mr, cur, _value, access_size, > > + (MAX(addr, cur) - addr), access_mask, attrs); > > + > > +/* XXX: Can't do this hack for writes */ > > +access_value >>= mask_bounds[0] * 8; > > +} > > Can you subtract access_addr[0] from mask_bounds[0] and mask_bounds[1] > (instead of cur) to remove the need for this right shift? I haven't looked at the patch since I sent it. Given you think the idea of the patch is okay I'll get back to working on it and think about this. Cheers, Andrew > > Thanks, > > Paolo signature.asc Description: This is a digitally signed message part
[Qemu-devel] [RFC PATCH 1/1] memory: Support unaligned accesses on aligned-only models
Signed-off-by: Andrew Jeffery <and...@aj.id.au> --- Hello, This RFC patch stems from a discussion on a patch for an ADC model[1] where it was pointed out that I should be able to use the .impl member of MemoryRegionOps to constrain how my read() and write() callbacks where invoked. I tried Phil's suggested approach and found I got reads of size 4, but with an address that was not 4-byte aligned. Looking at the source for access_with_adjusted_size() lead to the comment /* FIXME: support unaligned access? */ which at least suggests that the implementation isn't complete. So, this patch is a quick and incomplete attempt at resolving the issue to see whether I'm on the right track or way off in the weeds. I've lightly tested it with the ADC model mentioned above, and it appears to do the right thing (I changed the values generated by the ADC to distinguish between the lower and upper 16 bits). Things the patch is not: 1. Capable of handling unaligned writes 2. Tested on big-endian models If the general idea of the patch is reasonable I'll look to resolve the above to points. Cheers, Andrew [1] http://lists.nongnu.org/archive/html/qemu-arm/2017-05/msg00400.html memory.c | 144 +++ 1 file changed, 137 insertions(+), 7 deletions(-) diff --git a/memory.c b/memory.c index 0ddc4cc28deb..b9fae8d382bc 100644 --- a/memory.c +++ b/memory.c @@ -432,6 +432,7 @@ static MemTxResult memory_region_read_accessor(MemoryRegion *mr, { uint64_t tmp; + tmp = mr->ops->read(mr->opaque, addr, size); if (mr->subpage) { trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size); @@ -552,7 +553,7 @@ static MemTxResult memory_region_write_with_attrs_accessor(MemoryRegion *mr, return mr->ops->write_with_attrs(mr->opaque, addr, tmp, size, attrs); } -static MemTxResult access_with_adjusted_size(hwaddr addr, +static MemTxResult access_with_adjusted_size_aligned(hwaddr addr, uint64_t *value, unsigned size, unsigned access_size_min, @@ -567,10 +568,11 @@ static MemTxResult access_with_adjusted_size(hwaddr addr, MemoryRegion *mr, MemTxAttrs attrs) { + +MemTxResult r = MEMTX_OK; uint64_t access_mask; unsigned access_size; unsigned i; -MemTxResult r = MEMTX_OK; if (!access_size_min) { access_size_min = 1; @@ -579,7 +581,6 @@ static MemTxResult access_with_adjusted_size(hwaddr addr, access_size_max = 4; } -/* FIXME: support unaligned access? */ access_size = MAX(MIN(size, access_size_max), access_size_min); access_mask = -1ULL >> (64 - access_size * 8); if (memory_region_big_endian(mr)) { @@ -596,6 +597,133 @@ static MemTxResult access_with_adjusted_size(hwaddr addr, return r; } +/* Assume power-of-two size */ +#define align_down(addr, size) ((addr) & ~((size) - 1)) +#define align_up(addr, size) \ +({ typeof(size) __size = size; align_down((addr) + (__size) - 1, (__size)); }) + +static MemTxResult access_with_adjusted_size_unaligned(hwaddr addr, + uint64_t *value, + unsigned size, + unsigned access_size_min, + unsigned access_size_max, + bool unaligned, + MemTxResult (*access)(MemoryRegion *mr, +hwaddr addr, +uint64_t *value, +unsigned size, +unsigned shift, +uint64_t mask, +MemTxAttrs attrs), + MemoryRegion *mr, + MemTxAttrs attrs) +{ +uint64_t access_value = 0; +MemTxResult r = MEMTX_OK; +hwaddr access_addr[2]; +uint64_t access_mask; +unsigned access_size; + +if (unlikely(!access_size_min)) { +access_size_min = 1; +} +if (unlikely(!access_size_max)) { +access_size_max = 4; +} + +access_size = MAX(MIN(size, access_size_max), access_size_min); +access_addr[0] = align_down(addr, access_size); +access_addr[1] = align_up(addr + size, access_size); + +if (memory_region_big_endian(mr)) { +hwaddr cur; + +/* XXX: Big-endian path is untested... */ + +for (cur = access_addr[0]; cur < access_addr[1]; cur += access_size) { +uint64_t mask_bounds[2]; + +
Re: [Qemu-devel] [PATCH] timer/aspeed: fix timer enablement when a reload is not set
On Fri, 2017-06-09 at 07:40 +0200, Cédric Le Goater wrote: > On 06/09/2017 04:26 AM, Andrew Jeffery wrote: > > On Tue, 2017-06-06 at 10:55 +0200, Cédric Le Goater wrote: > > > When a timer is enabled before a reload value is set, the controller > > > waits for a reload value to be set before starting decrementing. This > > > fix tries to cover that case by changing the timer expiry only when > > > a reload value is valid. > > > > > > > Signed-off-by: Cédric Le Goater <c...@kaod.org> > > > > > > --- > > > hw/timer/aspeed_timer.c | 37 + > > > 1 file changed, 29 insertions(+), 8 deletions(-) > > > > > > diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c > > > index 9b70ee09b07f..50acbf530a3a 100644 > > > --- a/hw/timer/aspeed_timer.c > > > +++ b/hw/timer/aspeed_timer.c > > > @@ -130,15 +130,26 @@ static uint64_t calculate_next(struct AspeedTimer > > > *t) > > > next = seq[1]; > > > } else if (now < seq[2]) { > > > next = seq[2]; > > > -} else { > > > +} else if (t->reload) { > > > reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, > > > rate); > > > t->start = now - ((now - t->start) % reload_ns); > > > +} else { > > > +/* no reload value, return 0 */ > > > +break; > > > } > > > } > > > > > > return next; > > > } > > > > > > +static void aspeed_timer_mod(AspeedTimer *t) > > > +{ > > > +uint64_t next = calculate_next(t); > > > +if (next) { > > > +timer_mod(>timer, next); > > > +} > > > +} > > > + > > > static void aspeed_timer_expire(void *opaque) > > > { > > > AspeedTimer *t = opaque; > > > @@ -164,7 +175,7 @@ static void aspeed_timer_expire(void *opaque) > > > qemu_set_irq(t->irq, t->level); > > > } > > > > > > -timer_mod(>timer, calculate_next(t)); > > > +aspeed_timer_mod(t); > > > } > > > > > > static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg) > > > @@ -227,10 +238,23 @@ static void > > > aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, > > > uint32_t value) > > > { > > > AspeedTimer *t; > > > +uint32_t old_reload; > > > > > > trace_aspeed_timer_set_value(timer, reg, value); > > > t = >timers[timer]; > > > switch (reg) { > > > +case TIMER_REG_RELOAD: > > > +old_reload = t->reload; > > > +t->reload = value; > > > + > > > +/* If the reload value was not previously set, or zero, and > > > + * the current value is valid, try to start the timer if it is > > > + * enabled. > > > + */ > > > +if (old_reload || !t->reload) { > > > +break; > > > +} > > > > Maybe I need more caffeine, but I initially struggled to reconcile the > > condition with the comment, as the condition checks the inverse in > > order to break while the comment discusses the non-breaking case. > > I agree. The reload "value" is used in a hidden way to the activate the > timer. > > > However, after trying for several minutes, I'm not sure there's an easy > > way to improve it. > > I tried a few things. May be, we could move the following code in > its own routine and call it twice ? I don't think it's necessary. The comment serves as enough warning - it should at least make people think before modifying the code. Cheers, Andrew > > > > + > > > case TIMER_REG_STATUS: > > > if (timer_enabled(t)) { > > > uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > > > @@ -238,17 +262,14 @@ static void > > > aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, > > > uint32_t rate = calculate_rate(t); > > > > > > t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate); > > > -timer_mod(>timer, calculate_next(t)); > > > + aspeed_timer_mod(t); > > > } > > > break; > > > -case TIMER_REG_RELOAD: > > > -t->reload = value; > > > -break; > > > case TIMER_REG_MATCH_FIRST: > > > case TIMER_REG_MATCH_SECOND: > > > t->match[reg - 2] = value; > > > if (timer_enabled(t)) { > > > -timer_mod(>timer, calculate_next(t)); > > > +aspeed_timer_mod(t); > > > } > > > break; > > > default: > > > @@ -268,7 +289,7 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, > > > bool enable) > > > trace_aspeed_timer_ctrl_enable(t->id, enable); > > > if (enable) { > > > t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > > > -timer_mod(>timer, calculate_next(t)); > > > +aspeed_timer_mod(t); > > > } else { > > > timer_del(>timer); > > > } > > > > Reviewed-by: Andrew Jeffery <and...@aj.id.au> > > Thanks, > > C. signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [PATCH] timer/aspeed: fix timer enablement when a reload is not set
On Tue, 2017-06-06 at 10:55 +0200, Cédric Le Goater wrote: > When a timer is enabled before a reload value is set, the controller > waits for a reload value to be set before starting decrementing. This > fix tries to cover that case by changing the timer expiry only when > a reload value is valid. > > > Signed-off-by: Cédric Le Goater <c...@kaod.org> > --- > hw/timer/aspeed_timer.c | 37 + > 1 file changed, 29 insertions(+), 8 deletions(-) > > diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c > index 9b70ee09b07f..50acbf530a3a 100644 > --- a/hw/timer/aspeed_timer.c > +++ b/hw/timer/aspeed_timer.c > @@ -130,15 +130,26 @@ static uint64_t calculate_next(struct AspeedTimer *t) > next = seq[1]; > } else if (now < seq[2]) { > next = seq[2]; > -} else { > +} else if (t->reload) { > reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate); > t->start = now - ((now - t->start) % reload_ns); > +} else { > +/* no reload value, return 0 */ > +break; > } > } > > return next; > } > > +static void aspeed_timer_mod(AspeedTimer *t) > +{ > +uint64_t next = calculate_next(t); > +if (next) { > +timer_mod(>timer, next); > +} > +} > + > static void aspeed_timer_expire(void *opaque) > { > AspeedTimer *t = opaque; > @@ -164,7 +175,7 @@ static void aspeed_timer_expire(void *opaque) > qemu_set_irq(t->irq, t->level); > } > > -timer_mod(>timer, calculate_next(t)); > +aspeed_timer_mod(t); > } > > static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg) > @@ -227,10 +238,23 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState > *s, int timer, int reg, > uint32_t value) > { > AspeedTimer *t; > +uint32_t old_reload; > > trace_aspeed_timer_set_value(timer, reg, value); > t = >timers[timer]; > switch (reg) { > +case TIMER_REG_RELOAD: > +old_reload = t->reload; > +t->reload = value; > + > +/* If the reload value was not previously set, or zero, and > + * the current value is valid, try to start the timer if it is > + * enabled. > + */ > +if (old_reload || !t->reload) { > +break; > +} Maybe I need more caffeine, but I initially struggled to reconcile the condition with the comment, as the condition checks the inverse in order to break while the comment discusses the non-breaking case. However, after trying for several minutes, I'm not sure there's an easy way to improve it. > + > case TIMER_REG_STATUS: > if (timer_enabled(t)) { > uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > @@ -238,17 +262,14 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState > *s, int timer, int reg, > uint32_t rate = calculate_rate(t); > > t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate); > -timer_mod(>timer, calculate_next(t)); > +aspeed_timer_mod(t); > } > break; > -case TIMER_REG_RELOAD: > -t->reload = value; > -break; > case TIMER_REG_MATCH_FIRST: > case TIMER_REG_MATCH_SECOND: > t->match[reg - 2] = value; > if (timer_enabled(t)) { > -timer_mod(>timer, calculate_next(t)); > +aspeed_timer_mod(t); > } > break; > default: > @@ -268,7 +289,7 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool > enable) > trace_aspeed_timer_ctrl_enable(t->id, enable); > if (enable) { > t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > -timer_mod(>timer, calculate_next(t)); > +aspeed_timer_mod(t); > } else { > timer_del(>timer); > } Reviewed-by: Andrew Jeffery <and...@aj.id.au> signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [Qemu-arm] [PATCH 1/2] hw/adc: Add basic Aspeed ADC model
On Wed, 2017-05-24 at 02:15 -0300, Philippe Mathieu-Daudé wrote: > Hi Andrew, > > On 05/22/2017 02:14 AM, Andrew Jeffery wrote: > > On Mon, 2017-05-22 at 03:15 +, Ryan Chen wrote: > > > In ASPEED SoC chip, all register access have following rule. > > > Most of controller write access is only support 32bit access. > > > Read is support 8bits/16bits/32bits. > > This makes sens thinking about how a DMA controller can take advantage > of the ADC. > > > > > Thanks for clearing that up Ryan. > > > > Phil: I'll rework the model so the reads are 16-bits. > > This shouldn't be necessary, QEMU is supposed to supports different > access size for different implemented size, so you can declare your > implementation as 32-bit and valid accesses from 8 to 32: > > static const MemoryRegionOps aspeed_adc_ops = { > .read = aspeed_adc_read, > .write = aspeed_adc_write, > .endianness = DEVICE_LITTLE_ENDIAN, > .valid.min_access_size = 1, > .valid.max_access_size = 4, > .valid.unaligned = false, > +.impl.min_access_size = 4, > +.impl.max_access_size = 4, > }; > > This way an I/O access from the CPU or a DMA could use 8/16-bit while > you keep a 32-bit implementation. The adjustment is done by > access_with_adjusted_size() from memory.c. > > Afaik there is, however, no distinction between read/write different > access size in current QEMU MemoryRegionOps model. Yep, I realised all of the above when I went to implement it. Thanks for pointing it out though! Andrew signature.asc Description: This is a digitally signed message part
Re: [Qemu-devel] [Qemu-arm] [PATCH 1/2] hw/adc: Add basic Aspeed ADC model
On Mon, 2017-05-22 at 03:15 +, Ryan Chen wrote: > In ASPEED SoC chip, all register access have following rule. > Most of controller write access is only support 32bit access. > Read is support 8bits/16bits/32bits. Thanks for clearing that up Ryan. Phil: I'll rework the model so the reads are 16-bits. Thanks, Andrew > > > > Best Regards, > Ryan > > 信驊科技股份有限公司 > ASPEED Technology Inc. > 2F,No.15,Industry East Road 4.,Hsinchu Science Park, Hsinchu City 30077, > Taiwan > Tel: 886-3-578-9568 #857 > Fax: 886-3-578-9586 > * Email Confidentiality Notice > DISCLAIMER: > This message (and any attachments) may contain legally privileged and/or > other confidential information. If you have received it in error, please > notify the sender by reply e-mail and immediately delete the e-mail and any > attachments without copying or disclosing the contents. Thank you. > > -Original Message- > > From: Andrew Jeffery [mailto:and...@aj.id.au] > Sent: Monday, May 22, 2017 8:24 AM > > To: Philippe Mathieu-Daudé <f4...@amsat.org>; qemu-...@nongnu.org > > > > Cc: Peter Maydell <peter.mayd...@linaro.org>; Ryan Chen > > > > <ryan_c...@aspeedtech.com>; Alistair Francis <alist...@alistair23.me>; > > > > qemu-devel@nongnu.org; Cédric Le Goater <c...@kaod.org>; Joel Stanley > > > > <j...@jms.id.au> > Subject: Re: [Qemu-arm] [PATCH 1/2] hw/adc: Add basic Aspeed ADC model > > Hi Phil, > > On Sat, 2017-05-20 at 00:21 -0300, Philippe Mathieu-Daudé wrote: > > Hi Andrew, > > > > On 05/19/2017 09:26 PM, Andrew Jeffery wrote: > > > This model implements enough behaviour to do basic functionality > > > tests such as device initialisation and read out of dummy sample > > > values. The sample value generation strategy is similar to the STM > > > ADC already in the tree. > > > > > > > > Signed-off-by: Andrew Jeffery <and...@aj.id.au> > > > > > > --- > > > hw/adc/Makefile.objs| 1 + > > > hw/adc/aspeed_adc.c | 246 > > > > > > include/hw/adc/aspeed_adc.h | 33 ++ > > > 3 files changed, 280 insertions(+) > > > create mode 100644 hw/adc/aspeed_adc.c > > > create mode 100644 include/hw/adc/aspeed_adc.h > > > > > > diff --git a/hw/adc/Makefile.objs b/hw/adc/Makefile.objs index > > > 3f6dfdedaec7..2bf9362ba3c4 100644 > > > --- a/hw/adc/Makefile.objs > > > +++ b/hw/adc/Makefile.objs > > > @@ -1 +1,2 @@ > > > obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o > > > +obj-$(CONFIG_ASPEED_SOC) += aspeed_adc.o > > > diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c new file mode > > > 100644 index ..d08f1684f7bc > > > --- /dev/null > > > +++ b/hw/adc/aspeed_adc.c > > > @@ -0,0 +1,246 @@ > > > +/* > > > + * Aspeed ADC > > > + * > > > > > + * Andrew Jeffery <and...@aj.id.au> > > > > > > + * > > > + * Copyright 2017 IBM Corp. > > > + * > > > + * This code is licensed under the GPL version 2 or later. See > > > + * the COPYING file in the top-level directory. > > > + */ > > > + > > > +#include "qemu/osdep.h" > > > +#include "hw/adc/aspeed_adc.h" > > > +#include "qapi/error.h" > > > +#include "qemu/log.h" > > > + > > > +#define ASPEED_ADC_ENGINE_CTRL 0x00 #define > > > +ASPEED_ADC_ENGINE_CH_EN_MASK 0x #define > > > +ASPEED_ADC_ENGINE_CH_EN(x)((BIT(x)) << 16) #define > > > +ASPEED_ADC_ENGINE_INIT BIT(8) #define > > > +ASPEED_ADC_ENGINE_AUTO_COMPBIT(5) #define > > > +ASPEED_ADC_ENGINE_COMP BIT(4) #define > > > +ASPEED_ADC_ENGINE_MODE_MASK0x000e #define > > > +ASPEED_ADC_ENGINE_MODE_OFF(0b000 << 1) #define > > > +ASPEED_ADC_ENGINE_MODE_STANDBY(0b001 << 1) #define > > > +ASPEED_ADC_ENGINE_MODE_NORMAL (0b111 << 1) #define > > > +ASPEED_ADC_ENGINE_EN BIT(0) > > > + > > > +#define ASPEED_ADC_L_MASK ((1 << 10) - 1) #define > > > +ASPEED_ADC_L(x) ((x) & ASPEED_ADC_L_MASK) #define > > > +ASPEED_ADC_H(x) (((x) >> 16) & ASPEED_ADC_L_MASK) #define > > > +ASPEED_ADC_LH_MASK
Re: [Qemu-devel] [Qemu-arm] [PATCH 1/2] hw/adc: Add basic Aspeed ADC model
Hi Phil, On Sat, 2017-05-20 at 00:21 -0300, Philippe Mathieu-Daudé wrote: > Hi Andrew, > > On 05/19/2017 09:26 PM, Andrew Jeffery wrote: > > This model implements enough behaviour to do basic functionality tests > > such as device initialisation and read out of dummy sample values. The > > sample value generation strategy is similar to the STM ADC already in > > the tree. > > > > > > Signed-off-by: Andrew Jeffery <and...@aj.id.au> > > --- > > hw/adc/Makefile.objs| 1 + > > hw/adc/aspeed_adc.c | 246 > > > > include/hw/adc/aspeed_adc.h | 33 ++ > > 3 files changed, 280 insertions(+) > > create mode 100644 hw/adc/aspeed_adc.c > > create mode 100644 include/hw/adc/aspeed_adc.h > > > > diff --git a/hw/adc/Makefile.objs b/hw/adc/Makefile.objs > > index 3f6dfdedaec7..2bf9362ba3c4 100644 > > --- a/hw/adc/Makefile.objs > > +++ b/hw/adc/Makefile.objs > > @@ -1 +1,2 @@ > > obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o > > +obj-$(CONFIG_ASPEED_SOC) += aspeed_adc.o > > diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c > > new file mode 100644 > > index ..d08f1684f7bc > > --- /dev/null > > +++ b/hw/adc/aspeed_adc.c > > @@ -0,0 +1,246 @@ > > +/* > > + * Aspeed ADC > > + * > > > > + * Andrew Jeffery <and...@aj.id.au> > > + * > > + * Copyright 2017 IBM Corp. > > + * > > + * This code is licensed under the GPL version 2 or later. See > > + * the COPYING file in the top-level directory. > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "hw/adc/aspeed_adc.h" > > +#include "qapi/error.h" > > +#include "qemu/log.h" > > + > > +#define ASPEED_ADC_ENGINE_CTRL 0x00 > > +#define ASPEED_ADC_ENGINE_CH_EN_MASK 0x > > +#define ASPEED_ADC_ENGINE_CH_EN(x)((BIT(x)) << 16) > > +#define ASPEED_ADC_ENGINE_INIT BIT(8) > > +#define ASPEED_ADC_ENGINE_AUTO_COMPBIT(5) > > +#define ASPEED_ADC_ENGINE_COMP BIT(4) > > +#define ASPEED_ADC_ENGINE_MODE_MASK0x000e > > +#define ASPEED_ADC_ENGINE_MODE_OFF(0b000 << 1) > > +#define ASPEED_ADC_ENGINE_MODE_STANDBY(0b001 << 1) > > +#define ASPEED_ADC_ENGINE_MODE_NORMAL (0b111 << 1) > > +#define ASPEED_ADC_ENGINE_EN BIT(0) > > + > > +#define ASPEED_ADC_L_MASK ((1 << 10) - 1) > > +#define ASPEED_ADC_L(x) ((x) & ASPEED_ADC_L_MASK) > > +#define ASPEED_ADC_H(x) (((x) >> 16) & ASPEED_ADC_L_MASK) > > +#define ASPEED_ADC_LH_MASK (ASPEED_ADC_L_MASK << 16 | > > ASPEED_ADC_L_MASK) > > + > > +static inline uint32_t update_channels(uint32_t current) > > +{ > > +const uint32_t next = (current + 7) & 0x3ff; > > + > > +return (next << 16) | next; > > +} > > + > > +static bool breaks_threshold(AspeedADCState *s, int ch_off) > > +{ > > +const uint32_t a = ASPEED_ADC_L(s->channels[ch_off]); > > +const uint32_t a_lower = ASPEED_ADC_L(s->bounds[2 * ch_off]); > > +const uint32_t a_upper = ASPEED_ADC_H(s->bounds[2 * ch_off]); > > +const uint32_t b = ASPEED_ADC_H(s->channels[ch_off]); > > +const uint32_t b_lower = ASPEED_ADC_L(s->bounds[2 * ch_off + 1]); > > +const uint32_t b_upper = ASPEED_ADC_H(s->bounds[2 * ch_off + 1]); > > + > > +return ((a < a_lower || a > a_upper)) || > > + ((b < b_lower || b > b_upper)); > > +} > > + > > +static uint32_t read_channel_sample(AspeedADCState *s, int ch_off) > > +{ > > +uint32_t ret; > > + > > +/* Poor man's sampling */ > > +ret = s->channels[ch_off]; > > +s->channels[ch_off] = update_channels(s->channels[ch_off]); > > + > > +if (breaks_threshold(s, ch_off)) { > > +qemu_irq_raise(s->irq); > > +} > > + > > +return ret; > > +} > > + > > +#define TO_INDEX(addr, base) (((addr) - (base)) >> 2) > > + > > +static uint64_t aspeed_adc_read(void *opaque, hwaddr addr, > > + unsigned int size) > > +{ > > +AspeedADCState *s = ASPEED_ADC(opaque); > > +uint64_t ret; > > + > > +switch (addr) { > > +case 0x00: > > +ret = s->engine_ctrl; > > +
Re: [Qemu-devel] [PATCH 0/2] hw/adc: Implement a basic Aspeed ADC model
On Fri, 2017-05-19 at 17:51 -0700, no-re...@patchew.org wrote: > In file included from /tmp/qemu-test/src/hw/adc/aspeed_adc.c:15:0: > /tmp/qemu-test/src/hw/adc/aspeed_adc.c: In function 'aspeed_adc_read': > /tmp/qemu-test/src/hw/adc/aspeed_adc.c:106:34: error: format '%lx' expects > argument of type 'long unsigned int', but argument 3 has type 'hwaddr {aka > long long unsigned int}' [-Werror=format=] > qemu_log_mask(LOG_UNIMP, "%s: addr: 0x%lx, size: %u\n", __func__, > addr, > ^ > /tmp/qemu-test/src/include/qemu/log.h:94:22: note: in definition of macro > 'qemu_log_mask' > qemu_log(FMT, ## __VA_ARGS__); \ > ^~~ > /tmp/qemu-test/src/hw/adc/aspeed_adc.c: In function 'aspeed_adc_write': > /tmp/qemu-test/src/hw/adc/aspeed_adc.c:162:34: error: format '%lu' expects > argument of type 'long unsigned int', but argument 3 has type 'hwaddr {aka > long long unsigned int}' [-Werror=format=] > qemu_log_mask(LOG_UNIMP, "%s: %lu\n", __func__, addr); > ^ > /tmp/qemu-test/src/include/qemu/log.h:94:22: note: in definition of macro > 'qemu_log_mask' > qemu_log(FMT, ## __VA_ARGS__); \ > ^~~ > cc1: all warnings being treated as errors > /tmp/qemu-test/src/rules.mak:69: recipe for target 'hw/adc/aspeed_adc.o' > failed > make[1]: *** [hw/adc/aspeed_adc.o] Error 1 > make[1]: *** Waiting for unfinished jobs > CC aarch64-softmmu/hw/scsi/virtio-scsi-dataplane.o > Makefile:327: recipe for target 'subdir-aarch64-softmmu' failed > make: *** [subdir-aarch64-softmmu] Error 2 > make: *** Waiting for unfinished jobs > GEN x86_64-softmmu/qemu-system-x86_64.exe > tests/docker/Makefile.include:118: recipe for target 'docker-run' failed > make[1]: *** [docker-run] Error 2 > make[1]: Leaving directory '/var/tmp/patchew-tester-tmp-i73ef6w0/src' > tests/docker/Makefile.include:149: recipe for target > 'docker-run-test-mingw@fedora' failed > > make: *** [docker-run-test-mingw@fedora] Error 2 > === OUTPUT END === > > Test command exited with code: 2 I'll fix the format string issues in v2 along with any other issues identified in review. Separately, is it necessary for the bot to send the entirety of the build output? Can we make it a bit smarter to send just the error with some small amount of context? Maybe send the full log as an attachment? Or host it and link to it from the email? It's a bit tedious having to scroll through all that output to find the error at the bottom. Cheers, Andrew signature.asc Description: This is a digitally signed message part
[Qemu-devel] [PATCH 1/2] hw/adc: Add basic Aspeed ADC model
This model implements enough behaviour to do basic functionality tests such as device initialisation and read out of dummy sample values. The sample value generation strategy is similar to the STM ADC already in the tree. Signed-off-by: Andrew Jeffery <and...@aj.id.au> --- hw/adc/Makefile.objs| 1 + hw/adc/aspeed_adc.c | 246 include/hw/adc/aspeed_adc.h | 33 ++ 3 files changed, 280 insertions(+) create mode 100644 hw/adc/aspeed_adc.c create mode 100644 include/hw/adc/aspeed_adc.h diff --git a/hw/adc/Makefile.objs b/hw/adc/Makefile.objs index 3f6dfdedaec7..2bf9362ba3c4 100644 --- a/hw/adc/Makefile.objs +++ b/hw/adc/Makefile.objs @@ -1 +1,2 @@ obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o +obj-$(CONFIG_ASPEED_SOC) += aspeed_adc.o diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c new file mode 100644 index ..d08f1684f7bc --- /dev/null +++ b/hw/adc/aspeed_adc.c @@ -0,0 +1,246 @@ +/* + * Aspeed ADC + * + * Andrew Jeffery <and...@aj.id.au> + * + * Copyright 2017 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/adc/aspeed_adc.h" +#include "qapi/error.h" +#include "qemu/log.h" + +#define ASPEED_ADC_ENGINE_CTRL 0x00 +#define ASPEED_ADC_ENGINE_CH_EN_MASK 0x +#define ASPEED_ADC_ENGINE_CH_EN(x)((BIT(x)) << 16) +#define ASPEED_ADC_ENGINE_INIT BIT(8) +#define ASPEED_ADC_ENGINE_AUTO_COMPBIT(5) +#define ASPEED_ADC_ENGINE_COMP BIT(4) +#define ASPEED_ADC_ENGINE_MODE_MASK0x000e +#define ASPEED_ADC_ENGINE_MODE_OFF(0b000 << 1) +#define ASPEED_ADC_ENGINE_MODE_STANDBY(0b001 << 1) +#define ASPEED_ADC_ENGINE_MODE_NORMAL (0b111 << 1) +#define ASPEED_ADC_ENGINE_EN BIT(0) + +#define ASPEED_ADC_L_MASK ((1 << 10) - 1) +#define ASPEED_ADC_L(x) ((x) & ASPEED_ADC_L_MASK) +#define ASPEED_ADC_H(x) (((x) >> 16) & ASPEED_ADC_L_MASK) +#define ASPEED_ADC_LH_MASK (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK) + +static inline uint32_t update_channels(uint32_t current) +{ +const uint32_t next = (current + 7) & 0x3ff; + +return (next << 16) | next; +} + +static bool breaks_threshold(AspeedADCState *s, int ch_off) +{ +const uint32_t a = ASPEED_ADC_L(s->channels[ch_off]); +const uint32_t a_lower = ASPEED_ADC_L(s->bounds[2 * ch_off]); +const uint32_t a_upper = ASPEED_ADC_H(s->bounds[2 * ch_off]); +const uint32_t b = ASPEED_ADC_H(s->channels[ch_off]); +const uint32_t b_lower = ASPEED_ADC_L(s->bounds[2 * ch_off + 1]); +const uint32_t b_upper = ASPEED_ADC_H(s->bounds[2 * ch_off + 1]); + +return ((a < a_lower || a > a_upper)) || + ((b < b_lower || b > b_upper)); +} + +static uint32_t read_channel_sample(AspeedADCState *s, int ch_off) +{ +uint32_t ret; + +/* Poor man's sampling */ +ret = s->channels[ch_off]; +s->channels[ch_off] = update_channels(s->channels[ch_off]); + +if (breaks_threshold(s, ch_off)) { +qemu_irq_raise(s->irq); +} + +return ret; +} + +#define TO_INDEX(addr, base) (((addr) - (base)) >> 2) + +static uint64_t aspeed_adc_read(void *opaque, hwaddr addr, + unsigned int size) +{ +AspeedADCState *s = ASPEED_ADC(opaque); +uint64_t ret; + +switch (addr) { +case 0x00: +ret = s->engine_ctrl; +break; +case 0x04: +ret = s->irq_ctrl; +break; +case 0x08: +ret = s->vga_detect_ctrl; +break; +case 0x0c: +ret = s->adc_clk_ctrl; +break; +case 0x10 ... 0x2e: +ret = read_channel_sample(s, TO_INDEX(addr, 0x10)); +break; +case 0x30 ... 0x6e: +ret = s->bounds[TO_INDEX(addr, 0x30)]; +break; +case 0x70 ... 0xae: +ret = s->hysteresis[TO_INDEX(addr, 0x70)]; +break; +case 0xc0: +ret = s->irq_src; +break; +case 0xc4: +ret = s->comp_trim; +break; +default: +qemu_log_mask(LOG_UNIMP, "%s: addr: 0x%lx, size: %u\n", __func__, addr, +size); +ret = 0; +break; +} + +return ret; +} + +static void aspeed_adc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned int size) +{ +AspeedADCState *s = ASPEED_ADC(opaque); + +switch (addr) { +case 0x00: +{ +uint32_t init; + +init = !!(val & ASPEED_ADC_ENGINE_EN); +init *= ASPEED_ADC_ENGINE_INIT; + +val &= ~ASPEED_ADC_ENGINE_INIT; +val |= init; +} + +val &
[Qemu-devel] [PATCH 2/2] hw/arm: Integrate ADC model into Aspeed SoC
Signed-off-by: Andrew Jeffery <and...@aj.id.au> --- hw/arm/aspeed_soc.c | 15 +++ include/hw/arm/aspeed_soc.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 5c667d2c35b6..11f9588720d2 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -31,6 +31,7 @@ #define ASPEED_SOC_VIC_BASE 0x1E6C #define ASPEED_SOC_SDMC_BASE0x1E6E #define ASPEED_SOC_SCU_BASE 0x1E6E2000 +#define ASPEED_SOC_ADC_BASE 0x1E6E9000 #define ASPEED_SOC_SRAM_BASE0x1E72 #define ASPEED_SOC_TIMER_BASE 0x1E782000 #define ASPEED_SOC_WDT_BASE 0x1E785000 @@ -157,6 +158,10 @@ static void aspeed_soc_init(Object *obj) object_property_add_alias(obj, "hw-strap2", OBJECT(>scu), "hw-strap2", _abort); +object_initialize(>adc, sizeof(s->adc), TYPE_ASPEED_ADC); +object_property_add_child(obj, "adc", OBJECT(>adc), NULL); +qdev_set_parent_bus(DEVICE(>adc), sysbus_get_default()); + object_initialize(>fmc, sizeof(s->fmc), sc->info->fmc_typename); object_property_add_child(obj, "fmc", OBJECT(>fmc), NULL); qdev_set_parent_bus(DEVICE(>fmc), sysbus_get_default()); @@ -256,6 +261,16 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(>scu), 0, ASPEED_SOC_SCU_BASE); +/* ADC */ +object_property_set_bool(OBJECT(>adc), true, "realized", ); +if (err) { +error_propagate(errp, err); +return; +} +sysbus_mmio_map(SYS_BUS_DEVICE(>adc), 0, ASPEED_SOC_ADC_BASE); +sysbus_connect_irq(SYS_BUS_DEVICE(>adc), 0, +qdev_get_gpio_in(DEVICE(>vic), 31)); + /* UART - attach an 8250 to the IO space as our UART5 */ if (serial_hds[0]) { qemu_irq uart5 = qdev_get_gpio_in(DEVICE(>vic), uart_irqs[4]); diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index d16205c66b5f..3b4d66d30f08 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -15,6 +15,7 @@ #include "hw/arm/arm.h" #include "hw/intc/aspeed_vic.h" #include "hw/misc/aspeed_scu.h" +#include "hw/adc/aspeed_adc.h" #include "hw/misc/aspeed_sdmc.h" #include "hw/timer/aspeed_timer.h" #include "hw/i2c/aspeed_i2c.h" @@ -37,6 +38,7 @@ typedef struct AspeedSoCState { AspeedTimerCtrlState timerctrl; AspeedI2CState i2c; AspeedSCUState scu; +AspeedADCState adc; AspeedSMCState fmc; AspeedSMCState spi[ASPEED_SPIS_NUM]; AspeedSDMCState sdmc; -- 2.9.3
[Qemu-devel] [PATCH 0/2] hw/adc: Implement a basic Aspeed ADC model
Hello, This short series introduces a basic model for the Aspeed ADC and glues it into the generic Aspeed SoC definition. The register interface is enhanced slightly from the AST2400 to the AST2500, but in a backwards-compatible way by making use of reserved bits. As such I haven't made any effort to differentiate the two. The addition of a basic ADC model allows the Aspeed SDK kernel to boot under QEMU's ast2500-evb machine. The upstream kernel driver doesn't test the initialisation bit before completing its probe(), and thus doesn't get stuck if the bit is not set. This is in contrast to the SDK kernel which spins on the initialisation bit, never making forward progress in the absence of the ADC model. Tested with both Aspeed's SDK kernel and upstream Linux. Cheers, Andrew Andrew Jeffery (2): hw/adc: Add basic Aspeed ADC model hw/arm: Integrate ADC model into Aspeed SoC hw/adc/Makefile.objs| 1 + hw/adc/aspeed_adc.c | 246 hw/arm/aspeed_soc.c | 15 +++ include/hw/adc/aspeed_adc.h | 33 ++ include/hw/arm/aspeed_soc.h | 2 + 5 files changed, 297 insertions(+) create mode 100644 hw/adc/aspeed_adc.c create mode 100644 include/hw/adc/aspeed_adc.h -- 2.9.3