diff options
Diffstat (limited to 'hw')
69 files changed, 960 insertions, 450 deletions
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 263626abea..f8ba67531a 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -15,6 +15,7 @@ #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" #include "hw/arm/aspeed_eeprom.h" +#include "hw/block/flash.h" #include "hw/i2c/i2c_mux_pca954x.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/misc/pca9552.h" @@ -47,6 +48,13 @@ struct AspeedMachineState { char *spi_model; }; +/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ +#if HOST_LONG_BITS == 32 +#define ASPEED_RAM_SIZE(sz) MIN((sz), 1 * GiB) +#else +#define ASPEED_RAM_SIZE(sz) (sz) +#endif + /* Palmetto hardware value: 0x120CE416 */ #define PALMETTO_BMC_HW_STRAP1 ( \ SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \ @@ -300,17 +308,14 @@ void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, for (i = 0; i < count; ++i) { DriveInfo *dinfo = drive_get(IF_MTD, 0, unit0 + i); - qemu_irq cs_line; DeviceState *dev; dev = qdev_new(flashtype); if (dinfo) { qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo)); } + qdev_prop_set_uint8(dev, "cs", i); qdev_realize_and_unref(dev, BUS(s->spi), &error_fatal); - - cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); - qdev_connect_gpio_out_named(DEVICE(s), "cs", i, cs_line); } } @@ -392,12 +397,14 @@ static void aspeed_machine_init(MachineState *machine) connect_serial_hds_to_uarts(bmc); qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort); - aspeed_board_init_flashes(&bmc->soc.fmc, + if (defaults_enabled()) { + aspeed_board_init_flashes(&bmc->soc.fmc, bmc->fmc_model ? bmc->fmc_model : amc->fmc_model, amc->num_cs, 0); - aspeed_board_init_flashes(&bmc->soc.spi[0], + aspeed_board_init_flashes(&bmc->soc.spi[0], bmc->spi_model ? bmc->spi_model : amc->spi_model, 1, amc->num_cs); + } if (machine->kernel_filename && sc->num_cpus > 1) { /* With no u-boot we must set up a boot stub for the secondary CPU */ @@ -430,11 +437,12 @@ static void aspeed_machine_init(MachineState *machine) } if (!bmc->mmio_exec) { - DriveInfo *mtd0 = drive_get(IF_MTD, 0, 0); + DeviceState *dev = ssi_get_cs(bmc->soc.fmc.spi, 0); + BlockBackend *fmc0 = dev ? m25p80_get_blk(dev) : NULL; - if (mtd0) { + if (fmc0) { uint64_t rom_size = memory_region_size(&bmc->soc.spi_boot); - aspeed_install_boot_rom(bmc, blk_by_legacy_dinfo(mtd0), rom_size); + aspeed_install_boot_rom(bmc, fmc0, rom_size); } } @@ -1423,12 +1431,7 @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; -/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ -#if HOST_LONG_BITS == 32 -#define FUJI_BMC_RAM_SIZE (1 * GiB) -#else -#define FUJI_BMC_RAM_SIZE (2 * GiB) -#endif +#define FUJI_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) { @@ -1450,12 +1453,7 @@ static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; -/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ -#if HOST_LONG_BITS == 32 -#define BLETCHLEY_BMC_RAM_SIZE (1 * GiB) -#else -#define BLETCHLEY_BMC_RAM_SIZE (2 * GiB) -#endif +#define BLETCHLEY_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) { diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index f7e99baf62..aa5b0ddfaa 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1235,14 +1235,15 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) dinfo = drive_get(IF_SD, 0, 0); blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; - carddev = qdev_new(TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD_SPI); qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); - qdev_prop_set_bit(carddev, "spi", true); qdev_realize_and_unref(carddev, qdev_get_child_bus(sddev, "sd-bus"), &error_fatal); - ssddev = ssi_create_peripheral(bus, "ssd0323"); + ssddev = qdev_new("ssd0323"); + qdev_prop_set_uint8(ssddev, "cs", 1); + qdev_realize_and_unref(ssddev, bus, &error_fatal); gpio_d_splitter = qdev_new(TYPE_SPLIT_IRQ); qdev_prop_set_uint32(gpio_d_splitter, "num-lines", 2); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 3190cc0b8d..8dc2ea83a9 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -164,6 +164,7 @@ static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", j); qdev_realize_and_unref(flash_dev, BUS(spi), &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 1ee2b8697f..88c561ff63 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -740,6 +740,7 @@ static void versal_virt_init(MachineState *machine) qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", i); qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 4c84bb932a..21483f75fd 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -201,6 +201,7 @@ static void xlnx_zcu102_init(MachineState *machine) qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", i); qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); @@ -224,6 +225,7 @@ static void xlnx_zcu102_init(MachineState *machine) qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", i); qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index dc5ffbc4ff..afc3fdf4d6 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -25,6 +25,7 @@ #include "qemu/units.h" #include "sysemu/block-backend.h" #include "hw/block/block.h" +#include "hw/block/flash.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/ssi/ssi.h" @@ -1830,3 +1831,8 @@ static void m25p80_register_types(void) } type_init(m25p80_register_types) + +BlockBackend *m25p80_get_blk(DeviceState *dev) +{ + return M25P80(dev)->blk; +} diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 807e398541..eff0304a18 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -307,11 +307,11 @@ static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond, /* instant drain the fifo when there's no back-end */ if (!qemu_chr_fe_backend_connected(&s->chr)) { s->tx_count = 0; - return FALSE; + return G_SOURCE_REMOVE; } if (!s->tx_count) { - return FALSE; + return G_SOURCE_REMOVE; } ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_count); @@ -326,12 +326,12 @@ static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond, cadence_uart_xmit, s); if (!r) { s->tx_count = 0; - return FALSE; + return G_SOURCE_REMOVE; } } uart_update_status(s); - return FALSE; + return G_SOURCE_REMOVE; } static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf, diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c index f8dc89ee3d..d466cd93de 100644 --- a/hw/char/cmsdk-apb-uart.c +++ b/hw/char/cmsdk-apb-uart.c @@ -199,7 +199,7 @@ static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque) s->watch_tag = 0; if (!(s->ctrl & R_CTRL_TX_EN_MASK) || !(s->state & R_STATE_TXFULL_MASK)) { - return FALSE; + return G_SOURCE_REMOVE; } ret = qemu_chr_fe_write(&s->chr, &s->txbuf, 1); @@ -215,7 +215,7 @@ static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque) } /* Transmit pending */ trace_cmsdk_apb_uart_tx_pending(); - return FALSE; + return G_SOURCE_REMOVE; } buffer_drained: @@ -227,7 +227,7 @@ buffer_drained: s->intstatus |= R_INTSTATUS_TX_MASK; } cmsdk_apb_uart_update(s); - return FALSE; + return G_SOURCE_REMOVE; } static void uart_cancel_transmit(CMSDKAPBUART *s) diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index f70adb5308..51708c0836 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -147,7 +147,7 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond, /* instant drain the fifo when there's no back-end */ if (!qemu_chr_fe_backend_connected(&s->chr)) { s->tx_level = 0; - return FALSE; + return G_SOURCE_REMOVE; } if (!s->tx_level) { @@ -156,7 +156,7 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond, s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; ibex_uart_update_irqs(s); - return FALSE; + return G_SOURCE_REMOVE; } ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level); @@ -171,7 +171,7 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond, ibex_uart_xmit, s); if (!r) { s->tx_level = 0; - return FALSE; + return G_SOURCE_REMOVE; } } @@ -192,7 +192,7 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond, } ibex_uart_update_irqs(s); - return FALSE; + return G_SOURCE_REMOVE; } static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, diff --git a/hw/char/nrf51_uart.c b/hw/char/nrf51_uart.c index 3c6f982de9..dfe2276d71 100644 --- a/hw/char/nrf51_uart.c +++ b/hw/char/nrf51_uart.c @@ -93,13 +93,13 @@ static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque) */ goto buffer_drained; } - return FALSE; + return G_SOURCE_REMOVE; } buffer_drained: s->reg[R_UART_TXDRDY] = 1; s->pending_tx_byte = false; - return FALSE; + return G_SOURCE_REMOVE; } static void uart_cancel_transmit(NRF51UARTState *s) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 77bbc2a982..58edeb9ddb 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -48,14 +48,15 @@ DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr) return dev; } -#define PL011_INT_TX 0x20 -#define PL011_INT_RX 0x10 - +/* Flag Register, UARTFR */ #define PL011_FLAG_TXFE 0x80 #define PL011_FLAG_RXFF 0x40 #define PL011_FLAG_TXFF 0x20 #define PL011_FLAG_RXFE 0x10 +/* Data Register, UARTDR */ +#define DR_BE (1 << 10) + /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */ #define INT_OE (1 << 10) #define INT_BE (1 << 9) @@ -71,11 +72,33 @@ DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr) #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE) #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS) +/* Line Control Register, UARTLCR_H */ +#define LCR_FEN (1 << 4) +#define LCR_BRK (1 << 0) + static const unsigned char pl011_id_arm[8] = { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; static const unsigned char pl011_id_luminary[8] = { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; +static const char *pl011_regname(hwaddr offset) +{ + static const char *const rname[] = { + [0] = "DR", [1] = "RSR", [6] = "FR", [8] = "ILPR", [9] = "IBRD", + [10] = "FBRD", [11] = "LCRH", [12] = "CR", [13] = "IFLS", [14] = "IMSC", + [15] = "RIS", [16] = "MIS", [17] = "ICR", [18] = "DMACR", + }; + unsigned idx = offset >> 2; + + if (idx < ARRAY_SIZE(rname) && rname[idx]) { + return rname[idx]; + } + if (idx >= 0x3f8 && idx <= 0x400) { + return "ID"; + } + return "UNKN"; +} + /* Which bits in the interrupt status matter for each outbound IRQ line ? */ static const uint32_t irqmask[] = { INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */ @@ -100,7 +123,7 @@ static void pl011_update(PL011State *s) static bool pl011_is_fifo_enabled(PL011State *s) { - return (s->lcr & 0x10) != 0; + return (s->lcr & LCR_FEN) != 0; } static inline unsigned pl011_get_fifo_depth(PL011State *s) @@ -138,7 +161,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, s->flags |= PL011_FLAG_RXFE; } if (s->read_count == s->read_trigger - 1) - s->int_level &= ~ PL011_INT_RX; + s->int_level &= ~ INT_RX; trace_pl011_read_fifo(s->read_count); s->rsr = c >> 8; pl011_update(s); @@ -191,7 +214,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, break; } - trace_pl011_read(offset, r); + trace_pl011_read(offset, r, pl011_regname(offset)); return r; } @@ -202,7 +225,7 @@ static void pl011_set_read_trigger(PL011State *s) the threshold. However linux only reads the FIFO in response to an interrupt. Triggering the interrupt when the FIFO is non-empty seems to make things work. */ - if (s->lcr & 0x10) + if (s->lcr & LCR_FEN) s->read_trigger = (s->ifl >> 1) & 0x1c; else #endif @@ -234,7 +257,7 @@ static void pl011_write(void *opaque, hwaddr offset, PL011State *s = (PL011State *)opaque; unsigned char ch; - trace_pl011_write(offset, value); + trace_pl011_write(offset, value, pl011_regname(offset)); switch (offset >> 2) { case 0: /* UARTDR */ @@ -243,7 +266,7 @@ static void pl011_write(void *opaque, hwaddr offset, /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1); - s->int_level |= PL011_INT_TX; + s->int_level |= INT_TX; pl011_update(s); break; case 1: /* UARTRSR/UARTECR */ @@ -252,7 +275,7 @@ static void pl011_write(void *opaque, hwaddr offset, case 6: /* UARTFR */ /* Writes to Flag register are ignored. */ break; - case 8: /* UARTUARTILPR */ + case 8: /* UARTILPR */ s->ilpr = value; break; case 9: /* UARTIBRD */ @@ -265,11 +288,11 @@ static void pl011_write(void *opaque, hwaddr offset, break; case 11: /* UARTLCR_H */ /* Reset the FIFO state on FIFO enable or disable */ - if ((s->lcr ^ value) & 0x10) { + if ((s->lcr ^ value) & LCR_FEN) { pl011_reset_fifo(s); } - if ((s->lcr ^ value) & 0x1) { - int break_enable = value & 0x1; + if ((s->lcr ^ value) & LCR_BRK) { + int break_enable = value & LCR_BRK; qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &break_enable); } @@ -331,7 +354,7 @@ static void pl011_put_fifo(void *opaque, uint32_t value) s->flags |= PL011_FLAG_RXFF; } if (s->read_count == s->read_trigger) { - s->int_level |= PL011_INT_RX; + s->int_level |= INT_RX; pl011_update(s); } } @@ -343,8 +366,9 @@ static void pl011_receive(void *opaque, const uint8_t *buf, int size) static void pl011_event(void *opaque, QEMUChrEvent event) { - if (event == CHR_EVENT_BREAK) - pl011_put_fifo(opaque, 0x400); + if (event == CHR_EVENT_BREAK) { + pl011_put_fifo(opaque, DR_BE); + } } static void pl011_clock_update(void *opaque, ClockEvent event) @@ -358,6 +382,8 @@ static const MemoryRegionOps pl011_ops = { .read = pl011_read, .write = pl011_write, .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, }; static bool pl011_clock_needed(void *opaque) diff --git a/hw/char/serial.c b/hw/char/serial.c index 270e1b1094..f3094f860f 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -226,7 +226,7 @@ static gboolean serial_watch_cb(void *do_not_use, GIOCondition cond, SerialState *s = opaque; s->watch_tag = 0; serial_xmit(s); - return FALSE; + return G_SOURCE_REMOVE; } static void serial_xmit(SerialState *s) diff --git a/hw/char/trace-events b/hw/char/trace-events index 2ecb36232e..babf4d35ea 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -54,9 +54,9 @@ escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=0x%0 # pl011.c pl011_irq_state(int level) "irq state %d" -pl011_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl011_read(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s" pl011_read_fifo(int read_count) "FIFO read, read_count now %d" -pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl011_write(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s" pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d" pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d" pl011_put_fifo_full(void) "FIFO now full, RXFF set" diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index dd5a02e339..dbe0b28e60 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -45,7 +45,7 @@ static gboolean chr_write_unblocked(void *do_not_use, GIOCondition cond, vcon->watch = 0; virtio_serial_throttle_port(VIRTIO_SERIAL_PORT(vcon), false); - return FALSE; + return G_SOURCE_REMOVE; } /* Callback function that's called when the guest sends us data */ diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index e7ec268184..9138e98c3b 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -164,7 +164,7 @@ static int bochs_display_get_mode(BochsDisplayState *s, memset(mode, 0, sizeof(*mode)); switch (vbe[VBE_DISPI_INDEX_BPP]) { case 16: - /* best effort: support native endianess only */ + /* best effort: support native endianness only */ mode->format = PIXMAN_r5g6b5; mode->bytepp = 2; break; diff --git a/hw/display/qxl.c b/hw/display/qxl.c index f1c0eb7dfc..af941fb0c2 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1544,7 +1544,7 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, } } -/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or +/* return 1 if surface destroy was initiated (in QXL_ASYNC case) or * done (in QXL_SYNC case), 0 otherwise. */ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) { diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index d67b0ad7b5..32b32a3044 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -8,7 +8,7 @@ */ /* The controller can support a variety of different displays, but we only - implement one. Most of the commends relating to brightness and geometry + implement one. Most of the commands relating to brightness and geometry setup are ignored. */ #include "qemu/osdep.h" diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index ab229d32b7..09b1bbed0a 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -8,7 +8,7 @@ */ /* The controller can support a variety of different displays, but we only - implement one. Most of the commends relating to brightness and geometry + implement one. Most of the commands relating to brightness and geometry setup are ignored. */ #include "qemu/osdep.h" diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index b0828d65aa..822355ecc6 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -380,7 +380,7 @@ static inline void xlnx_dp_audio_mix_buffer(XlnxDPState *s) static void xlnx_dp_audio_callback(void *opaque, int avail) { /* - * Get some data from the DPDMA and compute these datas. + * Get some data from the DPDMA and compute these data. * Then wait for QEMU's audio subsystem to call this callback. */ XlnxDPState *s = XLNX_DP(opaque); diff --git a/hw/dma/etraxfs_dma.c b/hw/dma/etraxfs_dma.c index a1068b19ea..9c0003de51 100644 --- a/hw/dma/etraxfs_dma.c +++ b/hw/dma/etraxfs_dma.c @@ -28,6 +28,7 @@ #include "qemu/main-loop.h" #include "sysemu/runstate.h" #include "exec/address-spaces.h" +#include "exec/memory.h" #include "hw/cris/etraxfs_dma.h" diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 1f071a3811..7275d40749 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -226,7 +226,7 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) return 0; } -static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) +static int aspeed_i2c_bus_send(AspeedI2CBus *bus) { AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); int ret = -1; @@ -236,10 +236,10 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, - TX_COUNT); + TX_COUNT) + 1; if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { - for (i = pool_start; i < pool_tx_count; i++) { + for (i = 0; i < pool_tx_count; i++) { uint8_t *pool_base = aic->bus_pool_base(bus); trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count, @@ -273,7 +273,7 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) } SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); } else { - trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, + trace_aspeed_i2c_bus_send("BYTE", 0, 1, bus->regs[reg_byte_buf]); ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]); } @@ -293,10 +293,14 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, - RX_COUNT); + RX_SIZE) + 1; if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { uint8_t *pool_base = aic->bus_pool_base(bus); + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, + BUF_ORGANIZATION)) { + pool_base += 16; + } for (i = 0; i < pool_rx_count; i++) { pool_base[i] = i2c_recv(bus->bus); @@ -418,7 +422,7 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { - count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT); + count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) + 1; } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { count = bus->regs[reg_dma_len]; } else { /* BYTE mode */ @@ -446,10 +450,8 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) */ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) { - uint8_t pool_start = 0; uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); - uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); if (!aspeed_i2c_check_sram(bus)) { @@ -483,27 +485,11 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); - /* - * The START command is also a TX command, as the slave - * address is sent on the bus. Drop the TX flag if nothing - * else needs to be sent in this sequence. - */ - if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { - if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) - == 1) { - SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); - } else { - /* - * Increase the start index in the TX pool buffer to - * skip the address byte. - */ - pool_start++; - } - } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { if (bus->regs[reg_dma_len] == 0) { SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); } - } else { + } else if (!SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); } @@ -520,7 +506,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { aspeed_i2c_set_state(bus, I2CD_MTXD); - if (aspeed_i2c_bus_send(bus, pool_start)) { + if (aspeed_i2c_bus_send(bus)) { SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); i2c_end_transfer(bus->bus); } else { diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index d7eae548cb..9ad6a47739 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -1,6 +1,6 @@ /* * PC SMBus implementation - * splitted from acpi.c + * split from acpi.c * * Copyright (c) 2006 Fabrice Bellard * diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c index 44fe4eddbb..cef51663d0 100644 --- a/hw/i2c/pmbus_device.c +++ b/hw/i2c/pmbus_device.c @@ -190,15 +190,18 @@ static void pmbus_quick_cmd(SMBusDevice *smd, uint8_t read) } } -static void pmbus_pages_alloc(PMBusDevice *pmdev) +static uint8_t pmbus_pages_num(PMBusDevice *pmdev) { + const PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev); + /* some PMBus devices don't use the PAGE command, so they get 1 page */ - PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev); - if (k->device_num_pages == 0) { - k->device_num_pages = 1; - } - pmdev->num_pages = k->device_num_pages; - pmdev->pages = g_new0(PMBusPage, k->device_num_pages); + return k->device_num_pages ? : 1; +} + +static void pmbus_pages_alloc(PMBusDevice *pmdev) +{ + pmdev->num_pages = pmbus_pages_num(pmdev); + pmdev->pages = g_new0(PMBusPage, pmdev->num_pages); } void pmbus_check_limits(PMBusDevice *pmdev) @@ -1623,7 +1626,7 @@ static int pmbus_write_data(SMBusDevice *smd, uint8_t *buf, uint8_t len) break; passthrough: - /* Unimplimented registers get passed to the device */ + /* Unimplemented registers get passed to the device */ default: if (pmdc->write_data) { ret = pmdc->write_data(pmdev, buf, len); diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c index feb3ec6333..2ef2c7c5f6 100644 --- a/hw/i2c/smbus_slave.c +++ b/hw/i2c/smbus_slave.c @@ -2,7 +2,7 @@ * QEMU SMBus device emulation. * * This code is a helper for SMBus device emulation. It implements an - * I2C device inteface and runs the SMBus protocol from the device + * I2C device interface and runs the SMBus protocol from the device * point of view and maps those to simple calls to emulate. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index df70b4a033..34348a3324 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -22,7 +22,7 @@ #include "kvm/kvm_i386.h" #include "migration/vmstate.h" #include "hw/sysbus.h" -#include "hw/kvm/clock.h" +#include "hw/i386/kvm/clock.h" #include "hw/qdev-properties.h" #include "qapi/error.h" @@ -332,8 +332,10 @@ void kvmclock_create(bool create_always) { X86CPU *cpu = X86_CPU(first_cpu); - if (!kvm_enabled() || !kvm_has_adjust_clock()) + assert(kvm_enabled()); + if (!kvm_has_adjust_clock()) { return; + } if (create_always || cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) | diff --git a/hw/i386/kvm/clock.h b/hw/i386/kvm/clock.h new file mode 100644 index 0000000000..401c7e445b --- /dev/null +++ b/hw/i386/kvm/clock.h @@ -0,0 +1,18 @@ +/* + * QEMU KVM support, paravirtual clock device + * + * Copyright (C) 2011 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU GPL version 2. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_I386_KVM_CLOCK_H +#define HW_I386_KVM_CLOCK_H + +void kvmclock_create(bool create_always); + +#endif diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 7227a2156c..8deeb62774 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -32,7 +32,7 @@ #include "hw/loader.h" #include "hw/irq.h" -#include "hw/kvm/clock.h" +#include "hw/i386/kvm/clock.h" #include "hw/i386/microvm.h" #include "hw/i386/x86.h" #include "target/i386/cpu.h" @@ -180,7 +180,9 @@ static void microvm_devices_init(MicrovmMachineState *mms) x86ms->ioapic2 = ioapic_init_secondary(gsi_state); } - kvmclock_create(true); + if (kvm_enabled()) { + kvmclock_create(true); + } mms->virtio_irq_base = 5; mms->virtio_num_transports = 8; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index f0df12f6fa..8321f36f97 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -46,7 +46,7 @@ #include "hw/ide/piix.h" #include "hw/irq.h" #include "sysemu/kvm.h" -#include "hw/kvm/clock.h" +#include "hw/i386/kvm/clock.h" #include "hw/sysbus.h" #include "hw/i2c/smbus_eeprom.h" #include "exec/memory.h" @@ -193,7 +193,7 @@ static void pc_init1(MachineState *machine, pc_machine_init_sgx_epc(pcms); x86_cpus_init(x86ms, pcmc->default_cpu_version); - if (pcmc->kvmclock_enabled) { + if (kvm_enabled() && pcmc->kvmclock_enabled) { kvmclock_create(pcmc->kvmclock_create_always); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 8ecc78c822..2dd1158b70 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -36,7 +36,7 @@ #include "hw/rtc/mc146818rtc.h" #include "sysemu/tcg.h" #include "sysemu/kvm.h" -#include "hw/kvm/clock.h" +#include "hw/i386/kvm/clock.h" #include "hw/pci-host/q35.h" #include "hw/pci/pcie_port.h" #include "hw/qdev-properties.h" @@ -185,7 +185,9 @@ static void pc_q35_init(MachineState *machine) pc_machine_init_sgx_epc(pcms); x86_cpus_init(x86ms, pcmc->default_cpu_version); - kvmclock_create(pcmc->kvmclock_create_always); + if (kvm_enabled()) { + kvmclock_create(pcmc->kvmclock_create_always); + } /* pci enabled */ if (pcmc->pci_enabled) { diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 48d550f633..d0a774bc17 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -41,9 +41,10 @@ #include "trace.h" static void check_cmd(AHCIState *s, int port); -static int handle_cmd(AHCIState *s, int port, uint8_t slot); +static void handle_cmd(AHCIState *s, int port, uint8_t slot); static void ahci_reset_port(AHCIState *s, int port); -static bool ahci_write_fis_d2h(AHCIDevice *ad); +static bool ahci_write_fis_d2h(AHCIDevice *ad, bool d2h_fis_i); +static void ahci_clear_cmd_issue(AHCIDevice *ad, uint8_t slot); static void ahci_init_d2h(AHCIDevice *ad); static int ahci_dma_prepare_buf(const IDEDMA *dma, int32_t limit); static bool ahci_map_clb_address(AHCIDevice *ad); @@ -328,6 +329,11 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) ahci_check_irq(s); break; case AHCI_PORT_REG_CMD: + if ((pr->cmd & PORT_CMD_START) && !(val & PORT_CMD_START)) { + pr->scr_act = 0; + pr->cmd_issue = 0; + } + /* Block any Read-only fields from being set; * including LIST_ON and FIS_ON. * The spec requires to set ICC bits to zero after the ICC change @@ -591,9 +597,8 @@ static void check_cmd(AHCIState *s, int port) if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) { for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) { - if ((pr->cmd_issue & (1U << slot)) && - !handle_cmd(s, port, slot)) { - pr->cmd_issue &= ~(1U << slot); + if (pr->cmd_issue & (1U << slot)) { + handle_cmd(s, port, slot); } } } @@ -618,7 +623,7 @@ static void ahci_init_d2h(AHCIDevice *ad) return; } - if (ahci_write_fis_d2h(ad)) { + if (ahci_write_fis_d2h(ad, true)) { ad->init_d2h_sent = true; /* We're emulating receiving the first Reg H2D Fis from the device; * Update the SIG register, but otherwise proceed as normal. */ @@ -801,8 +806,14 @@ static void ahci_write_fis_sdb(AHCIState *s, NCQTransferState *ncq_tfs) pr->scr_act &= ~ad->finished; ad->finished = 0; - /* Trigger IRQ if interrupt bit is set (which currently, it always is) */ - if (sdb_fis->flags & 0x40) { + /* + * TFES IRQ is always raised if ERR_STAT is set, regardless of I bit. + * If ERR_STAT is not set, trigger SDBS IRQ if interrupt bit is set + * (which currently, it always is). + */ + if (sdb_fis->status & ERR_STAT) { + ahci_trigger_irq(s, ad, AHCI_PORT_IRQ_BIT_TFES); + } else if (sdb_fis->flags & 0x40) { ahci_trigger_irq(s, ad, AHCI_PORT_IRQ_BIT_SDBS); } } @@ -850,7 +861,7 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len, bool pio_fis_i) } } -static bool ahci_write_fis_d2h(AHCIDevice *ad) +static bool ahci_write_fis_d2h(AHCIDevice *ad, bool d2h_fis_i) { AHCIPortRegs *pr = &ad->port_regs; uint8_t *d2h_fis; @@ -864,7 +875,7 @@ static bool ahci_write_fis_d2h(AHCIDevice *ad) d2h_fis = &ad->res_fis[RES_FIS_RFIS]; d2h_fis[0] = SATA_FIS_TYPE_REGISTER_D2H; - d2h_fis[1] = (1 << 6); /* interrupt bit */ + d2h_fis[1] = d2h_fis_i ? (1 << 6) : 0; /* interrupt bit */ d2h_fis[2] = s->status; d2h_fis[3] = s->error; @@ -890,7 +901,10 @@ static bool ahci_write_fis_d2h(AHCIDevice *ad) ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_TFES); } - ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_DHRS); + if (d2h_fis_i) { + ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_DHRS); + } + return true; } @@ -998,7 +1012,6 @@ static void ncq_err(NCQTransferState *ncq_tfs) ide_state->error = ABRT_ERR; ide_state->status = READY_STAT | ERR_STAT; - ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag); qemu_sglist_destroy(&ncq_tfs->sglist); ncq_tfs->used = 0; } @@ -1008,7 +1021,7 @@ static void ncq_finish(NCQTransferState *ncq_tfs) /* If we didn't error out, set our finished bit. Errored commands * do not get a bit set for the SDB FIS ACT register, nor do they * clear the outstanding bit in scr_act (PxSACT). */ - if (!(ncq_tfs->drive->port_regs.scr_err & (1 << ncq_tfs->tag))) { + if (ncq_tfs->used) { ncq_tfs->drive->finished |= (1 << ncq_tfs->tag); } @@ -1120,6 +1133,24 @@ static void process_ncq_command(AHCIState *s, int port, const uint8_t *cmd_fis, return; } + /* + * A NCQ command clears the bit in PxCI after the command has been QUEUED + * successfully (ERROR not set, BUSY and DRQ cleared). + * + * For NCQ commands, PxCI will always be cleared here. + * + * (Once the NCQ command is COMPLETED, the device will send a SDB FIS with + * the interrupt bit set, which will clear PxSACT and raise an interrupt.) + */ + ahci_clear_cmd_issue(ad, slot); + + /* + * In reality, for NCQ commands, PxCI is cleared after receiving a D2H FIS + * without the interrupt bit set, but since ahci_write_fis_d2h() can raise + * an IRQ on error, we need to call them in reverse order. + */ + ahci_write_fis_d2h(ad, false); + ncq_tfs->used = 1; ncq_tfs->drive = ad; ncq_tfs->slot = slot; @@ -1192,6 +1223,7 @@ static void handle_reg_h2d_fis(AHCIState *s, int port, { IDEState *ide_state = &s->dev[port].port.ifs[0]; AHCICmdHdr *cmd = get_cmd_header(s, port, slot); + AHCIDevice *ad = &s->dev[port]; uint16_t opts = le16_to_cpu(cmd->opts); if (cmd_fis[1] & 0x0F) { @@ -1268,11 +1300,19 @@ static void handle_reg_h2d_fis(AHCIState *s, int port, /* Reset transferred byte counter */ cmd->status = 0; + /* + * A non-NCQ command clears the bit in PxCI after the command has COMPLETED + * successfully (ERROR not set, BUSY and DRQ cleared). + * + * For non-NCQ commands, PxCI will always be cleared by ahci_cmd_done(). + */ + ad->busy_slot = slot; + /* We're ready to process the command in FIS byte 2. */ ide_bus_exec_cmd(&s->dev[port].port, cmd_fis[2]); } -static int handle_cmd(AHCIState *s, int port, uint8_t slot) +static void handle_cmd(AHCIState *s, int port, uint8_t slot) { IDEState *ide_state; uint64_t tbl_addr; @@ -1283,12 +1323,12 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { /* Engine currently busy, try again later */ trace_handle_cmd_busy(s, port); - return -1; + return; } if (!s->dev[port].lst) { trace_handle_cmd_nolist(s, port); - return -1; + return; } cmd = get_cmd_header(s, port, slot); /* remember current slot handle for later */ @@ -1298,7 +1338,7 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) ide_state = &s->dev[port].port.ifs[0]; if (!ide_state->blk) { trace_handle_cmd_badport(s, port); - return -1; + return; } tbl_addr = le64_to_cpu(cmd->tbl_addr); @@ -1307,7 +1347,7 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); if (!cmd_fis) { trace_handle_cmd_badfis(s, port); - return -1; + return; } else if (cmd_len != 0x80) { ahci_trigger_irq(s, &s->dev[port], AHCI_PORT_IRQ_BIT_HBFS); trace_handle_cmd_badmap(s, port, cmd_len); @@ -1331,15 +1371,6 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) out: dma_memory_unmap(s->as, cmd_fis, cmd_len, DMA_DIRECTION_TO_DEVICE, cmd_len); - - if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { - /* async command, complete later */ - s->dev[port].busy_slot = slot; - return -1; - } - - /* done handling the command */ - return 0; } /* Transfer PIO data between RAM and device */ @@ -1493,22 +1524,39 @@ static int ahci_dma_rw_buf(const IDEDMA *dma, bool is_write) return 1; } +static void ahci_clear_cmd_issue(AHCIDevice *ad, uint8_t slot) +{ + IDEState *ide_state = &ad->port.ifs[0]; + + if (!(ide_state->status & ERR_STAT) && + !(ide_state->status & (BUSY_STAT | DRQ_STAT))) { + ad->port_regs.cmd_issue &= ~(1 << slot); + } +} + +/* Non-NCQ command is done - This function is never called for NCQ commands. */ static void ahci_cmd_done(const IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); + IDEState *ide_state = &ad->port.ifs[0]; trace_ahci_cmd_done(ad->hba, ad->port_no); /* no longer busy */ if (ad->busy_slot != -1) { - ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot); + ahci_clear_cmd_issue(ad, ad->busy_slot); ad->busy_slot = -1; } - /* update d2h status */ - ahci_write_fis_d2h(ad); + /* + * In reality, for non-NCQ commands, PxCI is cleared after receiving a D2H + * FIS with the interrupt bit set, but since ahci_write_fis_d2h() will raise + * an IRQ, we need to call them in reverse order. + */ + ahci_write_fis_d2h(ad, true); - if (ad->port_regs.cmd_issue && !ad->check_bh) { + if (!(ide_state->status & ERR_STAT) && + ad->port_regs.cmd_issue && !ad->check_bh) { ad->check_bh = qemu_bh_new_guarded(ahci_check_cmd_bh, ad, &ad->mem_reentrancy_guard); qemu_bh_schedule(ad->check_bh); diff --git a/hw/ide/ahci_internal.h b/hw/ide/ahci_internal.h index 2480455372..c244bbd8be 100644 --- a/hw/ide/ahci_internal.h +++ b/hw/ide/ahci_internal.h @@ -61,13 +61,13 @@ enum AHCIHostReg { AHCI_HOST_REG_CTL = 1, /* GHC: global host control */ AHCI_HOST_REG_IRQ_STAT = 2, /* IS: interrupt status */ AHCI_HOST_REG_PORTS_IMPL = 3, /* PI: bitmap of implemented ports */ - AHCI_HOST_REG_VERSION = 4, /* VS: AHCI spec. version compliancy */ + AHCI_HOST_REG_VERSION = 4, /* VS: AHCI spec. version compliance */ AHCI_HOST_REG_CCC_CTL = 5, /* CCC_CTL: CCC Control */ AHCI_HOST_REG_CCC_PORTS = 6, /* CCC_PORTS: CCC Ports */ AHCI_HOST_REG_EM_LOC = 7, /* EM_LOC: Enclosure Mgmt Location */ AHCI_HOST_REG_EM_CTL = 8, /* EM_CTL: Enclosure Mgmt Control */ AHCI_HOST_REG_CAP2 = 9, /* CAP2: host capabilities, extended */ - AHCI_HOST_REG_BOHC = 10, /* BOHC: firmare/os handoff ctrl & status */ + AHCI_HOST_REG_BOHC = 10, /* BOHC: firmware/os handoff ctrl & status */ AHCI_HOST_REG__COUNT = 11 }; diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index cabe9048b1..c0bcfa4414 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -257,7 +257,7 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp) pci_conf[CNTRL] = CNTRL_EN_CH0; // enable IDE0 if (d->secondary) { - /* XXX: if not enabled, really disable the seconday IDE controller */ + /* XXX: if not enabled, really disable the secondary IDE controller */ pci_conf[CNTRL] |= CNTRL_EN_CH1; /* enable IDE1 */ } diff --git a/hw/ide/core.c b/hw/ide/core.c index de48ff9f86..b5e0dcd29b 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -533,9 +533,9 @@ BlockAIOCB *ide_issue_trim( void ide_abort_command(IDEState *s) { - ide_transfer_stop(s); s->status = READY_STAT | ERR_STAT; s->error = ABRT_ERR; + ide_transfer_stop(s); } static void ide_set_retry(IDEState *s) @@ -1698,7 +1698,7 @@ static bool cmd_set_features(IDEState *s, uint8_t cmd) put_le16(identify_data + 63, 0x07); put_le16(identify_data + 88, 0x3f); break; - case 0x02: /* sigle word dma mode*/ + case 0x02: /* single word dma mode */ put_le16(identify_data + 62, 0x07 | (1 << (val + 8))); put_le16(identify_data + 63, 0x07); put_le16(identify_data + 88, 0x3f); diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 4a34f03047..68ad30e2f5 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -28,7 +28,6 @@ #include "hw/intc/kvm_irqcount.h" #include "trace.h" #include "hw/boards.h" -#include "sysemu/hax.h" #include "sysemu/kvm.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" @@ -271,7 +270,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp) /* Note: We need at least 1M to map the VAPIC option ROM */ if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK && - !hax_enabled() && current_machine->ram_size >= 1024 * 1024) { + current_machine->ram_size >= 1024 * 1024) { vapic = sysbus_create_simple("kvmvapic", -1, NULL); } s->vapic = vapic; diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index e536b3ec26..9b10e90519 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -85,28 +85,6 @@ static uint8_t pnv_xive_block_id(PnvXive *xive) } /* - * Remote access to controllers. HW uses MMIOs. For now, a simple scan - * of the chips is good enough. - * - * TODO: Block scope support - */ -static PnvXive *pnv_xive_get_remote(uint8_t blk) -{ - PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); - int i; - - for (i = 0; i < pnv->num_chips; i++) { - Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]); - PnvXive *xive = &chip9->xive; - - if (pnv_xive_block_id(xive) == blk) { - return xive; - } - } - return NULL; -} - -/* * VST accessors for SBE, EAT, ENDT, NVT * * Indirect VST tables are arrays of VSDs pointing to a page (of same @@ -209,6 +187,42 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type, return pnv_xive_vst_addr_direct(xive, type, vsd, (idx % vst_per_page)); } +/* + * This is a simplified model of operation forwarding on a remote IC. + * + * A PC MMIO address is built to identify the NVT structure. The load + * on the remote IC will return the address of the structure in RAM, + * which will then be used by pnv_xive_vst_write/read to perform the + * RAM operation. + */ +static uint64_t pnv_xive_vst_addr_remote(PnvXive *xive, uint32_t type, + uint64_t vsd, uint8_t blk, + uint32_t idx) +{ + const XiveVstInfo *info = &vst_infos[type]; + uint64_t remote_addr = vsd & VSD_ADDRESS_MASK; + uint64_t vst_addr; + MemTxResult result; + + if (type != VST_TSEL_VPDT) { + xive_error(xive, "VST: invalid access on remote VST %s %x/%x !?", + info->name, blk, idx); + return 0; + } + + remote_addr |= idx << xive->pc_shift; + + vst_addr = address_space_ldq_be(&address_space_memory, remote_addr, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + xive_error(xive, "VST: read failed at @0x%" HWADDR_PRIx + " for NVT %x/%x\n", remote_addr, blk, idx); + return 0; + } + + return vst_addr; +} + static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk, uint32_t idx) { @@ -225,9 +239,7 @@ static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk, /* Remote VST access */ if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) { - xive = pnv_xive_get_remote(blk); - - return xive ? pnv_xive_vst_addr(xive, type, blk, idx) : 0; + return pnv_xive_vst_addr_remote(xive, type, vsd, blk, idx); } if (VSD_INDIRECT & vsd) { @@ -242,12 +254,20 @@ static int pnv_xive_vst_read(PnvXive *xive, uint32_t type, uint8_t blk, { const XiveVstInfo *info = &vst_infos[type]; uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx); + MemTxResult result; if (!addr) { return -1; } - cpu_physical_memory_read(addr, data, info->size); + result = address_space_read(&address_space_memory, addr, + MEMTXATTRS_UNSPECIFIED, data, + info->size); + if (result != MEMTX_OK) { + xive_error(xive, "VST: read failed at @0x%" HWADDR_PRIx + " for VST %s %x/%x\n", addr, info->name, blk, idx); + return -1; + } return 0; } @@ -258,16 +278,27 @@ static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk, { const XiveVstInfo *info = &vst_infos[type]; uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx); + MemTxResult result; if (!addr) { return -1; } if (word_number == XIVE_VST_WORD_ALL) { - cpu_physical_memory_write(addr, data, info->size); + result = address_space_write(&address_space_memory, addr, + MEMTXATTRS_UNSPECIFIED, data, + info->size); } else { - cpu_physical_memory_write(addr + word_number * 4, - data + word_number * 4, 4); + result = address_space_write(&address_space_memory, + addr + word_number * 4, + MEMTXATTRS_UNSPECIFIED, + data + word_number * 4, 4); + } + + if (result != MEMTX_OK) { + xive_error(xive, "VST: write failed at @0x%" HWADDR_PRIx + "for VST %s %x/%x\n", addr, info->name, blk, idx); + return -1; } return 0; } @@ -275,12 +306,26 @@ static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk, static int pnv_xive_get_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx, XiveEND *end) { + PnvXive *xive = PNV_XIVE(xrtr); + + if (pnv_xive_block_id(xive) != blk) { + xive_error(xive, "VST: END %x/%x is remote !?", blk, idx); + return -1; + } + return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end); } static int pnv_xive_write_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx, XiveEND *end, uint8_t word_number) { + PnvXive *xive = PNV_XIVE(xrtr); + + if (pnv_xive_block_id(xive) != blk) { + xive_error(xive, "VST: END %x/%x is remote !?", blk, idx); + return -1; + } + return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end, word_number); } @@ -1349,6 +1394,50 @@ static const MemoryRegionOps pnv_xive_ic_reg_ops = { #define PNV_XIVE_SYNC_PUSH 0xf00 /* Sync push context */ #define PNV_XIVE_SYNC_VPC 0xf80 /* Sync remove VPC store */ +static void pnv_xive_end_notify(XiveRouter *xrtr, XiveEAS *eas) +{ + PnvXive *xive = PNV_XIVE(xrtr); + uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w); + uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w); + uint32_t end_data = xive_get_field64(EAS_END_DATA, eas->w); + uint64_t end_vsd = xive->vsds[VST_TSEL_EQDT][end_blk]; + + switch (GETFIELD(VSD_MODE, end_vsd)) { + case VSD_MODE_EXCLUSIVE: + /* Perform the END notification on the local IC. */ + xive_router_end_notify(xrtr, eas); + break; + + case VSD_MODE_FORWARD: { + MemTxResult result; + uint64_t notif_port = end_vsd & VSD_ADDRESS_MASK; + uint64_t data = XIVE_TRIGGER_END | XIVE_TRIGGER_PQ | + be64_to_cpu(eas->w); + + /* Forward the store on the remote IC notify page. */ + address_space_stq_be(&address_space_memory, notif_port, data, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + xive_error(xive, "IC: Forward notif END %x/%x [%x] failed @%" + HWADDR_PRIx, end_blk, end_idx, end_data, notif_port); + return; + } + break; + } + + case VSD_MODE_INVALID: + default: + /* Set FIR */ + xive_error(xive, "IC: Invalid END VSD for block %x", end_blk); + return; + } +} + +/* + * The notify page can either be used to receive trigger events from + * the HW controllers (PHB, PSI) or to reroute interrupts between + * Interrupt controllers. + */ static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val) { uint8_t blk; @@ -1357,8 +1446,8 @@ static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val) trace_pnv_xive_ic_hw_trigger(addr, val); if (val & XIVE_TRIGGER_END) { - xive_error(xive, "IC: END trigger at @0x%"HWADDR_PRIx" data 0x%"PRIx64, - addr, val); + val = cpu_to_be64(val); + pnv_xive_end_notify(XIVE_ROUTER(xive), (XiveEAS *) &val); return; } @@ -1703,16 +1792,20 @@ static const MemoryRegionOps pnv_xive_vc_ops = { }; /* - * Presenter Controller MMIO region. The Virtualization Controller - * updates the IPB in the NVT table when required. Not modeled. + * Presenter Controller MMIO region. Points to the NVT sets. + * + * HW implements all possible mem ops to the underlying NVT structure + * but QEMU does not need to be so precise. The model implementation + * simply returns the RAM address of the NVT structure which is then + * used by pnv_xive_vst_write/read to perform the RAM operation. */ -static uint64_t pnv_xive_pc_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t pnv_xive_pc_read(void *opaque, hwaddr offset, unsigned size) { PnvXive *xive = PNV_XIVE(opaque); + uint32_t nvt_idx = offset >> xive->pc_shift; + uint8_t blk = pnv_xive_block_id(xive); /* TODO: VDT -> block xlate */ - xive_error(xive, "PC: invalid read @%"HWADDR_PRIx, addr); - return -1; + return pnv_xive_vst_addr(xive, VST_TSEL_VPDT, blk, nvt_idx); } static void pnv_xive_pc_write(void *opaque, hwaddr addr, @@ -1898,6 +1991,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) memory_region_init_io(&xive->ic_notify_mmio, OBJECT(dev), &pnv_xive_ic_notify_ops, xive, "xive-ic-notify", 1 << xive->ic_shift); + xive->ic_notify_mmio.disable_reentrancy_guard = true; /* The Pervasive LSI trigger and EOI pages (not modeled) */ memory_region_init_io(&xive->ic_lsi_mmio, OBJECT(dev), &pnv_xive_ic_lsi_ops, @@ -1933,6 +2027,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) /* Presenter Controller MMIO region (not modeled) */ memory_region_init_io(&xive->pc_mmio, OBJECT(xive), &pnv_xive_pc_ops, xive, "xive-pc", PNV9_XIVE_PC_SIZE); + xive->pc_mmio.disable_reentrancy_guard = true; /* Thread Interrupt Management Area (Direct) */ memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &pnv_xive_tm_ops, @@ -1998,6 +2093,7 @@ static void pnv_xive_class_init(ObjectClass *klass, void *data) xrc->get_nvt = pnv_xive_get_nvt; xrc->write_nvt = pnv_xive_write_nvt; xrc->get_block_id = pnv_xive_get_block_id; + xrc->end_notify = pnv_xive_end_notify; xnc->notify = pnv_xive_notify; xpc->match_nvt = pnv_xive_match_nvt; diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index bbb44a533c..4b8d0a5d81 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -240,12 +240,20 @@ static int pnv_xive2_vst_read(PnvXive2 *xive, uint32_t type, uint8_t blk, { const XiveVstInfo *info = &vst_infos[type]; uint64_t addr = pnv_xive2_vst_addr(xive, type, blk, idx); + MemTxResult result; if (!addr) { return -1; } - cpu_physical_memory_read(addr, data, info->size); + result = address_space_read(&address_space_memory, addr, + MEMTXATTRS_UNSPECIFIED, data, + info->size); + if (result != MEMTX_OK) { + xive2_error(xive, "VST: read failed at @0x%" HWADDR_PRIx + " for VST %s %x/%x\n", addr, info->name, blk, idx); + return -1; + } return 0; } @@ -256,16 +264,27 @@ static int pnv_xive2_vst_write(PnvXive2 *xive, uint32_t type, uint8_t blk, { const XiveVstInfo *info = &vst_infos[type]; uint64_t addr = pnv_xive2_vst_addr(xive, type, blk, idx); + MemTxResult result; if (!addr) { return -1; } if (word_number == XIVE_VST_WORD_ALL) { - cpu_physical_memory_write(addr, data, info->size); + result = address_space_write(&address_space_memory, addr, + MEMTXATTRS_UNSPECIFIED, data, + info->size); } else { - cpu_physical_memory_write(addr + word_number * 4, - data + word_number * 4, 4); + result = address_space_write(&address_space_memory, + addr + word_number * 4, + MEMTXATTRS_UNSPECIFIED, + data + word_number * 4, 4); + } + + if (result != MEMTX_OK) { + xive2_error(xive, "VST: write failed at @0x%" HWADDR_PRIx + "for VST %s %x/%x\n", addr, info->name, blk, idx); + return -1; } return 0; } diff --git a/hw/intc/pnv_xive_regs.h b/hw/intc/pnv_xive_regs.h index c78f030c02..793847638b 100644 --- a/hw/intc/pnv_xive_regs.h +++ b/hw/intc/pnv_xive_regs.h @@ -228,6 +228,7 @@ * VSD and is only meant to be used in indirect mode ! */ #define VSD_MODE PPC_BITMASK(0, 1) +#define VSD_MODE_INVALID 0 #define VSD_MODE_SHARED 1 #define VSD_MODE_EXCLUSIVE 2 #define VSD_MODE_FORWARD 3 diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 56670b2cac..df3ee0496f 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -1518,6 +1518,13 @@ static void xive_router_realize(DeviceState *dev, Error **errp) assert(xrtr->xfb); } +static void xive_router_end_notify_handler(XiveRouter *xrtr, XiveEAS *eas) +{ + XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr); + + return xrc->end_notify(xrtr, eas); +} + /* * Encode the HW CAM line in the block group mode format : * @@ -1664,8 +1671,7 @@ static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk, * another chip. We don't model the PowerBus but the END trigger * message has the same parameters than in the function below. */ -static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk, - uint32_t end_idx, uint32_t end_data) +void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas) { XiveEND end; uint8_t priority; @@ -1675,6 +1681,10 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk, XiveNVT nvt; bool found; + uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w); + uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w); + uint32_t end_data = xive_get_field64(EAS_END_DATA, eas->w); + /* END cache lookup */ if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) { qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No END %x/%x\n", end_blk, @@ -1817,10 +1827,7 @@ do_escalation: /* * The END trigger becomes an Escalation trigger */ - xive_router_end_notify(xrtr, - xive_get_field32(END_W4_ESC_END_BLOCK, end.w4), - xive_get_field32(END_W4_ESC_END_INDEX, end.w4), - xive_get_field32(END_W5_ESC_END_DATA, end.w5)); + xive_router_end_notify_handler(xrtr, (XiveEAS *) &end.w4); } void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked) @@ -1871,10 +1878,7 @@ void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked) /* * The event trigger becomes an END trigger */ - xive_router_end_notify(xrtr, - xive_get_field64(EAS_END_BLOCK, eas.w), - xive_get_field64(EAS_END_INDEX, eas.w), - xive_get_field64(EAS_END_DATA, eas.w)); + xive_router_end_notify_handler(xrtr, &eas); } static Property xive_router_properties[] = { @@ -1887,12 +1891,16 @@ static void xive_router_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass); + XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass); dc->desc = "XIVE Router Engine"; device_class_set_props(dc, xive_router_properties); /* Parent is SysBusDeviceClass. No need to call its realize hook */ dc->realize = xive_router_realize; xnc->notify = xive_router_notify; + + /* By default, the router handles END triggers locally */ + xrc->end_notify = xive_router_end_notify; } static const TypeInfo xive_router_info = { diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index babb053035..ea0fb68cf0 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -192,6 +192,7 @@ petalogix_ml605_init(MachineState *machine) blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(dev, "cs", i); qdev_realize_and_unref(dev, BUS(spi), &error_fatal); cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); diff --git a/hw/mips/malta.c b/hw/mips/malta.c index f9618fa5f5..16e9c4773f 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -627,7 +627,7 @@ static void bl_setup_gt64120_jump_kernel(void **p, uint64_t run_addr, 10, 10, 11, 11 /* PIIX IRQRC[A:D] */ }; - /* Bus endianess is always reversed */ + /* Bus endianness is always reversed */ #if TARGET_BIG_ENDIAN #define cpu_to_gt32(x) (x) #else diff --git a/hw/net/i82596.c b/hw/net/i82596.c index ab26f8bea1..6defa9d3a1 100644 --- a/hw/net/i82596.c +++ b/hw/net/i82596.c @@ -15,6 +15,7 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" +#include "exec/address-spaces.h" #include "qemu/module.h" #include "trace.h" #include "i82596.h" diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 67793a86f1..d5b6820d1d 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -712,7 +712,7 @@ static int ppce500_prep_device_tree(PPCE500MachineState *machine, p->kernel_base = kernel_base; p->kernel_size = kernel_size; - qemu_register_reset(ppce500_reset_device_tree, p); + qemu_register_reset_nosnapshotload(ppce500_reset_device_tree, p); p->notifier.notify = ppce500_init_notify; qemu_add_machine_init_done_notifier(&p->notifier); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 510ff0eaaf..9acc7adfc9 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -81,6 +81,7 @@ static void ppc_heathrow_reset(void *opaque) { PowerPCCPU *cpu = opaque; + cpu_ppc_tb_reset(&cpu->env); cpu_reset(CPU(cpu)); } diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 075367d94d..bd397cf2b5 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -99,6 +99,7 @@ static void pegasos2_cpu_reset(void *opaque) cpu->env.gpr[1] = 2 * VOF_STACK_SIZE - 0x20; cpu->env.nip = 0x100; } + cpu_ppc_tb_reset(&cpu->env); } static void pegasos2_pci_irq(void *opaque, int n, int level) diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 9b39d527de..8c7afe037f 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -61,6 +61,8 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu) hreg_compute_hflags(env); ppc_maybe_interrupt(env); + cpu_ppc_tb_reset(env); + pcc->intc_reset(pc->chip, cpu); } diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 0e0a3d93c3..aeb116d919 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -32,6 +32,7 @@ #include "qemu/main-loop.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" +#include "sysemu/replay.h" #include "sysemu/runstate.h" #include "kvm_ppc.h" #include "migration/vmstate.h" @@ -58,7 +59,9 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) if (old_pending != env->pending_interrupts) { ppc_maybe_interrupt(env); - kvmppc_set_interrupt(cpu, irq, level); + if (kvm_enabled()) { + kvmppc_set_interrupt(cpu, irq, level); + } } trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts, @@ -482,10 +485,32 @@ void ppce500_set_mpic_proxy(bool enabled) /*****************************************************************************/ /* PowerPC time base and decrementer emulation */ +/* + * Conversion between QEMU_CLOCK_VIRTUAL ns and timebase (TB) ticks: + * TB ticks are arrived at by multiplying tb_freq then dividing by + * ns per second, and rounding down. TB ticks drive all clocks and + * timers in the target machine. + * + * Converting TB intervals to ns for the purpose of setting a + * QEMU_CLOCK_VIRTUAL timer should go the other way, but rounding + * up. Rounding down could cause the timer to fire before the TB + * value has been reached. + */ +static uint64_t ns_to_tb(uint32_t freq, int64_t clock) +{ + return muldiv64(clock, freq, NANOSECONDS_PER_SECOND); +} + +/* virtual clock in TB ticks, not adjusted by TB offset */ +static int64_t tb_to_ns_round_up(uint32_t freq, uint64_t tb) +{ + return muldiv64_round_up(tb, NANOSECONDS_PER_SECOND, freq); +} + uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) { /* TB time in tb periods */ - return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; + return ns_to_tb(tb_env->tb_freq, vmclk) + tb_offset; } uint64_t cpu_ppc_load_tbl (CPUPPCState *env) @@ -497,7 +522,8 @@ uint64_t cpu_ppc_load_tbl (CPUPPCState *env) return env->spr[SPR_TBL]; } - tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + tb_env->tb_offset); trace_ppc_tb_load(tb); return tb; @@ -508,7 +534,8 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + tb_env->tb_offset); trace_ppc_tb_load(tb); return tb >> 32; @@ -526,8 +553,7 @@ uint32_t cpu_ppc_load_tbu (CPUPPCState *env) static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t *tb_offsetp, uint64_t value) { - *tb_offsetp = value - - muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); + *tb_offsetp = value - ns_to_tb(tb_env->tb_freq, vmclk); trace_ppc_tb_store(value, *tb_offsetp); } @@ -565,7 +591,8 @@ uint64_t cpu_ppc_load_atbl (CPUPPCState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + tb_env->atb_offset); trace_ppc_tb_load(tb); return tb; @@ -576,7 +603,8 @@ uint32_t cpu_ppc_load_atbu (CPUPPCState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + tb_env->atb_offset); trace_ppc_tb_load(tb); return tb >> 32; @@ -683,64 +711,77 @@ bool ppc_decr_clear_on_delivery(CPUPPCState *env) return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); } -static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) +static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now, + uint64_t next) { ppc_tb_t *tb_env = env->tb_env; - int64_t decr, diff; + uint64_t n; + int64_t decr; - diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - if (diff >= 0) { - decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); - } else if (tb_env->flags & PPC_TIMER_BOOKE) { + n = ns_to_tb(tb_env->decr_freq, now); + if (next > n && tb_env->flags & PPC_TIMER_BOOKE) { decr = 0; - } else { - decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); + } else { + decr = next - n; } + trace_ppc_decr_load(decr); return decr; } -target_ulong cpu_ppc_load_decr(CPUPPCState *env) +static target_ulong _cpu_ppc_load_decr(CPUPPCState *env, int64_t now) { ppc_tb_t *tb_env = env->tb_env; uint64_t decr; - if (kvm_enabled()) { - return env->spr[SPR_DECR]; - } - - decr = _cpu_ppc_load_decr(env, tb_env->decr_next); + decr = __cpu_ppc_load_decr(env, now, tb_env->decr_next); /* * If large decrementer is enabled then the decrementer is signed extened * to 64 bits, otherwise it is a 32 bit value. */ if (env->spr[SPR_LPCR] & LPCR_LD) { - return decr; + PowerPCCPU *cpu = env_archcpu(env); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + return sextract64(decr, 0, pcc->lrg_decr_bits); } return (uint32_t) decr; } -target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) +target_ulong cpu_ppc_load_decr(CPUPPCState *env) +{ + if (kvm_enabled()) { + return env->spr[SPR_DECR]; + } else { + return _cpu_ppc_load_decr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + } +} + +static target_ulong _cpu_ppc_load_hdecr(CPUPPCState *env, int64_t now) { PowerPCCPU *cpu = env_archcpu(env); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); ppc_tb_t *tb_env = env->tb_env; uint64_t hdecr; - hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); + hdecr = __cpu_ppc_load_decr(env, now, tb_env->hdecr_next); /* * If we have a large decrementer (POWER9 or later) then hdecr is sign * extended to 64 bits, otherwise it is 32 bits. */ if (pcc->lrg_decr_bits > 32) { - return hdecr; + return sextract64(hdecr, 0, pcc->lrg_decr_bits); } return (uint32_t) hdecr; } +target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) +{ + return _cpu_ppc_load_hdecr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); +} + uint64_t cpu_ppc_load_purr (CPUPPCState *env) { ppc_tb_t *tb_env = env->tb_env; @@ -785,7 +826,7 @@ static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); } -static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, +static void __cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, uint64_t *nextp, QEMUTimer *timer, void (*raise_excp)(void *), void (*lower_excp)(PowerPCCPU *), @@ -794,7 +835,7 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, { CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env = env->tb_env; - uint64_t now, next; + uint64_t next; int64_t signed_value; int64_t signed_decr; @@ -806,10 +847,14 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, trace_ppc_decr_store(nr_bits, decr, value); - if (kvm_enabled()) { - /* KVM handles decrementer exceptions, we don't need our own timer */ - return; - } + /* + * Calculate the next decrementer event and set a timer. + * decr_next is in timebase units to keep rounding simple. Note it is + * not adjusted by tb_offset because if TB changes via tb_offset changing, + * decrementer does not change, so not directly comparable with TB. + */ + next = ns_to_tb(tb_env->decr_freq, now) + value; + *nextp = next; /* nextp is in timebase units */ /* * Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt. @@ -832,21 +877,17 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, (*lower_excp)(cpu); } - /* Calculate the next timer event */ - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); - *nextp = next; - /* Adjust timer */ - timer_mod(timer, next); + timer_mod(timer, tb_to_ns_round_up(tb_env->decr_freq, next)); } -static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr, - target_ulong value, int nr_bits) +static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, + target_ulong decr, target_ulong value, + int nr_bits) { ppc_tb_t *tb_env = cpu->env.tb_env; - __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, + __cpu_ppc_store_decr(cpu, now, &tb_env->decr_next, tb_env->decr_timer, tb_env->decr_timer->cb, &cpu_ppc_decr_lower, tb_env->flags, decr, value, nr_bits); } @@ -855,13 +896,22 @@ void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) { PowerPCCPU *cpu = env_archcpu(env); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + int64_t now; + target_ulong decr; int nr_bits = 32; + if (kvm_enabled()) { + /* KVM handles decrementer exceptions, we don't need our own timer */ + return; + } + if (env->spr[SPR_LPCR] & LPCR_LD) { nr_bits = pcc->lrg_decr_bits; } - _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + decr = _cpu_ppc_load_decr(env, now); + _cpu_ppc_store_decr(cpu, now, decr, value, nr_bits); } static void cpu_ppc_decr_cb(void *opaque) @@ -871,14 +921,15 @@ static void cpu_ppc_decr_cb(void *opaque) cpu_ppc_decr_excp(cpu); } -static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr, - target_ulong value, int nr_bits) +static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, int64_t now, + target_ulong hdecr, target_ulong value, + int nr_bits) { ppc_tb_t *tb_env = cpu->env.tb_env; if (tb_env->hdecr_timer != NULL) { /* HDECR (Book3S 64bit) is edge-based, not level like DECR */ - __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, + __cpu_ppc_store_decr(cpu, now, &tb_env->hdecr_next, tb_env->hdecr_timer, tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, PPC_DECR_UNDERFLOW_TRIGGERED, hdecr, value, nr_bits); @@ -889,9 +940,12 @@ void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) { PowerPCCPU *cpu = env_archcpu(env); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + int64_t now; + target_ulong hdecr; - _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, - pcc->lrg_decr_bits); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + hdecr = _cpu_ppc_load_hdecr(env, now); + _cpu_ppc_store_hdecr(cpu, now, hdecr, value, pcc->lrg_decr_bits); } static void cpu_ppc_hdecr_cb(void *opaque) @@ -901,29 +955,16 @@ static void cpu_ppc_hdecr_cb(void *opaque) cpu_ppc_hdecr_excp(cpu); } -void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) +static void _cpu_ppc_store_purr(CPUPPCState *env, int64_t now, uint64_t value) { ppc_tb_t *tb_env = env->tb_env; - cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), - &tb_env->purr_offset, value); + cpu_ppc_store_tb(tb_env, now, &tb_env->purr_offset, value); } -static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) +void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) { - CPUPPCState *env = opaque; - PowerPCCPU *cpu = env_archcpu(env); - ppc_tb_t *tb_env = env->tb_env; - - tb_env->tb_freq = freq; - tb_env->decr_freq = freq; - /* There is a bug in Linux 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee at startup, - * it's not ready to handle it... - */ - _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); - _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); - cpu_ppc_store_purr(env, 0x0000000000000000ULL); + _cpu_ppc_store_purr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), value); } static void timebase_save(PPCTimebase *tb) @@ -936,8 +977,14 @@ static void timebase_save(PPCTimebase *tb) return; } - /* not used anymore, we keep it for compatibility */ - tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); + if (replay_mode == REPLAY_MODE_NONE) { + /* not used anymore, we keep it for compatibility */ + tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); + } else { + /* simpler for record-replay to avoid this event, compat not needed */ + tb->time_of_the_day_ns = 0; + } + /* * tb_offset is only expected to be changed by QEMU so * there is no need to update it from KVM here @@ -1027,7 +1074,7 @@ const VMStateDescription vmstate_ppc_timebase = { }; /* Set up (once) timebase frequency (in Hz) */ -clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) +void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq) { PowerPCCPU *cpu = env_archcpu(env); ppc_tb_t *tb_env; @@ -1040,16 +1087,41 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; } /* Create new timer */ - tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); + tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + &cpu_ppc_decr_cb, cpu); if (env->has_hv_mode && !cpu->vhyp) { - tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, - cpu); + tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + &cpu_ppc_hdecr_cb, cpu); } else { tb_env->hdecr_timer = NULL; } - cpu_ppc_set_tb_clk(env, freq); - return &cpu_ppc_set_tb_clk; + tb_env->tb_freq = freq; + tb_env->decr_freq = freq; +} + +void cpu_ppc_tb_reset(CPUPPCState *env) +{ + PowerPCCPU *cpu = env_archcpu(env); + ppc_tb_t *tb_env = env->tb_env; + + timer_del(tb_env->decr_timer); + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); + tb_env->decr_next = 0; + if (tb_env->hdecr_timer != NULL) { + timer_del(tb_env->hdecr_timer); + ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); + tb_env->hdecr_next = 0; + } + + /* + * There is a bug in Linux 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee at startup, + * it's not ready to handle it... + */ + cpu_ppc_store_decr(env, -1); + cpu_ppc_store_hdecr(env, -1); + cpu_ppc_store_purr(env, 0x0000000000000000ULL); } void cpu_ppc_tb_free(CPUPPCState *env) @@ -1125,9 +1197,7 @@ static void cpu_4xx_fit_cb (void *opaque) /* Cannot occur, but makes gcc happy */ return; } - next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); - if (next == now) - next++; + next = now + tb_to_ns_round_up(tb_env->tb_freq, next); timer_mod(ppc40x_timer->fit_timer, next); env->spr[SPR_40x_TSR] |= 1 << 26; if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { @@ -1153,14 +1223,15 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) } else { trace_ppc4xx_pit_start(ppc40x_timer->pit_reload); now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - next = now + muldiv64(ppc40x_timer->pit_reload, - NANOSECONDS_PER_SECOND, tb_env->decr_freq); - if (is_excp) - next += tb_env->decr_next - now; - if (next == now) - next++; + + if (is_excp) { + tb_env->decr_next += ppc40x_timer->pit_reload; + } else { + tb_env->decr_next = ns_to_tb(tb_env->decr_freq, now) + + ppc40x_timer->pit_reload; + } + next = tb_to_ns_round_up(tb_env->decr_freq, tb_env->decr_next); timer_mod(tb_env->decr_timer, next); - tb_env->decr_next = next; } } @@ -1213,9 +1284,7 @@ static void cpu_4xx_wdt_cb (void *opaque) /* Cannot occur, but makes gcc happy */ return; } - next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); - if (next == now) - next++; + next = now + tb_to_ns_round_up(tb_env->decr_freq, next); trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { case 0x0: @@ -1465,5 +1534,7 @@ void ppc_irq_reset(PowerPCCPU *cpu) CPUPPCState *env = &cpu->env; env->irq_input_state = 0; - kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); + if (kvm_enabled()) { + kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); + } } diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index d9231c7317..f6fd35fcb9 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -67,6 +67,7 @@ static void ppc_prep_reset(void *opaque) PowerPCCPU *cpu = opaque; cpu_reset(CPU(cpu)); + cpu_ppc_tb_reset(&cpu->env); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 07e91e3800..f7cc6a890f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1022,7 +1022,6 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) { MachineState *machine = MACHINE(spapr); SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); - uint8_t rng_seed[32]; int chosen; _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen")); @@ -1100,8 +1099,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) spapr_dt_ov5_platform_support(spapr, fdt, chosen); } - qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); - _FDT(fdt_setprop(fdt, chosen, "rng-seed", rng_seed, sizeof(rng_seed))); + _FDT(fdt_setprop(fdt, chosen, "rng-seed", spapr->fdt_rng_seed, 32)); _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5")); } @@ -1322,6 +1320,22 @@ void spapr_set_all_lpcrs(target_ulong value, target_ulong mask) } } +/* May be used when the machine is not running */ +void spapr_init_all_lpcrs(target_ulong value, target_ulong mask) +{ + CPUState *cs; + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + target_ulong lpcr; + + lpcr = env->spr[SPR_LPCR]; + lpcr &= ~(LPCR_HR | LPCR_UPRT); + ppc_store_lpcr(cpu, lpcr); + } +} + + static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry) { @@ -1583,7 +1597,7 @@ int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp) } /* We're setting up a hash table, so that means we're not radix */ spapr->patb_entry = 0; - spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT); + spapr_init_all_lpcrs(0, LPCR_HR | LPCR_UPRT); return 0; } @@ -1638,6 +1652,14 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason) void *fdt; int rc; + if (reason != SHUTDOWN_CAUSE_SNAPSHOT_LOAD) { + /* + * Record-replay snapshot load must not consume random, this was + * already replayed from initial machine reset. + */ + qemu_guest_getrandom_nofail(spapr->fdt_rng_seed, 32); + } + pef_kvm_reset(machine->cgs, &error_fatal); spapr_caps_apply(spapr); @@ -1661,7 +1683,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason) spapr_ovec_cleanup(spapr->ov5_cas); spapr->ov5_cas = spapr_ovec_new(); - ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); + ppc_init_compat_all(spapr->max_compat_pvr, &error_fatal); /* * This is fixing some of the default configuration of the XIVE diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index b482d9754a..91fae56573 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -74,6 +74,8 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu) kvm_check_mmu(cpu, &error_fatal); + cpu_ppc_tb_reset(env); + spapr_irq_cpu_intc_reset(spapr, cpu); } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 9b1f225d4a..b7dc388f2f 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -3,6 +3,7 @@ #include "qapi/error.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" +#include "sysemu/tcg.h" #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" @@ -789,6 +790,54 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, SpaprMachineState *spapr, return H_SUCCESS; } +static target_ulong h_set_mode_resource_set_ciabr(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong mflags, + target_ulong value1, + target_ulong value2) +{ + CPUPPCState *env = &cpu->env; + + assert(tcg_enabled()); /* KVM will have handled this */ + + if (mflags) { + return H_UNSUPPORTED_FLAG; + } + if (value2) { + return H_P4; + } + if ((value1 & PPC_BITMASK(62, 63)) == 0x3) { + return H_P3; + } + + ppc_store_ciabr(env, value1); + + return H_SUCCESS; +} + +static target_ulong h_set_mode_resource_set_dawr0(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong mflags, + target_ulong value1, + target_ulong value2) +{ + CPUPPCState *env = &cpu->env; + + assert(tcg_enabled()); /* KVM will have handled this */ + + if (mflags) { + return H_UNSUPPORTED_FLAG; + } + if (value2 & PPC_BIT(61)) { + return H_P4; + } + + ppc_store_dawr0(env, value1); + ppc_store_dawrx0(env, value2); + + return H_SUCCESS; +} + static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong mflags, @@ -858,6 +907,14 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong ret = H_P2; switch (resource) { + case H_SET_MODE_RESOURCE_SET_CIABR: + ret = h_set_mode_resource_set_ciabr(cpu, spapr, args[0], args[2], + args[3]); + break; + case H_SET_MODE_RESOURCE_SET_DAWR0: + ret = h_set_mode_resource_set_dawr0(cpu, spapr, args[0], args[2], + args[3]); + break; case H_SET_MODE_RESOURCE_LE: ret = h_set_mode_resource_le(cpu, spapr, args[0], args[2], args[3]); break; diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c index 18c3f92317..e3b430a81f 100644 --- a/hw/ppc/vof.c +++ b/hw/ppc/vof.c @@ -1024,6 +1024,8 @@ void vof_cleanup(Vof *vof) } vof->claimed = NULL; vof->of_instances = NULL; + vof->of_instance_last = 0; + vof->claimed_base = 0; } void vof_build_dt(void *fdt, Vof *vof) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 35a335b8d0..ec76dce6c9 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -674,9 +674,8 @@ static void sifive_u_machine_init(MachineState *machine) dinfo = drive_get(IF_SD, 0, 0); blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; - card_dev = qdev_new(TYPE_SD_CARD); + card_dev = qdev_new(TYPE_SD_CARD_SPI); qdev_prop_set_drive_err(card_dev, "drive", blk, &error_fatal); - qdev_prop_set_bit(card_dev, "spi", true); qdev_realize_and_unref(card_dev, qdev_get_child_bus(sd_dev, "sd-bus"), &error_fatal); diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 77a717d355..4823befdef 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -87,6 +87,14 @@ enum SDCardStates { sd_disconnect_state, }; +typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req); + +typedef struct SDProto { + const char *name; + sd_cmd_handler cmd[SDMMC_CMD_MAX]; + sd_cmd_handler acmd[SDMMC_CMD_MAX]; +} SDProto; + struct SDState { DeviceState parent_obj; @@ -107,7 +115,6 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; - bool spi; /* Runtime changeables */ @@ -137,7 +144,6 @@ struct SDState { qemu_irq readonly_cb; qemu_irq inserted_cb; QEMUTimer *ocr_power_timer; - const char *proto_name; bool enable; uint8_t dat_lines; bool cmd_line; @@ -145,6 +151,33 @@ struct SDState { static void sd_realize(DeviceState *dev, Error **errp); +static const struct SDProto *sd_proto(SDState *sd) +{ + SDCardClass *sc = SD_CARD_GET_CLASS(sd); + + return sc->proto; +} + +static const SDProto sd_proto_spi; + +static bool sd_is_spi(SDState *sd) +{ + return sd_proto(sd) == &sd_proto_spi; +} + +static const char *sd_version_str(enum SDPhySpecificationVersion version) +{ + static const char *sdphy_version[] = { + [SD_PHY_SPECv1_10_VERS] = "v1.10", + [SD_PHY_SPECv2_00_VERS] = "v2.00", + [SD_PHY_SPECv3_01_VERS] = "v3.01", + }; + if (version >= ARRAY_SIZE(sdphy_version)) { + return "unsupported version"; + } + return sdphy_version[version]; +} + static const char *sd_state_name(enum SDCardStates state) { static const char *state_name[] = { @@ -309,7 +342,7 @@ static void sd_set_ocr(SDState *sd) /* All voltages OK */ sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; - if (sd->spi) { + if (sd_is_spi(sd)) { /* * We don't need to emulate power up sequence in SPI-mode. * Thus, the card's power up status bit should be set to 1 when reset. @@ -714,13 +747,12 @@ SDState *sd_init(BlockBackend *blk, bool is_spi) SDState *sd; Error *err = NULL; - obj = object_new(TYPE_SD_CARD); + obj = object_new(is_spi ? TYPE_SD_CARD_SPI : TYPE_SD_CARD); dev = DEVICE(obj); if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) { error_reportf_err(err, "sd_init failed: "); return NULL; } - qdev_prop_set_bit(dev, "spi", is_spi); /* * Realizing the device properly would put it into the QOM @@ -966,6 +998,106 @@ static bool address_in_range(SDState *sd, const char *desc, return true; } +static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req) +{ + qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong state: %s (spec %s)\n", + sd_proto(sd)->name, req.cmd, sd_state_name(sd->state), + sd_version_str(sd->spec_version)); + + return sd_illegal; +} + +static sd_rsp_type_t sd_cmd_illegal(SDState *sd, SDRequest req) +{ + qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown CMD%i for spec %s\n", + sd_proto(sd)->name, req.cmd, + sd_version_str(sd->spec_version)); + + return sd_illegal; +} + +/* Commands that are recognised but not yet implemented. */ +static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) +{ + qemu_log_mask(LOG_UNIMP, "%s: CMD%i not implemented\n", + sd_proto(sd)->name, req.cmd); + + return sd_illegal; +} + +static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) +{ + if (sd->state != sd_inactive_state) { + sd->state = sd_idle_state; + sd_reset(DEVICE(sd)); + } + + return sd_is_spi(sd) ? sd_r1 : sd_r0; +} + +static sd_rsp_type_t sd_cmd_SEND_OP_CMD(SDState *sd, SDRequest req) +{ + sd->state = sd_transfer_state; + + return sd_r1; +} + +static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) +{ + if (sd->state != sd_ready_state) { + return sd_invalid_state_for_cmd(sd, req); + } + + sd->state = sd_identification_state; + + return sd_r2_i; +} + +static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) +{ + switch (sd->state) { + case sd_identification_state: + case sd_standby_state: + sd->state = sd_standby_state; + sd_set_rca(sd); + return sd_r6; + + default: + return sd_invalid_state_for_cmd(sd, req); + } +} + +static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) +{ + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + return sd_cmd_illegal(sd, req); + } + + if (sd->state != sd_transfer_state) { + return sd_invalid_state_for_cmd(sd, req); + } + + sd->state = sd_sendingdata_state; + sd->data_offset = 0; + + return sd_r1; +} + +static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) +{ + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + return sd_cmd_illegal(sd, req); + } + + if (sd->state != sd_transfer_state) { + return sd_invalid_state_for_cmd(sd, req); + } + + sd->multi_blk_cnt = req.arg; + + return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint32_t rca = 0x0000; @@ -975,7 +1107,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) * However there is no ACMD55, so we want to trace this particular case. */ if (req.cmd != 55 || sd->expecting_acmd) { - trace_sdcard_normal_command(sd->proto_name, + trace_sdcard_normal_command(sd_proto(sd)->name, sd_cmd_name(req.cmd), req.cmd, req.arg, sd_state_name(sd->state)); } @@ -999,58 +1131,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_illegal; } + if (sd_proto(sd)->cmd[req.cmd]) { + return sd_proto(sd)->cmd[req.cmd](sd, req); + } + switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ - case 0: /* CMD0: GO_IDLE_STATE */ - switch (sd->state) { - case sd_inactive_state: - return sd->spi ? sd_r1 : sd_r0; - - default: - sd->state = sd_idle_state; - sd_reset(DEVICE(sd)); - return sd->spi ? sd_r1 : sd_r0; - } - break; - - case 1: /* CMD1: SEND_OP_CMD */ - if (!sd->spi) - goto bad_cmd; - - sd->state = sd_transfer_state; - return sd_r1; - - case 2: /* CMD2: ALL_SEND_CID */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_ready_state: - sd->state = sd_identification_state; - return sd_r2_i; - - default: - break; - } - break; - - case 3: /* CMD3: SEND_RELATIVE_ADDR */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_identification_state: - case sd_standby_state: - sd->state = sd_standby_state; - sd_set_rca(sd); - return sd_r6; - - default: - break; - } - break; - case 4: /* CMD4: SEND_DSR */ - if (sd->spi) - goto bad_cmd; switch (sd->state) { case sd_standby_state: break; @@ -1060,9 +1147,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; - case 5: /* CMD5: reserved for SDIO cards */ - return sd_illegal; - case 6: /* CMD6: SWITCH_FUNCTION */ switch (sd->mode) { case sd_data_transfer_mode: @@ -1078,8 +1162,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 7: /* CMD7: SELECT/DESELECT_CARD */ - if (sd->spi) - goto bad_cmd; switch (sd->state) { case sd_standby_state: if (sd->rca != rca) @@ -1126,7 +1208,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* No response if not exactly one VHS bit is set. */ if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { - return sd->spi ? sd_r7 : sd_r0; + return sd_is_spi(sd) ? sd_r7 : sd_r0; } /* Accept. */ @@ -1142,8 +1224,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r2_s; case sd_transfer_state: - if (!sd->spi) + if (!sd_is_spi(sd)) { break; + } sd->state = sd_sendingdata_state; memcpy(sd->data, sd->csd, 16); sd->data_start = addr; @@ -1164,8 +1247,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r2_i; case sd_transfer_state: - if (!sd->spi) + if (!sd_is_spi(sd)) { break; + } sd->state = sd_sendingdata_state; memcpy(sd->data, sd->cid, 16); sd->data_start = addr; @@ -1197,7 +1281,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 13: /* CMD13: SEND_STATUS */ switch (sd->mode) { case sd_data_transfer_mode: - if (!sd->spi && sd->rca != rca) { + if (!sd_is_spi(sd) && sd->rca != rca) { return sd_r0; } @@ -1209,8 +1293,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 15: /* CMD15: GO_INACTIVE_STATE */ - if (sd->spi) - goto bad_cmd; switch (sd->mode) { case sd_data_transfer_mode: if (sd->rca != rca) @@ -1224,7 +1306,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; - /* Block read commands (Classs 2) */ + /* Block read commands (Class 2) */ case 16: /* CMD16: SET_BLOCKLEN */ switch (sd->state) { case sd_transfer_state: @@ -1261,31 +1343,6 @@ 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; - return sd_r1; - } - 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; - return sd_r1; - - default: - break; - } - break; - /* Block write commands (Class 4) */ case 24: /* CMD24: WRITE_SINGLE_BLOCK */ case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ @@ -1317,8 +1374,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 26: /* CMD26: PROGRAM_CID */ - if (sd->spi) - goto bad_cmd; switch (sd->state) { case sd_transfer_state: sd->state = sd_receivingdata_state; @@ -1468,15 +1523,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; - case 52 ... 54: - /* CMD52, CMD53, CMD54: reserved for SDIO cards - * (see the SDIO Simplified Specification V2.0) - * Handle as illegal command but do not complain - * on stderr, as some OSes may use these in their - * probing for presence of an SDIO card. - */ - return sd_illegal; - /* Application specific commands (Class 8) */ case 55: /* CMD55: APP_CMD */ switch (sd->state) { @@ -1492,7 +1538,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) default: break; } - if (!sd->spi) { + if (!sd_is_spi(sd)) { if (sd->rca != rca) { return sd_r0; } @@ -1517,39 +1563,32 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 58: /* CMD58: READ_OCR (SPI) */ - if (!sd->spi) { - goto bad_cmd; - } return sd_r3; case 59: /* CMD59: CRC_ON_OFF (SPI) */ - if (!sd->spi) { - goto bad_cmd; - } return sd_r1; default: - bad_cmd: qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd); return sd_illegal; } - qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state: %s\n", - req.cmd, sd_state_name(sd->state)); - return sd_illegal; + return sd_invalid_state_for_cmd(sd, req); } static sd_rsp_type_t sd_app_command(SDState *sd, SDRequest req) { - trace_sdcard_app_command(sd->proto_name, sd_acmd_name(req.cmd), + trace_sdcard_app_command(sd_proto(sd)->name, sd_acmd_name(req.cmd), req.cmd, req.arg, sd_state_name(sd->state)); sd->card_status |= APP_CMD; + + if (sd_proto(sd)->acmd[req.cmd]) { + return sd_proto(sd)->acmd[req.cmd](sd, req); + } + switch (req.cmd) { case 6: /* ACMD6: SET_BUS_WIDTH */ - if (sd->spi) { - goto unimplemented_spi_cmd; - } switch (sd->state) { case sd_transfer_state: sd->sd_status[0] &= 0x3f; @@ -1600,11 +1639,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, break; case 41: /* ACMD41: SD_APP_OP_COND */ - if (sd->spi) { - /* SEND_OP_CMD */ - sd->state = sd_transfer_state; - return sd_r1; - } if (sd->state != sd_idle_state) { break; } @@ -1680,12 +1714,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, default: /* Fall back to standard commands. */ return sd_normal_command(sd, req); - - unimplemented_spi_cmd: - /* Commands that are recognised but not yet implemented in SPI mode. */ - qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n", - req.cmd); - return sd_illegal; } qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd); @@ -1836,7 +1864,7 @@ void sd_write_byte(SDState *sd, uint8_t value) if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) return; - trace_sdcard_write_data(sd->proto_name, + trace_sdcard_write_data(sd_proto(sd)->name, sd_acmd_name(sd->current_cmd), sd->current_cmd, value); switch (sd->current_cmd) { @@ -1992,7 +2020,7 @@ uint8_t sd_read_byte(SDState *sd) io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; - trace_sdcard_read_data(sd->proto_name, + trace_sdcard_read_data(sd_proto(sd)->name, sd_acmd_name(sd->current_cmd), sd->current_cmd, io_len); switch (sd->current_cmd) { @@ -2111,6 +2139,40 @@ void sd_enable(SDState *sd, bool enable) sd->enable = enable; } +static const SDProto sd_proto_spi = { + .name = "SPI", + .cmd = { + [0] = sd_cmd_GO_IDLE_STATE, + [1] = sd_cmd_SEND_OP_CMD, + [2 ... 4] = sd_cmd_illegal, + [5] = sd_cmd_illegal, + [7] = sd_cmd_illegal, + [15] = sd_cmd_illegal, + [26] = sd_cmd_illegal, + [52 ... 54] = sd_cmd_illegal, + }, + .acmd = { + [6] = sd_cmd_unimplemented, + [41] = sd_cmd_SEND_OP_CMD, + }, +}; + +static const SDProto sd_proto_sd = { + .name = "SD", + .cmd = { + [0] = sd_cmd_GO_IDLE_STATE, + [1] = sd_cmd_illegal, + [2] = sd_cmd_ALL_SEND_CID, + [3] = sd_cmd_SEND_RELATIVE_ADDR, + [5] = sd_cmd_illegal, + [19] = sd_cmd_SEND_TUNING_BLOCK, + [23] = sd_cmd_SET_BLOCK_COUNT, + [52 ... 54] = sd_cmd_illegal, + [58] = sd_cmd_illegal, + [59] = sd_cmd_illegal, + }, +}; + static void sd_instance_init(Object *obj) { SDState *sd = SD_CARD(obj); @@ -2131,8 +2193,6 @@ static void sd_realize(DeviceState *dev, Error **errp) SDState *sd = SD_CARD(dev); int ret; - sd->proto_name = sd->spi ? "SPI" : "SD"; - switch (sd->spec_version) { case SD_PHY_SPECv1_10_VERS ... SD_PHY_SPECv3_01_VERS: @@ -2189,7 +2249,6 @@ static Property sd_properties[] = { * whether card should be in SSI or MMC/SD mode. It is also up to the * board to ensure that ssi transfers only occur when the chip select * is asserted. */ - DEFINE_PROP_BOOL("spi", SDState, spi, false), DEFINE_PROP_END_OF_LIST() }; @@ -2216,6 +2275,7 @@ static void sd_class_init(ObjectClass *klass, void *data) sc->enable = sd_enable; sc->get_inserted = sd_get_inserted; sc->get_readonly = sd_get_readonly; + sc->proto = &sd_proto_sd; } static const TypeInfo sd_info = { @@ -2228,9 +2288,31 @@ static const TypeInfo sd_info = { .instance_finalize = sd_instance_finalize, }; +/* + * 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 + * board to ensure that ssi transfers only occur when the chip select + * is asserted. + */ +static void sd_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SDCardClass *sc = SD_CARD_CLASS(klass); + + dc->desc = "SD SPI"; + sc->proto = &sd_proto_spi; +} + +static const TypeInfo sd_spi_info = { + .name = TYPE_SD_CARD_SPI, + .parent = TYPE_SD_CARD, + .class_init = sd_spi_class_init, +}; + static void sd_register_types(void) { type_register_static(&sd_info); + type_register_static(&sd_spi_info); } type_init(sd_register_types) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 362c2c86aa..5564765a9b 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1811,7 +1811,7 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) * on i.MX, but since it is not used by QEMU we do not care. * * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...) - * here becuase it will result in a call to + * here because it will result in a call to * sdhci_send_command(s) which we don't want. * */ diff --git a/hw/sd/sdmmc-internal.c b/hw/sd/sdmmc-internal.c index 2053def3f1..8648a7808d 100644 --- a/hw/sd/sdmmc-internal.c +++ b/hw/sd/sdmmc-internal.c @@ -14,7 +14,7 @@ const char *sd_cmd_name(uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [0] = "GO_IDLE_STATE", + [0] = "GO_IDLE_STATE", [1] = "SEND_OP_CMD", [2] = "ALL_SEND_CID", [3] = "SEND_RELATIVE_ADDR", [4] = "SET_DSR", [5] = "IO_SEND_OP_COND", [6] = "SWITCH_FUNC", [7] = "SELECT/DESELECT_CARD", diff --git a/hw/sensor/isl_pmbus_vr.c b/hw/sensor/isl_pmbus_vr.c index eb344dd5a9..e51269f6b8 100644 --- a/hw/sensor/isl_pmbus_vr.c +++ b/hw/sensor/isl_pmbus_vr.c @@ -101,7 +101,7 @@ static void isl_pmbus_vr_exit_reset(Object *obj) } } -/* The raa228000 uses different direct mode coefficents from most isl devices */ +/* The raa228000 uses different direct mode coefficients from most isl devices */ static void raa228000_exit_reset(Object *obj) { PMBusDevice *pmdev = PMBUS_DEVICE(obj); diff --git a/hw/sensor/max34451.c b/hw/sensor/max34451.c index a91d8bd487..9db52ef677 100644 --- a/hw/sensor/max34451.c +++ b/hw/sensor/max34451.c @@ -734,7 +734,7 @@ static void max34451_init(Object *obj) /* * get and set the temperature of the internal temperature sensor in - * centidegrees Celcius i.e.: 2500 -> 25.00 C, max is 327.67 C + * centidegrees Celsius i.e.: 2500 -> 25.00 C, max is 327.67 C */ for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) { object_property_add(obj, "temperature[*]", "uint16", diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 7281169322..2a4001b774 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -692,6 +692,14 @@ static void aspeed_smc_reset(DeviceState *d) memset(s->regs, 0, sizeof s->regs); } + for (i = 0; i < asc->cs_num_max; i++) { + DeviceState *dev = ssi_get_cs(s->spi, i); + if (dev) { + qemu_irq cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); + qdev_connect_gpio_out_named(DEVICE(s), "cs", i, cs_line); + } + } + /* Unselect all peripherals */ for (i = 0; i < asc->cs_num_max; ++i) { s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE; diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index d54a109bee..1f3e540ab8 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -13,6 +13,7 @@ */ #include "qemu/osdep.h" +#include "hw/qdev-properties.h" #include "hw/ssi/ssi.h" #include "migration/vmstate.h" #include "qemu/module.h" @@ -26,10 +27,46 @@ struct SSIBus { #define TYPE_SSI_BUS "SSI" OBJECT_DECLARE_SIMPLE_TYPE(SSIBus, SSI_BUS) +DeviceState *ssi_get_cs(SSIBus *bus, uint8_t cs_index) +{ + BusState *b = BUS(bus); + BusChild *kid; + + QTAILQ_FOREACH(kid, &b->children, sibling) { + SSIPeripheral *kid_ssi = SSI_PERIPHERAL(kid->child); + if (kid_ssi->cs_index == cs_index) { + return kid->child; + } + } + + return NULL; +} + +static bool ssi_bus_check_address(BusState *b, DeviceState *dev, Error **errp) +{ + SSIPeripheral *s = SSI_PERIPHERAL(dev); + + if (ssi_get_cs(SSI_BUS(b), s->cs_index)) { + error_setg(errp, "CS index '0x%x' in use by a %s device", s->cs_index, + object_get_typename(OBJECT(dev))); + return false; + } + + return true; +} + +static void ssi_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->check_address = ssi_bus_check_address; +} + static const TypeInfo ssi_bus_info = { .name = TYPE_SSI_BUS, .parent = TYPE_BUS, .instance_size = sizeof(SSIBus), + .class_init = ssi_bus_class_init, }; static void ssi_cs_default(void *opaque, int n, int level) @@ -71,6 +108,11 @@ static void ssi_peripheral_realize(DeviceState *dev, Error **errp) ssc->realize(s, errp); } +static Property ssi_peripheral_properties[] = { + DEFINE_PROP_UINT8("cs", SSIPeripheral, cs_index, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void ssi_peripheral_class_init(ObjectClass *klass, void *data) { SSIPeripheralClass *ssc = SSI_PERIPHERAL_CLASS(klass); @@ -81,6 +123,7 @@ static void ssi_peripheral_class_init(ObjectClass *klass, void *data) if (!ssc->transfer_raw) { ssc->transfer_raw = ssi_transfer_raw_default; } + device_class_set_props(dc, ssi_peripheral_properties); } static const TypeInfo ssi_peripheral_info = { diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index c328660075..3ee9c73b87 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -518,7 +518,7 @@ static void emulated_realize(CCIDCardState *base, Error **errp) goto out2; } - /* TODO: a passthru backened that works on local machine. third card type?*/ + /* TODO: a passthru backend that works on local machine. third card type?*/ if (card->backend == BACKEND_CERTIFICATES) { if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) { ret = emulated_initialize_vcard_from_certificates(card); diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index c930c60921..19b4534c20 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1464,7 +1464,7 @@ static int ehci_process_itd(EHCIState *ehci, usb_handle_packet(dev, &ehci->ipacket); usb_packet_unmap(&ehci->ipacket, &ehci->isgl); } else { - DPRINTF("ISOCH: attempt to addess non-iso endpoint\n"); + DPRINTF("ISOCH: attempt to address non-iso endpoint\n"); ehci->ipacket.status = USB_RET_NAK; ehci->ipacket.actual_length = 0; } @@ -1513,7 +1513,7 @@ static int ehci_process_itd(EHCIState *ehci, /* This state is the entry point for asynchronous schedule - * processing. Entry here consitutes a EHCI start event state (4.8.5) + * processing. Entry here constitutes a EHCI start event state (4.8.5) */ static int ehci_state_waitlisthead(EHCIState *ehci, int async) { @@ -2458,7 +2458,7 @@ static void usb_ehci_vm_state_change(void *opaque, bool running, RunState state) /* * The schedule rebuilt from guest memory could cause the migration dest * to miss a QH unlink, and fail to cancel packets, since the unlinked QH - * will never have existed on the destination. Therefor we must flush the + * will never have existed on the destination. Therefore we must flush the * async schedule on savevm to catch any not yet noticed unlinks. */ if (state == RUN_STATE_SAVE_VM) { diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index cc5cde6983..7ff1b65ced 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1355,7 +1355,7 @@ static uint32_t ohci_get_frame_remaining(OHCIState *ohci) if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) { return ohci->frt << 31; } - /* Being in USB operational state guarnatees sof_time was set already. */ + /* Being in USB operational state guarantees sof_time was set already. */ tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time; if (tks < 0) { tks = 0; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index b89b618ec2..324177ad5d 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -2434,7 +2434,6 @@ static void xhci_detach_slot(XHCIState *xhci, USBPort *uport) static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) { dma_addr_t ctx; - uint8_t bw_ctx[xhci->numports+1]; DPRINTF("xhci_get_port_bandwidth()\n"); @@ -2442,11 +2441,10 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) DPRINTF("xhci: bandwidth context at "DMA_ADDR_FMT"\n", ctx); - /* TODO: actually implement real values here */ - bw_ctx[0] = 0; - memset(&bw_ctx[1], 80, xhci->numports); /* 80% */ - if (dma_memory_write(xhci->as, ctx, bw_ctx, sizeof(bw_ctx), - MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + /* TODO: actually implement real values here. This is 80% for all ports. */ + if (stb_dma(xhci->as, ctx, 0, MEMTXATTRS_UNSPECIFIED) != MEMTX_OK || + dma_memory_set(xhci->as, ctx + 1, 80, xhci->numports, + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory write failed!\n", __func__); return CC_TRB_ERROR; diff --git a/hw/usb/quirks.h b/hw/usb/quirks.h index c3e595f40b..94b2c95341 100644 --- a/hw/usb/quirks.h +++ b/hw/usb/quirks.h @@ -67,7 +67,7 @@ static const struct usb_device_id usbredir_raw_serial_ids[] = { { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */ - { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */ + { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME built-in converter */ { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 39fbaaab16..c9893df867 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -278,7 +278,7 @@ static gboolean usbredir_write_unblocked(void *do_not_use, GIOCondition cond, dev->watch = 0; usbredirparser_do_write(dev->parser); - return FALSE; + return G_SOURCE_REMOVE; } static int usbredir_write(void *priv, uint8_t *data, int count) @@ -471,7 +471,7 @@ static int bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep); dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1; } - /* Since we're interupting the stream anyways, drop enough packets to get + /* Since we're interrupting the stream anyways, drop enough packets to get back to our target buffer size */ if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) { if (dev->endpoint[EP2I(ep)].bufpq_size > diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 6bb9655c8d..ed7dc210d3 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -248,7 +248,7 @@ usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret # dev-hub.c usb_hub_reset(int addr) "dev %d" -usb_hub_control(int addr, int request, int value, int index, int length) "dev %d, req 0x%x, value %d, index %d, langth %d" +usb_hub_control(int addr, int request, int value, int index, int length) "dev %d, req 0x%x, value %d, index %d, length %d" usb_hub_get_port_status(int addr, int nr, int status, int changed) "dev %d, port %d, status 0x%x, changed 0x%x" usb_hub_set_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s" usb_hub_clear_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s" diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 38ee660a30..09ec326aea 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -451,7 +451,7 @@ static int usbback_check_and_submit(struct usbback_req *usbback_req) wValue = le16_to_cpu(ctrl->wValue); /* - * When the device is first connected or resetted, USB device has no + * When the device is first connected or reset, USB device has no * address. In this initial state, following requests are sent to device * address (#0), * diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index b20744f7c7..31bcfdf705 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -340,11 +340,9 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar) return s->msix && s->msix->bar_index == bar; } -extern void *pci_assign_dev_load_option_rom(PCIDevice *dev, - int *size, - unsigned int domain, - unsigned int bus, unsigned int slot, - unsigned int function); +void *pci_assign_dev_load_option_rom(PCIDevice *dev, int *size, + unsigned int domain, unsigned int bus, + unsigned int slot, unsigned int function); static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev) { return (xen_igd_gfx_pt_enabled() diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 6c9447565d..8cef88c61b 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -30,6 +30,7 @@ #include "hw/irq.h" #include "qemu/log.h" #include "qemu/timer.h" +#include "qemu/atomic.h" void check_interrupts(CPUXtensaState *env) { |