diff options
Diffstat (limited to 'hw')
42 files changed, 1078 insertions, 547 deletions
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index bf46f03b7e..d4c3ab758d 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -12,4 +12,4 @@ common-obj-$(CONFIG_NVME_PCI) += nvme.o obj-$(CONFIG_SH4) += tc58128.o obj-$(CONFIG_VIRTIO) += virtio-blk.o -obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/ +obj-$(CONFIG_VIRTIO) += dataplane/ diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 38ad38f49f..45e0c8f6e9 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -18,10 +18,8 @@ #include "hw/block/block.h" #include "sysemu/blockdev.h" #include "hw/virtio/virtio-blk.h" -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE -# include "dataplane/virtio-blk.h" -# include "migration/migration.h" -#endif +#include "dataplane/virtio-blk.h" +#include "migration/migration.h" #include "block/scsi.h" #ifdef __linux__ # include <scsi/sg.h> @@ -435,7 +433,6 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) .num_writes = 0, }; -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start * dataplane here instead of waiting for .set_status(). */ @@ -443,7 +440,6 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) virtio_blk_data_plane_start(s->dataplane); return; } -#endif while ((req = virtio_blk_get_request(s))) { virtio_blk_handle_request(req, &mrb); @@ -500,11 +496,9 @@ static void virtio_blk_reset(VirtIODevice *vdev) { VirtIOBlock *s = VIRTIO_BLK(vdev); -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE if (s->dataplane) { virtio_blk_data_plane_stop(s->dataplane); } -#endif /* * This should cancel pending requests, but can't do nicely until there @@ -594,12 +588,10 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) VirtIOBlock *s = VIRTIO_BLK(vdev); uint32_t features; -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK))) { virtio_blk_data_plane_stop(s->dataplane); } -#endif if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { return; @@ -694,7 +686,6 @@ static const BlockDevOps virtio_block_ops = { .resize_cb = virtio_blk_resize, }; -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE /* Disable dataplane thread during live migration since it does not * update the dirty memory bitmap yet. */ @@ -725,7 +716,6 @@ static void virtio_blk_migration_state_changed(Notifier *notifier, void *data) } } } -#endif /* CONFIG_VIRTIO_BLK_DATA_PLANE */ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) { @@ -762,7 +752,6 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); s->complete_request = virtio_blk_complete_request; -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err); if (err != NULL) { error_propagate(errp, err); @@ -771,7 +760,6 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) } s->migration_state_notifier.notify = virtio_blk_migration_state_changed; add_migration_state_change_notifier(&s->migration_state_notifier); -#endif s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, @@ -789,11 +777,9 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBlock *s = VIRTIO_BLK(dev); -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE remove_migration_state_change_notifier(&s->migration_state_notifier); virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; -#endif qemu_del_vm_change_state_handler(s->change); unregister_savevm(dev, "virtio-blk", s); blockdev_mark_auto_del(s->bs); @@ -818,9 +804,7 @@ static Property virtio_blk_properties[] = { #ifdef __linux__ DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true), #endif -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, blk.data_plane, 0, false), -#endif DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/core/machine.c b/hw/core/machine.c index f0046d6de3..7f3418c5af 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -24,6 +24,7 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); + g_free(ms->accel); ms->accel = g_strdup(value); } @@ -79,6 +80,7 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); + g_free(ms->kernel_filename); ms->kernel_filename = g_strdup(value); } @@ -93,6 +95,7 @@ static void machine_set_initrd(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); + g_free(ms->initrd_filename); ms->initrd_filename = g_strdup(value); } @@ -107,6 +110,7 @@ static void machine_set_append(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); + g_free(ms->kernel_cmdline); ms->kernel_cmdline = g_strdup(value); } @@ -121,6 +125,7 @@ static void machine_set_dtb(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); + g_free(ms->dtb); ms->dtb = g_strdup(value); } @@ -135,6 +140,7 @@ static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); + g_free(ms->dumpdtb); ms->dumpdtb = g_strdup(value); } @@ -176,6 +182,7 @@ static void machine_set_dt_compatible(Object *obj, const char *value, Error **er { MachineState *ms = MACHINE(obj); + g_free(ms->dt_compatible); ms->dt_compatible = g_strdup(value); } @@ -232,6 +239,7 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); + g_free(ms->firmware); ms->firmware = g_strdup(value); } diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index ae0900f651..84caa1d694 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -388,28 +388,12 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) static int qdev_add_one_global(QemuOpts *opts, void *opaque) { GlobalProperty *g; - ObjectClass *oc; g = g_malloc0(sizeof(*g)); g->driver = qemu_opt_get(opts, "driver"); g->property = qemu_opt_get(opts, "property"); g->value = qemu_opt_get(opts, "value"); - oc = object_class_dynamic_cast(object_class_by_name(g->driver), - TYPE_DEVICE); - if (oc) { - DeviceClass *dc = DEVICE_CLASS(oc); - - if (dc->hotpluggable) { - /* If hotpluggable then skip not_used checking. */ - g->not_used = false; - } else { - /* Maybe a typo. */ - g->not_used = true; - } - } else { - /* Maybe a typo. */ - g->not_used = true; - } + g->user_provided = true; qdev_prop_register_global(g); return 0; } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 3d12560f43..66556d3bf9 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -955,19 +955,35 @@ void qdev_prop_register_global_list(GlobalProperty *props) } } -int qdev_prop_check_global(void) +int qdev_prop_check_globals(void) { GlobalProperty *prop; int ret = 0; QTAILQ_FOREACH(prop, &global_props, next) { - if (!prop->not_used) { + ObjectClass *oc; + DeviceClass *dc; + if (prop->used) { + continue; + } + if (!prop->user_provided) { + continue; + } + oc = object_class_by_name(prop->driver); + oc = object_class_dynamic_cast(oc, TYPE_DEVICE); + if (!oc) { + error_report("Warning: global %s.%s has invalid class name", + prop->driver, prop->property); + ret = 1; + continue; + } + dc = DEVICE_CLASS(oc); + if (!dc->hotpluggable && !prop->used) { + error_report("Warning: global %s.%s=%s not used", + prop->driver, prop->property, prop->value); + ret = 1; continue; } - ret = 1; - error_report("Warning: \"-global %s.%s=%s\" not used", - prop->driver, prop->property, prop->value); - } return ret; } @@ -983,7 +999,7 @@ void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, if (strcmp(typename, prop->driver) != 0) { continue; } - prop->not_used = false; + prop->used = true; object_property_parse(OBJECT(dev), prop->value, prop->property, &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/display/tcx.c b/hw/display/tcx.c index b1cd2a93a9..a9f9f66d15 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -33,10 +33,20 @@ #define MAXX 1024 #define MAXY 768 -#define TCX_DAC_NREGS 16 -#define TCX_THC_NREGS_8 0x081c -#define TCX_THC_NREGS_24 0x1000 +#define TCX_DAC_NREGS 16 +#define TCX_THC_NREGS 0x1000 +#define TCX_DHC_NREGS 0x4000 #define TCX_TEC_NREGS 0x1000 +#define TCX_ALT_NREGS 0x8000 +#define TCX_STIP_NREGS 0x800000 +#define TCX_BLIT_NREGS 0x800000 +#define TCX_RSTIP_NREGS 0x800000 +#define TCX_RBLIT_NREGS 0x800000 + +#define TCX_THC_MISC 0x818 +#define TCX_THC_CURSXY 0x8fc +#define TCX_THC_CURSMASK 0x900 +#define TCX_THC_CURSBITS 0x980 #define TYPE_TCX "SUNW,tcx" #define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX) @@ -45,6 +55,7 @@ typedef struct TCXState { SysBusDevice parent_obj; QemuConsole *con; + qemu_irq irq; uint8_t *vram; uint32_t *vram24, *cplane; hwaddr prom_addr; @@ -52,17 +63,30 @@ typedef struct TCXState { MemoryRegion vram_mem; MemoryRegion vram_8bit; MemoryRegion vram_24bit; + MemoryRegion stip; + MemoryRegion blit; MemoryRegion vram_cplane; - MemoryRegion dac; + MemoryRegion rstip; + MemoryRegion rblit; MemoryRegion tec; + MemoryRegion dac; + MemoryRegion thc; + MemoryRegion dhc; + MemoryRegion alt; MemoryRegion thc24; - MemoryRegion thc8; + ram_addr_t vram24_offset, cplane_offset; + uint32_t tmpblit; uint32_t vram_size; - uint32_t palette[256]; - uint8_t r[256], g[256], b[256]; + uint32_t palette[260]; + uint8_t r[260], g[260], b[260]; uint16_t width, height, depth; uint8_t dac_index, dac_state; + uint32_t thcmisc; + uint32_t cursmask[32]; + uint32_t cursbits[32]; + uint16_t cursx; + uint16_t cursy; } TCXState; static void tcx_set_dirty(TCXState *s) @@ -70,10 +94,36 @@ static void tcx_set_dirty(TCXState *s) memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY); } -static void tcx24_set_dirty(TCXState *s) +static inline int tcx24_check_dirty(TCXState *s, ram_addr_t page, + ram_addr_t page24, ram_addr_t cpage) { - memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4); - memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4); + int ret; + + ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, + DIRTY_MEMORY_VGA); + ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, + DIRTY_MEMORY_VGA); + return ret; +} + +static inline void tcx24_reset_dirty(TCXState *ts, ram_addr_t page_min, + ram_addr_t page_max, ram_addr_t page24, + ram_addr_t cpage) +{ + memory_region_reset_dirty(&ts->vram_mem, + page_min, + (page_max - page_min) + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + memory_region_reset_dirty(&ts->vram_mem, + page24 + page_min * 4, + (page_max - page_min) * 4 + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + memory_region_reset_dirty(&ts->vram_mem, + cpage + page_min * 4, + (page_max - page_min) * 4 + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); } static void update_palette_entries(TCXState *s, int start, int end) @@ -102,11 +152,7 @@ static void update_palette_entries(TCXState *s, int start, int end) break; } } - if (s->depth == 24) { - tcx24_set_dirty(s); - } else { - tcx_set_dirty(s); - } + tcx_set_dirty(s); } static void tcx_draw_line32(TCXState *s1, uint8_t *d, @@ -116,7 +162,7 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d, uint8_t val; uint32_t *p = (uint32_t *)d; - for(x = 0; x < width; x++) { + for (x = 0; x < width; x++) { val = *s++; *p++ = s1->palette[val]; } @@ -129,7 +175,7 @@ static void tcx_draw_line16(TCXState *s1, uint8_t *d, uint8_t val; uint16_t *p = (uint16_t *)d; - for(x = 0; x < width; x++) { + for (x = 0; x < width; x++) { val = *s++; *p++ = s1->palette[val]; } @@ -147,6 +193,83 @@ static void tcx_draw_line8(TCXState *s1, uint8_t *d, } } +static void tcx_draw_cursor32(TCXState *s1, uint8_t *d, + int y, int width) +{ + int x, len; + uint32_t mask, bits; + uint32_t *p = (uint32_t *)d; + + y = y - s1->cursy; + mask = s1->cursmask[y]; + bits = s1->cursbits[y]; + len = MIN(width - s1->cursx, 32); + p = &p[s1->cursx]; + for (x = 0; x < len; x++) { + if (mask & 0x80000000) { + if (bits & 0x80000000) { + *p = s1->palette[259]; + } else { + *p = s1->palette[258]; + } + } + p++; + mask <<= 1; + bits <<= 1; + } +} + +static void tcx_draw_cursor16(TCXState *s1, uint8_t *d, + int y, int width) +{ + int x, len; + uint32_t mask, bits; + uint16_t *p = (uint16_t *)d; + + y = y - s1->cursy; + mask = s1->cursmask[y]; + bits = s1->cursbits[y]; + len = MIN(width - s1->cursx, 32); + p = &p[s1->cursx]; + for (x = 0; x < len; x++) { + if (mask & 0x80000000) { + if (bits & 0x80000000) { + *p = s1->palette[259]; + } else { + *p = s1->palette[258]; + } + } + p++; + mask <<= 1; + bits <<= 1; + } +} + +static void tcx_draw_cursor8(TCXState *s1, uint8_t *d, + int y, int width) +{ + int x, len; + uint32_t mask, bits; + + y = y - s1->cursy; + mask = s1->cursmask[y]; + bits = s1->cursbits[y]; + len = MIN(width - s1->cursx, 32); + d = &d[s1->cursx]; + for (x = 0; x < len; x++) { + if (mask & 0x80000000) { + if (bits & 0x80000000) { + *d = s1->palette[259]; + } else { + *d = s1->palette[258]; + } + } + d++; + mask <<= 1; + bits <<= 1; + } +} + /* XXX Could be much more optimal: * detect if line/page/whole screen is in 24 bit mode @@ -162,11 +285,10 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, uint8_t val, *p8; uint32_t *p = (uint32_t *)d; uint32_t dval; - bgr = is_surface_bgr(surface); for(x = 0; x < width; x++, s++, s24++) { - if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) { - // 24-bit direct, BGR order + if (be32_to_cpu(*cplane) & 0x03000000) { + /* 24-bit direct, BGR order */ p8 = (uint8_t *)s24; p8++; b = *p8++; @@ -177,47 +299,18 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, else dval = rgb_to_pixel32(r, g, b); } else { + /* 8-bit pseudocolor */ val = *s; dval = s1->palette[val]; } *p++ = dval; + cplane++; } } -static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24, - ram_addr_t cpage) -{ - int ret; - - ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, - DIRTY_MEMORY_VGA); - ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, - DIRTY_MEMORY_VGA); - return ret; -} - -static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, - ram_addr_t page_max, ram_addr_t page24, - ram_addr_t cpage) -{ - memory_region_reset_dirty(&ts->vram_mem, - page_min, - (page_max - page_min) + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - memory_region_reset_dirty(&ts->vram_mem, - page24 + page_min * 4, - (page_max - page_min) * 4 + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - memory_region_reset_dirty(&ts->vram_mem, - cpage + page_min * 4, - (page_max - page_min) * 4 + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); -} - /* Fixed line length 1024 allows us to do nice tricks not possible on VGA... */ + static void tcx_update_display(void *opaque) { TCXState *ts = opaque; @@ -226,6 +319,7 @@ static void tcx_update_display(void *opaque) int y, y_start, dd, ds; uint8_t *d, *s; void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); + void (*fc)(TCXState *s1, uint8_t *dst, int y, int width); if (surface_bits_per_pixel(surface) == 0) { return; @@ -243,20 +337,23 @@ static void tcx_update_display(void *opaque) switch (surface_bits_per_pixel(surface)) { case 32: f = tcx_draw_line32; + fc = tcx_draw_cursor32; break; case 15: case 16: f = tcx_draw_line16; + fc = tcx_draw_cursor16; break; default: case 8: f = tcx_draw_line8; + fc = tcx_draw_cursor8; break; case 0: return; } - for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { + for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) { if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA)) { if (y_start < 0) @@ -265,18 +362,38 @@ static void tcx_update_display(void *opaque) page_min = page; if (page > page_max) page_max = page; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; } else { if (y_start >= 0) { /* flush to display */ @@ -286,6 +403,7 @@ static void tcx_update_display(void *opaque) } d += dd * 4; s += ds * 4; + y += 4; } } if (y_start >= 0) { @@ -328,9 +446,9 @@ static void tcx24_update_display(void *opaque) dd = surface_stride(surface); ds = 1024; - for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE, + for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE, page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { - if (check_dirty(ts, page, page24, cpage)) { + if (tcx24_check_dirty(ts, page, page24, cpage)) { if (y_start < 0) y_start = y; if (page < page_min) @@ -338,25 +456,41 @@ static void tcx24_update_display(void *opaque) if (page > page_max) page_max = page; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; } else { if (y_start >= 0) { /* flush to display */ @@ -368,6 +502,7 @@ static void tcx24_update_display(void *opaque) s += ds * 4; cptr += ds * 4; s24 += ds * 4; + y += 4; } } if (y_start >= 0) { @@ -377,7 +512,7 @@ static void tcx24_update_display(void *opaque) } /* reset modified pages */ if (page_max >= page_min) { - reset_dirty(ts, page_min, page_max, page24, cpage); + tcx24_reset_dirty(ts, page_min, page_max, page24, cpage); } } @@ -394,7 +529,6 @@ static void tcx24_invalidate_display(void *opaque) TCXState *s = opaque; tcx_set_dirty(s); - tcx24_set_dirty(s); qemu_console_resize(s->con, s->width, s->height); } @@ -403,12 +537,7 @@ static int vmstate_tcx_post_load(void *opaque, int version_id) TCXState *s = opaque; update_palette_entries(s, 0, 256); - if (s->depth == 24) { - tcx24_set_dirty(s); - } else { - tcx_set_dirty(s); - } - + tcx_set_dirty(s); return 0; } @@ -435,56 +564,87 @@ static void tcx_reset(DeviceState *d) TCXState *s = TCX(d); /* Initialize palette */ - memset(s->r, 0, 256); - memset(s->g, 0, 256); - memset(s->b, 0, 256); + memset(s->r, 0, 260); + memset(s->g, 0, 260); + memset(s->b, 0, 260); s->r[255] = s->g[255] = s->b[255] = 255; - update_palette_entries(s, 0, 256); + s->r[256] = s->g[256] = s->b[256] = 255; + s->r[258] = s->g[258] = s->b[258] = 255; + update_palette_entries(s, 0, 260); memset(s->vram, 0, MAXX*MAXY); memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4), DIRTY_MEMORY_VGA); s->dac_index = 0; s->dac_state = 0; + s->cursx = 0xf000; /* Put cursor off screen */ + s->cursy = 0xf000; } static uint64_t tcx_dac_readl(void *opaque, hwaddr addr, unsigned size) { - return 0; + TCXState *s = opaque; + uint32_t val = 0; + + switch (s->dac_state) { + case 0: + val = s->r[s->dac_index] << 24; + s->dac_state++; + break; + case 1: + val = s->g[s->dac_index] << 24; + s->dac_state++; + break; + case 2: + val = s->b[s->dac_index] << 24; + s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ + default: + s->dac_state = 0; + break; + } + + return val; } static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { TCXState *s = opaque; + unsigned index; switch (addr) { - case 0: + case 0: /* Address */ s->dac_index = val >> 24; s->dac_state = 0; break; - case 4: + case 4: /* Pixel colours */ + case 12: /* Overlay (cursor) colours */ + if (addr & 8) { + index = (s->dac_index & 3) + 256; + } else { + index = s->dac_index; + } switch (s->dac_state) { case 0: - s->r[s->dac_index] = val >> 24; - update_palette_entries(s, s->dac_index, s->dac_index + 1); + s->r[index] = val >> 24; + update_palette_entries(s, index, index + 1); s->dac_state++; break; case 1: - s->g[s->dac_index] = val >> 24; - update_palette_entries(s, s->dac_index, s->dac_index + 1); + s->g[index] = val >> 24; + update_palette_entries(s, index, index + 1); s->dac_state++; break; case 2: - s->b[s->dac_index] = val >> 24; - update_palette_entries(s, s->dac_index, s->dac_index + 1); - s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement + s->b[index] = val >> 24; + update_palette_entries(s, index, index + 1); + s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ default: s->dac_state = 0; break; } break; - default: + default: /* Control registers */ break; } } @@ -499,20 +659,266 @@ static const MemoryRegionOps tcx_dac_ops = { }, }; -static uint64_t dummy_readl(void *opaque, hwaddr addr, +static uint64_t tcx_stip_readl(void *opaque, hwaddr addr, + unsigned size) +{ + return 0; +} + +static void tcx_stip_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + int i; + uint32_t col; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + col = cpu_to_be32(s->tmpblit); + if (s->depth == 24) { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + s->vram24[addr + i] = col; + } + val <<= 1; + } + } else { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + } + val <<= 1; + } + } + memory_region_set_dirty(&s->vram_mem, addr, 32); + } +} + +static void tcx_rstip_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + int i; + uint32_t col; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + col = cpu_to_be32(s->tmpblit); + if (s->depth == 24) { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + s->vram24[addr + i] = col; + s->cplane[addr + i] = col; + } + val <<= 1; + } + } else { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + } + val <<= 1; + } + } + memory_region_set_dirty(&s->vram_mem, addr, 32); + } +} + +static const MemoryRegionOps tcx_stip_ops = { + .read = tcx_stip_readl, + .write = tcx_stip_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const MemoryRegionOps tcx_rstip_ops = { + .read = tcx_stip_readl, + .write = tcx_rstip_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static uint64_t tcx_blit_readl(void *opaque, hwaddr addr, + unsigned size) +{ + return 0; +} + +static void tcx_blit_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + uint32_t adsr, len; + int i; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + adsr = val & 0xffffff; + len = ((val >> 24) & 0x1f) + 1; + if (adsr == 0xffffff) { + memset(&s->vram[addr], s->tmpblit, len); + if (s->depth == 24) { + val = s->tmpblit & 0xffffff; + val = cpu_to_be32(val); + for (i = 0; i < len; i++) { + s->vram24[addr + i] = val; + } + } + } else { + memcpy(&s->vram[addr], &s->vram[adsr], len); + if (s->depth == 24) { + memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); + } + } + memory_region_set_dirty(&s->vram_mem, addr, len); + } +} + +static void tcx_rblit_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + uint32_t adsr, len; + int i; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + adsr = val & 0xffffff; + len = ((val >> 24) & 0x1f) + 1; + if (adsr == 0xffffff) { + memset(&s->vram[addr], s->tmpblit, len); + if (s->depth == 24) { + val = s->tmpblit & 0xffffff; + val = cpu_to_be32(val); + for (i = 0; i < len; i++) { + s->vram24[addr + i] = val; + s->cplane[addr + i] = val; + } + } + } else { + memcpy(&s->vram[addr], &s->vram[adsr], len); + if (s->depth == 24) { + memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); + memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4); + } + } + memory_region_set_dirty(&s->vram_mem, addr, len); + } +} + +static const MemoryRegionOps tcx_blit_ops = { + .read = tcx_blit_readl, + .write = tcx_blit_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const MemoryRegionOps tcx_rblit_ops = { + .read = tcx_blit_readl, + .write = tcx_rblit_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void tcx_invalidate_cursor_position(TCXState *s) +{ + int ymin, ymax, start, end; + + /* invalidate only near the cursor */ + ymin = s->cursy; + if (ymin >= s->height) { + return; + } + ymax = MIN(s->height, ymin + 32); + start = ymin * 1024; + end = ymax * 1024; + + memory_region_set_dirty(&s->vram_mem, start, end-start); +} + +static uint64_t tcx_thc_readl(void *opaque, hwaddr addr, + unsigned size) +{ + TCXState *s = opaque; + uint64_t val; + + if (addr == TCX_THC_MISC) { + val = s->thcmisc | 0x02000000; + } else { + val = 0; + } + return val; +} + +static void tcx_thc_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + + if (addr == TCX_THC_CURSXY) { + tcx_invalidate_cursor_position(s); + s->cursx = val >> 16; + s->cursy = val; + tcx_invalidate_cursor_position(s); + } else if (addr >= TCX_THC_CURSMASK && addr < TCX_THC_CURSMASK + 128) { + s->cursmask[(addr - TCX_THC_CURSMASK) >> 2] = val; + tcx_invalidate_cursor_position(s); + } else if (addr >= TCX_THC_CURSBITS && addr < TCX_THC_CURSBITS + 128) { + s->cursbits[(addr - TCX_THC_CURSBITS) >> 2] = val; + tcx_invalidate_cursor_position(s); + } else if (addr == TCX_THC_MISC) { + s->thcmisc = val; + } + +} + +static const MemoryRegionOps tcx_thc_ops = { + .read = tcx_thc_readl, + .write = tcx_thc_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr, unsigned size) { return 0; } -static void dummy_writel(void *opaque, hwaddr addr, +static void tcx_dummy_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { + return; } -static const MemoryRegionOps dummy_ops = { - .read = dummy_readl, - .write = dummy_writel, +static const MemoryRegionOps tcx_dummy_ops = { + .read = tcx_dummy_readl, + .write = tcx_dummy_writel, .endianness = DEVICE_NATIVE_ENDIAN, .valid = { .min_access_size = 4, @@ -540,20 +946,50 @@ static void tcx_initfn(Object *obj) memory_region_set_readonly(&s->rom, true); sysbus_init_mmio(sbd, &s->rom); - /* DAC */ + /* 2/STIP : Stippler */ + memory_region_init_io(&s->stip, OBJECT(s), &tcx_stip_ops, s, "tcx.stip", + TCX_STIP_NREGS); + sysbus_init_mmio(sbd, &s->stip); + + /* 3/BLIT : Blitter */ + memory_region_init_io(&s->blit, OBJECT(s), &tcx_blit_ops, s, "tcx.blit", + TCX_BLIT_NREGS); + sysbus_init_mmio(sbd, &s->blit); + + /* 5/RSTIP : Raw Stippler */ + memory_region_init_io(&s->rstip, OBJECT(s), &tcx_rstip_ops, s, "tcx.rstip", + TCX_RSTIP_NREGS); + sysbus_init_mmio(sbd, &s->rstip); + + /* 6/RBLIT : Raw Blitter */ + memory_region_init_io(&s->rblit, OBJECT(s), &tcx_rblit_ops, s, "tcx.rblit", + TCX_RBLIT_NREGS); + sysbus_init_mmio(sbd, &s->rblit); + + /* 7/TEC : ??? */ + memory_region_init_io(&s->tec, OBJECT(s), &tcx_dummy_ops, s, + "tcx.tec", TCX_TEC_NREGS); + sysbus_init_mmio(sbd, &s->tec); + + /* 8/CMAP : DAC */ memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS); sysbus_init_mmio(sbd, &s->dac); - /* TEC (dummy) */ - memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s, - "tcx.tec", TCX_TEC_NREGS); - sysbus_init_mmio(sbd, &s->tec); + /* 9/THC : Cursor */ + memory_region_init_io(&s->thc, OBJECT(s), &tcx_thc_ops, s, "tcx.thc", + TCX_THC_NREGS); + sysbus_init_mmio(sbd, &s->thc); - /* THC: NetBSD writes here even with 8-bit display: dummy */ - memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24", - TCX_THC_NREGS_24); - sysbus_init_mmio(sbd, &s->thc24); + /* 11/DHC : ??? */ + memory_region_init_io(&s->dhc, OBJECT(s), &tcx_dummy_ops, s, "tcx.dhc", + TCX_DHC_NREGS); + sysbus_init_mmio(sbd, &s->dhc); + + /* 12/ALT : ??? */ + memory_region_init_io(&s->alt, OBJECT(s), &tcx_dummy_ops, s, "tcx.alt", + TCX_ALT_NREGS); + sysbus_init_mmio(sbd, &s->alt); return; } @@ -572,7 +1008,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) vmstate_register_ram_global(&s->vram_mem); vram_base = memory_region_get_ram_ptr(&s->vram_mem); - /* FCode ROM */ + /* 10/ROM : FCode ROM */ vmstate_register_ram_global(&s->rom); fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); if (fcode_filename) { @@ -583,7 +1019,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) } } - /* 8-bit plane */ + /* 0/DFB8 : 8-bit plane */ s->vram = vram_base; size = s->vram_size; memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", @@ -592,34 +1028,39 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) vram_offset += size; vram_base += size; - if (s->depth == 24) { - /* 24-bit plane */ - size = s->vram_size * 4; - s->vram24 = (uint32_t *)vram_base; - s->vram24_offset = vram_offset; - memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", - &s->vram_mem, vram_offset, size); - sysbus_init_mmio(sbd, &s->vram_24bit); - vram_offset += size; - vram_base += size; - - /* Control plane */ - size = s->vram_size * 4; - s->cplane = (uint32_t *)vram_base; - s->cplane_offset = vram_offset; - memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", - &s->vram_mem, vram_offset, size); - sysbus_init_mmio(sbd, &s->vram_cplane); + /* 1/DFB24 : 24bit plane */ + size = s->vram_size * 4; + s->vram24 = (uint32_t *)vram_base; + s->vram24_offset = vram_offset; + memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", + &s->vram_mem, vram_offset, size); + sysbus_init_mmio(sbd, &s->vram_24bit); + vram_offset += size; + vram_base += size; + + /* 4/RDFB32 : Raw Framebuffer */ + size = s->vram_size * 4; + s->cplane = (uint32_t *)vram_base; + s->cplane_offset = vram_offset; + memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", + &s->vram_mem, vram_offset, size); + sysbus_init_mmio(sbd, &s->vram_cplane); - s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); - } else { - /* THC 8 bit (dummy) */ - memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8", - TCX_THC_NREGS_8); - sysbus_init_mmio(sbd, &s->thc8); + /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ + if (s->depth == 8) { + memory_region_init_io(&s->thc24, OBJECT(s), &tcx_dummy_ops, s, + "tcx.thc24", TCX_THC_NREGS); + sysbus_init_mmio(sbd, &s->thc24); + } + + sysbus_init_irq(sbd, &s->irq); + if (s->depth == 8) { s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); + } else { + s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); } + s->thcmisc = 0; qemu_console_resize(s->con, s->width, s->height); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 77b6782fed..82a7daa188 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -72,8 +72,10 @@ #define DPRINTF(fmt, ...) #endif -/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ -unsigned acpi_data_size = 0x20000; +/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables + * (128K) and other BIOS datastructures (less than 4K reported to be used at + * the moment, 32K should be enough for a while). */ +static unsigned acpi_data_size = 0x20000 + 0x8000; void pc_set_legacy_acpi_data_size(void) { acpi_data_size = 0x10000; diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index ba69de30e0..8978643fff 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -78,8 +78,7 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset) val = pr->cmd; break; case PORT_TFDATA: - val = ((uint16_t)s->dev[port].port.ifs[0].error << 8) | - s->dev[port].port.ifs[0].status; + val = pr->tfdata; break; case PORT_SIG: val = pr->sig; @@ -251,14 +250,13 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) check_cmd(s, port); break; case PORT_TFDATA: - s->dev[port].port.ifs[0].error = (val >> 8) & 0xff; - s->dev[port].port.ifs[0].status = val & 0xff; + /* Read Only. */ break; case PORT_SIG: - pr->sig = val; + /* Read Only */ break; case PORT_SCR_STAT: - pr->scr_stat = val; + /* Read Only */ break; case PORT_SCR_CTL: if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) && @@ -497,6 +495,8 @@ static void ahci_reset_port(AHCIState *s, int port) pr->scr_stat = 0; pr->scr_err = 0; pr->scr_act = 0; + pr->tfdata = 0x7F; + pr->sig = 0xFFFFFFFF; d->busy_slot = -1; d->init_d2h_sent = false; @@ -528,16 +528,16 @@ static void ahci_reset_port(AHCIState *s, int port) s->dev[port].port_state = STATE_RUN; if (!ide_state->bs) { - s->dev[port].port_regs.sig = 0; + pr->sig = 0; ide_state->status = SEEK_STAT | WRERR_STAT; } else if (ide_state->drive_kind == IDE_CD) { - s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM; + pr->sig = SATA_SIGNATURE_CDROM; ide_state->lcyl = 0x14; ide_state->hcyl = 0xeb; DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl); ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT; } else { - s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK; + pr->sig = SATA_SIGNATURE_DISK; ide_state->status = SEEK_STAT | WRERR_STAT; } @@ -563,7 +563,8 @@ static void debug_print_fis(uint8_t *fis, int cmd_len) static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) { - AHCIPortRegs *pr = &s->dev[port].port_regs; + AHCIDevice *ad = &s->dev[port]; + AHCIPortRegs *pr = &ad->port_regs; IDEState *ide_state; uint8_t *sdb_fis; @@ -572,8 +573,8 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) return; } - sdb_fis = &s->dev[port].res_fis[RES_FIS_SDBFIS]; - ide_state = &s->dev[port].port.ifs[0]; + sdb_fis = &ad->res_fis[RES_FIS_SDBFIS]; + ide_state = &ad->port.ifs[0]; /* clear memory */ *(uint32_t*)sdb_fis = 0; @@ -582,9 +583,14 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) sdb_fis[0] = ide_state->error; sdb_fis[2] = ide_state->status & 0x77; s->dev[port].finished |= finished; - *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished); + *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(ad->finished); + + /* Update shadow registers (except BSY 0x80 and DRQ 0x08) */ + pr->tfdata = (ad->port.ifs[0].error << 8) | + (ad->port.ifs[0].status & 0x77) | + (pr->tfdata & 0x88); - ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_SDB_FIS); + ahci_trigger_irq(s, ad, PORT_IRQ_SDB_FIS); } static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len) @@ -642,6 +648,10 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len) pio_fis[18] = 0; pio_fis[19] = 0; + /* Update shadow registers: */ + pr->tfdata = (ad->port.ifs[0].error << 8) | + ad->port.ifs[0].status; + if (pio_fis[2] & ERR_STAT) { ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR); } @@ -693,6 +703,10 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) d2h_fis[i] = 0; } + /* Update shadow registers: */ + pr->tfdata = (ad->port.ifs[0].error << 8) | + ad->port.ifs[0].status; + if (d2h_fis[2] & ERR_STAT) { ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR); } @@ -791,6 +805,9 @@ static void ncq_cb(void *opaque, int ret) NCQTransferState *ncq_tfs = (NCQTransferState *)opaque; IDEState *ide_state = &ncq_tfs->drive->port.ifs[0]; + if (ret == -ECANCELED) { + return; + } /* Clear bit for this tag in SActive */ ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag); diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 6d52cda4cc..10218dfa3a 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -136,6 +136,7 @@ void ide_atapi_cmd_ok(IDEState *s) s->error = 0; s->status = READY_STAT | SEEK_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_transfer_stop(s); ide_set_irq(s->bus); } @@ -149,6 +150,7 @@ void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; s->sense_key = sense_key; s->asc = asc; + ide_transfer_stop(s); ide_set_irq(s->bus); } @@ -176,9 +178,7 @@ void ide_atapi_cmd_reply_end(IDEState *s) #endif if (s->packet_transfer_size <= 0) { /* end of transfer */ - s->status = READY_STAT | SEEK_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_transfer_stop(s); + ide_atapi_cmd_ok(s); ide_set_irq(s->bus); #ifdef DEBUG_IDE_ATAPI printf("status=0x%x\n", s->status); @@ -188,7 +188,6 @@ void ide_atapi_cmd_reply_end(IDEState *s) if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { ret = cd_read_sector(s, s->lba, s->io_buffer, s->cd_sector_size); if (ret < 0) { - ide_transfer_stop(s); ide_atapi_io_error(s, ret); return; } diff --git a/hw/ide/core.c b/hw/ide/core.c index 6fba056783..190700ac74 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -372,23 +372,21 @@ static void trim_aio_cancel(BlockDriverAIOCB *acb) { TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common); - /* Exit the loop in case bdrv_aio_cancel calls ide_issue_trim_cb again. */ + /* Exit the loop so ide_issue_trim_cb will not continue */ iocb->j = iocb->qiov->niov - 1; iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1; - /* Tell ide_issue_trim_cb not to trigger the completion, too. */ - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; + iocb->ret = -ECANCELED; if (iocb->aiocb) { - bdrv_aio_cancel(iocb->aiocb); + bdrv_aio_cancel_async(iocb->aiocb); + iocb->aiocb = NULL; } - qemu_aio_release(iocb); } static const AIOCBInfo trim_aiocb_info = { .aiocb_size = sizeof(TrimAIOCB), - .cancel = trim_aio_cancel, + .cancel_async = trim_aio_cancel, }; static void ide_trim_bh_cb(void *opaque) @@ -399,7 +397,7 @@ static void ide_trim_bh_cb(void *opaque) qemu_bh_delete(iocb->bh); iocb->bh = NULL; - qemu_aio_release(iocb); + qemu_aio_unref(iocb); } static void ide_issue_trim_cb(void *opaque, int ret) @@ -568,6 +566,9 @@ static void ide_sector_read_cb(void *opaque, int ret) s->pio_aiocb = NULL; s->status &= ~BUSY_STAT; + if (ret == -ECANCELED) { + return; + } block_acct_done(bdrv_get_stats(s->bs), &s->acct); if (ret != 0) { if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO | @@ -678,6 +679,9 @@ void ide_dma_cb(void *opaque, int ret) int64_t sector_num; bool stay_active = false; + if (ret == -ECANCELED) { + return; + } if (ret < 0) { int op = IDE_RETRY_DMA; @@ -803,6 +807,9 @@ static void ide_sector_write_cb(void *opaque, int ret) IDEState *s = opaque; int n; + if (ret == -ECANCELED) { + return; + } block_acct_done(bdrv_get_stats(s->bs), &s->acct); s->pio_aiocb = NULL; @@ -882,6 +889,9 @@ static void ide_flush_cb(void *opaque, int ret) s->pio_aiocb = NULL; + if (ret == -ECANCELED) { + return; + } if (ret < 0) { /* XXX: What sector number to set here? */ if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) { diff --git a/hw/ide/ich.c b/hw/ide/ich.c index a2f1639310..8eb77a1472 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -71,6 +71,7 @@ #include <hw/ide/pci.h> #include <hw/ide/ahci.h> +#define ICH9_MSI_CAP_OFFSET 0x80 #define ICH9_SATA_CAP_OFFSET 0xA8 #define ICH9_IDP_BAR 4 @@ -115,7 +116,6 @@ static int pci_ich9_ahci_init(PCIDevice *dev) /* XXX Software should program this register */ dev->config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */ - msi_init(dev, 0x50, 1, true, false); d->ahci.irq = pci_allocate_irq(dev); pci_register_bar(dev, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO, @@ -135,6 +135,11 @@ static int pci_ich9_ahci_init(PCIDevice *dev) (ICH9_IDP_BAR + 0x4) | (ICH9_IDP_INDEX_LOG2 << 4)); d->ahci.idp_offset = ICH9_IDP_INDEX; + /* Although the AHCI 1.3 specification states that the first capability + * should be PMCAP, the Intel ICH9 data sheet specifies that the ICH9 + * AHCI device puts the MSI capability first, pointing to 0x80. */ + msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false); + return 0; } diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c index 40dcaa6558..d66f3d2425 100644 --- a/hw/misc/vfio.c +++ b/hw/misc/vfio.c @@ -1098,10 +1098,10 @@ static void vfio_bar_write(void *opaque, hwaddr addr, buf.byte = data; break; case 2: - buf.word = data; + buf.word = cpu_to_le16(data); break; case 4: - buf.dword = data; + buf.dword = cpu_to_le32(data); break; default: hw_error("vfio: unsupported write size, %d bytes", size); @@ -1158,10 +1158,10 @@ static uint64_t vfio_bar_read(void *opaque, data = buf.byte; break; case 2: - data = buf.word; + data = le16_to_cpu(buf.word); break; case 4: - data = buf.dword; + data = le32_to_cpu(buf.dword); break; default: hw_error("vfio: unsupported read size, %d bytes", size); @@ -1188,7 +1188,7 @@ static uint64_t vfio_bar_read(void *opaque, static const MemoryRegionOps vfio_bar_ops = { .read = vfio_bar_read, .write = vfio_bar_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void vfio_pci_load_rom(VFIODevice *vdev) @@ -1255,7 +1255,7 @@ static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size) uint16_t word; uint32_t dword; uint64_t qword; - } buf; + } val; uint64_t data = 0; /* Load the ROM lazily when the guest tries to read it */ @@ -1263,21 +1263,21 @@ static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size) vfio_pci_load_rom(vdev); } - memcpy(&buf, vdev->rom + addr, + memcpy(&val, vdev->rom + addr, (addr < vdev->rom_size) ? MIN(size, vdev->rom_size - addr) : 0); switch (size) { case 1: - data = buf.byte; + data = val.byte; break; case 2: - data = buf.word; + data = le16_to_cpu(val.word); break; case 4: - data = buf.dword; + data = le32_to_cpu(val.dword); break; default: - hw_error("vfio: unsupported read size, %d bytes", size); + hw_error("vfio: unsupported read size, %d bytes\n", size); break; } @@ -1296,7 +1296,7 @@ static void vfio_rom_write(void *opaque, hwaddr addr, static const MemoryRegionOps vfio_rom_ops = { .read = vfio_rom_read, .write = vfio_rom_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, }; static bool vfio_blacklist_opt_rom(VFIODevice *vdev) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index b21e7a434f..4e3a061622 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -28,7 +28,6 @@ #include <sys/socket.h> #include <linux/kvm.h> #include <fcntl.h> -#include <linux/virtio_ring.h> #include <netpacket/packet.h> #include <net/ethernet.h> #include <net/if.h> @@ -36,6 +35,7 @@ #include <stdio.h> +#include "hw/virtio/virtio_ring.h" #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-bus.h" @@ -163,11 +163,11 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) if (r < 0) { goto fail; } - if (!qemu_has_vnet_hdr_len(options->net_backend, - sizeof(struct virtio_net_hdr_mrg_rxbuf))) { - net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); - } if (backend_kernel) { + if (!qemu_has_vnet_hdr_len(options->net_backend, + sizeof(struct virtio_net_hdr_mrg_rxbuf))) { + net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); + } if (~net->dev.features & net->dev.backend_features) { fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n", diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 826a2a5fca..2040eac9a1 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1125,8 +1125,6 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) return num_packets; } - assert(vdev->vm_running); - if (q->async_tx.elem.out_num) { virtio_queue_set_notification(q->tx_vq, 0); return num_packets; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 2ab4460f04..2becc9ff07 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -541,7 +541,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX))); /* - * According to PAPR, rtas ibm,os-term, does not gaurantee a return + * According to PAPR, rtas ibm,os-term does not guarantee a return * back to the guest cpu. * * While an additional ibm,extended-os-term property indicates that diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 49c2aaff1f..b67c039a70 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -243,17 +243,25 @@ static void copy_sense_id_to_guest(SenseId *dest, SenseId *src) } } -static CCW1 copy_ccw_from_guest(hwaddr addr) +static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1) { - CCW1 tmp; + CCW0 tmp0; + CCW1 tmp1; CCW1 ret; - cpu_physical_memory_read(addr, &tmp, sizeof(tmp)); - ret.cmd_code = tmp.cmd_code; - ret.flags = tmp.flags; - ret.count = be16_to_cpu(tmp.count); - ret.cda = be32_to_cpu(tmp.cda); - + if (fmt1) { + cpu_physical_memory_read(addr, &tmp1, sizeof(tmp1)); + ret.cmd_code = tmp1.cmd_code; + ret.flags = tmp1.flags; + ret.count = be16_to_cpu(tmp1.count); + ret.cda = be32_to_cpu(tmp1.cda); + } else { + cpu_physical_memory_read(addr, &tmp0, sizeof(tmp0)); + ret.cmd_code = tmp0.cmd_code; + ret.flags = tmp0.flags; + ret.count = be16_to_cpu(tmp0.count); + ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16); + } return ret; } @@ -268,7 +276,8 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) return -EIO; } - ccw = copy_ccw_from_guest(ccw_addr); + /* Translate everything to format-1 ccws - the information is the same. */ + ccw = copy_ccw_from_guest(ccw_addr, sch->ccw_fmt_1); /* Check for invalid command codes. */ if ((ccw.cmd_code & 0x0f) == 0) { @@ -285,6 +294,13 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); + if (!ccw.cda) { + if (sch->ccw_no_data_cnt == 255) { + return -EINVAL; + } + sch->ccw_no_data_cnt++; + } + /* Look at the command. */ switch (ccw.cmd_code) { case CCW_CMD_NOOP: @@ -386,6 +402,8 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND); return; } + sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT); + sch->ccw_no_data_cnt = 0; } else { s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND); } @@ -1347,6 +1365,8 @@ void subch_device_save(SubchDev *s, QEMUFile *f) qemu_put_byte(f, s->id.ciw[i].command); qemu_put_be16(f, s->id.ciw[i].count); } + qemu_put_byte(f, s->ccw_fmt_1); + qemu_put_byte(f, s->ccw_no_data_cnt); return; } @@ -1402,6 +1422,8 @@ int subch_device_load(SubchDev *s, QEMUFile *f) s->id.ciw[i].command = qemu_get_byte(f); s->id.ciw[i].count = qemu_get_be16(f); } + s->ccw_fmt_1 = qemu_get_byte(f); + s->ccw_no_data_cnt = qemu_get_byte(f); return 0; } diff --git a/hw/s390x/css.h b/hw/s390x/css.h index c864ea765b..33104ac58e 100644 --- a/hw/s390x/css.h +++ b/hw/s390x/css.h @@ -76,7 +76,9 @@ struct SubchDev { hwaddr channel_prog; CCW1 last_cmd; bool last_cmd_valid; + bool ccw_fmt_1; bool thinint_active; + uint8_t ccw_no_data_cnt; /* transport-provided data: */ int (*ccw_cb) (SubchDev *, CCW1); SenseId id; diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 78f87a2570..2feab35585 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -527,7 +527,7 @@ static void apc_init(hwaddr power_base, qemu_irq cpu_halt) sysbus_connect_irq(s, 0, cpu_halt); } -static void tcx_init(hwaddr addr, int vram_size, int width, +static void tcx_init(hwaddr addr, qemu_irq irq, int vram_size, int width, int height, int depth) { DeviceState *dev; @@ -541,25 +541,43 @@ static void tcx_init(hwaddr addr, int vram_size, int width, qdev_prop_set_uint64(dev, "prom_addr", addr); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); - /* FCode ROM */ + + /* 10/ROM : FCode ROM */ sysbus_mmio_map(s, 0, addr); - /* DAC */ - sysbus_mmio_map(s, 1, addr + 0x00200000ULL); - /* TEC (dummy) */ - sysbus_mmio_map(s, 2, addr + 0x00700000ULL); - /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */ - sysbus_mmio_map(s, 3, addr + 0x00301000ULL); - /* 8-bit plane */ - sysbus_mmio_map(s, 4, addr + 0x00800000ULL); - if (depth == 24) { - /* 24-bit plane */ - sysbus_mmio_map(s, 5, addr + 0x02000000ULL); - /* Control plane */ - sysbus_mmio_map(s, 6, addr + 0x0a000000ULL); + /* 2/STIP : Stipple */ + sysbus_mmio_map(s, 1, addr + 0x04000000ULL); + /* 3/BLIT : Blitter */ + sysbus_mmio_map(s, 2, addr + 0x06000000ULL); + /* 5/RSTIP : Raw Stipple */ + sysbus_mmio_map(s, 3, addr + 0x0c000000ULL); + /* 6/RBLIT : Raw Blitter */ + sysbus_mmio_map(s, 4, addr + 0x0e000000ULL); + /* 7/TEC : Transform Engine */ + sysbus_mmio_map(s, 5, addr + 0x00700000ULL); + /* 8/CMAP : DAC */ + sysbus_mmio_map(s, 6, addr + 0x00200000ULL); + /* 9/THC : */ + if (depth == 8) { + sysbus_mmio_map(s, 7, addr + 0x00300000ULL); } else { - /* THC 8 bit (dummy) */ - sysbus_mmio_map(s, 5, addr + 0x00300000ULL); + sysbus_mmio_map(s, 7, addr + 0x00301000ULL); } + /* 11/DHC : */ + sysbus_mmio_map(s, 8, addr + 0x00240000ULL); + /* 12/ALT : */ + sysbus_mmio_map(s, 9, addr + 0x00280000ULL); + /* 0/DFB8 : 8-bit plane */ + sysbus_mmio_map(s, 10, addr + 0x00800000ULL); + /* 1/DFB24 : 24bit plane */ + sysbus_mmio_map(s, 11, addr + 0x02000000ULL); + /* 4/RDFB32: Raw framebuffer. Control plane */ + sysbus_mmio_map(s, 12, addr + 0x0a000000ULL); + /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ + if (depth == 8) { + sysbus_mmio_map(s, 13, addr + 0x00301000ULL); + } + + sysbus_connect_irq(s, 0, irq); } static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width, @@ -976,8 +994,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, exit(1); } - tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, - graphic_depth); + tcx_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, + graphic_width, graphic_height, graphic_depth); } } diff --git a/hw/usb/bus.c b/hw/usb/bus.c index c7c4dadedd..da1eba9fbd 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -9,7 +9,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); static char *usb_get_dev_path(DeviceState *dev); static char *usb_get_fw_dev_path(DeviceState *qdev); -static int usb_qdev_exit(DeviceState *qdev); +static void usb_qdev_unrealize(DeviceState *qdev, Error **errp); static Property usb_props[] = { DEFINE_PROP_STRING("port", USBDevice, port_path), @@ -107,13 +107,13 @@ USBBus *usb_bus_find(int busnr) return NULL; } -static int usb_device_init(USBDevice *dev) +static void usb_device_realize(USBDevice *dev, Error **errp) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); - if (klass->init) { - return klass->init(dev); + + if (klass->realize) { + klass->realize(dev, errp); } - return 0; } USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr) @@ -232,36 +232,41 @@ void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps) } } -static int usb_qdev_init(DeviceState *qdev) +static void usb_qdev_realize(DeviceState *qdev, Error **errp) { USBDevice *dev = USB_DEVICE(qdev); - int rc; + Error *local_err = NULL; pstrcpy(dev->product_desc, sizeof(dev->product_desc), usb_device_get_product_desc(dev)); dev->auto_attach = 1; QLIST_INIT(&dev->strings); usb_ep_init(dev); - rc = usb_claim_port(dev); - if (rc != 0) { - return rc; + + usb_claim_port(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } - rc = usb_device_init(dev); - if (rc != 0) { + + usb_device_realize(dev, &local_err); + if (local_err) { usb_release_port(dev); - return rc; + error_propagate(errp, local_err); + return; } + if (dev->auto_attach) { - rc = usb_device_attach(dev); - if (rc != 0) { - usb_qdev_exit(qdev); - return rc; + usb_device_attach(dev, &local_err); + if (local_err) { + usb_qdev_unrealize(qdev, NULL); + error_propagate(errp, local_err); + return; } } - return 0; } -static int usb_qdev_exit(DeviceState *qdev) +static void usb_qdev_unrealize(DeviceState *qdev, Error **errp) { USBDevice *dev = USB_DEVICE(qdev); @@ -272,7 +277,6 @@ static int usb_qdev_exit(DeviceState *qdev) if (dev->port) { usb_release_port(dev); } - return 0; } typedef struct LegacyUSBFactory @@ -392,7 +396,7 @@ void usb_unregister_port(USBBus *bus, USBPort *port) bus->nfree--; } -int usb_claim_port(USBDevice *dev) +void usb_claim_port(USBDevice *dev, Error **errp) { USBBus *bus = usb_bus_from_device(dev); USBPort *port; @@ -406,9 +410,9 @@ int usb_claim_port(USBDevice *dev) } } if (port == NULL) { - error_report("Error: usb port %s (bus %s) not found (in use?)", - dev->port_path, bus->qbus.name); - return -1; + error_setg(errp, "Error: usb port %s (bus %s) not found (in use?)", + dev->port_path, bus->qbus.name); + return; } } else { if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) { @@ -416,9 +420,9 @@ int usb_claim_port(USBDevice *dev) usb_create_simple(bus, "usb-hub"); } if (bus->nfree == 0) { - error_report("Error: tried to attach usb device %s to a bus " - "with no free ports", dev->product_desc); - return -1; + error_setg(errp, "Error: tried to attach usb device %s to a bus " + "with no free ports", dev->product_desc); + return; } port = QTAILQ_FIRST(&bus->free); } @@ -432,7 +436,6 @@ int usb_claim_port(USBDevice *dev) QTAILQ_INSERT_TAIL(&bus->used, port, next); bus->nused++; - return 0; } void usb_release_port(USBDevice *dev) @@ -475,7 +478,7 @@ static void usb_mask_to_str(char *dest, size_t size, } } -int usb_device_attach(USBDevice *dev) +void usb_check_attach(USBDevice *dev, Error **errp) { USBBus *bus = usb_bus_from_device(dev); USBPort *port = dev->port; @@ -489,18 +492,28 @@ int usb_device_attach(USBDevice *dev) devspeed, portspeed); if (!(port->speedmask & dev->speedmask)) { - error_report("Warning: speed mismatch trying to attach" - " usb device \"%s\" (%s speed)" - " to bus \"%s\", port \"%s\" (%s speed)", - dev->product_desc, devspeed, - bus->qbus.name, port->path, portspeed); - return -1; + error_setg(errp, "Warning: speed mismatch trying to attach" + " usb device \"%s\" (%s speed)" + " to bus \"%s\", port \"%s\" (%s speed)", + dev->product_desc, devspeed, + bus->qbus.name, port->path, portspeed); + return; + } +} + +void usb_device_attach(USBDevice *dev, Error **errp) +{ + USBPort *port = dev->port; + Error *local_err = NULL; + + usb_check_attach(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } dev->attached++; usb_attach(port); - - return 0; } int usb_device_detach(USBDevice *dev) @@ -688,9 +701,9 @@ static void usb_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->bus_type = TYPE_USB_BUS; - k->init = usb_qdev_init; k->unplug = qdev_simple_unplug_cb; - k->exit = usb_qdev_exit; + k->realize = usb_qdev_realize; + k->unrealize = usb_qdev_unrealize; k->props = usb_props; } diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 7b9957b3c3..67deffebcf 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -628,7 +628,7 @@ static void usb_audio_handle_destroy(USBDevice *dev) streambuf_fini(&s->out.buf); } -static int usb_audio_initfn(USBDevice *dev) +static void usb_audio_realize(USBDevice *dev, Error **errp) { USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); @@ -651,7 +651,6 @@ static int usb_audio_initfn(USBDevice *dev) s, output_callback, &s->out.as); AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]); AUD_set_active_out(s->out.voice, 0); - return 0; } static const VMStateDescription vmstate_usb_audio = { @@ -676,7 +675,7 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_SOUND, dc->categories); k->product_desc = "QEMU USB Audio Interface"; k->usb_desc = &desc_audio; - k->init = usb_audio_initfn; + k->realize = usb_audio_realize; k->handle_reset = usb_audio_handle_reset; k->handle_control = usb_audio_handle_control; k->handle_data = usb_audio_handle_data; diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index a76e58191e..390d475c16 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -501,7 +501,7 @@ static void usb_bt_handle_destroy(USBDevice *dev) s->hci->acl_recv = NULL; } -static int usb_bt_initfn(USBDevice *dev) +static void usb_bt_realize(USBDevice *dev, Error **errp) { struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev); @@ -516,8 +516,6 @@ static int usb_bt_initfn(USBDevice *dev) s->hci->acl_recv = usb_bt_out_hci_packet_acl; usb_bt_handle_reset(&s->dev); s->intr = usb_ep_get(dev, USB_TOKEN_IN, USB_EVT_EP); - - return 0; } static USBDevice *usb_bt_init(USBBus *bus, const char *cmdline) @@ -560,7 +558,7 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_bt_initfn; + uc->realize = usb_bt_realize; uc->product_desc = "QEMU BT dongle"; uc->usb_desc = &desc_bluetooth; uc->handle_reset = usb_bt_handle_reset; diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 67a57f1dcd..467ec86da6 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -566,7 +566,7 @@ static void usb_hid_handle_destroy(USBDevice *dev) hid_free(&us->hid); } -static int usb_hid_initfn(USBDevice *dev, int kind) +static void usb_hid_initfn(USBDevice *dev, int kind) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); @@ -579,10 +579,9 @@ static int usb_hid_initfn(USBDevice *dev, int kind) if (us->display && us->hid.s) { qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL); } - return 0; } -static int usb_tablet_initfn(USBDevice *dev) +static void usb_tablet_realize(USBDevice *dev, Error **errp) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); @@ -594,22 +593,22 @@ static int usb_tablet_initfn(USBDevice *dev) dev->usb_desc = &desc_tablet2; break; default: - error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)", - us->usb_version); - return -1; + error_setg(errp, "Invalid usb version %d for usb-tablet " + "(must be 1 or 2)", us->usb_version); + return; } - return usb_hid_initfn(dev, HID_TABLET); + usb_hid_initfn(dev, HID_TABLET); } -static int usb_mouse_initfn(USBDevice *dev) +static void usb_mouse_realize(USBDevice *dev, Error **errp) { - return usb_hid_initfn(dev, HID_MOUSE); + usb_hid_initfn(dev, HID_MOUSE); } -static int usb_keyboard_initfn(USBDevice *dev) +static void usb_keyboard_realize(USBDevice *dev, Error **errp) { - return usb_hid_initfn(dev, HID_KEYBOARD); + usb_hid_initfn(dev, HID_KEYBOARD); } static int usb_ptr_post_load(void *opaque, int version_id) @@ -669,7 +668,7 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) USBDeviceClass *uc = USB_DEVICE_CLASS(klass); usb_hid_class_initfn(klass, data); - uc->init = usb_tablet_initfn; + uc->realize = usb_tablet_realize; uc->product_desc = "QEMU USB Tablet"; dc->vmsd = &vmstate_usb_ptr; dc->props = usb_tablet_properties; @@ -689,7 +688,7 @@ static void usb_mouse_class_initfn(ObjectClass *klass, void *data) USBDeviceClass *uc = USB_DEVICE_CLASS(klass); usb_hid_class_initfn(klass, data); - uc->init = usb_mouse_initfn; + uc->realize = usb_mouse_realize; uc->product_desc = "QEMU USB Mouse"; uc->usb_desc = &desc_mouse; dc->vmsd = &vmstate_usb_ptr; @@ -714,7 +713,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) USBDeviceClass *uc = USB_DEVICE_CLASS(klass); usb_hid_class_initfn(klass, data); - uc->init = usb_keyboard_initfn; + uc->realize = usb_keyboard_realize; uc->product_desc = "QEMU USB Keyboard"; uc->usb_desc = &desc_keyboard; dc->vmsd = &vmstate_usb_kbd; diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 749217497a..0482f58719 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -511,15 +511,15 @@ static USBPortOps usb_hub_port_ops = { .complete = usb_hub_complete, }; -static int usb_hub_initfn(USBDevice *dev) +static void usb_hub_realize(USBDevice *dev, Error **errp) { USBHubState *s = DO_UPCAST(USBHubState, dev, dev); USBHubPort *port; int i; if (dev->port->hubcount == 5) { - error_report("usb hub chain too deep"); - return -1; + error_setg(errp, "usb hub chain too deep"); + return; } usb_desc_create_serial(dev); @@ -533,7 +533,6 @@ static int usb_hub_initfn(USBDevice *dev) usb_port_location(&port->port, dev->port, i+1); } usb_hub_handle_reset(dev); - return 0; } static const VMStateDescription vmstate_usb_hub_port = { @@ -564,7 +563,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_hub_initfn; + uc->realize = usb_hub_realize; uc->product_desc = "QEMU USB Hub"; uc->usb_desc = &desc_hub; uc->find_device = usb_hub_find_device; diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 0820046906..108ece8190 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -1060,7 +1060,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) } } -static int usb_mtp_initfn(USBDevice *dev) +static void usb_mtp_realize(USBDevice *dev, Error **errp) { MTPState *s = DO_UPCAST(MTPState, dev, dev); @@ -1075,7 +1075,6 @@ static int usb_mtp_initfn(USBDevice *dev) s->desc = g_strdup("none"); } } - return 0; } static const VMStateDescription vmstate_usb_mtp = { @@ -1100,7 +1099,7 @@ static void usb_mtp_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_mtp_initfn; + uc->realize = usb_mtp_realize; uc->product_desc = "QEMU USB MTP"; uc->usb_desc = &desc; uc->cancel_packet = usb_mtp_cancel_packet; diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 518d5366d1..23e3c45b5f 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -27,7 +27,7 @@ #include "hw/usb.h" #include "hw/usb/desc.h" #include "net/net.h" -#include "qapi/qmp/qerror.h" +#include "qemu/error-report.h" #include "qemu/queue.h" #include "qemu/config-file.h" #include "sysemu/sysemu.h" @@ -1341,7 +1341,7 @@ static NetClientInfo net_usbnet_info = { .cleanup = usbnet_cleanup, }; -static int usb_net_initfn(USBDevice *dev) +static void usb_net_realize(USBDevice *dev, Error **errrp) { USBNetState *s = DO_UPCAST(USBNetState, dev, dev); @@ -1373,7 +1373,6 @@ static int usb_net_initfn(USBDevice *dev) usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac); add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet@0"); - return 0; } static USBDevice *usb_net_init(USBBus *bus, const char *cmdline) @@ -1392,7 +1391,7 @@ static USBDevice *usb_net_init(USBBus *bus, const char *cmdline) idx = net_client_init(opts, 0, &local_err); if (local_err) { - qerror_report_err(local_err); + error_report("%s", error_get_pretty(local_err)); error_free(local_err); return NULL; } @@ -1421,7 +1420,7 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_net_initfn; + uc->realize = usb_net_realize; uc->product_desc = "QEMU USB Network Interface"; uc->usb_desc = &desc_net; uc->handle_reset = usb_net_handle_reset; diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index d3606142c9..1cee450259 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -9,7 +9,7 @@ */ #include "qemu-common.h" -#include "qemu/error-report.h" +#include "monitor/monitor.h" #include "hw/usb.h" #include "hw/usb/desc.h" #include "sysemu/char.h" @@ -460,7 +460,7 @@ static void usb_serial_event(void *opaque, int event) break; case CHR_EVENT_OPENED: if (!s->dev.attached) { - usb_device_attach(&s->dev); + usb_device_attach(&s->dev, &error_abort); } break; case CHR_EVENT_CLOSED: @@ -471,17 +471,24 @@ static void usb_serial_event(void *opaque, int event) } } -static int usb_serial_initfn(USBDevice *dev) +static void usb_serial_realize(USBDevice *dev, Error **errp) { USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev); + Error *local_err = NULL; usb_desc_create_serial(dev); usb_desc_init(dev); dev->auto_attach = 0; if (!s->cs) { - error_report("Property chardev is required"); - return -1; + error_setg(errp, "Property chardev is required"); + return; + } + + usb_check_attach(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, @@ -489,9 +496,8 @@ static int usb_serial_initfn(USBDevice *dev) usb_serial_handle_reset(dev); if (s->cs->be_open && !dev->attached) { - usb_device_attach(dev); + usb_device_attach(dev, &error_abort); } - return 0; } static USBDevice *usb_serial_init(USBBus *bus, const char *filename) @@ -582,7 +588,7 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_serial_initfn; + uc->realize = usb_serial_realize; uc->product_desc = "QEMU USB Serial"; uc->usb_desc = &desc_serial; uc->handle_reset = usb_serial_handle_reset; @@ -610,7 +616,7 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_serial_initfn; + uc->realize = usb_serial_realize; uc->product_desc = "QEMU USB Braille"; uc->usb_desc = &desc_braille; uc->handle_reset = usb_serial_handle_reset; diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 470e69ffc8..d37ed02d2e 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1304,7 +1304,7 @@ static int ccid_card_init(DeviceState *qdev) return ret; } -static int ccid_initfn(USBDevice *dev) +static void ccid_realize(USBDevice *dev, Error **errp) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); @@ -1332,7 +1332,6 @@ static int ccid_initfn(USBDevice *dev) ccid_reset_parameters(s); ccid_reset(s); s->debug = parse_debug_env("QEMU_CCID_DEBUG", D_VERBOSE, s->debug); - return 0; } static int ccid_post_load(void *opaque, int version_id) @@ -1441,7 +1440,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = ccid_initfn; + uc->realize = ccid_realize; uc->product_desc = "QEMU USB CCID"; uc->usb_desc = &desc_ccid; uc->handle_reset = ccid_handle_reset; diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index ae4efcbd2d..bd7cc53e07 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -409,19 +409,19 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) switch (s->mode) { case USB_MSDM_CBW: if (p->iov.size != 31) { - fprintf(stderr, "usb-msd: Bad CBW size"); + error_report("usb-msd: Bad CBW size"); goto fail; } usb_packet_copy(p, &cbw, 31); if (le32_to_cpu(cbw.sig) != 0x43425355) { - fprintf(stderr, "usb-msd: Bad signature %08x\n", - le32_to_cpu(cbw.sig)); + error_report("usb-msd: Bad signature %08x", + le32_to_cpu(cbw.sig)); goto fail; } DPRINTF("Command on LUN %d\n", cbw.lun); scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun); if (scsi_dev == NULL) { - fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); + error_report("usb-msd: Bad LUN %d", cbw.lun); goto fail; } tag = le32_to_cpu(cbw.tag); @@ -549,12 +549,17 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) static void usb_msd_password_cb(void *opaque, int err) { MSDState *s = opaque; + Error *local_err = NULL; - if (!err) - err = usb_device_attach(&s->dev); + if (!err) { + usb_device_attach(&s->dev, &local_err); + } - if (err) + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); qdev_unplug(&s->dev.qdev, NULL); + } } static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req) @@ -590,7 +595,7 @@ static const struct SCSIBusInfo usb_msd_scsi_info_bot = { .load_request = usb_msd_load_request, }; -static int usb_msd_initfn_storage(USBDevice *dev) +static void usb_msd_realize_storage(USBDevice *dev, Error **errp) { MSDState *s = DO_UPCAST(MSDState, dev, dev); BlockDriverState *bs = s->conf.bs; @@ -598,8 +603,8 @@ static int usb_msd_initfn_storage(USBDevice *dev) Error *err = NULL; if (!bs) { - error_report("drive property not set"); - return -1; + error_setg(errp, "drive property not set"); + return; } blkconf_serial(&s->conf, &dev->serial); @@ -624,7 +629,8 @@ static int usb_msd_initfn_storage(USBDevice *dev) s->conf.bootindex, dev->serial, &err); if (!scsi_dev) { - return -1; + error_propagate(errp, err); + return; } s->bus.qbus.allow_hotplug = 0; usb_msd_handle_reset(dev); @@ -637,11 +643,9 @@ static int usb_msd_initfn_storage(USBDevice *dev) autostart = 0; } } - - return 0; } -static int usb_msd_initfn_bot(USBDevice *dev) +static void usb_msd_realize_bot(USBDevice *dev, Error **errp) { MSDState *s = DO_UPCAST(MSDState, dev, dev); @@ -651,8 +655,6 @@ static int usb_msd_initfn_bot(USBDevice *dev) &usb_msd_scsi_info_bot, NULL); s->bus.qbus.allow_hotplug = 0; usb_msd_handle_reset(dev); - - return 0; } static USBDevice *usb_msd_init(USBBus *bus, const char *filename) @@ -666,8 +668,10 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) char fmt[32]; /* parse -usbdevice disk: syntax into drive opts */ - snprintf(id, sizeof(id), "usb%d", nr++); - opts = qemu_opts_create(qemu_find_opts("drive"), id, 0, NULL); + do { + snprintf(id, sizeof(id), "usb%d", nr++); + opts = qemu_opts_create(qemu_find_opts("drive"), id, 1, NULL); + } while (!opts); p1 = strchr(filename, ':'); if (p1++) { @@ -678,13 +682,13 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) pstrcpy(fmt, len, p2); qemu_opt_set(opts, "format", fmt); } else if (*filename != ':') { - printf("unrecognized USB mass-storage option %s\n", filename); + error_report("unrecognized USB mass-storage option %s", filename); return NULL; } filename = p1; } if (!*filename) { - printf("block device specification needed\n"); + error_report("block device specification needed"); return NULL; } qemu_opt_set(opts, "file", filename); @@ -758,7 +762,7 @@ static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_msd_initfn_storage; + uc->realize = usb_msd_realize_storage; dc->props = msd_properties; usb_msd_class_initfn_common(klass); } @@ -767,7 +771,7 @@ static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data) { USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_msd_initfn_bot; + uc->realize = usb_msd_realize_bot; usb_msd_class_initfn_common(klass); } diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 9832385119..04fc515dbe 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -13,6 +13,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "trace.h" +#include "qemu/error-report.h" #include "hw/usb.h" #include "hw/usb/desc.h" @@ -648,7 +649,7 @@ static void usb_uas_handle_control(USBDevice *dev, USBPacket *p, if (ret >= 0) { return; } - fprintf(stderr, "%s: unhandled control request\n", __func__); + error_report("%s: unhandled control request", __func__); p->status = USB_RET_STALL; } @@ -814,8 +815,8 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) usb_uas_task(uas, &iu); break; default: - fprintf(stderr, "%s: unknown command iu: id 0x%x\n", - __func__, iu.hdr.id); + error_report("%s: unknown command iu: id 0x%x", + __func__, iu.hdr.id); p->status = USB_RET_STALL; break; } @@ -861,7 +862,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) p->status = USB_RET_ASYNC; break; } else { - fprintf(stderr, "%s: no inflight request\n", __func__); + error_report("%s: no inflight request", __func__); p->status = USB_RET_STALL; break; } @@ -879,7 +880,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) usb_uas_start_next_transfer(uas); break; default: - fprintf(stderr, "%s: invalid endpoint %d\n", __func__, p->ep->nr); + error_report("%s: invalid endpoint %d", __func__, p->ep->nr); p->status = USB_RET_STALL; break; } @@ -892,7 +893,7 @@ static void usb_uas_handle_destroy(USBDevice *dev) qemu_bh_delete(uas->status_bh); } -static int usb_uas_init(USBDevice *dev) +static void usb_uas_realize(USBDevice *dev, Error **errp) { UASDevice *uas = DO_UPCAST(UASDevice, dev, dev); @@ -905,8 +906,6 @@ static int usb_uas_init(USBDevice *dev) scsi_bus_new(&uas->bus, sizeof(uas->bus), DEVICE(dev), &usb_uas_scsi_info, NULL); - - return 0; } static const VMStateDescription vmstate_usb_uas = { @@ -928,7 +927,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_uas_init; + uc->realize = usb_uas_realize; uc->product_desc = desc_strings[STR_PRODUCT]; uc->usb_desc = &desc; uc->cancel_packet = usb_uas_cancel_io; diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 1b73fd0aab..844eafadf7 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -335,14 +335,13 @@ static void usb_wacom_handle_destroy(USBDevice *dev) } } -static int usb_wacom_initfn(USBDevice *dev) +static void usb_wacom_realize(USBDevice *dev, Error **errp) { USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev); usb_desc_create_serial(dev); usb_desc_init(dev); s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); s->changed = 1; - return 0; } static const VMStateDescription vmstate_usb_wacom = { @@ -357,7 +356,7 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data) uc->product_desc = "QEMU PenPartner Tablet"; uc->usb_desc = &desc_wacom; - uc->init = usb_wacom_initfn; + uc->realize = usb_wacom_realize; uc->handle_reset = usb_wacom_handle_reset; uc->handle_control = usb_wacom_handle_control; uc->handle_data = usb_wacom_handle_data; diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 289ca3b853..490f2b6af9 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -23,6 +23,7 @@ typedef struct EHCIPCIInfo { uint16_t vendor_id; uint16_t device_id; uint8_t revision; + bool companion; } EHCIPCIInfo; static int usb_ehci_pci_initfn(PCIDevice *dev) @@ -71,6 +72,7 @@ static int usb_ehci_pci_initfn(PCIDevice *dev) static void usb_ehci_pci_init(Object *obj) { + DeviceClass *dc = OBJECT_GET_CLASS(DeviceClass, obj, TYPE_DEVICE); EHCIPCIState *i = PCI_EHCI(obj); EHCIState *s = &i->ehci; @@ -81,6 +83,10 @@ static void usb_ehci_pci_init(Object *obj) s->portscbase = 0x44; s->portnr = NB_PORTS; + if (!dc->hotpluggable) { + s->companion_enable = true; + } + usb_ehci_init(s, DEVICE(obj)); } @@ -137,7 +143,6 @@ static void ehci_class_init(ObjectClass *klass, void *data) k->exit = usb_ehci_pci_exit; k->class_id = PCI_CLASS_SERIAL_USB; k->config_write = usb_ehci_pci_write_config; - dc->hotpluggable = false; dc->vmsd = &vmstate_ehci_pci; dc->props = ehci_pci_properties; } @@ -161,6 +166,9 @@ static void ehci_data_class_init(ObjectClass *klass, void *data) k->device_id = i->device_id; k->revision = i->revision; set_bit(DEVICE_CATEGORY_USB, dc->categories); + if (i->companion) { + dc->hotpluggable = false; + } } static struct EHCIPCIInfo ehci_pci_info[] = { @@ -174,11 +182,13 @@ static struct EHCIPCIInfo ehci_pci_info[] = { .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1, .revision = 0x03, + .companion = true, },{ .name = "ich9-usb-ehci2", /* 00:1a.7 */ .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI2, .revision = 0x03, + .companion = true, } }; diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index bacb7ceac9..1cc0fc116d 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2347,10 +2347,13 @@ static USBPortOps ehci_port_ops = { .complete = ehci_async_complete_packet, }; -static USBBusOps ehci_bus_ops = { +static USBBusOps ehci_bus_ops_companion = { .register_companion = ehci_register_companion, .wakeup_endpoint = ehci_wakeup_endpoint, }; +static USBBusOps ehci_bus_ops_standalone = { + .wakeup_endpoint = ehci_wakeup_endpoint, +}; static void usb_ehci_pre_save(void *opaque) { @@ -2456,7 +2459,8 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp) return; } - usb_bus_new(&s->bus, sizeof(s->bus), &ehci_bus_ops, dev); + usb_bus_new(&s->bus, sizeof(s->bus), s->companion_enable ? + &ehci_bus_ops_companion : &ehci_bus_ops_standalone, dev); for (i = 0; i < s->portnr; i++) { usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops, USB_SPEED_MASK_HIGH); diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 4858b7e80c..2bc259c9b4 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -262,6 +262,7 @@ struct EHCIState { MemoryRegion mem_opreg; MemoryRegion mem_ports; int companion_count; + bool companion_enable; uint16_t capsbase; uint16_t opregbase; uint16_t portscbase; diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 83bec34185..9a84eb6950 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -31,20 +31,11 @@ #include "hw/pci/pci.h" #include "hw/sysbus.h" #include "hw/qdev-dma.h" +#include "trace.h" -//#define DEBUG_OHCI -/* Dump packet contents. */ -//#define DEBUG_PACKET -//#define DEBUG_ISOCH /* This causes frames to occur 1000x slower */ //#define OHCI_TIME_WARP 1 -#ifdef DEBUG_OHCI -#define DPRINTF printf -#else -#define DPRINTF(...) -#endif - /* Number of Downstream Ports on the root hub. */ #define OHCI_MAX_PORTS 15 @@ -350,7 +341,7 @@ static void ohci_attach(USBPort *port1) ohci_set_interrupt(s, OHCI_INTR_RD); } - DPRINTF("usb-ohci: Attached port %d\n", port1->index); + trace_usb_ohci_port_attach(port1->index); if (old_state != port->ctrl) { ohci_set_interrupt(s, OHCI_INTR_RHSC); @@ -375,7 +366,7 @@ static void ohci_detach(USBPort *port1) port->ctrl &= ~OHCI_PORT_PES; port->ctrl |= OHCI_PORT_PESC; } - DPRINTF("usb-ohci: Detached port %d\n", port1->index); + trace_usb_ohci_port_detach(port1->index); if (old_state != port->ctrl) { ohci_set_interrupt(s, OHCI_INTR_RHSC); @@ -388,14 +379,14 @@ static void ohci_wakeup(USBPort *port1) OHCIPort *port = &s->rhport[port1->index]; uint32_t intr = 0; if (port->ctrl & OHCI_PORT_PSS) { - DPRINTF("usb-ohci: port %d: wakeup\n", port1->index); + trace_usb_ohci_port_wakeup(port1->index); port->ctrl |= OHCI_PORT_PSSC; port->ctrl &= ~OHCI_PORT_PSS; intr = OHCI_INTR_RHSC; } /* Note that the controller can be suspended even if this port is not */ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { - DPRINTF("usb-ohci: remote-wakeup: SUSPEND->RESUME\n"); + trace_usb_ohci_remote_wakeup(s->name); /* This is the one state transition the controller can do by itself */ s->ctl &= ~OHCI_CTL_HCFS; s->ctl |= OHCI_USB_RESUME; @@ -497,7 +488,7 @@ static void ohci_reset(void *opaque) ohci->async_td = 0; } ohci_stop_endpoints(ohci); - DPRINTF("usb-ohci: Reset %s\n", ohci->name); + trace_usb_ohci_reset(ohci->name); } /* Get an array of dwords from main memory */ @@ -690,9 +681,8 @@ static void ohci_process_lists(OHCIState *ohci, int completion); static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) { OHCIState *ohci = container_of(packet, OHCIState, usb_packet); -#ifdef DEBUG_PACKET - DPRINTF("Async packet complete\n"); -#endif + + trace_usb_ohci_async_complete(); ohci->async_complete = true; ohci_process_lists(ohci, 1); } @@ -704,9 +694,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, { int dir; size_t len = 0; -#ifdef DEBUG_ISOCH const char *str = NULL; -#endif int pid; int ret; int i; @@ -723,7 +711,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, addr = ed->head & OHCI_DPTR_MASK; if (ohci_read_iso_td(ohci, addr, &iso_td)) { - printf("usb-ohci: ISO_TD read error at %x\n", addr); + trace_usb_ohci_iso_td_read_failed(addr); ohci_die(ohci); return 0; } @@ -732,31 +720,25 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, frame_count = OHCI_BM(iso_td.flags, TD_FC); relative_frame_number = USUB(ohci->frame_number, starting_frame); -#ifdef DEBUG_ISOCH - printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n" - "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" - "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" - "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" - "frame_number 0x%.8x starting_frame 0x%.8x\n" - "frame_count 0x%.8x relative %d\n" - "di 0x%.8x cc 0x%.8x\n", + trace_usb_ohci_iso_td_head( ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK, iso_td.flags, iso_td.bp, iso_td.next, iso_td.be, - iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3], - iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7], - ohci->frame_number, starting_frame, - frame_count, relative_frame_number, - OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC)); -#endif + ohci->frame_number, starting_frame, + frame_count, relative_frame_number); + trace_usb_ohci_iso_td_head_offset( + iso_td.offset[0], iso_td.offset[1], + iso_td.offset[2], iso_td.offset[3], + iso_td.offset[4], iso_td.offset[5], + iso_td.offset[6], iso_td.offset[7]); if (relative_frame_number < 0) { - DPRINTF("usb-ohci: ISO_TD R=%d < 0\n", relative_frame_number); + trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number); return 1; } else if (relative_frame_number > frame_count) { /* ISO TD expired - retire the TD to the Done Queue and continue with the next ISO TD of the same ED */ - DPRINTF("usb-ohci: ISO_TD R=%d > FC=%d\n", relative_frame_number, - frame_count); + trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number, + frame_count); OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); ed->head &= ~OHCI_DPTR_MASK; ed->head |= (iso_td.next & OHCI_DPTR_MASK); @@ -775,30 +757,24 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, dir = OHCI_BM(ed->flags, ED_D); switch (dir) { case OHCI_TD_DIR_IN: -#ifdef DEBUG_ISOCH str = "in"; -#endif pid = USB_TOKEN_IN; break; case OHCI_TD_DIR_OUT: -#ifdef DEBUG_ISOCH str = "out"; -#endif pid = USB_TOKEN_OUT; break; case OHCI_TD_DIR_SETUP: -#ifdef DEBUG_ISOCH str = "setup"; -#endif pid = USB_TOKEN_SETUP; break; default: - printf("usb-ohci: Bad direction %d\n", dir); + trace_usb_ohci_iso_td_bad_direction(dir); return 1; } if (!iso_td.bp || !iso_td.be) { - printf("usb-ohci: ISO_TD bp 0x%.8x be 0x%.8x\n", iso_td.bp, iso_td.be); + trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be); return 1; } @@ -808,14 +784,12 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || ((relative_frame_number < frame_count) && !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) { - printf("usb-ohci: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n", - start_offset, next_offset); + trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset); return 1; } if ((relative_frame_number < frame_count) && (start_offset > next_offset)) { - printf("usb-ohci: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n", - start_offset, next_offset); + trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset); return 1; } @@ -875,10 +849,8 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, ret = ohci->usb_packet.status; } -#ifdef DEBUG_ISOCH - printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n", - start_offset, end_offset, start_addr, end_addr, str, len, ret); -#endif + trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr, + str, len, ret); /* Writeback */ if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) { @@ -898,13 +870,13 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); } else { if (ret > (ssize_t) len) { - printf("usb-ohci: DataOverrun %d > %zu\n", ret, len); + trace_usb_ohci_iso_td_data_overrun(ret, len); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, OHCI_CC_DATAOVERRUN); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, len); } else if (ret >= 0) { - printf("usb-ohci: DataUnderrun %d\n", ret); + trace_usb_ohci_iso_td_data_underrun(ret); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, OHCI_CC_DATAUNDERRUN); } else { @@ -918,14 +890,14 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, break; case USB_RET_NAK: case USB_RET_STALL: - printf("usb-ohci: got NAK/STALL %d\n", ret); + trace_usb_ohci_iso_td_nak(ret); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, OHCI_CC_STALL); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); break; default: - printf("usb-ohci: Bad device response %d\n", ret); + trace_usb_ohci_iso_td_bad_response(ret); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, OHCI_CC_UNDEXPETEDPID); break; @@ -950,6 +922,43 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, return 1; } +#ifdef trace_event_get_state +static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) +{ + bool print16 = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_SHORT); + bool printall = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_FULL); + const int width = 16; + int i; + char tmp[3 * width + 1]; + char *p = tmp; + + if (!printall && !print16) { + return; + } + + for (i = 0; ; i++) { + if (i && (!(i % width) || (i == len))) { + if (!printall) { + trace_usb_ohci_td_pkt_short(msg, tmp); + break; + } + trace_usb_ohci_td_pkt_full(msg, tmp); + p = tmp; + *p = 0; + } + if (i == len) { + break; + } + + p += sprintf(p, " %.2x", buf[i]); + } +} +#else +static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) +{ +} +#endif + /* Service a transport descriptor. Returns nonzero to terminate processing of this endpoint. */ @@ -957,9 +966,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) { int dir; size_t len = 0, pktlen = 0; -#ifdef DEBUG_PACKET const char *str = NULL; -#endif int pid; int ret; int i; @@ -974,13 +981,11 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) /* See if this TD has already been submitted to the device. */ completion = (addr == ohci->async_td); if (completion && !ohci->async_complete) { -#ifdef DEBUG_PACKET - DPRINTF("Skipping async TD\n"); -#endif + trace_usb_ohci_td_skip_async(); return 1; } if (ohci_read_td(ohci, addr, &td)) { - fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); + trace_usb_ohci_td_read_error(addr); ohci_die(ohci); return 0; } @@ -998,25 +1003,19 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) switch (dir) { case OHCI_TD_DIR_IN: -#ifdef DEBUG_PACKET str = "in"; -#endif pid = USB_TOKEN_IN; break; case OHCI_TD_DIR_OUT: -#ifdef DEBUG_PACKET str = "out"; -#endif pid = USB_TOKEN_OUT; break; case OHCI_TD_DIR_SETUP: -#ifdef DEBUG_PACKET str = "setup"; -#endif pid = USB_TOKEN_SETUP; break; default: - fprintf(stderr, "usb-ohci: Bad direction\n"); + trace_usb_ohci_td_bad_direction(dir); return 1; } if (td.cbp && td.be) { @@ -1043,19 +1042,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) } flag_r = (td.flags & OHCI_TD_R) != 0; -#ifdef DEBUG_PACKET - DPRINTF(" TD @ 0x%.8x %" PRId64 " of %" PRId64 - " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", - addr, (int64_t)pktlen, (int64_t)len, str, flag_r, td.cbp, td.be); - - if (pktlen > 0 && dir != OHCI_TD_DIR_IN) { - DPRINTF(" data:"); - for (i = 0; i < pktlen; i++) { - printf(" %.2x", ohci->usb_buf[i]); - } - DPRINTF("\n"); - } -#endif + trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str, + flag_r, td.cbp, td.be); + ohci_td_pkt("OUT", ohci->usb_buf, pktlen); + if (completion) { ohci->async_td = 0; ohci->async_complete = false; @@ -1066,9 +1056,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) This should be sufficient as long as devices respond in a timely manner. */ -#ifdef DEBUG_PACKET - DPRINTF("Too many pending packets\n"); -#endif + trace_usb_ohci_td_too_many_pending(); return 1; } dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); @@ -1077,9 +1065,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) OHCI_BM(td.flags, TD_DI) == 0); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); usb_handle_packet(dev, &ohci->usb_packet); -#ifdef DEBUG_PACKET - DPRINTF("status=%d\n", ohci->usb_packet.status); -#endif + trace_usb_ohci_td_packet_status(ohci->usb_packet.status); + if (ohci->usb_packet.status == USB_RET_ASYNC) { usb_device_flush_ep_queue(dev, ep); ohci->async_td = addr; @@ -1098,12 +1085,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) DMA_DIRECTION_FROM_DEVICE)) { ohci_die(ohci); } -#ifdef DEBUG_PACKET - DPRINTF(" data:"); - for (i = 0; i < ret; i++) - printf(" %.2x", ohci->usb_buf[i]); - DPRINTF("\n"); -#endif + ohci_td_pkt("IN", ohci->usb_buf, pktlen); } else { ret = pktlen; } @@ -1137,28 +1119,28 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) ed->head |= OHCI_ED_C; } else { if (ret >= 0) { - DPRINTF("usb-ohci: Underrun\n"); + trace_usb_ohci_td_underrun(); OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); } else { switch (ret) { case USB_RET_IOERROR: case USB_RET_NODEV: - DPRINTF("usb-ohci: got DEV ERROR\n"); + trace_usb_ohci_td_dev_error(); OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); break; case USB_RET_NAK: - DPRINTF("usb-ohci: got NAK\n"); + trace_usb_ohci_td_nak(); return 1; case USB_RET_STALL: - DPRINTF("usb-ohci: got STALL\n"); + trace_usb_ohci_td_stall(); OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); break; case USB_RET_BABBLE: - DPRINTF("usb-ohci: got BABBLE\n"); + trace_usb_ohci_td_babble(); OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); break; default: - fprintf(stderr, "usb-ohci: Bad device response %d\n", ret); + trace_usb_ohci_td_bad_device_response(ret); OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); OHCI_SET_BM(td.flags, TD_EC, 3); break; @@ -1198,7 +1180,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) for (cur = head; cur; cur = next_ed) { if (ohci_read_ed(ohci, cur, &ed)) { - fprintf(stderr, "usb-ohci: ED read error at %x\n", cur); + trace_usb_ohci_ed_read_error(cur); ohci_die(ohci); return 0; } @@ -1219,16 +1201,15 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) } while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { -#ifdef DEBUG_PACKET - DPRINTF("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u " - "h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur, + trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0, + (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, + ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); + trace_usb_ohci_ed_pkt_flags( OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, - OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0, - (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, - ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); -#endif + OHCI_BM(ed.flags, ED_MPS)); + active = 1; if ((ed.flags & OHCI_ED_F) == 0) { @@ -1263,8 +1244,7 @@ static void ohci_process_lists(OHCIState *ohci, int completion) { if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) { - DPRINTF("usb-ohci: head %x, cur %x\n", - ohci->ctrl_head, ohci->ctrl_cur); + trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur); } if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) { ohci->ctrl_cur = 0; @@ -1287,7 +1267,7 @@ static void ohci_frame_boundary(void *opaque) struct ohci_hcca hcca; if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) { - fprintf(stderr, "usb-ohci: HCCA read error at %x\n", ohci->hcca); + trace_usb_ohci_hcca_read_error(ohci->hcca); ohci_die(ohci); return; } @@ -1356,12 +1336,12 @@ static int ohci_bus_start(OHCIState *ohci) ohci); if (ohci->eof_timer == NULL) { - fprintf(stderr, "usb-ohci: %s: timer_new_ns failed\n", ohci->name); + trace_usb_ohci_bus_eof_timer_failed(ohci->name); ohci_die(ohci); return 0; } - DPRINTF("usb-ohci: %s: USB Operational\n", ohci->name); + trace_usb_ohci_start(ohci->name); ohci_sof(ohci); @@ -1371,6 +1351,7 @@ static int ohci_bus_start(OHCIState *ohci) /* Stop sending SOF tokens on the bus */ static void ohci_bus_stop(OHCIState *ohci) { + trace_usb_ohci_stop(ohci->name); if (ohci->eof_timer) { timer_del(ohci->eof_timer); timer_free(ohci->eof_timer); @@ -1416,8 +1397,7 @@ static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) val &= OHCI_FMI_FI; if (val != ohci->fi) { - DPRINTF("usb-ohci: %s: FrameInterval = 0x%x (%u)\n", - ohci->name, ohci->fi, ohci->fi); + trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi); } ohci->fi = val; @@ -1449,20 +1429,19 @@ static void ohci_set_ctl(OHCIState *ohci, uint32_t val) if (old_state == new_state) return; + trace_usb_ohci_set_ctl(ohci->name, new_state); switch (new_state) { case OHCI_USB_OPERATIONAL: ohci_bus_start(ohci); break; case OHCI_USB_SUSPEND: ohci_bus_stop(ohci); - DPRINTF("usb-ohci: %s: USB Suspended\n", ohci->name); break; case OHCI_USB_RESUME: - DPRINTF("usb-ohci: %s: USB Resume\n", ohci->name); + trace_usb_ohci_resume(ohci->name); break; case OHCI_USB_RESET: ohci_reset(ohci); - DPRINTF("usb-ohci: %s: USB Reset\n", ohci->name); break; } } @@ -1507,7 +1486,7 @@ static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) for (i = 0; i < ohci->num_ports; i++) ohci_port_power(ohci, i, 0); - DPRINTF("usb-ohci: powered down all ports\n"); + trace_usb_ohci_hub_power_down(); } if (val & OHCI_RHS_LPSC) { @@ -1515,7 +1494,7 @@ static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) for (i = 0; i < ohci->num_ports; i++) ohci_port_power(ohci, i, 1); - DPRINTF("usb-ohci: powered up all ports\n"); + trace_usb_ohci_hub_power_up(); } if (val & OHCI_RHS_DRWE) @@ -1547,11 +1526,11 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) { - DPRINTF("usb-ohci: port %d: SUSPEND\n", portnum); + trace_usb_ohci_port_suspend(portnum); } if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { - DPRINTF("usb-ohci: port %d: RESET\n", portnum); + trace_usb_ohci_port_reset(portnum); usb_device_reset(port->port.dev); port->ctrl &= ~OHCI_PORT_PRS; /* ??? Should this also set OHCI_PORT_PESC. */ @@ -1579,7 +1558,7 @@ static uint64_t ohci_mem_read(void *opaque, /* Only aligned reads are allowed on OHCI */ if (addr & 3) { - fprintf(stderr, "usb-ohci: Mis-aligned read\n"); + trace_usb_ohci_mem_read_unaligned(addr); return 0xffffffff; } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { /* HcRhPortStatus */ @@ -1685,7 +1664,7 @@ static uint64_t ohci_mem_read(void *opaque, break; default: - fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); + trace_usb_ohci_mem_read_bad_offset(addr); retval = 0xffffffff; } } @@ -1702,7 +1681,7 @@ static void ohci_mem_write(void *opaque, /* Only aligned reads are allowed on OHCI */ if (addr & 3) { - fprintf(stderr, "usb-ohci: Mis-aligned write\n"); + trace_usb_ohci_mem_write_unaligned(addr); return; } @@ -1816,7 +1795,7 @@ static void ohci_mem_write(void *opaque, break; default: - fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); + trace_usb_ohci_mem_write_bad_offset(addr); break; } } @@ -1869,8 +1848,7 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev, usb_bit_time = 1; } #endif - DPRINTF("usb-ohci: usb_bit_time=%" PRId64 " usb_frame_time=%" PRId64 "\n", - usb_frame_time, usb_bit_time); + trace_usb_ohci_init_time(usb_frame_time, usb_bit_time); } ohci->num_ports = num_ports; @@ -1928,7 +1906,7 @@ static void ohci_die(OHCIState *ohci) { OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); - fprintf(stderr, "%s: DMA error\n", __func__); + trace_usb_ohci_die(); ohci_set_interrupt(ohci, OHCI_INTR_UE); ohci_bus_stop(ohci); @@ -1959,6 +1937,7 @@ static void usb_ohci_exit(PCIDevice *dev) OHCIPCIState *ohci = PCI_OHCI(dev); OHCIState *s = &ohci->state; + trace_usb_ohci_exit(s->name); ohci_bus_stop(s); if (s->async_td) { diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 3b3ebcda8b..5b88f3070f 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1279,13 +1279,18 @@ static void usb_uhci_exit(PCIDevice *dev) } } -static Property uhci_properties[] = { +static Property uhci_properties_companion[] = { DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280), DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128), DEFINE_PROP_END_OF_LIST(), }; +static Property uhci_properties_standalone[] = { + DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280), + DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128), + DEFINE_PROP_END_OF_LIST(), +}; static void uhci_class_init(ObjectClass *klass, void *data) { @@ -1300,9 +1305,14 @@ static void uhci_class_init(ObjectClass *klass, void *data) k->device_id = info->device_id; k->revision = info->revision; k->class_id = PCI_CLASS_SERIAL_USB; - dc->hotpluggable = false; dc->vmsd = &vmstate_uhci; - dc->props = uhci_properties; + if (!info->unplug) { + /* uhci controllers in companion setups can't be hotplugged */ + dc->hotpluggable = false; + dc->props = uhci_properties_companion; + } else { + dc->props = uhci_properties_standalone; + } set_bit(DEVICE_CATEGORY_USB, dc->categories); u->info = *info; } diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 73ced1f5f8..c556367cb1 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3874,7 +3874,6 @@ static void xhci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xhci; dc->props = xhci_properties; dc->reset = xhci_reset; - dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_USB, dc->categories); k->init = usb_xhci_initfn; k->exit = usb_xhci_exit; diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index c189147f91..45b74e5307 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -275,7 +275,7 @@ static void usb_host_libusb_error(const char *func, int rc) } else { errname = "?"; } - fprintf(stderr, "%s: %d [%s]\n", func, rc, errname); + error_report("%s: %d [%s]", func, rc, errname); } /* ------------------------------------------------------------------------ */ @@ -834,6 +834,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev) int bus_num = libusb_get_bus_number(dev); int addr = libusb_get_device_address(dev); int rc; + Error *local_err = NULL; trace_usb_host_open_started(bus_num, addr); @@ -869,8 +870,10 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev) "host:%d.%d", bus_num, addr); } - rc = usb_device_attach(udev); - if (rc) { + usb_device_attach(udev, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); goto fail; } @@ -948,21 +951,21 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data) } } -static int usb_host_initfn(USBDevice *udev) +static void usb_host_realize(USBDevice *udev, Error **errp) { USBHostDevice *s = USB_HOST_DEVICE(udev); if (s->match.vendor_id > 0xffff) { - error_report("vendorid out of range"); - return -1; + error_setg(errp, "vendorid out of range"); + return; } if (s->match.product_id > 0xffff) { - error_report("productid out of range"); - return -1; + error_setg(errp, "productid out of range"); + return; } if (s->match.addr > 127) { - error_report("hostaddr out of range"); - return -1; + error_setg(errp, "hostaddr out of range"); + return; } loglevel = s->loglevel; @@ -977,7 +980,6 @@ static int usb_host_initfn(USBDevice *udev) QTAILQ_INSERT_TAIL(&hostdevs, s, next); add_boot_device_path(s->bootindex, &udev->qdev, NULL); usb_host_auto_check(NULL); - return 0; } static void usb_host_handle_destroy(USBDevice *udev) @@ -1374,14 +1376,13 @@ static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps, if (rc < 0) { usb_host_libusb_error("libusb_alloc_streams", rc); } else if (rc != streams) { - fprintf(stderr, - "libusb_alloc_streams: got less streams then requested %d < %d\n", - rc, streams); + error_report("libusb_alloc_streams: got less streams " + "then requested %d < %d", rc, streams); } return (rc == streams) ? 0 : -1; #else - fprintf(stderr, "libusb_alloc_streams: error not implemented\n"); + error_report("libusb_alloc_streams: error not implemented"); return -1; #endif } @@ -1477,7 +1478,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_host_initfn; + uc->realize = usb_host_realize; uc->product_desc = "USB Host Device"; uc->cancel_packet = usb_host_cancel_packet; uc->handle_data = usb_host_handle_data; diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 44522d9005..e2c98962a2 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1256,6 +1256,7 @@ static void usbredir_device_reject_bh(void *opaque) static void usbredir_do_attach(void *opaque) { USBRedirDevice *dev = opaque; + Error *local_err = NULL; /* In order to work properly with XHCI controllers we need these caps */ if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !( @@ -1270,7 +1271,10 @@ static void usbredir_do_attach(void *opaque) return; } - if (usb_device_attach(&dev->dev) != 0) { + usb_device_attach(&dev->dev, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); WARNING("rejecting device due to speed mismatch\n"); usbredir_reject_device(dev); } @@ -1357,14 +1361,14 @@ static void usbredir_init_endpoints(USBRedirDevice *dev) } } -static int usbredir_initfn(USBDevice *udev) +static void usbredir_realize(USBDevice *udev, Error **errp) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); int i; if (dev->cs == NULL) { - qerror_report(QERR_MISSING_PARAMETER, "chardev"); - return -1; + error_set(errp, QERR_MISSING_PARAMETER, "chardev"); + return; } if (dev->filter_str) { @@ -1372,9 +1376,9 @@ static int usbredir_initfn(USBDevice *udev) &dev->filter_rules, &dev->filter_rules_count); if (i) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter", - "a usb device filter string"); - return -1; + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "filter", + "a usb device filter string"); + return; } } @@ -1398,7 +1402,6 @@ static int usbredir_initfn(USBDevice *udev) qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); add_boot_device_path(dev->bootindex, &udev->qdev, NULL); - return 0; } static void usbredir_cleanup_device_queues(USBRedirDevice *dev) @@ -2477,7 +2480,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) USBDeviceClass *uc = USB_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - uc->init = usbredir_initfn; + uc->realize = usbredir_realize; uc->product_desc = "USB Redirection Device"; uc->handle_destroy = usbredir_handle_destroy; uc->cancel_packet = usbredir_cancel_packet; diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index ec9e855bc1..d21c397756 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -2,7 +2,7 @@ common-obj-y += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o common-obj-y += virtio-bus.o common-obj-y += virtio-mmio.o -common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/ +common-obj-$(CONFIG_VIRTIO) += dataplane/ obj-y += virtio.o virtio-balloon.o obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 67cb2b823e..372706a234 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -181,7 +181,8 @@ static int get_desc(Vring *vring, VirtQueueElement *elem, /* Stop for now if there are not enough iovecs available. */ if (*num >= VIRTQUEUE_MAX_SIZE) { - return -ENOBUFS; + error_report("Invalid SG num: %u", *num); + return -EFAULT; } /* TODO handle non-contiguous memory across region boundaries */ diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index ddb5da181c..f5608140f9 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -86,9 +86,6 @@ * 12 is historical, and due to x86 page size. */ #define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 -/* Flags track per-device state like workarounds for quirks in older guests. */ -#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0) - static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, VirtIOPCIProxy *dev); @@ -314,12 +311,14 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) msix_unuse_all_vectors(&proxy->pci_dev); } - /* Linux before 2.6.34 sets the device as OK without enabling - the PCI device bus master bit. In this case we need to disable - some safety checks. */ - if ((val & VIRTIO_CONFIG_S_DRIVER_OK) && - !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { - proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; + /* Linux before 2.6.34 drives the device without enabling + the PCI device bus master bit. Enable it automatically + for the guest. This is a PCI spec violation but so is + initiating DMA with bus master bit clear. */ + if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) { + pci_default_write_config(&proxy->pci_dev, PCI_COMMAND, + proxy->pci_dev.config[PCI_COMMAND] | + PCI_COMMAND_MASTER, 1); } break; case VIRTIO_MSI_CONFIG_VECTOR: @@ -470,13 +469,18 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + uint8_t cmd = proxy->pci_dev.config[PCI_COMMAND]; + pci_default_write_config(pci_dev, address, val, len); if (range_covers_byte(address, len, PCI_COMMAND) && !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) && - !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) { + (cmd & PCI_COMMAND_MASTER)) { + /* Bus driver disables bus mastering - make it act + * as a kind of reset to render the device quiescent. */ virtio_pci_stop_ioeventfd(proxy); - virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK); + virtio_reset(vdev); + msix_unuse_all_vectors(&proxy->pci_dev); } } @@ -885,11 +889,19 @@ static void virtio_pci_vmstate_change(DeviceState *d, bool running) VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); if (running) { - /* Try to find out if the guest has bus master disabled, but is - in ready state. Then we have a buggy guest OS. */ - if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && - !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { - proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; + /* Linux before 2.6.34 drives the device without enabling + the PCI device bus master bit. Enable it automatically + for the guest. This is a PCI spec violation but so is + initiating DMA with bus master bit clear. + Note: this only makes a difference when migrating + across QEMU versions from an old QEMU, as for new QEMU + bus master and driver bits are always in sync. + TODO: consider enabling conditionally for compat machine types. */ + if (vdev->status & (VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER)) { + pci_default_write_config(&proxy->pci_dev, PCI_COMMAND, + proxy->pci_dev.config[PCI_COMMAND] | + PCI_COMMAND_MASTER, 1); } virtio_pci_start_ioeventfd(proxy); } else { @@ -1030,7 +1042,6 @@ static void virtio_pci_reset(DeviceState *qdev) virtio_pci_stop_ioeventfd(proxy); virtio_bus_reset(bus); msix_unuse_all_vectors(&proxy->pci_dev); - proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG; } static Property virtio_pci_properties[] = { diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index ac222385d6..5c981801f3 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1108,10 +1108,7 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state) BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK); - - if (running) { - vdev->vm_running = running; - } + vdev->vm_running = running; if (backend_run) { virtio_set_status(vdev, vdev->status); @@ -1124,10 +1121,6 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state) if (!backend_run) { virtio_set_status(vdev, vdev->status); } - - if (!running) { - vdev->vm_running = running; - } } void virtio_init(VirtIODevice *vdev, const char *name, |