Hi Cedric, > From: Cédric Le Goater <c...@kaod.org> > On 5/30/24 09:42, Jamin Lin wrote: > > Hi Cedric, > >> From: Cédric Le Goater <c...@kaod.org>> Hello Jamin > >> > >> On 5/27/24 10:02, Jamin Lin wrote: > >>> AST2700 dram size calculation is not back compatible AST2600. > >>> According to the DDR capacity hardware behavior, if users write the > >>> data to address which is beyond the ram size, it would write the > >>> data to address 0. > >>> For example: > >>> a. sdram base address "0x4 00000000" > >>> b. sdram size is 1 GiB > >>> The available address range is from "0x4 00000000" to "0x4 40000000". > >>> If users write 0xdeadbeef to address "0x6 00000000", the value of > >>> DRAM address 0 (base address 0x4 00000000) should be 0xdeadbeef. > >>> > >>> Add aspeed_soc_ast2700_dram_init to calculate the dram size and add > >>> memory I/O whose address range is from max_ram_size - ram_size to > >>> max_ram_size and its read/write handler to emulate DDR capacity > >>> hardware > >> behavior. > >>> > >>> Signed-off-by: Troy Lee <troy_...@aspeedtech.com> > >>> Signed-off-by: Jamin Lin <jamin_...@aspeedtech.com> > >>> --- > >>> hw/arm/aspeed_ast27x0.c | 94 > >> ++++++++++++++++++++++++++++++++++++- > >>> include/hw/arm/aspeed_soc.h | 1 + > >>> 2 files changed, 94 insertions(+), 1 deletion(-) > >>> > >>> diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index > >>> a3a03fc1ca..19380087fa 100644 > >>> --- a/hw/arm/aspeed_ast27x0.c > >>> +++ b/hw/arm/aspeed_ast27x0.c > >>> @@ -20,6 +20,7 @@ > >>> #include "sysemu/sysemu.h" > >>> #include "hw/intc/arm_gicv3.h" > >>> #include "qapi/qmp/qlist.h" > >>> +#include "qemu/log.h" > >>> > >>> static const hwaddr aspeed_soc_ast2700_memmap[] = { > >>> [ASPEED_DEV_SPI_BOOT] = 0x400000000, @@ -191,6 > +192,97 > >> @@ > >>> static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev) > >>> return qdev_get_gpio_in(a->intc.gic, sc->irqmap[dev]); > >>> } > >>> > >>> +static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr, > >>> + unsigned > >> int > >>> +size) { > >>> + qemu_log_mask(LOG_GUEST_ERROR, > >>> + "%s: read @%" PRIx64 " out of ram size\n", > >>> + __func__, addr); > >>> + return 0; > >>> +} > >>> + > >>> +static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, > >> uint64_t data, > >>> + unsigned int > size) > >> { > >>> + AspeedSoCState *s = ASPEED_SOC(opaque); > >>> + uint32_t test_pattern = 0xdeadbeef; > >>> + bool invalid_pattern = true; > >>> + uint32_t *ram_ptr; > >>> + int sz; > >>> + > >>> + ram_ptr = memory_region_get_ram_ptr(s->dram_mr); > >>> + > >>> + /* > >>> + * Emulate ddr capacity hardware behavior. > >>> + * If writes the test_pattern to address which is beyond the ram size, > >>> + * it would write the test_pattern to address 0. > >>> + */ > >>> + for (sz = 4; sz > 0 ; sz--) { > >>> + test_pattern = (test_pattern << 4) + sz; > >>> + if (data == test_pattern) { > >>> + ram_ptr[0] = test_pattern; > >>> + invalid_pattern = false; > >>> + break; > >>> + } > >>> + } > >>> + > >>> + if (invalid_pattern) { > >>> + qemu_log_mask(LOG_GUEST_ERROR, > >>> + "%s: write invalid pattern @%" PRIx64 > >>> + " to addr @%" HWADDR_PRIx "]\n", > >>> + __func__, data, addr); > >>> + } > >>> +} > >> > >> > >> I would simplify with write transaction on the DRAM memory region of > >> the SoC. > >> > >> For that, initialize a 'dram_as' on top of 'dram_mr' in > >> aspeed_soc_ast2700_dram_init(): > >> > >> address_space_init(&s->dram_as, s->dram_mr, "dram"); > >> > >> Then, in aspeed_ram_capacity_write(), add : > >> > >> address_space_write(&s->dram_as, addr % ram_size, > >> MEMTXATTRS_UNSPECIFIED, > >> &data, size); > >> > >> and check returned error. > >> > >> It should be enough to detect the RAM size from FW. > >> > >> > >> Thanks, > >> > >> C. > >> > > Thanks for your suggestion and review. > > I changed to use address space APIs to write DRAM memory > region(s->dram_mr). > > I have a question about aspeed_ram_capacity_write function > implementation. > > Could you tell me which solution you prefer? Do you want to use solution 1? > > I prefer solution 1 because no assumption is made on what software does. > It simply implements the wraparound HW does on RAM accesses. > > Thanks, > > C.
Got it. I will update it in v5 patch (solution 1) Thanks for your help and suggestion. Jamin > > > > > Thanks-Jamin > > > > Solution 1: > > static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t > data, > > unsigned int > size) { > > AspeedSoCState *s = ASPEED_SOC(opaque); > > ram_addr_t ram_size; > > MemTxResult result; > > > > ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size", > > &error_abort); > > > > /* > > * Emulate ddr capacity hardware behavior. > > * If writes the data to the address which is beyond the ram size, > > * it would write the data to the "address % ram_size". > > */ > > result = address_space_write(&s->dram_as, addr % ram_size, > > MEMTXATTRS_UNSPECIFIED, > &data, 4); > > if (result != MEMTX_OK) { > > qemu_log_mask(LOG_GUEST_ERROR, > > "%s: DRAM write failed, addr:0x%" > HWADDR_PRIx > > ", data :0x%" PRIx64 "\n", > > __func__, addr % ram_size, data); > > } > > } > > We don't care the test pattern. If users write the data to the invalid > > address, > the date will be written into the DRAM memory region at "addr % dram_size". > > Ex: dram size is 1G and the available address range is from "0x4 00000000" > to "0x4 3FFFFFFF" > > > > Users write data(0x12345678) at invalid address "0x5 00000000" and the > data would be written at address "0x4 00000000" > > => md 400000000 1 > > 400000000: dbeef432 > > => mw 500000000 12345678 > > => md 400000000 1 > > 400000000: 12345678 > > > > Solution 2: > > static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t > data, > > unsigned int > size) { > > AspeedSoCState *s = ASPEED_SOC(opaque); > > uint32_t test_pattern = 0xdeadbeef; > > bool invalid_pattern = true; > > ram_addr_t ram_size; > > MemTxResult result; > > int sz; > > > > ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size", > > &error_abort); > > > > /* > > * Emulate ddr capacity hardware behavior. > > * If writes the test_pattern to the address which is beyond the ram > size, > > * it would write the test_pattern to the "address % ram_size". > > */ > > for (sz = 4; sz > 0 ; sz--) { > > test_pattern = (test_pattern << 4) + sz; > > if (data == test_pattern) { > > result = address_space_write(&s->dram_as, addr % > ram_size, > > > MEMTXATTRS_UNSPECIFIED, &data, 4); > > if (result != MEMTX_OK) { > > qemu_log_mask(LOG_GUEST_ERROR, > > "%s: DRAM write failed, pattern:0x%" > PRIx64 > > ", addr:0x%" HWADDR_PRIx "\n", > > __func__, data, addr % ram_size); > > return; > > } > > invalid_pattern = false; > > break; > > } > > } > > > > if (invalid_pattern) { > > qemu_log_mask(LOG_GUEST_ERROR, > > "%s: DRAM write invalid pattern:0x%" PRIx64 > > ", addr:0x%" HWADDR_PRIx "\n", > > __func__, data, addr); > > } > > } > > It check test patterns. If users write the invalid test pattern to the > > invalid > address, the date will NOT be written into the DRAM memory region at "addr > % dram_size". > > Ex: dram size is 1G and the available address range is from "0x4 00000000" > to "0x4 3FFFFFFF" > > > > Users write invalid test pattern (0x12345678) at invalid address "0x5 > 00000000" and the data would not be written at address "0x4 00000000" > > > > Invalid test pattern > > => md 400000000 1 > > 400000000: dbeef432 > > => mw 500000000 12345678 > > => md 400000000 1 > > 400000000: dbeef432 > > > > Only valid pattern would be written at address "0x4 00000000" > > Pattern --> (0xdeadbeef << 4) + 4 > > => md 400000000 1 > > 400000000: dbeef432 > > => mw 500000000 deadbeef4 > > => md 400000000 1 > > 400000000: eadbeef4 > > > >> > >> > >> > >>> +static const MemoryRegionOps aspeed_ram_capacity_ops = { > >>> + .read = aspeed_ram_capacity_read, > >>> + .write = aspeed_ram_capacity_write, > >>> + .endianness = DEVICE_LITTLE_ENDIAN, > >>> + .valid = { > >>> + .min_access_size = 1, > >>> + .max_access_size = 8, > >>> + }, > >>> +}; > >>> + > >>> +/* > >>> + * SDMC should be realized first to get correct RAM size and max > >>> +size > >>> + * values > >>> + */ > >>> +static bool aspeed_soc_ast2700_dram_init(DeviceState *dev, Error > >>> +**errp) { > >>> + ram_addr_t ram_size, max_ram_size; > >>> + Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev); > >>> + AspeedSoCState *s = ASPEED_SOC(dev); > >>> + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); > >>> + > >>> + ram_size = object_property_get_uint(OBJECT(&s->sdmc), > "ram-size", > >>> + &error_abort); > >>> + max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), > >> "max-ram-size", > >>> + &error_abort); > >>> + > >>> + memory_region_init(&s->dram_container, OBJECT(s), > "ram-container", > >>> + ram_size); > >>> + memory_region_add_subregion(&s->dram_container, 0, > s->dram_mr); > >>> + > >>> + /* > >>> + * Add a memory region beyond the RAM region to emulate > >>> + * ddr capacity hardware behavior. > >>> + */ > >>> + if (ram_size < max_ram_size) { > >>> + memory_region_init_io(&a->dram_empty, OBJECT(s), > >>> + &aspeed_ram_capacity_ops, s, > >>> + "ram-empty", max_ram_size - > >> ram_size); > >>> + > >>> + memory_region_add_subregion(s->memory, > >>> + > >> sc->memmap[ASPEED_DEV_SDRAM] + ram_size, > >>> + &a->dram_empty); > >>> + } > >>> + > >>> + memory_region_add_subregion(s->memory, > >>> + sc->memmap[ASPEED_DEV_SDRAM], > >> &s->dram_container); > >>> + return true; > >>> +} > >>> + > >>> static void aspeed_soc_ast2700_init(Object *obj) > >>> { > >>> Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj); @@ -461,7 > +553,7 > >> @@ > >>> static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) > >>> sc->memmap[ASPEED_DEV_SDMC]); > >>> > >>> /* RAM */ > >>> - if (!aspeed_soc_dram_init(s, errp)) { > >>> + if (!aspeed_soc_ast2700_dram_init(dev, errp)) { > >>> return; > >>> } > >>> > >>> diff --git a/include/hw/arm/aspeed_soc.h > >>> b/include/hw/arm/aspeed_soc.h index 9f177b6037..9dbf48f873 100644 > >>> --- a/include/hw/arm/aspeed_soc.h > >>> +++ b/include/hw/arm/aspeed_soc.h > >>> @@ -127,6 +127,7 @@ struct Aspeed27x0SoCState { > >>> > >>> ARMCPU cpu[ASPEED_CPUS_NUM]; > >>> AspeedINTCState intc; > >>> + MemoryRegion dram_empty; > >>> }; > >>> > >>> #define TYPE_ASPEED27X0_SOC "aspeed27x0-soc" > >