diff options
36 files changed, 788 insertions, 147 deletions
diff --git a/Makefile.objs b/Makefile.objs index 2c8cb72..7a9828d 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -213,6 +213,7 @@ trace-events-subdirs += hw/char trace-events-subdirs += hw/display trace-events-subdirs += hw/dma trace-events-subdirs += hw/hppa +trace-events-subdirs += hw/i2c trace-events-subdirs += hw/i386 trace-events-subdirs += hw/i386/xen trace-events-subdirs += hw/ide diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 8ba2558..7cf73d2 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -16,6 +16,7 @@ CONFIG_TSC2005=y CONFIG_LM832X=y CONFIG_TMP105=y CONFIG_TMP421=y +CONFIG_PCA9552=y CONFIG_STELLARIS=y CONFIG_STELLARIS_INPUT=y CONFIG_STELLARIS_ENET=y diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a7110a7..bb9d338 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 "hw/loader.h" @@ -45,6 +46,7 @@ enum { PALMETTO_BMC, AST2500_EVB, ROMULUS_BMC, + WITHERSPOON_BMC, }; /* Palmetto hardware value: 0x120CE416 */ @@ -82,8 +84,13 @@ 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 romulus_bmc_i2c_init(AspeedBoardState *bmc); +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc); static const AspeedBoardConfig aspeed_boards[] = { [PALMETTO_BMC] = { @@ -108,6 +115,15 @@ 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", + .hw_strap1 = WITHERSPOON_BMC_HW_STRAP1, + .fmc_model = "mx25l25635e", + .spi_model = "mx66l1g45g", + .num_cs = 2, + .i2c_init = witherspoon_bmc_i2c_init, }, }; @@ -248,11 +264,15 @@ static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->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(&soc->i2c), 0), "ds1338", 0x68); + smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), 0x50, + eeprom_buf); + /* add a TMP423 temperature sensor */ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), "tmp423", 0x4c); @@ -278,7 +298,6 @@ static void palmetto_bmc_class_init(ObjectClass *oc, void *data) mc->no_floppy = 1; mc->no_cdrom = 1; mc->no_parallel = 1; - mc->ignore_memory_transaction_failures = true; } static const TypeInfo palmetto_bmc_type = { @@ -290,9 +309,17 @@ static const TypeInfo palmetto_bmc_type = { static void ast2500_evb_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; + uint8_t *eeprom_buf = g_malloc0(8 * 1024); + + smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), 0x50, + eeprom_buf); /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->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(&soc->i2c), 11), "ds1338", 0x32); } static void ast2500_evb_init(MachineState *machine) @@ -311,7 +338,6 @@ static void ast2500_evb_class_init(ObjectClass *oc, void *data) mc->no_floppy = 1; mc->no_cdrom = 1; mc->no_parallel = 1; - mc->ignore_memory_transaction_failures = true; } static const TypeInfo ast2500_evb_type = { @@ -320,6 +346,15 @@ static const TypeInfo ast2500_evb_type = { .class_init = ast2500_evb_class_init, }; +static void romulus_bmc_i2c_init(AspeedBoardState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + + /* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is + * good enough */ + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); +} + static void romulus_bmc_init(MachineState *machine) { aspeed_board_init(machine, &aspeed_boards[ROMULUS_BMC]); @@ -336,7 +371,6 @@ static void romulus_bmc_class_init(ObjectClass *oc, void *data) mc->no_floppy = 1; mc->no_cdrom = 1; mc->no_parallel = 1; - mc->ignore_memory_transaction_failures = true; } static const TypeInfo romulus_bmc_type = { @@ -345,11 +379,59 @@ static const TypeInfo romulus_bmc_type = { .class_init = romulus_bmc_class_init, }; +static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + uint8_t *eeprom_buf = g_malloc0(8 * 1024); + + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60); + + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "tmp423", 0x4c); + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 5), "tmp423", 0x4c); + + /* The Witherspoon expects a TMP275 but a TMP105 is compatible */ + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->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(&soc->i2c), 11), "ds1338", 0x32); + + smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), 0x51, + eeprom_buf); + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "pca9552", + 0x60); +} + +static void witherspoon_bmc_init(MachineState *machine) +{ + aspeed_board_init(machine, &aspeed_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; +} + +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(&palmetto_bmc_type); type_register_static(&ast2500_evb_type); type_register_static(&romulus_bmc_type); + type_register_static(&witherspoon_bmc_type); } type_init(aspeed_machine_init) diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index e886f54..502a208 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -203,11 +203,11 @@ static uint64_t gptm_read(void *opaque, hwaddr offset, return s->rtc; } qemu_log_mask(LOG_UNIMP, - "GPTM: read of TAR but timer read not supported"); + "GPTM: read of TAR but timer read not supported\n"); return 0; case 0x4c: /* TBR */ qemu_log_mask(LOG_UNIMP, - "GPTM: read of TBR but timer read not supported"); + "GPTM: read of TBR but timer read not supported\n"); return 0; default: qemu_log_mask(LOG_GUEST_ERROR, @@ -836,11 +836,12 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset, break; case 0x20: /* MCR */ if (value & 1) { - qemu_log_mask(LOG_UNIMP, "stellaris_i2c: Loopback not implemented"); + qemu_log_mask(LOG_UNIMP, + "stellaris_i2c: Loopback not implemented\n"); } if (value & 0x20) { qemu_log_mask(LOG_UNIMP, - "stellaris_i2c: Slave mode not implemented"); + "stellaris_i2c: Slave mode not implemented\n"); } s->mcr = value & 0x31; break; @@ -1124,7 +1125,7 @@ static void stellaris_adc_write(void *opaque, hwaddr offset, s->sspri = value; break; case 0x28: /* PSSI */ - qemu_log_mask(LOG_UNIMP, "ADC: sample initiate unimplemented"); + qemu_log_mask(LOG_UNIMP, "ADC: sample initiate unimplemented\n"); break; case 0x30: /* SAC */ s->sac = value; diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index c70278c..f26fd8e 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -39,10 +39,6 @@ typedef struct XlnxZCU102 { #define ZCU102_MACHINE(obj) \ OBJECT_CHECK(XlnxZCU102, (obj), TYPE_ZCU102_MACHINE) -#define TYPE_EP108_MACHINE MACHINE_TYPE_NAME("xlnx-ep108") -#define EP108_MACHINE(obj) \ - OBJECT_CHECK(XlnxZCU102, (obj), TYPE_EP108_MACHINE) - static struct arm_boot_info xlnx_zcu102_binfo; static bool zcu102_get_secure(Object *obj, Error **errp) @@ -73,8 +69,9 @@ static void zcu102_set_virt(Object *obj, bool value, Error **errp) s->virt = value; } -static void xlnx_zynqmp_init(XlnxZCU102 *s, MachineState *machine) +static void xlnx_zcu102_init(MachineState *machine) { + XlnxZCU102 *s = ZCU102_MACHINE(machine); int i; uint64_t ram_size = machine->ram_size; @@ -183,60 +180,6 @@ static void xlnx_zynqmp_init(XlnxZCU102 *s, MachineState *machine) arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_zcu102_binfo); } -static void xlnx_ep108_init(MachineState *machine) -{ - XlnxZCU102 *s = EP108_MACHINE(machine); - - if (!qtest_enabled()) { - info_report("The Xilinx EP108 machine is deprecated, please use the " - "ZCU102 machine (which has the same features) instead."); - } - - xlnx_zynqmp_init(s, machine); -} - -static void xlnx_ep108_machine_instance_init(Object *obj) -{ - XlnxZCU102 *s = EP108_MACHINE(obj); - - /* EP108, we don't support setting secure or virt */ - s->secure = false; - s->virt = false; -} - -static void xlnx_ep108_machine_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Xilinx ZynqMP EP108 board (Deprecated, please use xlnx-zcu102)"; - mc->init = xlnx_ep108_init; - mc->block_default_type = IF_IDE; - mc->units_per_default_bus = 1; - mc->ignore_memory_transaction_failures = true; - mc->max_cpus = XLNX_ZYNQMP_NUM_APU_CPUS + XLNX_ZYNQMP_NUM_RPU_CPUS; - mc->default_cpus = XLNX_ZYNQMP_NUM_APU_CPUS; -} - -static const TypeInfo xlnx_ep108_machine_init_typeinfo = { - .name = MACHINE_TYPE_NAME("xlnx-ep108"), - .parent = TYPE_MACHINE, - .class_init = xlnx_ep108_machine_class_init, - .instance_init = xlnx_ep108_machine_instance_init, - .instance_size = sizeof(XlnxZCU102), -}; - -static void xlnx_ep108_machine_init_register_types(void) -{ - type_register_static(&xlnx_ep108_machine_init_typeinfo); -} - -static void xlnx_zcu102_init(MachineState *machine) -{ - XlnxZCU102 *s = ZCU102_MACHINE(machine); - - xlnx_zynqmp_init(s, machine); -} - static void xlnx_zcu102_machine_instance_init(Object *obj) { XlnxZCU102 *s = ZCU102_MACHINE(obj); @@ -289,4 +232,3 @@ static void xlnx_zcu102_machine_init_register_types(void) } type_init(xlnx_zcu102_machine_init_register_types) -type_init(xlnx_ep108_machine_init_register_types) diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index 6ebcb87..ccc75ea 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -60,7 +60,7 @@ static uint64_t digic_uart_read(void *opaque, hwaddr addr, default: qemu_log_mask(LOG_UNIMP, "digic-uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); + TARGET_FMT_plx "\n", addr << 2); } return ret; @@ -98,7 +98,7 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, default: qemu_log_mask(LOG_UNIMP, "digic-uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); + TARGET_FMT_plx "\n", addr << 2); } } diff --git a/hw/core/register.c b/hw/core/register.c index 0741a1a..d2d1636 100644 --- a/hw/core/register.c +++ b/hw/core/register.c @@ -96,7 +96,7 @@ void register_write(RegisterInfo *reg, uint64_t val, uint64_t we, if (test) { qemu_log_mask(LOG_UNIMP, "%s:%s writing %#" PRIx64 " to unimplemented bits:" \ - " %#" PRIx64 "", + " %#" PRIx64 "\n", prefix, reg->access->name, val, ac->unimp); } diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 6715b9c..c32ab08 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1074,7 +1074,9 @@ static void xlnx_dp_avbufm_write(void *opaque, hwaddr offset, uint64_t value, case AV_BUF_STC_SNAPSHOT1: case AV_BUF_HCOUNT_VCOUNT_INT0: case AV_BUF_HCOUNT_VCOUNT_INT1: - qemu_log_mask(LOG_UNIMP, "avbufm: unimplmented"); + qemu_log_mask(LOG_UNIMP, "avbufm: unimplemented register 0x%04" + PRIx64 "\n", + offset << 2); break; default: s->avbufm_registers[offset] = value; diff --git a/hw/i2c/core.c b/hw/i2c/core.c index ab72d5b..b547259 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "hw/i2c/i2c.h" +#include "trace.h" #define I2C_BROADCAST 0x00 @@ -130,14 +131,16 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) } QLIST_FOREACH(node, &bus->current_devs, next) { + I2CSlave *s = node->elt; int rv; - sc = I2C_SLAVE_GET_CLASS(node->elt); + sc = I2C_SLAVE_GET_CLASS(s); /* If the bus is already busy, assume this is a repeated start condition. */ if (sc->event) { - rv = sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND); + trace_i2c_event("start", s->address); + rv = sc->event(s, recv ? I2C_START_RECV : I2C_START_SEND); if (rv && !bus->broadcast) { if (bus_scanned) { /* First call, terminate the transfer. */ @@ -156,9 +159,11 @@ void i2c_end_transfer(I2CBus *bus) I2CNode *node, *next; QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) { - sc = I2C_SLAVE_GET_CLASS(node->elt); + I2CSlave *s = node->elt; + sc = I2C_SLAVE_GET_CLASS(s); if (sc->event) { - sc->event(node->elt, I2C_FINISH); + trace_i2c_event("finish", s->address); + sc->event(s, I2C_FINISH); } QLIST_REMOVE(node, next); g_free(node); @@ -169,14 +174,17 @@ void i2c_end_transfer(I2CBus *bus) int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send) { I2CSlaveClass *sc; + I2CSlave *s; I2CNode *node; int ret = 0; if (send) { QLIST_FOREACH(node, &bus->current_devs, next) { - sc = I2C_SLAVE_GET_CLASS(node->elt); + s = node->elt; + sc = I2C_SLAVE_GET_CLASS(s); if (sc->send) { - ret = ret || sc->send(node->elt, *data); + trace_i2c_send(s->address, *data); + ret = ret || sc->send(s, *data); } else { ret = -1; } @@ -189,7 +197,9 @@ int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send) sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt); if (sc->recv) { - ret = sc->recv(QLIST_FIRST(&bus->current_devs)->elt); + s = QLIST_FIRST(&bus->current_devs)->elt; + ret = sc->recv(s); + trace_i2c_recv(s->address, ret); if (ret < 0) { return ret; } else { @@ -226,6 +236,7 @@ void i2c_nack(I2CBus *bus) QLIST_FOREACH(node, &bus->current_devs, next) { sc = I2C_SLAVE_GET_CLASS(node->elt); if (sc->event) { + trace_i2c_event("nack", node->elt->address); sc->event(node->elt, I2C_NACK); } } diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index 125c887..f18aa3d 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -139,6 +139,16 @@ static void smbus_eeprom_register_types(void) type_init(smbus_eeprom_register_types) +void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf) +{ + DeviceState *dev; + + dev = qdev_create((BusState *) smbus, "smbus-eeprom"); + qdev_prop_set_uint8(dev, "address", address); + qdev_prop_set_ptr(dev, "data", eeprom_buf); + qdev_init_nofail(dev); +} + void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int eeprom_spd_size) { @@ -149,10 +159,6 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, } for (i = 0; i < nb_eeprom; i++) { - DeviceState *eeprom; - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50 + i); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); - qdev_init_nofail(eeprom); + smbus_eeprom_init_one(smbus, 0x50 + i, eeprom_buf + (i * 256)); } } diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events new file mode 100644 index 0000000..d339b61 --- /dev/null +++ b/hw/i2c/trace-events @@ -0,0 +1,7 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# hw/i2c/core.c + +i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)" +i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x" +i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x" diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 7b54d52..864b7c6 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -27,6 +27,7 @@ #include "hw/intc/arm_gicv3_common.h" #include "gicv3_internal.h" #include "hw/arm/linux-boot-if.h" +#include "sysemu/kvm.h" static int gicv3_pre_save(void *opaque) { @@ -141,6 +142,79 @@ static const VMStateDescription vmstate_gicv3_cpu = { } }; +static int gicv3_gicd_no_migration_shift_bug_pre_load(void *opaque) +{ + GICv3State *cs = opaque; + + /* + * The gicd_no_migration_shift_bug flag is used for migration compatibility + * for old version QEMU which may have the GICD bmp shift bug under KVM mode. + * Strictly, what we want to know is whether the migration source is using + * KVM. Since we don't have any way to determine that, we look at whether the + * destination is using KVM; this is close enough because for the older QEMU + * versions with this bug KVM -> TCG migration didn't work anyway. If the + * source is a newer QEMU without this bug it will transmit the migration + * subsection which sets the flag to true; otherwise it will remain set to + * the value we select here. + */ + if (kvm_enabled()) { + cs->gicd_no_migration_shift_bug = false; + } + + return 0; +} + +static int gicv3_gicd_no_migration_shift_bug_post_load(void *opaque, + int version_id) +{ + GICv3State *cs = opaque; + + if (cs->gicd_no_migration_shift_bug) { + return 0; + } + + /* Older versions of QEMU had a bug in the handling of state save/restore + * to the KVM GICv3: they got the offset in the bitmap arrays wrong, + * so that instead of the data for external interrupts 32 and up + * starting at bit position 32 in the bitmap, it started at bit + * position 64. If we're receiving data from a QEMU with that bug, + * we must move the data down into the right place. + */ + memmove(cs->group, (uint8_t *)cs->group + GIC_INTERNAL / 8, + sizeof(cs->group) - GIC_INTERNAL / 8); + memmove(cs->grpmod, (uint8_t *)cs->grpmod + GIC_INTERNAL / 8, + sizeof(cs->grpmod) - GIC_INTERNAL / 8); + memmove(cs->enabled, (uint8_t *)cs->enabled + GIC_INTERNAL / 8, + sizeof(cs->enabled) - GIC_INTERNAL / 8); + memmove(cs->pending, (uint8_t *)cs->pending + GIC_INTERNAL / 8, + sizeof(cs->pending) - GIC_INTERNAL / 8); + memmove(cs->active, (uint8_t *)cs->active + GIC_INTERNAL / 8, + sizeof(cs->active) - GIC_INTERNAL / 8); + memmove(cs->edge_trigger, (uint8_t *)cs->edge_trigger + GIC_INTERNAL / 8, + sizeof(cs->edge_trigger) - GIC_INTERNAL / 8); + + /* + * While this new version QEMU doesn't have this kind of bug as we fix it, + * so it needs to set the flag to true to indicate that and it's necessary + * for next migration to work from this new version QEMU. + */ + cs->gicd_no_migration_shift_bug = true; + + return 0; +} + +const VMStateDescription vmstate_gicv3_gicd_no_migration_shift_bug = { + .name = "arm_gicv3/gicd_no_migration_shift_bug", + .version_id = 1, + .minimum_version_id = 1, + .pre_load = gicv3_gicd_no_migration_shift_bug_pre_load, + .post_load = gicv3_gicd_no_migration_shift_bug_post_load, + .fields = (VMStateField[]) { + VMSTATE_BOOL(gicd_no_migration_shift_bug, GICv3State), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_gicv3 = { .name = "arm_gicv3", .version_id = 1, @@ -165,6 +239,10 @@ static const VMStateDescription vmstate_gicv3 = { VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, GICv3State, num_cpu, vmstate_gicv3_cpu, GICv3CPUState), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_gicv3_gicd_no_migration_shift_bug, + NULL } }; @@ -364,6 +442,7 @@ static void arm_gicv3_common_reset(DeviceState *dev) gicv3_gicd_group_set(s, i); } } + s->gicd_no_migration_shift_bug = true; } static void arm_gic_common_linux_init(ARMLinuxBootIf *obj, diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 0279b86..5649cac 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -164,6 +164,14 @@ static void kvm_dist_get_edge_trigger(GICv3State *s, uint32_t offset, uint32_t reg; int irq; + /* For the KVM GICv3, affinity routing is always enabled, and the first 2 + * GICD_ICFGR<n> registers are always RAZ/WI. The corresponding + * functionality is replaced by GICR_ICFGR<n>. It doesn't need to sync + * them. So it should increase the offset to skip GIC_INTERNAL irqs. + * This matches the for_each_dist_irq_reg() macro which also skips the + * first GIC_INTERNAL irqs. + */ + offset += (GIC_INTERNAL * 2) / 8; for_each_dist_irq_reg(irq, s->num_irq, 2) { kvm_gicd_access(s, offset, ®, false); reg = half_unshuffle32(reg >> 1); @@ -181,6 +189,14 @@ static void kvm_dist_put_edge_trigger(GICv3State *s, uint32_t offset, uint32_t reg; int irq; + /* For the KVM GICv3, affinity routing is always enabled, and the first 2 + * GICD_ICFGR<n> registers are always RAZ/WI. The corresponding + * functionality is replaced by GICR_ICFGR<n>. It doesn't need to sync + * them. So it should increase the offset to skip GIC_INTERNAL irqs. + * This matches the for_each_dist_irq_reg() macro which also skips the + * first GIC_INTERNAL irqs. + */ + offset += (GIC_INTERNAL * 2) / 8; for_each_dist_irq_reg(irq, s->num_irq, 2) { reg = *gic_bmp_ptr32(bmp, irq); if (irq % 32 != 0) { @@ -222,6 +238,15 @@ static void kvm_dist_getbmp(GICv3State *s, uint32_t offset, uint32_t *bmp) uint32_t reg; int irq; + /* For the KVM GICv3, affinity routing is always enabled, and the + * GICD_IGROUPR0/GICD_IGRPMODR0/GICD_ISENABLER0/GICD_ISPENDR0/ + * GICD_ISACTIVER0 registers are always RAZ/WI. The corresponding + * functionality is replaced by the GICR registers. It doesn't need to sync + * them. So it should increase the offset to skip GIC_INTERNAL irqs. + * This matches the for_each_dist_irq_reg() macro which also skips the + * first GIC_INTERNAL irqs. + */ + offset += (GIC_INTERNAL * 1) / 8; for_each_dist_irq_reg(irq, s->num_irq, 1) { kvm_gicd_access(s, offset, ®, false); *gic_bmp_ptr32(bmp, irq) = reg; @@ -235,6 +260,19 @@ static void kvm_dist_putbmp(GICv3State *s, uint32_t offset, uint32_t reg; int irq; + /* For the KVM GICv3, affinity routing is always enabled, and the + * GICD_IGROUPR0/GICD_IGRPMODR0/GICD_ISENABLER0/GICD_ISPENDR0/ + * GICD_ISACTIVER0 registers are always RAZ/WI. The corresponding + * functionality is replaced by the GICR registers. It doesn't need to sync + * them. So it should increase the offset and clroffset to skip GIC_INTERNAL + * irqs. This matches the for_each_dist_irq_reg() macro which also skips the + * first GIC_INTERNAL irqs. + */ + offset += (GIC_INTERNAL * 1) / 8; + if (clroffset != 0) { + clroffset += (GIC_INTERNAL * 1) / 8; + } + for_each_dist_irq_reg(irq, s->num_irq, 1) { /* If this bitmap is a set/clear register pair, first write to the * clear-reg to clear all bits before using the set-reg to write diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 5302e5c..52cce19 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -176,7 +176,7 @@ static uint64_t boston_platreg_read(void *opaque, hwaddr addr, uint32_t gic_freq, val; if (size != 4) { - qemu_log_mask(LOG_UNIMP, "%uB platform register read", size); + qemu_log_mask(LOG_UNIMP, "%uB platform register read\n", size); return 0; } @@ -205,7 +205,7 @@ static uint64_t boston_platreg_read(void *opaque, hwaddr addr, val |= PLAT_DDR_CFG_MHZ; return val; default: - qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx, + qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx "\n", addr & 0xffff); return 0; } @@ -215,7 +215,7 @@ static void boston_platreg_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { if (size != 4) { - qemu_log_mask(LOG_UNIMP, "%uB platform register write", size); + qemu_log_mask(LOG_UNIMP, "%uB platform register write\n", size); return; } @@ -237,7 +237,7 @@ static void boston_platreg_write(void *opaque, hwaddr addr, break; default: qemu_log_mask(LOG_UNIMP, "Write platform register 0x%" HWADDR_PRIx - " = 0x%" PRIx64, addr & 0xffff, val); + " = 0x%" PRIx64 "\n", addr & 0xffff, val); break; } } diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 00e834d..ecd8d61 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -7,6 +7,7 @@ common-obj-$(CONFIG_SGA) += sga.o common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o common-obj-$(CONFIG_EDU) += edu.o +common-obj-$(CONFIG_PCA9552) += pca9552.o common-obj-y += unimp.o common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c new file mode 100644 index 0000000..9775d52 --- /dev/null +++ b/hw/misc/pca9552.c @@ -0,0 +1,240 @@ +/* + * PCA9552 I2C LED blinker + * + * https://www.nxp.com/docs/en/application-note/AN264.pdf + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/hw.h" +#include "hw/misc/pca9552.h" +#include "hw/misc/pca9552_regs.h" + +#define PCA9552_LED_ON 0x0 +#define PCA9552_LED_OFF 0x1 +#define PCA9552_LED_PWM0 0x2 +#define PCA9552_LED_PWM1 0x3 + +static uint8_t pca9552_pin_get_config(PCA9552State *s, int pin) +{ + uint8_t reg = PCA9552_LS0 + (pin / 4); + uint8_t shift = (pin % 4) << 1; + + return extract32(s->regs[reg], shift, 2); +} + +static void pca9552_update_pin_input(PCA9552State *s) +{ + int i; + + for (i = 0; i < s->nr_leds; i++) { + uint8_t input_reg = PCA9552_INPUT0 + (i / 8); + uint8_t input_shift = (i % 8); + uint8_t config = pca9552_pin_get_config(s, i); + + switch (config) { + case PCA9552_LED_ON: + s->regs[input_reg] |= 1 << input_shift; + break; + case PCA9552_LED_OFF: + s->regs[input_reg] &= ~(1 << input_shift); + break; + case PCA9552_LED_PWM0: + case PCA9552_LED_PWM1: + /* TODO */ + default: + break; + } + } +} + +static uint8_t pca9552_read(PCA9552State *s, uint8_t reg) +{ + switch (reg) { + case PCA9552_INPUT0: + case PCA9552_INPUT1: + case PCA9552_PSC0: + case PCA9552_PWM0: + case PCA9552_PSC1: + case PCA9552_PWM1: + case PCA9552_LS0: + case PCA9552_LS1: + case PCA9552_LS2: + case PCA9552_LS3: + return s->regs[reg]; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected read to register %d\n", + __func__, reg); + return 0xFF; + } +} + +static void pca9552_write(PCA9552State *s, uint8_t reg, uint8_t data) +{ + switch (reg) { + case PCA9552_PSC0: + case PCA9552_PWM0: + case PCA9552_PSC1: + case PCA9552_PWM1: + s->regs[reg] = data; + break; + + case PCA9552_LS0: + case PCA9552_LS1: + case PCA9552_LS2: + case PCA9552_LS3: + s->regs[reg] = data; + pca9552_update_pin_input(s); + break; + + case PCA9552_INPUT0: + case PCA9552_INPUT1: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected write to register %d\n", + __func__, reg); + } +} + +/* + * When Auto-Increment is on, the register address is incremented + * after each byte is sent to or received by the device. The index + * rollovers to 0 when the maximum register address is reached. + */ +static void pca9552_autoinc(PCA9552State *s) +{ + if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) { + uint8_t reg = s->pointer & 0xf; + + reg = (reg + 1) % (s->max_reg + 1); + s->pointer = reg | PCA9552_AUTOINC; + } +} + +static int pca9552_recv(I2CSlave *i2c) +{ + PCA9552State *s = PCA9552(i2c); + uint8_t ret; + + ret = pca9552_read(s, s->pointer & 0xf); + + /* + * From the Specs: + * + * Important Note: When a Read sequence is initiated and the + * AI bit is set to Logic Level 1, the Read Sequence MUST + * start by a register different from 0. + * + * I don't know what should be done in this case, so throw an + * error. + */ + if (s->pointer == PCA9552_AUTOINC) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Autoincrement read starting with register 0\n", + __func__); + } + + pca9552_autoinc(s); + + return ret; +} + +static int pca9552_send(I2CSlave *i2c, uint8_t data) +{ + PCA9552State *s = PCA9552(i2c); + + /* First byte sent by is the register address */ + if (s->len == 0) { + s->pointer = data; + s->len++; + } else { + pca9552_write(s, s->pointer & 0xf, data); + + pca9552_autoinc(s); + } + + return 0; +} + +static int pca9552_event(I2CSlave *i2c, enum i2c_event event) +{ + PCA9552State *s = PCA9552(i2c); + + s->len = 0; + return 0; +} + +static const VMStateDescription pca9552_vmstate = { + .name = "PCA9552", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(len, PCA9552State), + VMSTATE_UINT8(pointer, PCA9552State), + VMSTATE_UINT8_ARRAY(regs, PCA9552State, PCA9552_NR_REGS), + VMSTATE_I2C_SLAVE(i2c, PCA9552State), + VMSTATE_END_OF_LIST() + } +}; + +static void pca9552_reset(DeviceState *dev) +{ + PCA9552State *s = PCA9552(dev); + + s->regs[PCA9552_PSC0] = 0xFF; + s->regs[PCA9552_PWM0] = 0x80; + s->regs[PCA9552_PSC1] = 0xFF; + s->regs[PCA9552_PWM1] = 0x80; + s->regs[PCA9552_LS0] = 0x55; /* all OFF */ + s->regs[PCA9552_LS1] = 0x55; + s->regs[PCA9552_LS2] = 0x55; + s->regs[PCA9552_LS3] = 0x55; + + pca9552_update_pin_input(s); + + s->pointer = 0xFF; + s->len = 0; +} + +static void pca9552_initfn(Object *obj) +{ + PCA9552State *s = PCA9552(obj); + + /* If support for the other PCA955X devices are implemented, these + * constant values might be part of class structure describing the + * PCA955X device + */ + s->max_reg = PCA9552_LS3; + s->nr_leds = 16; +} + +static void pca9552_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->event = pca9552_event; + k->recv = pca9552_recv; + k->send = pca9552_send; + dc->reset = pca9552_reset; + dc->vmsd = &pca9552_vmstate; +} + +static const TypeInfo pca9552_info = { + .name = TYPE_PCA9552, + .parent = TYPE_I2C_SLAVE, + .instance_init = pca9552_initfn, + .instance_size = sizeof(PCA9552State), + .class_init = pca9552_class_init, +}; + +static void pca9552_register_types(void) +{ + type_register_static(&pca9552_info); +} + +type_init(pca9552_register_types) diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 3300e8e..909c118 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -207,16 +207,18 @@ typedef struct { /* * Max frame size for the receiving buffer */ -#define FTGMAC100_MAX_FRAME_SIZE 10240 +#define FTGMAC100_MAX_FRAME_SIZE 9220 /* Limits depending on the type of the frame * * 9216 for Jumbo frames (+ 4 for VLAN) * 1518 for other frames (+ 4 for VLAN) */ -static int ftgmac100_max_frame_size(FTGMAC100State *s) +static int ftgmac100_max_frame_size(FTGMAC100State *s, uint16_t proto) { - return (s->maccr & FTGMAC100_MACCR_JUMBO_LF ? 9216 : 1518) + 4; + int max = (s->maccr & FTGMAC100_MACCR_JUMBO_LF ? 9216 : 1518); + + return max + (proto == ETH_P_VLAN ? 4 : 0); } static void ftgmac100_update_irq(FTGMAC100State *s) @@ -408,7 +410,6 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring, uint8_t *ptr = s->frame; uint32_t addr = tx_descriptor; uint32_t flags = 0; - int max_frame_size = ftgmac100_max_frame_size(s); while (1) { FTGMAC100Desc bd; @@ -427,11 +428,12 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring, flags = bd.des1; } - len = bd.des0 & 0x3FFF; - if (frame_size + len > max_frame_size) { + len = FTGMAC100_TXDES0_TXBUF_SIZE(bd.des0); + if (frame_size + len > sizeof(s->frame)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n", __func__, len); - len = max_frame_size - frame_size; + s->isr |= FTGMAC100_INT_XPKT_LOST; + len = sizeof(s->frame) - frame_size; } if (dma_memory_read(&address_space_memory, bd.des3, ptr, len)) { @@ -441,6 +443,22 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring, break; } + /* Check for VLAN */ + if (bd.des0 & FTGMAC100_TXDES0_FTS && + bd.des1 & FTGMAC100_TXDES1_INS_VLANTAG && + be16_to_cpu(PKT_GET_ETH_HDR(ptr)->h_proto) != ETH_P_VLAN) { + if (frame_size + len + 4 > sizeof(s->frame)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n", + __func__, len); + s->isr |= FTGMAC100_INT_XPKT_LOST; + len = sizeof(s->frame) - frame_size - 4; + } + memmove(ptr + 16, ptr + 12, len - 12); + stw_be_p(ptr + 12, ETH_P_VLAN); + stw_be_p(ptr + 14, bd.des1); + len += 4; + } + ptr += len; frame_size += len; if (bd.des0 & FTGMAC100_TXDES0_LTS) { @@ -758,8 +776,8 @@ static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len) return 0; } - /* TODO: this does not seem to work for ftgmac100 */ - mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; + mcast_idx = net_crc32_le(buf, ETH_ALEN); + mcast_idx = (~(mcast_idx >> 2)) & 0x3f; if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) { return 0; } @@ -788,7 +806,8 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, uint32_t buf_len; size_t size = len; uint32_t first = FTGMAC100_RXDES0_FRS; - int max_frame_size = ftgmac100_max_frame_size(s); + uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(buf)->h_proto); + int max_frame_size = ftgmac100_max_frame_size(s, proto); if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) != (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) { @@ -803,12 +822,6 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, return size; } - if (size < 64 && !(s->maccr & FTGMAC100_MACCR_RX_RUNT)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: dropped runt frame of %zd bytes\n", - __func__, size); - return size; - } - if (!ftgmac100_filter(s, buf, size)) { return size; } @@ -820,9 +833,9 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, /* Huge frames are truncated. */ if (size > max_frame_size) { - size = max_frame_size; qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %zd bytes\n", __func__, size); + size = max_frame_size; flags |= FTGMAC100_RXDES0_FTL; } @@ -861,7 +874,20 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, buf_len += size - 4; } buf_addr = bd.des3; - dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); + if (first && proto == ETH_P_VLAN && buf_len >= 18) { + bd.des1 = lduw_be_p(buf + 14) | FTGMAC100_RXDES1_VLANTAG_AVAIL; + + if (s->maccr & FTGMAC100_MACCR_RM_VLAN) { + dma_memory_write(&address_space_memory, buf_addr, buf, 12); + dma_memory_write(&address_space_memory, buf_addr + 12, buf + 16, + buf_len - 16); + } else { + dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); + } + } else { + bd.des1 = 0; + dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); + } buf += buf_len; if (size < 4) { dma_memory_write(&address_space_memory, buf_addr + buf_len, @@ -940,8 +966,6 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp) object_get_typename(OBJECT(dev)), DEVICE(dev)->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - - s->frame = g_malloc(FTGMAC100_MAX_FRAME_SIZE); } static const VMStateDescription vmstate_ftgmac100 = { diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index cbb64ad..13ad7d9 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -97,7 +97,7 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr, val = 0x24f000000000000ull; break; default: - qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx, + qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n", addr); } @@ -107,7 +107,7 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr, static void pnv_core_xscom_write(void *opaque, hwaddr addr, uint64_t val, unsigned int width) { - qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx, + qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n", addr); } diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index fe1cccc..fcbccf5 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -140,7 +140,7 @@ static uint64_t memcard_read(void *opaque, hwaddr addr, r = s->response[s->response_read_ptr++]; if (s->response_read_ptr > s->response_len) { qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: " - "read more cmd bytes than available. Clipping."); + "read more cmd bytes than available: clipping\n"); s->response_read_ptr = 0; } } @@ -1,9 +1,10 @@ /* * SD Memory Card emulation as defined in the "SD Memory Card Physical - * layer specification, Version 1.10." + * layer specification, Version 2.00." * * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> * Copyright (c) 2007 CodeSourcery + * Copyright (c) 2018 Philippe Mathieu-Daudé <f4bug@amsat.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -91,6 +92,7 @@ struct SDState { uint8_t sd_status[64]; /* Configurable properties */ + uint8_t spec_version; BlockBackend *blk; bool spi; @@ -310,11 +312,18 @@ static void sd_ocr_powerup(void *opaque) static void sd_set_scr(SDState *sd) { - sd->scr[0] = (0 << 4) /* SCR version 1.0 */ - | 0; /* Spec Versions 1.0 and 1.01 */ + sd->scr[0] = 0 << 4; /* SCR structure version 1.0 */ + if (sd->spec_version == SD_PHY_SPECv1_10_VERS) { + sd->scr[0] |= 1; /* Spec Version 1.10 */ + } else { + sd->scr[0] |= 2; /* Spec Version 2.00 or Version 3.0X */ + } sd->scr[1] = (2 << 4) /* SDSC Card (Security Version 1.01) */ | 0b0101; /* 1-bit or 4-bit width bus modes */ sd->scr[2] = 0x00; /* Extended Security is not supported. */ + if (sd->spec_version >= SD_PHY_SPECv3_01_VERS) { + sd->scr[2] |= 1 << 7; /* Spec Version 3.0X */ + } sd->scr[3] = 0x00; /* reserved for manufacturer usage */ sd->scr[4] = 0x00; @@ -960,8 +969,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_illegal; case 6: /* CMD6: SWITCH_FUNCTION */ - if (sd->spi) - goto bad_cmd; switch (sd->mode) { case sd_data_transfer_mode: sd_function_switch(sd, req.arg); @@ -1014,7 +1021,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 8: /* CMD8: SEND_IF_COND */ - /* Physical Layer Specification Version 2.00 command */ + if (sd->spec_version < SD_PHY_SPECv2_00_VERS) { + break; + } if (sd->state != sd_idle_state) { break; } @@ -1170,6 +1179,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + break; + } if (sd->state == sd_transfer_state) { sd->state = sd_sendingdata_state; sd->data_offset = 0; @@ -1178,6 +1190,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 23: /* CMD23: SET_BLOCK_COUNT */ + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + break; + } switch (sd->state) { case sd_transfer_state: sd->multi_blk_cnt = req.arg; @@ -1190,9 +1205,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Block write commands (Class 4) */ case 24: /* CMD24: WRITE_SINGLE_BLOCK */ - if (sd->spi) { - goto unimplemented_spi_cmd; - } switch (sd->state) { case sd_transfer_state: /* Writing in SPI mode not implemented. */ @@ -1217,9 +1229,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ - if (sd->spi) { - goto unimplemented_spi_cmd; - } switch (sd->state) { case sd_transfer_state: /* Writing in SPI mode not implemented. */ @@ -1259,9 +1268,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 27: /* CMD27: PROGRAM_CSD */ - if (sd->spi) { - goto unimplemented_spi_cmd; - } switch (sd->state) { case sd_transfer_state: sd->state = sd_receivingdata_state; @@ -1371,9 +1377,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Lock card commands (Class 7) */ case 42: /* CMD42: LOCK_UNLOCK */ - if (sd->spi) { - goto unimplemented_spi_cmd; - } switch (sd->state) { case sd_transfer_state: sd->state = sd_receivingdata_state; @@ -2072,6 +2075,15 @@ static void sd_realize(DeviceState *dev, Error **errp) sd->proto_name = sd->spi ? "SPI" : "SD"; + switch (sd->spec_version) { + case SD_PHY_SPECv1_10_VERS + ... SD_PHY_SPECv3_01_VERS: + break; + default: + error_setg(errp, "Invalid SD card Spec version: %u", sd->spec_version); + return; + } + if (sd->blk && blk_is_read_only(sd->blk)) { error_setg(errp, "Cannot use read-only drive as SD card"); return; @@ -2088,6 +2100,8 @@ static void sd_realize(DeviceState *dev, Error **errp) } static Property sd_properties[] = { + DEFINE_PROP_UINT8("spec_version", SDState, + spec_version, SD_PHY_SPECv2_00_VERS), DEFINE_PROP_DRIVE("drive", SDState, blk), /* We do not model the chip select pin, so allow the board to select * whether card should be in SSI or MMC/SD mode. It is also up to the diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index e1fcf73..4d73077 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -73,7 +73,7 @@ static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size) default: qemu_log_mask(LOG_UNIMP, "digic-timer: read access to unknown register 0x" - TARGET_FMT_plx, offset); + TARGET_FMT_plx "\n", offset); } return ret; @@ -109,7 +109,7 @@ static void digic_timer_write(void *opaque, hwaddr offset, default: qemu_log_mask(LOG_UNIMP, "digic-timer: read access to unknown register 0x" - TARGET_FMT_plx, offset); + TARGET_FMT_plx "\n", offset); } } diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h index cfe3fa6..4fdba02 100644 --- a/include/hw/i2c/smbus.h +++ b/include/hw/i2c/smbus.h @@ -76,6 +76,7 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data); int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, int len); +void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf); void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int size); diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index bccdfe1..d75b49d 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -217,6 +217,7 @@ struct GICv3State { uint32_t revision; bool security_extn; bool irq_reset_nonsecure; + bool gicd_no_migration_shift_bug; int dev_fd; /* kvm device fd if backed by kvm vgic support */ Error *migration_blocker; diff --git a/include/hw/misc/pca9552.h b/include/hw/misc/pca9552.h new file mode 100644 index 0000000..ebb43c6 --- /dev/null +++ b/include/hw/misc/pca9552.h @@ -0,0 +1,32 @@ +/* + * PCA9552 I2C LED blinker + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ +#ifndef PCA9552_H +#define PCA9552_H + +#include "hw/i2c/i2c.h" + +#define TYPE_PCA9552 "pca9552" +#define PCA9552(obj) OBJECT_CHECK(PCA9552State, (obj), TYPE_PCA9552) + +#define PCA9552_NR_REGS 10 + +typedef struct PCA9552State { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + + uint8_t len; + uint8_t pointer; + + uint8_t regs[PCA9552_NR_REGS]; + uint8_t max_reg; + uint8_t nr_leds; +} PCA9552State; + +#endif diff --git a/include/hw/misc/pca9552_regs.h b/include/hw/misc/pca9552_regs.h new file mode 100644 index 0000000..d8051cf --- /dev/null +++ b/include/hw/misc/pca9552_regs.h @@ -0,0 +1,32 @@ +/* + * PCA9552 I2C LED blinker registers + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ +#ifndef PCA9552_REGS_H +#define PCA9552_REGS_H + +/* + * Bits [0:3] are used to address a specific register. + */ +#define PCA9552_INPUT0 0 /* read only input register 0 */ +#define PCA9552_INPUT1 1 /* read only input register 1 */ +#define PCA9552_PSC0 2 /* read/write frequency prescaler 0 */ +#define PCA9552_PWM0 3 /* read/write PWM register 0 */ +#define PCA9552_PSC1 4 /* read/write frequency prescaler 1 */ +#define PCA9552_PWM1 5 /* read/write PWM register 1 */ +#define PCA9552_LS0 6 /* read/write LED0 to LED3 selector */ +#define PCA9552_LS1 7 /* read/write LED4 to LED7 selector */ +#define PCA9552_LS2 8 /* read/write LED8 to LED11 selector */ +#define PCA9552_LS3 9 /* read/write LED12 to LED15 selector */ + +/* + * Bit [4] is used to activate the Auto-Increment option of the + * register address + */ +#define PCA9552_AUTOINC (1 << 4) + +#endif diff --git a/include/hw/net/ftgmac100.h b/include/hw/net/ftgmac100.h index d9bc589..94cfe05 100644 --- a/include/hw/net/ftgmac100.h +++ b/include/hw/net/ftgmac100.h @@ -16,6 +16,11 @@ #include "hw/sysbus.h" #include "net/net.h" +/* + * Max frame size for the receiving buffer + */ +#define FTGMAC100_MAX_FRAME_SIZE 9220 + typedef struct FTGMAC100State { /*< private >*/ SysBusDevice parent_obj; @@ -26,7 +31,7 @@ typedef struct FTGMAC100State { qemu_irq irq; MemoryRegion iomem; - uint8_t *frame; + uint8_t frame[FTGMAC100_MAX_FRAME_SIZE]; uint32_t irq_state; uint32_t isr; diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index 9bdb3c9..b865aaf 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -54,6 +54,12 @@ #define APP_CMD (1 << 5) #define AKE_SEQ_ERROR (1 << 3) +enum SDPhySpecificationVersion { + SD_PHY_SPECv1_10_VERS = 1, + SD_PHY_SPECv2_00_VERS = 2, + SD_PHY_SPECv3_01_VERS = 3, +}; + typedef enum { SD_VOLTAGE_0_4V = 400, /* currently not supported */ SD_VOLTAGE_1_8V = 1800, diff --git a/qemu-doc.texi b/qemu-doc.texi index f00706b..2effe66 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2965,11 +2965,6 @@ support page sizes < 4096 any longer. @section System emulator machines -@subsection Xilinx EP108 (since 2.11.0) - -The ``xlnx-ep108'' machine has been replaced by the ``xlnx-zcu102'' machine. -The ``xlnx-zcu102'' machine has the same features and capabilites in QEMU. - @section Block device options @subsection "backing": "" (since 2.12.0) diff --git a/target/arm/helper.c b/target/arm/helper.c index f75aa6e..1248d84 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4570,7 +4570,7 @@ void hw_breakpoint_update(ARMCPU *cpu, int n) case 4: /* unlinked address mismatch (reserved if AArch64) */ case 5: /* linked address mismatch (reserved if AArch64) */ qemu_log_mask(LOG_UNIMP, - "arm: address mismatch breakpoint types not implemented"); + "arm: address mismatch breakpoint types not implemented\n"); return; case 0: /* unlinked address match */ case 1: /* linked address match */ @@ -4604,7 +4604,7 @@ void hw_breakpoint_update(ARMCPU *cpu, int n) case 8: /* unlinked VMID match (reserved if no EL2) */ case 10: /* unlinked context ID and VMID match (reserved if no EL2) */ qemu_log_mask(LOG_UNIMP, - "arm: unlinked context breakpoint types not implemented"); + "arm: unlinked context breakpoint types not implemented\n"); return; case 9: /* linked VMID match (reserved if no EL2) */ case 11: /* linked context ID and VMID match (reserved if no EL2) */ diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 37d6ffd..4b5dbdb 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -1556,7 +1556,7 @@ DISAS_INSN(undef) /* ??? This is both instructions that are as yet unimplemented for the 680x0 series, as well as those that are implemented but actually illegal for CPU32 or pre-68020. */ - qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x", + qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n", insn, s->insn_pc); gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED); } diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 3abf524..aec7558 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -293,7 +293,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write, if ((val_to_write & 3) == 0) { env->stvec = val_to_write >> 2 << 2; } else { - qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported"); + qemu_log_mask(LOG_UNIMP, + "CSR_STVEC: vectored traps not supported\n"); } break; case CSR_SCOUNTEREN: @@ -320,7 +321,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write, if ((val_to_write & 3) == 0) { env->mtvec = val_to_write >> 2 << 2; } else { - qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported"); + qemu_log_mask(LOG_UNIMP, + "CSR_MTVEC: vectored traps not supported\n"); } break; case CSR_MCOUNTEREN: diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 89db238..a11162e 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2234,7 +2234,7 @@ static void translate_rur(DisasContext *dc, const uint32_t arg[], if (uregnames[par[0]].name) { tcg_gen_mov_i32(cpu_R[arg[0]], cpu_UR[par[0]]); } else { - qemu_log_mask(LOG_UNIMP, "RUR %d not implemented, ", par[0]); + qemu_log_mask(LOG_UNIMP, "RUR %d not implemented\n", par[0]); } } } @@ -2375,7 +2375,7 @@ static void translate_slli(DisasContext *dc, const uint32_t arg[], { if (gen_window_check2(dc, arg[0], arg[1])) { if (arg[2] == 32) { - qemu_log_mask(LOG_GUEST_ERROR, "slli a%d, a%d, 32 is undefined", + qemu_log_mask(LOG_GUEST_ERROR, "slli a%d, a%d, 32 is undefined\n", arg[0], arg[1]); } tcg_gen_shli_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2] & 0x1f); @@ -2571,7 +2571,7 @@ static void translate_wur(DisasContext *dc, const uint32_t arg[], if (uregnames[par[0]].name) { gen_wur(par[0], cpu_R[arg[0]]); } else { - qemu_log_mask(LOG_UNIMP, "WUR %d not implemented, ", par[0]); + qemu_log_mask(LOG_UNIMP, "WUR %d not implemented\n", par[0]); } } } diff --git a/tests/Makefile.include b/tests/Makefile.include index 0eaa835..400d889 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -373,6 +373,7 @@ check-qtest-sparc64-y += tests/prom-env-test$(EXESUF) check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF) check-qtest-arm-y = tests/tmp105-test$(EXESUF) +check-qtest-arm-y += tests/pca9552-test$(EXESUF) check-qtest-arm-y += tests/ds1338-test$(EXESUF) check-qtest-arm-y += tests/m25p80-test$(EXESUF) gcov-files-arm-y += hw/misc/tmp105.c @@ -778,6 +779,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y) tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) +tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y) tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y) tests/m25p80-test$(EXESUF): tests/m25p80-test.o tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h index eb40b80..cc01358 100644 --- a/tests/libqos/i2c.h +++ b/tests/libqos/i2c.h @@ -21,6 +21,8 @@ struct I2CAdapter { QTestState *qts; }; +#define OMAP2_I2C_1_BASE 0x48070000 + void i2c_send(I2CAdapter *i2c, uint8_t addr, const uint8_t *buf, uint16_t len); void i2c_recv(I2CAdapter *i2c, uint8_t addr, diff --git a/tests/pca9552-test.c b/tests/pca9552-test.c new file mode 100644 index 0000000..5466a67 --- /dev/null +++ b/tests/pca9552-test.c @@ -0,0 +1,116 @@ +/* + * QTest testcase for the PCA9552 LED blinker + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "libqtest.h" +#include "libqos/i2c.h" +#include "hw/misc/pca9552_regs.h" + +#define PCA9552_TEST_ID "pca9552-test" +#define PCA9552_TEST_ADDR 0x60 + +static I2CAdapter *i2c; + +static uint8_t pca9552_get8(I2CAdapter *i2c, uint8_t addr, uint8_t reg) +{ + uint8_t resp[1]; + i2c_send(i2c, addr, ®, 1); + i2c_recv(i2c, addr, resp, 1); + return resp[0]; +} + +static void pca9552_set8(I2CAdapter *i2c, uint8_t addr, uint8_t reg, + uint8_t value) +{ + uint8_t cmd[2]; + uint8_t resp[1]; + + cmd[0] = reg; + cmd[1] = value; + i2c_send(i2c, addr, cmd, 2); + i2c_recv(i2c, addr, resp, 1); + g_assert_cmphex(resp[0], ==, cmd[1]); +} + +static void receive_autoinc(void) +{ + uint8_t resp; + uint8_t reg = PCA9552_LS0 | PCA9552_AUTOINC; + + i2c_send(i2c, PCA9552_TEST_ADDR, ®, 1); + + /* PCA9552_LS0 */ + i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1); + g_assert_cmphex(resp, ==, 0x54); + + /* PCA9552_LS1 */ + i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1); + g_assert_cmphex(resp, ==, 0x55); + + /* PCA9552_LS2 */ + i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1); + g_assert_cmphex(resp, ==, 0x55); + + /* PCA9552_LS3 */ + i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1); + g_assert_cmphex(resp, ==, 0x54); +} + +static void send_and_receive(void) +{ + uint8_t value; + + value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_LS0); + g_assert_cmphex(value, ==, 0x55); + + value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_INPUT0); + g_assert_cmphex(value, ==, 0x0); + + /* Switch on LED 0 */ + pca9552_set8(i2c, PCA9552_TEST_ADDR, PCA9552_LS0, 0x54); + value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_LS0); + g_assert_cmphex(value, ==, 0x54); + + value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_INPUT0); + g_assert_cmphex(value, ==, 0x01); + + /* Switch on LED 12 */ + pca9552_set8(i2c, PCA9552_TEST_ADDR, PCA9552_LS3, 0x54); + value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_LS3); + g_assert_cmphex(value, ==, 0x54); + + value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_INPUT1); + g_assert_cmphex(value, ==, 0x10); +} + +int main(int argc, char **argv) +{ + QTestState *s = NULL; + int ret; + + g_test_init(&argc, &argv, NULL); + + s = qtest_start("-machine n800 " + "-device pca9552,bus=i2c-bus.0,id=" PCA9552_TEST_ID + ",address=0x60"); + i2c = omap_i2c_create(s, OMAP2_I2C_1_BASE); + + qtest_add_func("/pca9552/tx-rx", send_and_receive); + qtest_add_func("/pca9552/rx-autoinc", receive_autoinc); + + ret = g_test_run(); + + if (s) { + qtest_quit(s); + } + g_free(i2c); + + return ret; +} diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c index d093cff..34cae7a 100644 --- a/tests/tmp105-test.c +++ b/tests/tmp105-test.c @@ -14,8 +14,6 @@ #include "qapi/qmp/qdict.h" #include "hw/misc/tmp105_regs.h" -#define OMAP2_I2C_1_BASE 0x48070000 - #define TMP105_TEST_ID "tmp105-test" #define TMP105_TEST_ADDR 0x49 |