From 4b9774ef482d789d27938d0a7c14936ad706c74f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:09 +0000 Subject: [PATCH 01/24] hw/intc/armv7m: Support byte and halfword accesses to CFSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Configurable Fault Status Register for ARMv7M and v8M is supposed to be byte and halfword accessible, but we were only implementing word accesses. Add support for the other access sizes, which are used by the Zephyr RTOS. Signed-off-by: Peter Maydell Reported-by: Andy Gross Reviewed-by: Philippe Mathieu-Daudé Message-id: 1512742372-31517-1-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index dd49b6c335..8ca6ceeb9b 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -896,13 +896,6 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) val |= (1 << 8); } return val; - case 0xd28: /* Configurable Fault Status. */ - /* The BFSR bits [15:8] are shared between security states - * and we store them in the NS copy - */ - val = cpu->env.v7m.cfsr[attrs.secure]; - val |= cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK; - return val; case 0xd2c: /* Hard Fault Status. */ return cpu->env.v7m.hfsr; case 0xd30: /* Debug Fault Status. */ @@ -1280,15 +1273,6 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, s->vectors[ARMV7M_EXCP_DEBUG].active = (value & (1 << 8)) != 0; nvic_irq_update(s); break; - case 0xd28: /* Configurable Fault Status. */ - cpu->env.v7m.cfsr[attrs.secure] &= ~value; /* W1C */ - if (attrs.secure) { - /* The BFSR bits [15:8] are shared between security states - * and we store them in the NS copy. - */ - cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK); - } - break; case 0xd2c: /* Hard Fault Status. */ cpu->env.v7m.hfsr &= ~value; /* W1C */ break; @@ -1667,6 +1651,14 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr, val = deposit32(val, i * 8, 8, get_prio(s, hdlidx, sbank)); } break; + case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */ + /* The BFSR bits [15:8] are shared between security states + * and we store them in the NS copy + */ + val = s->cpu->env.v7m.cfsr[attrs.secure]; + val |= s->cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK; + val = extract32(val, (offset - 0xd28) * 8, size * 8); + break; case 0xfe0 ... 0xfff: /* ID. */ if (offset & 3) { val = 0; @@ -1765,6 +1757,20 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, } nvic_irq_update(s); return MEMTX_OK; + case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */ + /* All bits are W1C, so construct 32 bit value with 0s in + * the parts not written by the access size + */ + value <<= ((offset - 0xd28) * 8); + + s->cpu->env.v7m.cfsr[attrs.secure] &= ~value; + if (attrs.secure) { + /* The BFSR bits [15:8] are shared between security states + * and we store them in the NS copy. + */ + s->cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK); + } + return MEMTX_OK; } if (size == 4) { nvic_writel(s, offset, value, attrs); From 8638f1ad7403b63db880dadce38e6690b5d82b64 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:10 +0000 Subject: [PATCH 02/24] get_phys_addr_pmsav7: Support AP=0b111 for v7M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For PMSAv7, the v7A/R Arm ARM defines that setting AP to 0b111 is an UNPREDICTABLE reserved combination. However, for v7M this value is documented as having the same behaviour as 0b110: read-only for both privileged and unprivileged. Accept this value on an M profile core rather than treating it as a guest error and a no-access page. Reported-by: Andy Gross Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 1512742402-31669-1-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index d1395f9b73..eb80f79ae1 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9272,6 +9272,13 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, case 6: *prot |= PAGE_READ | PAGE_EXEC; break; + case 7: + /* for v7M, same as 6; for R profile a reserved value */ + if (arm_feature(env, ARM_FEATURE_M)) { + *prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ default: qemu_log_mask(LOG_GUEST_ERROR, "DRACR[%d]: Bad value for AP bits: 0x%" @@ -9290,6 +9297,13 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, case 6: *prot |= PAGE_READ | PAGE_EXEC; break; + case 7: + /* for v7M, same as 6; for R profile a reserved value */ + if (arm_feature(env, ARM_FEATURE_M)) { + *prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ default: qemu_log_mask(LOG_GUEST_ERROR, "DRACR[%d]: Bad value for AP bits: 0x%" From a2a051591c599172993c07043e13e499736ed193 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:10 +0000 Subject: [PATCH 03/24] hw/arm/virt: Add virt-2.12 machine type Add virt-2.12 machine type. Signed-off-by: Peter Maydell --- hw/arm/virt.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 151592b1e5..543f9bd6cc 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1618,7 +1618,7 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_2_11_instance_init(Object *obj) +static void virt_2_12_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); @@ -1678,10 +1678,25 @@ static void virt_2_11_instance_init(Object *obj) vms->irqmap = a15irqmap; } -static void virt_machine_2_11_options(MachineClass *mc) +static void virt_machine_2_12_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(2, 11) +DEFINE_VIRT_MACHINE_AS_LATEST(2, 12) + +#define VIRT_COMPAT_2_11 \ + HW_COMPAT_2_11 + +static void virt_2_11_instance_init(Object *obj) +{ + virt_2_12_instance_init(obj); +} + +static void virt_machine_2_11_options(MachineClass *mc) +{ + virt_machine_2_12_options(mc); + SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_11); +} +DEFINE_VIRT_MACHINE(2, 11) #define VIRT_COMPAT_2_10 \ HW_COMPAT_2_10 From 3b39d734141a71296d08af3d4c32f872fafd782e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:11 +0000 Subject: [PATCH 04/24] target/arm: Handle page table walk load failures correctly Instead of ignoring the response from address_space_ld*() (indicating an attempt to read a page table descriptor from an invalid physical address), use it to report the failure correctly. Since this is another couple of locations where we need to decide the value of the ARMMMUFaultInfo ea bit based on a MemTxResult, we factor out that operation into a helper function. Signed-off-by: Peter Maydell --- target/arm/helper.c | 39 ++++++++++++++++++++++++++++++++++----- target/arm/internals.h | 10 ++++++++++ target/arm/op_helper.c | 7 +------ 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index eb80f79ae1..c83c901a86 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8305,6 +8305,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa, &txattrs, &s2prot, &s2size, fi, NULL); if (ret) { + assert(fi->type != ARMFault_None); fi->s2addr = addr; fi->stage2 = true; fi->s1ptw = true; @@ -8328,7 +8329,9 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; MemTxAttrs attrs = {}; + MemTxResult result = MEMTX_OK; AddressSpace *as; + uint32_t data; attrs.secure = is_secure; as = arm_addressspace(cs, attrs); @@ -8337,10 +8340,16 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } if (regime_translation_big_endian(env, mmu_idx)) { - return address_space_ldl_be(as, addr, attrs, NULL); + data = address_space_ldl_be(as, addr, attrs, &result); } else { - return address_space_ldl_le(as, addr, attrs, NULL); + data = address_space_ldl_le(as, addr, attrs, &result); } + if (result == MEMTX_OK) { + return data; + } + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; } static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, @@ -8349,7 +8358,9 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; MemTxAttrs attrs = {}; + MemTxResult result = MEMTX_OK; AddressSpace *as; + uint32_t data; attrs.secure = is_secure; as = arm_addressspace(cs, attrs); @@ -8358,10 +8369,16 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } if (regime_translation_big_endian(env, mmu_idx)) { - return address_space_ldq_be(as, addr, attrs, NULL); + data = address_space_ldq_be(as, addr, attrs, &result); } else { - return address_space_ldq_le(as, addr, attrs, NULL); + data = address_space_ldq_le(as, addr, attrs, &result); } + if (result == MEMTX_OK) { + return data; + } + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; } static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, @@ -8390,6 +8407,9 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } type = (desc & 3); domain = (desc >> 5) & 0x0f; if (regime_el(env, mmu_idx) == 1) { @@ -8426,6 +8446,9 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } switch (desc & 3) { case 0: /* Page translation fault. */ fi->type = ARMFault_Translation; @@ -8508,6 +8531,9 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } type = (desc & 3); if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) { /* Section translation fault, or attempt to use the encoding @@ -8559,6 +8585,9 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); switch (desc & 3) { case 0: /* Page translation fault. */ @@ -8964,7 +8993,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); - if (fi->s1ptw) { + if (fi->type != ARMFault_None) { goto do_fault; } diff --git a/target/arm/internals.h b/target/arm/internals.h index 876854d876..89f5d2fe12 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -687,6 +687,16 @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) return fsc; } +static inline bool arm_extabort_type(MemTxResult result) +{ + /* The EA bit in syndromes and fault status registers is an + * IMPDEF classification of external aborts. ARM implementations + * usually use this to indicate AXI bus Decode error (0) or + * Slave error (1); in QEMU we follow that. + */ + return result != MEMTX_DECODE_ERROR; +} + /* Do a page table walk and add page to TLB if possible */ bool arm_tlb_fill(CPUState *cpu, vaddr address, MMUAccessType access_type, int mmu_idx, diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index b36206343d..712c5c55b6 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -220,12 +220,7 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, /* now we have a real cpu fault */ cpu_restore_state(cs, retaddr); - /* The EA bit in syndromes and fault status registers is an - * IMPDEF classification of external aborts. ARM implementations - * usually use this to indicate AXI bus Decode error (0) or - * Slave error (1); in QEMU we follow that. - */ - fi.ea = (response != MEMTX_DECODE_ERROR); + fi.ea = arm_extabort_type(response); fi.type = ARMFault_SyncExternal; deliver_fault(cpu, addr, access_type, mmu_idx, &fi); } From 0cb57cc701839e7358918d5f2922ccbc04d28d17 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:11 +0000 Subject: [PATCH 05/24] hw/sd/pl181: Reset SD card on controller reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since pl181 is still using the legacy SD card API, the SD card created by sd_init() is not plugged into any bus. This means that the controller has to reset it manually. Failing to do this mostly didn't affect the guest since the guest typically does a programmed SD card reset as part of its SD controller driver initialization, but meant that migration failed because it's only in sd_reset() that we set up the wpgrps_size field. Cc: qemu-stable@nongnu.org Fixes: https://bugs.launchpad.net/qemu/+bug/1739378 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1515506513-31961-2-git-send-email-peter.maydell@linaro.org --- hw/sd/pl181.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index 55c8098ecd..3ba1f7dd23 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -480,6 +480,10 @@ static void pl181_reset(DeviceState *d) /* We can assume our GPIO outputs have been wired up now */ sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]); + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. + */ + device_reset(DEVICE(s->card)); } static void pl181_init(Object *obj) From 16bf0e0e7aaa8efc0b8ee7e2aecb2fa235f82d38 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:12 +0000 Subject: [PATCH 06/24] hw/sd/milkymist-memcard: Reset SD card on controller reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since milkymist-memcard is still using the legacy SD card API, the SD card created by sd_init() is not plugged into any bus. This means that the controller has to reset it manually. Failing to do this mostly didn't affect the guest since the guest typically does a programmed SD card reset as part of its SD controller driver initialization, but meant that migration failed because it's only in sd_reset() that we set up the wpgrps_size field. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1515506513-31961-3-git-send-email-peter.maydell@linaro.org --- hw/sd/milkymist-memcard.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 4008c81002..341da88552 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -248,6 +248,10 @@ static void milkymist_memcard_reset(DeviceState *d) for (i = 0; i < R_MAX; i++) { s->regs[i] = 0; } + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. + */ + device_reset(DEVICE(s->card)); } static int milkymist_memcard_init(SysBusDevice *dev) From 8046d44f3c9f67828d3368797d4d314433ee75e9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:12 +0000 Subject: [PATCH 07/24] hw/sd/ssi-sd: Reset SD card on controller reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since ssi-sd is still using the legacy SD card API, the SD card created by sd_init() is not plugged into any bus. This means that the controller has to reset it manually. Failing to do this mostly didn't affect the guest since the guest typically does a programmed SD card reset as part of its SD controller driver initialization, but meant that migration failed because it's only in sd_reset() that we set up the wpgrps_size field. In the case of sd-ssi, we have to implement an entire reset function since there wasn't one previously, and that requires a QOM cast macro that got omitted when this device was QOMified. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1515506513-31961-4-git-send-email-peter.maydell@linaro.org --- hw/sd/ssi-sd.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 24001dc3e6..f88f509e0a 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -50,6 +50,9 @@ typedef struct { SDState *sd; } ssi_sd_state; +#define TYPE_SSI_SD "ssi-sd" +#define SSI_SD(obj) OBJECT_CHECK(ssi_sd_state, (obj), TYPE_SSI_SD) + /* State word bits. */ #define SSI_SDR_LOCKED 0x0001 #define SSI_SDR_WP_ERASE 0x0002 @@ -241,7 +244,6 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); DriveInfo *dinfo; - s->mode = SSI_SD_CMD; /* FIXME use a qdev drive property instead of drive_get_next() */ dinfo = drive_get_next(IF_SD); s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true); @@ -251,6 +253,24 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) } } +static void ssi_sd_reset(DeviceState *dev) +{ + ssi_sd_state *s = SSI_SD(dev); + + s->mode = SSI_SD_CMD; + s->cmd = 0; + memset(s->cmdarg, 0, sizeof(s->cmdarg)); + memset(s->response, 0, sizeof(s->response)); + s->arglen = 0; + s->response_pos = 0; + s->stopping = 0; + + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. + */ + device_reset(DEVICE(s->sd)); +} + static void ssi_sd_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -260,10 +280,11 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->transfer = ssi_sd_transfer; k->cs_polarity = SSI_CS_LOW; dc->vmsd = &vmstate_ssi_sd; + dc->reset = ssi_sd_reset; } static const TypeInfo ssi_sd_info = { - .name = "ssi-sd", + .name = TYPE_SSI_SD, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ssi_sd_state), .class_init = ssi_sd_class_init, From ecd219f7abbc17b9d9170206410355bba287831f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jan 2018 13:28:13 +0000 Subject: [PATCH 08/24] hw/sd/omap_mmc: Reset SD card on controller reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since omap_mmc is still using the legacy SD card API, the SD card created by sd_init() is not plugged into any bus. This means that the controller has to reset it manually. Failing to do this mostly didn't affect the guest since the guest typically does a programmed SD card reset as part of its SD controller driver initialization, but would mean that migration fails because it's only in sd_reset() that we set up the wpgrps_size field. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1515506513-31961-5-git-send-email-peter.maydell@linaro.org --- hw/sd/omap_mmc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index e934cd3656..5b47cadf11 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -305,6 +305,12 @@ void omap_mmc_reset(struct omap_mmc_s *host) host->cdet_enable = 0; qemu_set_irq(host->coverswitch, host->cdet_state); host->clkdiv = 0; + + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. When omap_mmc is + * QOMified this must move into the QOM reset function. + */ + device_reset(DEVICE(host->card)); } static uint64_t omap_mmc_read(void *opaque, hwaddr offset, @@ -587,8 +593,6 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base, s->lines = 1; /* TODO: needs to be settable per-board */ s->rev = 1; - omap_mmc_reset(s); - memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", 0x800); memory_region_add_subregion(sysmem, base, &s->iomem); @@ -598,6 +602,8 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base, exit(1); } + omap_mmc_reset(s); + return s; } @@ -613,8 +619,6 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, s->lines = 4; s->rev = 2; - omap_mmc_reset(s); - memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", omap_l4_region_size(ta, 0)); omap_l4_attach(ta, 0, &s->iomem); @@ -628,6 +632,8 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0); sd_set_cb(s->card, NULL, s->cdet); + omap_mmc_reset(s); + return s; } From e90a99fe6bde9b85bff8c052ade51520f20d9bce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Jan 2018 13:28:13 +0000 Subject: [PATCH 09/24] target/arm: Split out vfp_expand_imm Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20180110063337.21538-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 44 ++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ba94f7d045..80ae019172 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -4985,6 +4985,33 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn) } } +/* The imm8 encodes the sign bit, enough bits to represent an exponent in + * the range 01....1xx to 10....0xx, and the most significant 4 bits of + * the mantissa; see VFPExpandImm() in the v8 ARM ARM. + */ +static uint64_t vfp_expand_imm(int size, uint8_t imm8) +{ + uint64_t imm; + + switch (size) { + case MO_64: + imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | + (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) | + extract32(imm8, 0, 6); + imm <<= 48; + break; + case MO_32: + imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | + (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) | + (extract32(imm8, 0, 6) << 3); + imm <<= 16; + break; + default: + g_assert_not_reached(); + } + return imm; +} + /* Floating point immediate * 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0 * +---+---+---+-----------+------+---+------------+-------+------+------+ @@ -5008,22 +5035,7 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn) return; } - /* The imm8 encodes the sign bit, enough bits to represent - * an exponent in the range 01....1xx to 10....0xx, - * and the most significant 4 bits of the mantissa; see - * VFPExpandImm() in the v8 ARM ARM. - */ - if (is_double) { - imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | - (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) | - extract32(imm8, 0, 6); - imm <<= 48; - } else { - imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | - (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) | - (extract32(imm8, 0, 6) << 3); - imm <<= 16; - } + imm = vfp_expand_imm(MO_32 + is_double, imm8); tcg_res = tcg_const_i64(imm); write_fp_dreg(s, rd, tcg_res); From 8081796a75414f9ed5ec3d97158e543ed45908ec Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Jan 2018 13:28:14 +0000 Subject: [PATCH 10/24] target/arm: Add fp16 support to vfp_expand_imm Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20180110063337.21538-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 80ae019172..cf537e9d9b 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -5006,6 +5006,11 @@ static uint64_t vfp_expand_imm(int size, uint8_t imm8) (extract32(imm8, 0, 6) << 3); imm <<= 16; break; + case MO_16: + imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | + (extract32(imm8, 6, 1) ? 0x3000 : 0x4000) | + (extract32(imm8, 0, 6) << 6); + break; default: g_assert_not_reached(); } From f82a0f449b2fdf314900116047ea6d9ee5a2da06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:15 +0000 Subject: [PATCH 11/24] sdhci: clean up includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-2-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci-internal.h | 4 ---- hw/sd/sdhci.c | 1 + include/hw/sd/sdhci.h | 7 ++++++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 161177cf39..248fd027f9 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -24,8 +24,6 @@ #ifndef SDHCI_INTERNAL_H #define SDHCI_INTERNAL_H -#include "hw/sd/sdhci.h" - /* R/W SDMA System Address register 0x0 */ #define SDHC_SYSAD 0x00 @@ -227,6 +225,4 @@ enum { sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */ }; -extern const VMStateDescription sdhci_vmstate; - #endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index b064a087c9..b7d2a20985 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -29,6 +29,7 @@ #include "sysemu/dma.h" #include "qemu/timer.h" #include "qemu/bitops.h" +#include "hw/sd/sdhci.h" #include "sdhci-internal.h" #include "qemu/log.h" diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 0f0c3f1e64..1335373d3c 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -26,17 +26,19 @@ #define SDHCI_H #include "qemu-common.h" -#include "hw/block/block.h" #include "hw/pci/pci.h" #include "hw/sysbus.h" #include "hw/sd/sd.h" /* SD/MMC host controller state */ typedef struct SDHCIState { + /*< private >*/ union { PCIDevice pcidev; SysBusDevice busdev; }; + + /*< public >*/ SDBus sdbus; MemoryRegion iomem; @@ -46,6 +48,7 @@ typedef struct SDHCIState { qemu_irq ro_cb; qemu_irq irq; + /* Registers cleared on reset */ uint32_t sdmasysad; /* SDMA System Address register */ uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */ uint16_t blkcnt; /* Blocks count for current transfer */ @@ -70,8 +73,10 @@ typedef struct SDHCIState { uint16_t acmd12errsts; /* Auto CMD12 error status register */ uint64_t admasysaddr; /* ADMA System Address Register */ + /* Read-only registers */ uint32_t capareg; /* Capabilities Register */ uint32_t maxcurr; /* Maximum Current Capabilities Register */ + uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */ uint32_t buf_maxsz; uint16_t data_count; /* current element in FIFO buffer */ From 03603958a4bdd35b464ee30b9afd6d134cff4cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:15 +0000 Subject: [PATCH 12/24] sdhci: remove dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-3-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 2 -- include/hw/sd/sdhci.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index b7d2a20985..365bc80009 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1200,8 +1200,6 @@ static void sdhci_uninitfn(SDHCIState *s) timer_free(s->insert_timer); timer_del(s->transfer_timer); timer_free(s->transfer_timer); - qemu_free_irq(s->eject_cb); - qemu_free_irq(s->ro_cb); g_free(s->fifo_buffer); s->fifo_buffer = NULL; diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 1335373d3c..dacd726537 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -44,8 +44,6 @@ typedef struct SDHCIState { QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ QEMUTimer *transfer_timer; - qemu_irq eject_cb; - qemu_irq ro_cb; qemu_irq irq; /* Registers cleared on reset */ From b635d98cf323ec7f9e639d52a0e0d29fa7b33e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:16 +0000 Subject: [PATCH 13/24] sdhci: use DEFINE_SDHCI_COMMON_PROPERTIES() for common sysbus/pci properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add common/sysbus/pci/sdbus comments to have clearer code blocks separation. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20180115182436.2066-4-f4bug@amsat.org Signed-off-by: Peter Maydell Reviewed-by: Peter Maydell --- hw/sd/sdhci.c | 25 +++++++++++++++++-------- include/hw/sd/sdhci.h | 4 +++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 365bc80009..c0b4b8457a 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" @@ -1185,6 +1186,14 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s) } } +/* --- qdev common --- */ + +#define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \ + /* Capabilities registers provide information on supported features + * of this specific host controller implementation */ \ + DEFINE_PROP_UINT32("capareg", _state, capareg, SDHC_CAPAB_REG_DEFAULT), \ + DEFINE_PROP_UINT32("maxcurr", _state, maxcurr, 0) + static void sdhci_initfn(SDHCIState *s) { qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), @@ -1264,12 +1273,10 @@ const VMStateDescription sdhci_vmstate = { }, }; -/* Capabilities registers provide information on supported features of this - * specific host controller implementation */ +/* --- qdev PCI --- */ + static Property sdhci_pci_properties[] = { - DEFINE_PROP_UINT32("capareg", SDHCIState, capareg, - SDHC_CAPAB_REG_DEFAULT), - DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0), + DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState), DEFINE_PROP_END_OF_LIST(), }; @@ -1320,10 +1327,10 @@ static const TypeInfo sdhci_pci_info = { }, }; +/* --- qdev SysBus --- */ + static Property sdhci_sysbus_properties[] = { - DEFINE_PROP_UINT32("capareg", SDHCIState, capareg, - SDHC_CAPAB_REG_DEFAULT), - DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0), + DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState), DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk, false), DEFINE_PROP_END_OF_LIST(), @@ -1374,6 +1381,8 @@ static const TypeInfo sdhci_sysbus_info = { .class_init = sdhci_sysbus_class_init, }; +/* --- qdev bus master --- */ + static void sdhci_bus_class_init(ObjectClass *klass, void *data) { SDBusClass *sbc = SD_BUS_CLASS(klass); diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index dacd726537..8041c9629e 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -79,13 +79,15 @@ typedef struct SDHCIState { uint32_t buf_maxsz; uint16_t data_count; /* current element in FIFO buffer */ uint8_t stopped_state;/* Current SDHC state */ - bool pending_insert_quirk;/* Quirk for Raspberry Pi card insert int */ bool pending_insert_state; /* Buffer Data Port Register - virtual access point to R and W buffers */ /* Software Reset Register - always reads as 0 */ /* Force Event Auto CMD12 Error Interrupt Reg - write only */ /* Force Event Error Interrupt Register- write only */ /* RO Host Controller Version Register always reads as 0x2401 */ + + /* Configurable properties */ + bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */ } SDHCIState; #define TYPE_PCI_SDHCI "sdhci-pci" From 1c92c50543332f7432269a9a317c8c7e4c6618ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:16 +0000 Subject: [PATCH 14/24] sdhci: refactor common sysbus/pci class_init() into sdhci_common_class_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now both inherited classes appear as DEVICE_CATEGORY_STORAGE. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-5-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index c0b4b8457a..15d0961ac7 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1273,6 +1273,15 @@ const VMStateDescription sdhci_vmstate = { }, }; +static void sdhci_common_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->vmsd = &sdhci_vmstate; + dc->reset = sdhci_poweron_reset; +} + /* --- qdev PCI --- */ static Property sdhci_pci_properties[] = { @@ -1310,10 +1319,9 @@ static void sdhci_pci_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_REDHAT; k->device_id = PCI_DEVICE_ID_REDHAT_SDHCI; k->class_id = PCI_CLASS_SYSTEM_SDHCI; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->vmsd = &sdhci_vmstate; dc->props = sdhci_pci_properties; - dc->reset = sdhci_poweron_reset; + + sdhci_common_class_init(klass, data); } static const TypeInfo sdhci_pci_info = { @@ -1366,10 +1374,10 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->vmsd = &sdhci_vmstate; dc->props = sdhci_sysbus_properties; dc->realize = sdhci_sysbus_realize; - dc->reset = sdhci_poweron_reset; + + sdhci_common_class_init(klass, data); } static const TypeInfo sdhci_sysbus_info = { From 253674981e2449128ab25b35659a55857c60d5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:17 +0000 Subject: [PATCH 15/24] sdhci: refactor common sysbus/pci realize() into sdhci_common_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-6-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 15d0961ac7..cf0c079990 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1214,6 +1214,15 @@ static void sdhci_uninitfn(SDHCIState *s) s->fifo_buffer = NULL; } +static void sdhci_common_realize(SDHCIState *s, Error **errp) +{ + s->buf_maxsz = sdhci_get_fifolen(s); + s->fifo_buffer = g_malloc0(s->buf_maxsz); + + memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", + SDHC_REGISTERS_MAP_SIZE); +} + static bool sdhci_pending_insert_vmstate_needed(void *opaque) { SDHCIState *s = opaque; @@ -1292,14 +1301,16 @@ static Property sdhci_pci_properties[] = { static void sdhci_pci_realize(PCIDevice *dev, Error **errp) { SDHCIState *s = PCI_SDHCI(dev); + + sdhci_initfn(s); + sdhci_common_realize(s, errp); + if (errp && *errp) { + return; + } + dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ - sdhci_initfn(s); - s->buf_maxsz = sdhci_get_fifolen(s); - s->fifo_buffer = g_malloc0(s->buf_maxsz); s->irq = pci_allocate_irq(dev); - memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", - SDHC_REGISTERS_MAP_SIZE); pci_register_bar(dev, 0, 0, &s->iomem); } @@ -1362,11 +1373,12 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) SDHCIState *s = SYSBUS_SDHCI(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - s->buf_maxsz = sdhci_get_fifolen(s); - s->fifo_buffer = g_malloc0(s->buf_maxsz); + sdhci_common_realize(s, errp); + if (errp && *errp) { + return; + } + sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", - SDHC_REGISTERS_MAP_SIZE); sysbus_init_mmio(sbd, &s->iomem); } From 8b7455c75e9ff506fe979f3e7ef6402b78dd7983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:17 +0000 Subject: [PATCH 16/24] sdhci: refactor common sysbus/pci unrealize() into sdhci_common_unrealize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-7-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index cf0c079990..bbe4570326 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -32,6 +32,7 @@ #include "qemu/bitops.h" #include "hw/sd/sdhci.h" #include "sdhci-internal.h" +#include "qapi/error.h" #include "qemu/log.h" /* host controller debug messages */ @@ -1223,6 +1224,17 @@ static void sdhci_common_realize(SDHCIState *s, Error **errp) SDHC_REGISTERS_MAP_SIZE); } +static void sdhci_common_unrealize(SDHCIState *s, Error **errp) +{ + /* This function is expected to be called only once for each class: + * - SysBus: via DeviceClass->unrealize(), + * - PCI: via PCIDeviceClass->exit(). + * However to avoid double-free and/or use-after-free we still nullify + * this variable (better safe than sorry!). */ + g_free(s->fifo_buffer); + s->fifo_buffer = NULL; +} + static bool sdhci_pending_insert_vmstate_needed(void *opaque) { SDHCIState *s = opaque; @@ -1317,6 +1329,8 @@ static void sdhci_pci_realize(PCIDevice *dev, Error **errp) static void sdhci_pci_exit(PCIDevice *dev) { SDHCIState *s = PCI_SDHCI(dev); + + sdhci_common_unrealize(s, &error_abort); sdhci_uninitfn(s); } @@ -1382,12 +1396,20 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) sysbus_init_mmio(sbd, &s->iomem); } +static void sdhci_sysbus_unrealize(DeviceState *dev, Error **errp) +{ + SDHCIState *s = SYSBUS_SDHCI(dev); + + sdhci_common_unrealize(s, &error_abort); +} + static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->props = sdhci_sysbus_properties; dc->realize = sdhci_sysbus_realize; + dc->unrealize = sdhci_sysbus_unrealize; sdhci_common_class_init(klass, data); } From 00b004b347f3eab1327112cf446e82b983af5209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:18 +0000 Subject: [PATCH 17/24] sdhci: use qemu_log_mask(UNIMP) instead of fprintf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-8-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index bbe4570326..7ffb1dbec5 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -947,7 +947,8 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s); break; default: - ERRPRINT("bad %ub read: addr[0x%04x]\n", size, (int)offset); + qemu_log_mask(LOG_UNIMP, "SDHC rd_%ub @0x%02" HWADDR_PRIx " " + "not implemented\n", size, offset); break; } @@ -1153,8 +1154,8 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) sdhci_update_irq(s); break; default: - ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n", - size, (int)offset, value >> shift, value >> shift); + qemu_log_mask(LOG_UNIMP, "SDHC wr_%ub @0x%02" HWADDR_PRIx " <- 0x%08x " + "not implemented\n", size, offset, value >> shift); break; } DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n", From 8be487d8f184f2f721cabeac559fb7a6cba18c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:18 +0000 Subject: [PATCH 18/24] sdhci: convert the DPRINT() calls into trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zero-initialize ADMADescr 'dscr' in sdhci_do_adma() to avoid: hw/sd/sdhci.c: In function ‘sdhci_do_adma’: hw/sd/sdhci.c:714:29: error: ‘dscr.addr’ may be used uninitialized in this function [-Werror=maybe-uninitialized] trace_sdhci_adma("link", s->admasysaddr); ^ Signed-off-by: Philippe Mathieu-Daudé Acked-by: Alistair Francis Message-id: 20180115182436.2066-9-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 89 ++++++++++++++++------------------------------ hw/sd/trace-events | 14 ++++++++ 2 files changed, 44 insertions(+), 59 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 7ffb1dbec5..68f1aee5dc 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -34,30 +34,7 @@ #include "sdhci-internal.h" #include "qapi/error.h" #include "qemu/log.h" - -/* host controller debug messages */ -#ifndef SDHC_DEBUG -#define SDHC_DEBUG 0 -#endif - -#define DPRINT_L1(fmt, args...) \ - do { \ - if (SDHC_DEBUG) { \ - fprintf(stderr, "QEMU SDHC: " fmt, ## args); \ - } \ - } while (0) -#define DPRINT_L2(fmt, args...) \ - do { \ - if (SDHC_DEBUG > 1) { \ - fprintf(stderr, "QEMU SDHC: " fmt, ## args); \ - } \ - } while (0) -#define ERRPRINT(fmt, args...) \ - do { \ - if (SDHC_DEBUG) { \ - fprintf(stderr, "QEMU SDHC ERROR: " fmt, ## args); \ - } \ - } while (0) +#include "trace.h" #define TYPE_SDHCI_BUS "sdhci-bus" #define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS) @@ -156,8 +133,8 @@ static void sdhci_raise_insertion_irq(void *opaque) static void sdhci_set_inserted(DeviceState *dev, bool level) { SDHCIState *s = (SDHCIState *)dev; - DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject"); + trace_sdhci_set_inserted(level ? "insert" : "eject"); if ((s->norintsts & SDHC_NIS_REMOVE) && level) { /* Give target some time to notice card ejection */ timer_mod(s->insert_timer, @@ -239,7 +216,8 @@ static void sdhci_send_command(SDHCIState *s) s->acmd12errsts = 0; request.cmd = s->cmdreg >> 8; request.arg = s->argument; - DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg); + + trace_sdhci_send_command(request.cmd, request.arg); rlen = sdbus_do_command(&s->sdbus, &request, response); if (s->cmdreg & SDHC_CMD_RESPONSE) { @@ -247,7 +225,7 @@ static void sdhci_send_command(SDHCIState *s) s->rspreg[0] = (response[0] << 24) | (response[1] << 16) | (response[2] << 8) | response[3]; s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0; - DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]); + trace_sdhci_response4(s->rspreg[0]); } else if (rlen == 16) { s->rspreg[0] = (response[11] << 24) | (response[12] << 16) | (response[13] << 8) | response[14]; @@ -257,11 +235,10 @@ static void sdhci_send_command(SDHCIState *s) (response[5] << 8) | response[6]; s->rspreg[3] = (response[0] << 16) | (response[1] << 8) | response[2]; - DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.." - "64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n", - s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]); + trace_sdhci_response16(s->rspreg[3], s->rspreg[2], + s->rspreg[1], s->rspreg[0]); } else { - ERRPRINT("Timeout waiting for command response\n"); + trace_sdhci_error("timeout waiting for command response"); if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) { s->errintsts |= SDHC_EIS_CMDTIMEOUT; s->norintsts |= SDHC_NIS_ERR; @@ -295,7 +272,7 @@ static void sdhci_end_transfer(SDHCIState *s) request.cmd = 0x0C; request.arg = 0; - DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg); + trace_sdhci_end_transfer(request.cmd, request.arg); sdbus_do_command(&s->sdbus, &request, response); /* Auto CMD12 response goes to the upper Response register */ s->rspreg[3] = (response[0] << 24) | (response[1] << 16) | @@ -364,7 +341,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size) /* first check that a valid data exists in host controller input buffer */ if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) { - ERRPRINT("Trying to read from empty buffer\n"); + trace_sdhci_error("read from empty buffer"); return 0; } @@ -373,8 +350,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size) s->data_count++; /* check if we've read all valid data (blksize bytes) from buffer */ if ((s->data_count) >= (s->blksize & 0x0fff)) { - DPRINT_L2("All %u bytes of data have been read from input buffer\n", - s->data_count); + trace_sdhci_read_dataport(s->data_count); s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */ s->data_count = 0; /* next buff read must start at position [0] */ @@ -457,7 +433,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size) /* Check that there is free space left in a buffer */ if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) { - ERRPRINT("Can't write to data buffer: buffer full\n"); + trace_sdhci_error("Can't write to data buffer: buffer full"); return; } @@ -466,8 +442,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size) s->data_count++; value >>= 8; if (s->data_count >= (s->blksize & 0x0fff)) { - DPRINT_L2("write buffer filled with %u bytes of data\n", - s->data_count); + trace_sdhci_write_dataport(s->data_count); s->data_count = 0; s->prnsts &= ~SDHC_SPACE_AVAILABLE; if (s->prnsts & SDHC_DOING_WRITE) { @@ -655,15 +630,14 @@ static void sdhci_do_adma(SDHCIState *s) { unsigned int n, begin, length; const uint16_t block_size = s->blksize & 0x0fff; - ADMADescr dscr; + ADMADescr dscr = {}; int i; for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) { s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH; get_adma_description(s, &dscr); - DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n", - dscr.addr, dscr.length, dscr.attr); + trace_sdhci_adma_loop(dscr.addr, dscr.length, dscr.attr); if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) { /* Indicate that error occurred in ST_FDS state */ @@ -746,8 +720,7 @@ static void sdhci_do_adma(SDHCIState *s) break; case SDHC_ADMA_ATTR_ACT_LINK: /* link to next descriptor table */ s->admasysaddr = dscr.addr; - DPRINT_L1("ADMA link: admasysaddr=0x%" PRIx64 "\n", - s->admasysaddr); + trace_sdhci_adma("link", s->admasysaddr); break; default: s->admasysaddr += dscr.incr; @@ -755,8 +728,7 @@ static void sdhci_do_adma(SDHCIState *s) } if (dscr.attr & SDHC_ADMA_ATTR_INT) { - DPRINT_L1("ADMA interrupt: admasysaddr=0x%" PRIx64 "\n", - s->admasysaddr); + trace_sdhci_adma("interrupt", s->admasysaddr); if (s->norintstsen & SDHC_NISEN_DMA) { s->norintsts |= SDHC_NIS_DMA; } @@ -767,15 +739,15 @@ static void sdhci_do_adma(SDHCIState *s) /* ADMA transfer terminates if blkcnt == 0 or by END attribute */ if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) { - DPRINT_L2("ADMA transfer completed\n"); + trace_sdhci_adma_transfer_completed(); if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) && (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && s->blkcnt != 0)) { - ERRPRINT("SD/MMC host ADMA length mismatch\n"); + trace_sdhci_error("SD/MMC host ADMA length mismatch"); s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH | SDHC_ADMAERR_STATE_ST_TFR; if (s->errintstsen & SDHC_EISEN_ADMAERR) { - ERRPRINT("Set ADMA error flag\n"); + trace_sdhci_error("Set ADMA error flag"); s->errintsts |= SDHC_EIS_ADMAERR; s->norintsts |= SDHC_NIS_ERR; } @@ -811,7 +783,7 @@ static void sdhci_data_transfer(void *opaque) break; case SDHC_CTRL_ADMA1_32: if (!(s->capareg & SDHC_CAN_DO_ADMA1)) { - ERRPRINT("ADMA1 not supported\n"); + trace_sdhci_error("ADMA1 not supported"); break; } @@ -819,7 +791,7 @@ static void sdhci_data_transfer(void *opaque) break; case SDHC_CTRL_ADMA2_32: if (!(s->capareg & SDHC_CAN_DO_ADMA2)) { - ERRPRINT("ADMA2 not supported\n"); + trace_sdhci_error("ADMA2 not supported"); break; } @@ -828,14 +800,14 @@ static void sdhci_data_transfer(void *opaque) case SDHC_CTRL_ADMA2_64: if (!(s->capareg & SDHC_CAN_DO_ADMA2) || !(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) { - ERRPRINT("64 bit ADMA not supported\n"); + trace_sdhci_error("64 bit ADMA not supported"); break; } sdhci_do_adma(s); break; default: - ERRPRINT("Unsupported DMA type\n"); + trace_sdhci_error("Unsupported DMA type"); break; } } else { @@ -870,8 +842,8 @@ static inline bool sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num) { if ((s->data_count & 0x3) != byte_num) { - ERRPRINT("Non-sequential access to Buffer Data Port register" - "is prohibited\n"); + trace_sdhci_error("Non-sequential access to Buffer Data Port register" + "is prohibited\n"); return false; } return true; @@ -901,8 +873,7 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) case SDHC_BDATA: if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) { ret = sdhci_read_dataport(s, size); - DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, - ret, ret); + trace_sdhci_access("rd", size << 3, offset, "->", ret, ret); return ret; } break; @@ -954,7 +925,7 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) ret >>= (offset & 0x3) * 8; ret &= (1ULL << (size * 8)) - 1; - DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, ret, ret); + trace_sdhci_access("rd", size << 3, offset, "->", ret, ret); return ret; } @@ -1158,8 +1129,8 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) "not implemented\n", size, offset, value >> shift); break; } - DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n", - size, (int)offset, value >> shift, value >> shift); + trace_sdhci_access("wr", size << 3, offset, "<-", + value >> shift, value >> shift); } static const MemoryRegionOps sdhci_mmio_ops = { diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 6eca3470e2..0a121156a3 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -1,5 +1,19 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/sd/sdhci.c +sdhci_set_inserted(const char *level) "card state changed: %s" +sdhci_send_command(uint8_t cmd, uint32_t arg) "CMD%02u ARG[0x%08x]" +sdhci_error(const char *msg) "%s" +sdhci_response4(uint32_t r0) "RSPREG[31..0]=0x%08x" +sdhci_response16(uint32_t r3, uint32_t r2, uint32_t r1, uint32_t r0) "RSPREG[127..96]=0x%08x, RSPREG[95..64]=0x%08x, RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x" +sdhci_end_transfer(uint8_t cmd, uint32_t arg) "Automatically issue CMD%02u 0x%08x" +sdhci_adma(const char *desc, uint32_t sysad) "%s: admasysaddr=0x%" PRIx32 +sdhci_adma_loop(uint64_t addr, uint16_t length, uint8_t attr) "addr=0x%08" PRIx64 ", len=%d, attr=0x%x" +sdhci_adma_transfer_completed(void) "" +sdhci_access(const char *access, unsigned int size, uint64_t offset, const char *dir, uint64_t val, uint64_t val2) "%s%u: addr[0x%04" PRIx64 "] %s 0x%08" PRIx64 " (%" PRIu64 ")" +sdhci_read_dataport(uint16_t data_count) "all %u bytes of data have been read from input buffer" +sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of data" + # hw/sd/milkymist-memcard.c milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" From 24bddf9d4a278018e38ed7380871a5d1a0c65f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:19 +0000 Subject: [PATCH 19/24] sdhci: move MASK_TRNMOD with other SDHC_TRN* defines in "sd-internal.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-10-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci-internal.h | 1 + hw/sd/sdhci.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 248fd027f9..e941bc2386 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -43,6 +43,7 @@ #define SDHC_TRNS_ACMD12 0x0004 #define SDHC_TRNS_READ 0x0010 #define SDHC_TRNS_MULTI 0x0020 +#define SDHC_TRNMOD_MASK 0x0037 /* R/W Command Register 0x0 */ #define SDHC_CMDREG 0x0E diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 68f1aee5dc..4265b6a20e 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -99,7 +99,6 @@ (SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \ (SDHC_CAPAB_TOCLKFREQ)) -#define MASK_TRNMOD 0x0037 #define MASKED_WRITE(reg, mask, val) (reg = (reg & (mask)) | (val)) static uint8_t sdhci_slotint(SDHCIState *s) @@ -1026,7 +1025,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) if (!(s->capareg & SDHC_CAN_DO_DMA)) { value &= ~SDHC_TRNS_DMA; } - MASKED_WRITE(s->trnmod, mask, value & MASK_TRNMOD); + MASKED_WRITE(s->trnmod, mask, value & SDHC_TRNMOD_MASK); MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16); /* Writing to the upper byte of CMDREG triggers SD command generation */ From cd2094219f2734cb0e759ffe9d5f4a5493ca1cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:19 +0000 Subject: [PATCH 20/24] sdhci: rename the SDHC_CAPAB register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-11-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci-internal.h | 2 +- hw/sd/sdhci.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index e941bc2386..fc807f08f3 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -174,7 +174,7 @@ #define SDHC_ACMD12ERRSTS 0x3C /* HWInit Capabilities Register 0x05E80080 */ -#define SDHC_CAPAREG 0x40 +#define SDHC_CAPAB 0x40 #define SDHC_CAN_DO_DMA 0x00400000 #define SDHC_CAN_DO_ADMA2 0x00080000 #define SDHC_CAN_DO_ADMA1 0x00100000 diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 4265b6a20e..c4e486e2ff 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -898,7 +898,7 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) case SDHC_ACMD12ERRSTS: ret = s->acmd12errsts; break; - case SDHC_CAPAREG: + case SDHC_CAPAB: ret = s->capareg; break; case SDHC_MAXCURR: From 5efc9016e52596ec054b19bb0ae1d274f77f2a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:20 +0000 Subject: [PATCH 21/24] sdhci: fix CAPAB/MAXCURR registers, both are 64bit and read-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit running qtests: $ make check-qtest-arm GTESTER check-qtest-arm SDHC rd_4b @0x44 not implemented SDHC wr_4b @0x40 <- 0x89abcdef not implemented SDHC wr_4b @0x44 <- 0x01234567 not implemented Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-12-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 23 +++++++++++++++++++---- include/hw/sd/sdhci.h | 4 ++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index c4e486e2ff..d4fcebcd6a 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -899,10 +899,16 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) ret = s->acmd12errsts; break; case SDHC_CAPAB: - ret = s->capareg; + ret = (uint32_t)s->capareg; + break; + case SDHC_CAPAB + 4: + ret = (uint32_t)(s->capareg >> 32); break; case SDHC_MAXCURR: - ret = s->maxcurr; + ret = (uint32_t)s->maxcurr; + break; + case SDHC_MAXCURR + 4: + ret = (uint32_t)(s->maxcurr >> 32); break; case SDHC_ADMAERR: ret = s->admaerr; @@ -1123,6 +1129,15 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) } sdhci_update_irq(s); break; + + case SDHC_CAPAB: + case SDHC_CAPAB + 4: + case SDHC_MAXCURR: + case SDHC_MAXCURR + 4: + qemu_log_mask(LOG_GUEST_ERROR, "SDHC wr_%ub @0x%02" HWADDR_PRIx + " <- 0x%08x read-only\n", size, offset, value >> shift); + break; + default: qemu_log_mask(LOG_UNIMP, "SDHC wr_%ub @0x%02" HWADDR_PRIx " <- 0x%08x " "not implemented\n", size, offset, value >> shift); @@ -1163,8 +1178,8 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s) #define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \ /* Capabilities registers provide information on supported features * of this specific host controller implementation */ \ - DEFINE_PROP_UINT32("capareg", _state, capareg, SDHC_CAPAB_REG_DEFAULT), \ - DEFINE_PROP_UINT32("maxcurr", _state, maxcurr, 0) + DEFINE_PROP_UINT64("capareg", _state, capareg, SDHC_CAPAB_REG_DEFAULT), \ + DEFINE_PROP_UINT64("maxcurr", _state, maxcurr, 0) static void sdhci_initfn(SDHCIState *s) { diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 8041c9629e..442e30aff2 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -72,8 +72,8 @@ typedef struct SDHCIState { uint64_t admasysaddr; /* ADMA System Address Register */ /* Read-only registers */ - uint32_t capareg; /* Capabilities Register */ - uint32_t maxcurr; /* Maximum Current Capabilities Register */ + uint64_t capareg; /* Capabilities Register */ + uint64_t maxcurr; /* Maximum Current Capabilities Register */ uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */ uint32_t buf_maxsz; From 5d2c0464fa7e3b00ed8eb4791ba1e955e29b685b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 16 Jan 2018 13:28:20 +0000 Subject: [PATCH 22/24] sdhci: Implement write method of ACMD12ERRSTS register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180115182436.2066-13-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index d4fcebcd6a..9bdbcd0a04 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1129,6 +1129,9 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) } sdhci_update_irq(s); break; + case SDHC_ACMD12ERRSTS: + MASKED_WRITE(s->acmd12errsts, mask, value); + break; case SDHC_CAPAB: case SDHC_CAPAB + 4: From dd55c485ec2fcd28c245061b320398d35b92d30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:21 +0000 Subject: [PATCH 23/24] sdhci: fix the PCI device, using the PCI address space for DMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While SysBus devices can use the get_system_memory() address space, PCI devices should use the bus master address space for DMA. Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Message-id: 20180115182436.2066-14-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 29 +++++++++++++++-------------- include/hw/sd/sdhci.h | 1 + 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 9bdbcd0a04..dd400695e4 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -496,7 +496,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) s->blkcnt--; } } - dma_memory_write(&address_space_memory, s->sdmasysad, + dma_memory_write(s->dma_as, s->sdmasysad, &s->fifo_buffer[begin], s->data_count - begin); s->sdmasysad += s->data_count - begin; if (s->data_count == block_size) { @@ -518,7 +518,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) s->data_count = block_size; boundary_count -= block_size - begin; } - dma_memory_read(&address_space_memory, s->sdmasysad, + dma_memory_read(s->dma_as, s->sdmasysad, &s->fifo_buffer[begin], s->data_count - begin); s->sdmasysad += s->data_count - begin; if (s->data_count == block_size) { @@ -556,11 +556,9 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s) for (n = 0; n < datacnt; n++) { s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); } - dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer, - datacnt); + dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt); } else { - dma_memory_read(&address_space_memory, s->sdmasysad, s->fifo_buffer, - datacnt); + dma_memory_read(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt); for (n = 0; n < datacnt; n++) { sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); } @@ -584,7 +582,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) hwaddr entry_addr = (hwaddr)s->admasysaddr; switch (SDHC_DMA_TYPE(s->hostctl)) { case SDHC_CTRL_ADMA2_32: - dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma2, + dma_memory_read(s->dma_as, entry_addr, (uint8_t *)&adma2, sizeof(adma2)); adma2 = le64_to_cpu(adma2); /* The spec does not specify endianness of descriptor table. @@ -596,7 +594,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) dscr->incr = 8; break; case SDHC_CTRL_ADMA1_32: - dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma1, + dma_memory_read(s->dma_as, entry_addr, (uint8_t *)&adma1, sizeof(adma1)); adma1 = le32_to_cpu(adma1); dscr->addr = (hwaddr)(adma1 & 0xFFFFF000); @@ -609,12 +607,12 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) } break; case SDHC_CTRL_ADMA2_64: - dma_memory_read(&address_space_memory, entry_addr, + dma_memory_read(s->dma_as, entry_addr, (uint8_t *)(&dscr->attr), 1); - dma_memory_read(&address_space_memory, entry_addr + 2, + dma_memory_read(s->dma_as, entry_addr + 2, (uint8_t *)(&dscr->length), 2); dscr->length = le16_to_cpu(dscr->length); - dma_memory_read(&address_space_memory, entry_addr + 4, + dma_memory_read(s->dma_as, entry_addr + 4, (uint8_t *)(&dscr->addr), 8); dscr->attr = le64_to_cpu(dscr->attr); dscr->attr &= 0xfffffff8; @@ -673,7 +671,7 @@ static void sdhci_do_adma(SDHCIState *s) s->data_count = block_size; length -= block_size - begin; } - dma_memory_write(&address_space_memory, dscr.addr, + dma_memory_write(s->dma_as, dscr.addr, &s->fifo_buffer[begin], s->data_count - begin); dscr.addr += s->data_count - begin; @@ -697,7 +695,7 @@ static void sdhci_do_adma(SDHCIState *s) s->data_count = block_size; length -= block_size - begin; } - dma_memory_read(&address_space_memory, dscr.addr, + dma_memory_read(s->dma_as, dscr.addr, &s->fifo_buffer[begin], s->data_count - begin); dscr.addr += s->data_count - begin; @@ -1312,7 +1310,8 @@ static void sdhci_pci_realize(PCIDevice *dev, Error **errp) dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ s->irq = pci_allocate_irq(dev); - pci_register_bar(dev, 0, 0, &s->iomem); + s->dma_as = pci_get_address_space(dev); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem); } static void sdhci_pci_exit(PCIDevice *dev) @@ -1381,6 +1380,8 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) return; } + s->dma_as = &address_space_memory; + sysbus_init_irq(sbd, &s->irq); sysbus_init_mmio(sbd, &s->iomem); } diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 442e30aff2..4a102b86ce 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -41,6 +41,7 @@ typedef struct SDHCIState { /*< public >*/ SDBus sdbus; MemoryRegion iomem; + AddressSpace *dma_as; QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ QEMUTimer *transfer_timer; From 60765b6ceeb4998a0d4220b3a53f1f185061da77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jan 2018 13:28:21 +0000 Subject: [PATCH 24/24] sdhci: add a 'dma' property to the sysbus devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a 'dma' property allowing machine creation to provide the address-space SDHCI DMA operates on. [based on a patch from Alistair Francis from qemu/xilinx tag xilinx-v2016.1] Signed-off-by: Philippe Mathieu-Daudé Message-id: 20180115182436.2066-15-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 18 +++++++++++++++++- include/hw/sd/sdhci.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index dd400695e4..f9264d3be5 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1354,6 +1354,8 @@ static Property sdhci_sysbus_properties[] = { DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState), DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk, false), + DEFINE_PROP_LINK("dma", SDHCIState, + dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; @@ -1367,6 +1369,11 @@ static void sdhci_sysbus_init(Object *obj) static void sdhci_sysbus_finalize(Object *obj) { SDHCIState *s = SYSBUS_SDHCI(obj); + + if (s->dma_mr) { + object_unparent(OBJECT(s->dma_mr)); + } + sdhci_uninitfn(s); } @@ -1380,7 +1387,12 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) return; } - s->dma_as = &address_space_memory; + if (s->dma_mr) { + address_space_init(s->dma_as, s->dma_mr, "sdhci-dma"); + } else { + /* use system_memory() if property "dma" not set */ + s->dma_as = &address_space_memory; + } sysbus_init_irq(sbd, &s->irq); sysbus_init_mmio(sbd, &s->iomem); @@ -1391,6 +1403,10 @@ static void sdhci_sysbus_unrealize(DeviceState *dev, Error **errp) SDHCIState *s = SYSBUS_SDHCI(dev); sdhci_common_unrealize(s, &error_abort); + + if (s->dma_mr) { + address_space_destroy(s->dma_as); + } } static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 4a102b86ce..cb37182536 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -42,6 +42,7 @@ typedef struct SDHCIState { SDBus sdbus; MemoryRegion iomem; AddressSpace *dma_as; + MemoryRegion *dma_mr; QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ QEMUTimer *transfer_timer;