diff options
Diffstat (limited to 'hw')
42 files changed, 1023 insertions, 1062 deletions
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 2b55d52150..5f8a878f20 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -581,7 +581,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3 if (st->ctl & 0x01) { /* reset */ dprint(d, 1, "st #%d: reset\n", reg->stream); - st->ctl = SD_STS_FIFO_READY << 24; + st->ctl = SD_STS_FIFO_READY << 24 | SD_CTL_STREAM_RESET; } if ((st->ctl & 0x02) != (old & 0x02)) { uint32_t stnr = (st->ctl >> 20) & 0x0f; diff --git a/hw/block/block.c b/hw/block/block.c index d47ebf005a..25f45df723 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -171,8 +171,7 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, perm |= BLK_PERM_WRITE; } - shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | - BLK_PERM_GRAPH_MOD; + shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED; if (resizable) { shared_perm |= BLK_PERM_RESIZE; } diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index ee5a5352dc..49276e46f2 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -154,17 +154,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) g_free(s); } -static bool virtio_blk_data_plane_handle_output(VirtIODevice *vdev, - VirtQueue *vq) -{ - VirtIOBlock *s = (VirtIOBlock *)vdev; - - assert(s->dataplane); - assert(s->dataplane_started); - - return virtio_blk_handle_vq(s, vq); -} - /* Context: QEMU global mutex held */ int virtio_blk_data_plane_start(VirtIODevice *vdev) { @@ -258,8 +247,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) for (i = 0; i < nvqs; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, - virtio_blk_data_plane_handle_output); + virtio_queue_aio_attach_host_notifier(vq, s->ctx); } aio_context_release(s->ctx); return 0; @@ -302,7 +290,7 @@ static void virtio_blk_data_plane_stop_bh(void *opaque) for (i = 0; i < s->conf->num_queues; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL); + virtio_queue_aio_detach_host_notifier(vq, s->ctx); } } diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index f139cd7cc9..82676cdd01 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -767,12 +767,11 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) return 0; } -bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) +void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) { VirtIOBlockReq *req; MultiReqBuffer mrb = {}; bool suppress_notifications = virtio_queue_get_notification(vq); - bool progress = false; aio_context_acquire(blk_get_aio_context(s->blk)); blk_io_plug(s->blk); @@ -783,7 +782,6 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) } while ((req = virtio_blk_get_request(s, vq))) { - progress = true; if (virtio_blk_handle_request(req, &mrb)) { virtqueue_detach_element(req->vq, &req->elem, 0); virtio_blk_free_request(req); @@ -802,19 +800,13 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) blk_io_unplug(s->blk); aio_context_release(blk_get_aio_context(s->blk)); - return progress; -} - -static void virtio_blk_handle_output_do(VirtIOBlock *s, VirtQueue *vq) -{ - virtio_blk_handle_vq(s, vq); } static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBlock *s = (VirtIOBlock *)vdev; - if (s->dataplane) { + if (s->dataplane && !s->dataplane_started) { /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start * dataplane here instead of waiting for .set_status(). */ @@ -823,7 +815,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) return; } } - virtio_blk_handle_output_do(s, vq); + virtio_blk_handle_vq(s, vq); } void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) diff --git a/hw/display/Kconfig b/hw/display/Kconfig index a2306b67d8..a1b159becd 100644 --- a/hw/display/Kconfig +++ b/hw/display/Kconfig @@ -49,7 +49,7 @@ config VGA_ISA depends on ISA_BUS select VGA -config VGA_ISA_MM +config VGA_MMIO bool select VGA diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index f2b874d5e3..bccf32af69 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -24,6 +24,9 @@ static const struct edid_mode { { .xres = 2048, .yres = 1152 }, { .xres = 1920, .yres = 1080, .dta = 31 }, + /* dea/dta extension timings (all @ 60 Hz) */ + { .xres = 3840, .yres = 2160, .dta = 97 }, + /* additional standard timings 3 (all @ 60Hz) */ { .xres = 1920, .yres = 1200, .xtra3 = 10, .bit = 0 }, { .xres = 1600, .yres = 1200, .xtra3 = 9, .bit = 2 }, @@ -401,10 +404,10 @@ void qemu_edid_generate(uint8_t *edid, size_t size, info->name = "QEMU Monitor"; } if (!info->prefx) { - info->prefx = 1024; + info->prefx = 1280; } if (!info->prefy) { - info->prefy = 768; + info->prefy = 800; } if (info->prefx >= 4096 || info->prefy >= 4096) { large_screen = 1; diff --git a/hw/display/macfb.c b/hw/display/macfb.c index 277d3e6633..4bd7c3ad6a 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -661,9 +661,9 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp) memory_region_init_ram(&s->mem_vram, OBJECT(dev), "macfb-vram", MACFB_VRAM_SIZE, &error_abort); + memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA); s->vram = memory_region_get_ram_ptr(&s->mem_vram); s->vram_bit_mask = MACFB_VRAM_SIZE - 1; - memory_region_set_coalescing(&s->mem_vram); s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s); macfb_update_mode(s); diff --git a/hw/display/meson.build b/hw/display/meson.build index 861c43ff98..adc53dd8b6 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -18,7 +18,7 @@ softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xenfb.c')) softmmu_ss.add(when: 'CONFIG_VGA_PCI', if_true: files('vga-pci.c')) softmmu_ss.add(when: 'CONFIG_VGA_ISA', if_true: files('vga-isa.c')) -softmmu_ss.add(when: 'CONFIG_VGA_ISA_MM', if_true: files('vga-isa-mm.c')) +softmmu_ss.add(when: 'CONFIG_VGA_MMIO', if_true: files('vga-mmio.c')) softmmu_ss.add(when: 'CONFIG_VMWARE_VGA', if_true: files('vmware_vga.c')) softmmu_ss.add(when: 'CONFIG_BOCHS_DISPLAY', if_true: files('bochs-display.c')) diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c deleted file mode 100644 index 7321b7a06d..0000000000 --- a/hw/display/vga-isa-mm.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * QEMU ISA MM VGA Emulator. - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qemu/bitops.h" -#include "qemu/units.h" -#include "migration/vmstate.h" -#include "hw/display/vga.h" -#include "vga_int.h" -#include "ui/pixel_ops.h" - -#define VGA_RAM_SIZE (8 * MiB) - -typedef struct ISAVGAMMState { - VGACommonState vga; - int it_shift; -} ISAVGAMMState; - -/* Memory mapped interface */ -static uint64_t vga_mm_read(void *opaque, hwaddr addr, unsigned size) -{ - ISAVGAMMState *s = opaque; - - return vga_ioport_read(&s->vga, addr >> s->it_shift) & - MAKE_64BIT_MASK(0, size * 8); -} - -static void vga_mm_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - ISAVGAMMState *s = opaque; - - vga_ioport_write(&s->vga, addr >> s->it_shift, - value & MAKE_64BIT_MASK(0, size * 8)); -} - -static const MemoryRegionOps vga_mm_ctrl_ops = { - .read = vga_mm_read, - .write = vga_mm_write, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .impl.min_access_size = 1, - .impl.max_access_size = 4, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void vga_mm_init(ISAVGAMMState *s, hwaddr vram_base, - hwaddr ctrl_base, int it_shift, - MemoryRegion *address_space) -{ - MemoryRegion *s_ioport_ctrl, *vga_io_memory; - - s->it_shift = it_shift; - s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl)); - memory_region_init_io(s_ioport_ctrl, NULL, &vga_mm_ctrl_ops, s, - "vga-mm-ctrl", 0x100000); - memory_region_set_flush_coalesced(s_ioport_ctrl); - - vga_io_memory = g_malloc(sizeof(*vga_io_memory)); - /* XXX: endianness? */ - memory_region_init_io(vga_io_memory, NULL, &vga_mem_ops, &s->vga, - "vga-mem", 0x20000); - - vmstate_register(NULL, 0, &vmstate_vga_common, s); - - memory_region_add_subregion(address_space, ctrl_base, s_ioport_ctrl); - s->vga.bank_offset = 0; - memory_region_add_subregion(address_space, - vram_base + 0x000a0000, vga_io_memory); - memory_region_set_coalescing(vga_io_memory); -} - -int isa_vga_mm_init(hwaddr vram_base, - hwaddr ctrl_base, int it_shift, - MemoryRegion *address_space) -{ - ISAVGAMMState *s; - - s = g_malloc0(sizeof(*s)); - - s->vga.vram_size_mb = VGA_RAM_SIZE / MiB; - s->vga.global_vmstate = true; - vga_common_init(&s->vga, NULL); - vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space); - - s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s); - - memory_region_add_subregion(address_space, - VBE_DISPI_LFB_PHYSICAL_ADDRESS, - &s->vga.vram); - - return 0; -} diff --git a/hw/display/vga-mmio.c b/hw/display/vga-mmio.c new file mode 100644 index 0000000000..4969368081 --- /dev/null +++ b/hw/display/vga-mmio.c @@ -0,0 +1,139 @@ +/* + * QEMU MMIO VGA Emulator. + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "hw/display/vga.h" +#include "hw/qdev-properties.h" +#include "vga_int.h" + +/* + * QEMU interface: + * + sysbus MMIO region 0: VGA I/O registers + * + sysbus MMIO region 1: VGA MMIO registers + * + sysbus MMIO region 2: VGA memory + */ + +OBJECT_DECLARE_SIMPLE_TYPE(VGAMmioState, VGA_MMIO) + +struct VGAMmioState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + VGACommonState vga; + MemoryRegion iomem; + MemoryRegion lowmem; + + uint8_t it_shift; +}; + +static uint64_t vga_mm_read(void *opaque, hwaddr addr, unsigned size) +{ + VGAMmioState *s = opaque; + + return vga_ioport_read(&s->vga, addr >> s->it_shift) & + MAKE_64BIT_MASK(0, size * 8); +} + +static void vga_mm_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + VGAMmioState *s = opaque; + + vga_ioport_write(&s->vga, addr >> s->it_shift, + value & MAKE_64BIT_MASK(0, size * 8)); +} + +static const MemoryRegionOps vga_mm_ctrl_ops = { + .read = vga_mm_read, + .write = vga_mm_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void vga_mmio_reset(DeviceState *dev) +{ + VGAMmioState *s = VGA_MMIO(dev); + + vga_common_reset(&s->vga); +} + +static void vga_mmio_realizefn(DeviceState *dev, Error **errp) +{ + VGAMmioState *s = VGA_MMIO(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(dev), &vga_mm_ctrl_ops, s, + "vga-mmio", 0x100000); + memory_region_set_flush_coalesced(&s->iomem); + sysbus_init_mmio(sbd, &s->iomem); + + /* XXX: endianness? */ + memory_region_init_io(&s->lowmem, OBJECT(dev), &vga_mem_ops, &s->vga, + "vga-lowmem", 0x20000); + memory_region_set_coalescing(&s->lowmem); + sysbus_init_mmio(sbd, &s->lowmem); + + s->vga.bank_offset = 0; + s->vga.global_vmstate = true; + vga_common_init(&s->vga, OBJECT(dev)); + sysbus_init_mmio(sbd, &s->vga.vram); + s->vga.con = graphic_console_init(dev, 0, s->vga.hw_ops, &s->vga); +} + +static Property vga_mmio_properties[] = { + DEFINE_PROP_UINT8("it_shift", VGAMmioState, it_shift, 0), + DEFINE_PROP_UINT32("vgamem_mb", VGAMmioState, vga.vram_size_mb, 8), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vga_mmio_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = vga_mmio_realizefn; + dc->reset = vga_mmio_reset; + dc->vmsd = &vmstate_vga_common; + device_class_set_props(dc, vga_mmio_properties); + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); +} + +static const TypeInfo vga_mmio_info = { + .name = TYPE_VGA_MMIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VGAMmioState), + .class_init = vga_mmio_class_initfn, +}; + +static void vga_mmio_register_types(void) +{ + type_register_static(&vga_mmio_info); +} + +type_init(vga_mmio_register_types) diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index d4a440e815..09818231bd 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -485,9 +485,6 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) { VhostUserGPU *g = VHOST_USER_GPU(vdev); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return false; - } return vhost_virtqueue_pending(&g->vhost->dev, idx); } @@ -496,9 +493,6 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) { VhostUserGPU *g = VHOST_USER_GPU(vdev); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return; - } vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); } diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 9376a8f4ce..6236711e1b 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -123,6 +123,7 @@ typedef struct { int mouse_dx; /* current values, needed for 'poll' mode */ int mouse_dy; int mouse_dz; + int mouse_dw; uint8_t mouse_buttons; } PS2MouseState; @@ -715,7 +716,7 @@ static int ps2_mouse_send_packet(PS2MouseState *s) /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ const int needed = s->mouse_type ? 4 : 3; unsigned int b; - int dx1, dy1, dz1; + int dx1, dy1, dz1, dw1; if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { return 0; @@ -724,6 +725,7 @@ static int ps2_mouse_send_packet(PS2MouseState *s) dx1 = s->mouse_dx; dy1 = s->mouse_dy; dz1 = s->mouse_dz; + dw1 = s->mouse_dw; /* XXX: increase range to 8 bits ? */ if (dx1 > 127) dx1 = 127; @@ -740,6 +742,9 @@ static int ps2_mouse_send_packet(PS2MouseState *s) /* extra byte for IMPS/2 or IMEX */ switch(s->mouse_type) { default: + /* Just ignore the wheels if not supported */ + s->mouse_dz = 0; + s->mouse_dw = 0; break; case 3: if (dz1 > 127) @@ -747,13 +752,41 @@ static int ps2_mouse_send_packet(PS2MouseState *s) else if (dz1 < -127) dz1 = -127; ps2_queue_noirq(&s->common, dz1 & 0xff); + s->mouse_dz -= dz1; + s->mouse_dw = 0; break; case 4: - if (dz1 > 7) - dz1 = 7; - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + /* + * This matches what the Linux kernel expects for exps/2 in + * drivers/input/mouse/psmouse-base.c. Note, if you happen to + * press/release the 4th or 5th buttons at the same moment as a + * horizontal wheel scroll, those button presses will get lost. I'm not + * sure what to do about that, since by this point we don't know + * whether those buttons actually changed state. + */ + if (dw1 != 0) { + if (dw1 > 31) { + dw1 = 31; + } else if (dw1 < -31) { + dw1 = -31; + } + + /* + * linux kernel expects first 6 bits to represent the value + * for horizontal scroll + */ + b = (dw1 & 0x3f) | 0x40; + s->mouse_dw -= dw1; + } else { + if (dz1 > 7) { + dz1 = 7; + } else if (dz1 < -7) { + dz1 = -7; + } + + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + s->mouse_dz -= dz1; + } ps2_queue_noirq(&s->common, b); break; } @@ -764,7 +797,6 @@ static int ps2_mouse_send_packet(PS2MouseState *s) /* update deltas */ s->mouse_dx -= dx1; s->mouse_dy -= dy1; - s->mouse_dz -= dz1; return 1; } @@ -806,6 +838,12 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { s->mouse_dz++; } + + if (btn->button == INPUT_BUTTON_WHEEL_RIGHT) { + s->mouse_dw--; + } else if (btn->button == INPUT_BUTTON_WHEEL_LEFT) { + s->mouse_dw++; + } } else { s->mouse_buttons &= ~bmap[btn->button]; } @@ -833,8 +871,10 @@ static void ps2_mouse_sync(DeviceState *dev) /* if not remote, send event. Multiple events are sent if too big deltas */ while (ps2_mouse_send_packet(s)) { - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) + if (s->mouse_dx == 0 && s->mouse_dy == 0 + && s->mouse_dz == 0 && s->mouse_dw == 0) { break; + } } } } @@ -1036,6 +1076,7 @@ static void ps2_mouse_reset(void *opaque) s->mouse_dx = 0; s->mouse_dy = 0; s->mouse_dz = 0; + s->mouse_dw = 0; s->mouse_buttons = 0; } diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index e4c7c9b88a..55dfe5036f 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -672,12 +672,13 @@ static void q800_init(MachineState *machine) /* Remove qtest_enabled() check once firmware files are in the tree */ if (!qtest_enabled()) { - if (bios_size < 0 || bios_size > MACROM_SIZE) { + if (bios_size <= 0 || bios_size > MACROM_SIZE) { error_report("could not load MacROM '%s'", bios_name); exit(1); } - ptr = rom_ptr(MACROM_ADDR, MACROM_SIZE); + ptr = rom_ptr(MACROM_ADDR, bios_size); + assert(ptr != NULL); stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */ stl_phys(cs->as, 4, MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */ diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 0efa4a45c7..78e926a554 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -304,10 +304,17 @@ type_init(virt_machine_register_types) } \ type_init(machvirt_machine_##major##_##minor##_init); +static void virt_machine_7_0_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE(7, 0, true) + static void virt_machine_6_2_options(MachineClass *mc) { + virt_machine_7_0_options(mc); + compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len); } -DEFINE_VIRT_MACHINE(6, 2, true) +DEFINE_VIRT_MACHINE(6, 2, false) static void virt_machine_6_1_options(MachineClass *mc) { diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index b4c5549ce8..725525358d 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -16,7 +16,7 @@ config JAZZ select I8254 select I8257 select PCSPK - select VGA_ISA_MM + select VGA_MMIO select G364FB select DP8393X select ESP diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index f5a26e174d..44f0d48bfd 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -43,6 +43,7 @@ #include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" #include "hw/display/vga.h" +#include "hw/display/bochs-vbe.h" #include "hw/audio/pcspk.h" #include "hw/input/i8042.h" #include "hw/sysbus.h" @@ -274,7 +275,13 @@ static void mips_jazz_init(MachineState *machine, } break; case JAZZ_PICA61: - isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory()); + dev = qdev_new(TYPE_VGA_MMIO); + qdev_prop_set_uint8(dev, "it_shift", 0); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus_mmio_map(sysbus, 0, 0x60000000); + sysbus_mmio_map(sysbus, 1, 0x400a0000); + sysbus_mmio_map(sysbus, 2, VBE_DISPI_LFB_PHYSICAL_ADDRESS); break; default: break; diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c index 126ee35b70..89d71cfb8e 100644 --- a/hw/net/vhost_net-stub.c +++ b/hw/net/vhost_net-stub.c @@ -101,12 +101,3 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) { return 0; } - -bool vhost_net_config_pending(VHostNetState *net) -{ - return false; -} - -void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) -{ -} diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 9c9fd0a73f..30379d2ca4 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -457,15 +457,6 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, vhost_virtqueue_mask(&net->dev, dev, idx, mask); } -bool vhost_net_config_pending(VHostNetState *net) -{ - return vhost_config_pending(&net->dev); -} - -void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) -{ - vhost_config_mask(&net->dev, dev, mask); -} VHostNetState *get_vhost_net(NetClientState *nc) { VHostNetState *vhost_net = 0; diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 5806a50c8d..cf8ab0f8af 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3168,9 +3168,6 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) VirtIONet *n = VIRTIO_NET(vdev); NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); assert(n->vhost_started); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return vhost_net_config_pending(get_vhost_net(nc->peer)); - } return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); } @@ -3180,11 +3177,8 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, VirtIONet *n = VIRTIO_NET(vdev); NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); assert(n->vhost_started); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - vhost_net_config_mask(get_vhost_net(nc->peer), vdev, mask); - return; - } - vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); + vhost_net_virtqueue_mask(get_vhost_net(nc->peer), + vdev, idx, mask); } static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index c78084cce7..7fb35dc031 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -19,6 +19,7 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "qom/object.h" +#include "sysemu/sysemu.h" #define phb3_error(phb, fmt, ...) \ qemu_log_mask(LOG_GUEST_ERROR, "phb3[%d:%d]: " fmt "\n", \ @@ -981,10 +982,6 @@ static void pnv_phb3_instance_init(Object *obj) /* Power Bus Common Queue */ object_initialize_child(obj, "pbcq", &phb->pbcq, TYPE_PNV_PBCQ); - /* Root Port */ - object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB3_ROOT_PORT); - qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0)); - qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false); } static void pnv_phb3_realize(DeviceState *dev, Error **errp) @@ -994,6 +991,30 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); int i; + /* User created devices */ + if (!phb->chip) { + Error *local_err = NULL; + BusState *s; + + phb->chip = pnv_get_chip(pnv, phb->chip_id); + if (!phb->chip) { + error_setg(errp, "invalid chip id: %d", phb->chip_id); + return; + } + + /* + * Reparent user created devices to the chip to build + * correctly the device tree. + */ + pnv_chip_parent_fixup(phb->chip, OBJECT(phb), phb->phb_id); + + s = qdev_get_parent_bus(DEVICE(phb->chip)); + if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) { + error_propagate(errp, local_err); + return; + } + } + if (phb->phb_id >= PNV_CHIP_GET_CLASS(phb->chip)->num_phbs) { error_setg(errp, "invalid PHB index: %d", phb->phb_id); return; @@ -1053,10 +1074,10 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb); - /* Add a single Root port */ - qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id); - qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id); - qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal); + if (defaults_enabled()) { + pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), + TYPE_PNV_PHB3_ROOT_PORT); + } } void pnv_phb3_update_regions(PnvPHB3 *phb) @@ -1107,7 +1128,7 @@ static void pnv_phb3_class_init(ObjectClass *klass, void *data) dc->realize = pnv_phb3_realize; device_class_set_props(dc, pnv_phb3_properties); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->user_creatable = false; + dc->user_creatable = true; } static const TypeInfo pnv_phb3_type_info = { @@ -1142,8 +1163,24 @@ static const TypeInfo pnv_phb3_root_bus_info = { static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp) { PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + PCIDevice *pci = PCI_DEVICE(dev); + PCIBus *bus = pci_get_bus(pci); + PnvPHB3 *phb = NULL; Error *local_err = NULL; + phb = (PnvPHB3 *) object_dynamic_cast(OBJECT(bus->qbus.parent), + TYPE_PNV_PHB3); + + if (!phb) { + error_setg(errp, +"pnv_phb3_root_port devices must be connected to pnv-phb3 buses"); + return; + } + + /* Set unique chassis/slot values for the root port */ + qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id); + qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id); + rpc->parent_realize(dev, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -1161,7 +1198,7 @@ static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data) device_class_set_parent_realize(dc, pnv_phb3_root_port_realize, &rpc->parent_realize); - dc->user_creatable = false; + dc->user_creatable = true; k->vendor_id = PCI_VENDOR_ID_IBM; k->device_id = 0x03dc; diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 5ba26e250a..a7b638831e 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -22,12 +22,17 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "qom/object.h" +#include "sysemu/sysemu.h" #include "trace.h" #define phb_error(phb, fmt, ...) \ qemu_log_mask(LOG_GUEST_ERROR, "phb4[%d:%d]: " fmt "\n", \ (phb)->chip_id, (phb)->phb_id, ## __VA_ARGS__) +#define phb_pec_error(pec, fmt, ...) \ + qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n", \ + (pec)->chip_id, (pec)->index, ## __VA_ARGS__) + /* * QEMU version of the GETFIELD/SETFIELD macros * @@ -151,7 +156,10 @@ static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off, } pdev = pci_find_device(pci->bus, 0, 0); - assert(pdev); + if (!pdev) { + phb_error(phb, "rc_config_write device not found\n"); + return; + } pci_host_config_write_common(pdev, off, PHB_RC_CONFIG_SIZE, bswap32(val), 4); @@ -170,7 +178,10 @@ static uint64_t pnv_phb4_rc_config_read(PnvPHB4 *phb, unsigned off, } pdev = pci_find_device(pci->bus, 0, 0); - assert(pdev); + if (!pdev) { + phb_error(phb, "rc_config_read device not found\n"); + return ~0ull; + } val = pci_host_config_read_common(pdev, off, PHB_RC_CONFIG_SIZE, 4); return bswap32(val); @@ -847,6 +858,284 @@ const MemoryRegionOps pnv_phb4_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; +static uint64_t pnv_pec_stk_nest_xscom_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); + uint32_t reg = addr >> 3; + + /* TODO: add list of allowed registers and error out if not */ + return stack->nest_regs[reg]; +} + +static void pnv_phb4_update_regions(PnvPhb4PecStack *stack) +{ + PnvPHB4 *phb = stack->phb; + + /* Unmap first always */ + if (memory_region_is_mapped(&phb->mr_regs)) { + memory_region_del_subregion(&stack->phbbar, &phb->mr_regs); + } + if (memory_region_is_mapped(&phb->xsrc.esb_mmio)) { + memory_region_del_subregion(&stack->intbar, &phb->xsrc.esb_mmio); + } + + /* Map registers if enabled */ + if (memory_region_is_mapped(&stack->phbbar)) { + memory_region_add_subregion(&stack->phbbar, 0, &phb->mr_regs); + } + + /* Map ESB if enabled */ + if (memory_region_is_mapped(&stack->intbar)) { + memory_region_add_subregion(&stack->intbar, 0, &phb->xsrc.esb_mmio); + } + + /* Check/update m32 */ + pnv_phb4_check_all_mbt(phb); +} + +static void pnv_pec_stk_update_map(PnvPhb4PecStack *stack) +{ + PnvPhb4PecState *pec = stack->pec; + MemoryRegion *sysmem = get_system_memory(); + uint64_t bar_en = stack->nest_regs[PEC_NEST_STK_BAR_EN]; + uint64_t bar, mask, size; + char name[64]; + + /* + * NOTE: This will really not work well if those are remapped + * after the PHB has created its sub regions. We could do better + * if we had a way to resize regions but we don't really care + * that much in practice as the stuff below really only happens + * once early during boot + */ + + /* Handle unmaps */ + if (memory_region_is_mapped(&stack->mmbar0) && + !(bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) { + memory_region_del_subregion(sysmem, &stack->mmbar0); + } + if (memory_region_is_mapped(&stack->mmbar1) && + !(bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) { + memory_region_del_subregion(sysmem, &stack->mmbar1); + } + if (memory_region_is_mapped(&stack->phbbar) && + !(bar_en & PEC_NEST_STK_BAR_EN_PHB)) { + memory_region_del_subregion(sysmem, &stack->phbbar); + } + if (memory_region_is_mapped(&stack->intbar) && + !(bar_en & PEC_NEST_STK_BAR_EN_INT)) { + memory_region_del_subregion(sysmem, &stack->intbar); + } + + /* Update PHB */ + pnv_phb4_update_regions(stack); + + /* Handle maps */ + if (!memory_region_is_mapped(&stack->mmbar0) && + (bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) { + bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0] >> 8; + mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0_MASK]; + size = ((~mask) >> 8) + 1; + snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio0", + pec->chip_id, pec->index, stack->stack_no); + memory_region_init(&stack->mmbar0, OBJECT(stack), name, size); + memory_region_add_subregion(sysmem, bar, &stack->mmbar0); + stack->mmio0_base = bar; + stack->mmio0_size = size; + } + if (!memory_region_is_mapped(&stack->mmbar1) && + (bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) { + bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1] >> 8; + mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1_MASK]; + size = ((~mask) >> 8) + 1; + snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio1", + pec->chip_id, pec->index, stack->stack_no); + memory_region_init(&stack->mmbar1, OBJECT(stack), name, size); + memory_region_add_subregion(sysmem, bar, &stack->mmbar1); + stack->mmio1_base = bar; + stack->mmio1_size = size; + } + if (!memory_region_is_mapped(&stack->phbbar) && + (bar_en & PEC_NEST_STK_BAR_EN_PHB)) { + bar = stack->nest_regs[PEC_NEST_STK_PHB_REGS_BAR] >> 8; + size = PNV_PHB4_NUM_REGS << 3; + snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-phb", + pec->chip_id, pec->index, stack->stack_no); + memory_region_init(&stack->phbbar, OBJECT(stack), name, size); + memory_region_add_subregion(sysmem, bar, &stack->phbbar); + } + if (!memory_region_is_mapped(&stack->intbar) && + (bar_en & PEC_NEST_STK_BAR_EN_INT)) { + bar = stack->nest_regs[PEC_NEST_STK_INT_BAR] >> 8; + size = PNV_PHB4_MAX_INTs << 16; + snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-int", + stack->pec->chip_id, stack->pec->index, stack->stack_no); + memory_region_init(&stack->intbar, OBJECT(stack), name, size); + memory_region_add_subregion(sysmem, bar, &stack->intbar); + } + + /* Update PHB */ + pnv_phb4_update_regions(stack); +} + +static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); + PnvPhb4PecState *pec = stack->pec; + uint32_t reg = addr >> 3; + + switch (reg) { + case PEC_NEST_STK_PCI_NEST_FIR: + stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] = val; + break; + case PEC_NEST_STK_PCI_NEST_FIR_CLR: + stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] &= val; + break; + case PEC_NEST_STK_PCI_NEST_FIR_SET: + stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] |= val; + break; + case PEC_NEST_STK_PCI_NEST_FIR_MSK: + stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] = val; + break; + case PEC_NEST_STK_PCI_NEST_FIR_MSKC: + stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] &= val; + break; + case PEC_NEST_STK_PCI_NEST_FIR_MSKS: + stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] |= val; + break; + case PEC_NEST_STK_PCI_NEST_FIR_ACT0: + case PEC_NEST_STK_PCI_NEST_FIR_ACT1: + stack->nest_regs[reg] = val; + break; + case PEC_NEST_STK_PCI_NEST_FIR_WOF: + stack->nest_regs[reg] = 0; + break; + case PEC_NEST_STK_ERR_REPORT_0: + case PEC_NEST_STK_ERR_REPORT_1: + case PEC_NEST_STK_PBCQ_GNRL_STATUS: + /* Flag error ? */ + break; + case PEC_NEST_STK_PBCQ_MODE: + stack->nest_regs[reg] = val & 0xff00000000000000ull; + break; + case PEC_NEST_STK_MMIO_BAR0: + case PEC_NEST_STK_MMIO_BAR0_MASK: + case PEC_NEST_STK_MMIO_BAR1: + case PEC_NEST_STK_MMIO_BAR1_MASK: + if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & + (PEC_NEST_STK_BAR_EN_MMIO0 | + PEC_NEST_STK_BAR_EN_MMIO1)) { + phb_pec_error(pec, "Changing enabled BAR unsupported\n"); + } + stack->nest_regs[reg] = val & 0xffffffffff000000ull; + break; + case PEC_NEST_STK_PHB_REGS_BAR: + if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_PHB) { + phb_pec_error(pec, "Changing enabled BAR unsupported\n"); + } + stack->nest_regs[reg] = val & 0xffffffffffc00000ull; + break; + case PEC_NEST_STK_INT_BAR: + if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_INT) { + phb_pec_error(pec, "Changing enabled BAR unsupported\n"); + } + stack->nest_regs[reg] = val & 0xfffffff000000000ull; + break; + case PEC_NEST_STK_BAR_EN: + stack->nest_regs[reg] = val & 0xf000000000000000ull; + pnv_pec_stk_update_map(stack); + break; + case PEC_NEST_STK_DATA_FRZ_TYPE: + case PEC_NEST_STK_PBCQ_TUN_BAR: + /* Not used for now */ + stack->nest_regs[reg] = val; + break; + default: + qemu_log_mask(LOG_UNIMP, "phb4_pec: nest_xscom_write 0x%"HWADDR_PRIx + "=%"PRIx64"\n", addr, val); + } +} + +static const MemoryRegionOps pnv_pec_stk_nest_xscom_ops = { + .read = pnv_pec_stk_nest_xscom_read, + .write = pnv_pec_stk_nest_xscom_write, + .valid.min_access_size = 8, + .valid.max_access_size = 8, + .impl.min_access_size = 8, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static uint64_t pnv_pec_stk_pci_xscom_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); + uint32_t reg = addr >> 3; + + /* TODO: add list of allowed registers and error out if not */ + return stack->pci_regs[reg]; +} + +static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); + uint32_t reg = addr >> 3; + + switch (reg) { + case PEC_PCI_STK_PCI_FIR: + stack->pci_regs[reg] = val; + break; + case PEC_PCI_STK_PCI_FIR_CLR: + stack->pci_regs[PEC_PCI_STK_PCI_FIR] &= val; + break; + case PEC_PCI_STK_PCI_FIR_SET: + stack->pci_regs[PEC_PCI_STK_PCI_FIR] |= val; + break; + case PEC_PCI_STK_PCI_FIR_MSK: + stack->pci_regs[reg] = val; + break; + case PEC_PCI_STK_PCI_FIR_MSKC: + stack->pci_regs[PEC_PCI_STK_PCI_FIR_MSK] &= val; + break; + case PEC_PCI_STK_PCI_FIR_MSKS: + stack->pci_regs[PEC_PCI_STK_PCI_FIR_MSK] |= val; + break; + case PEC_PCI_STK_PCI_FIR_ACT0: + case PEC_PCI_STK_PCI_FIR_ACT1: + stack->pci_regs[reg] = val; + break; + case PEC_PCI_STK_PCI_FIR_WOF: + stack->pci_regs[reg] = 0; + break; + case PEC_PCI_STK_ETU_RESET: + stack->pci_regs[reg] = val & 0x8000000000000000ull; + /* TODO: Implement reset */ + break; + case PEC_PCI_STK_PBAIB_ERR_REPORT: + break; + case PEC_PCI_STK_PBAIB_TX_CMD_CRED: + case PEC_PCI_STK_PBAIB_TX_DAT_CRED: + stack->pci_regs[reg] = val; + break; + default: + qemu_log_mask(LOG_UNIMP, "phb4_pec_stk: pci_xscom_write 0x%"HWADDR_PRIx + "=%"PRIx64"\n", addr, val); + } +} + +static const MemoryRegionOps pnv_pec_stk_pci_xscom_ops = { + .read = pnv_pec_stk_pci_xscom_read, + .write = pnv_pec_stk_pci_xscom_write, + .valid.min_access_size = 8, + .valid.max_access_size = 8, + .impl.min_access_size = 8, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + static int pnv_phb4_map_irq(PCIDevice *pci_dev, int irq_num) { /* Check that out properly ... */ @@ -1063,6 +1352,23 @@ static const TypeInfo pnv_phb4_iommu_memory_region_info = { }; /* + * Return the index/phb-id of a PHB4 that belongs to a + * pec->stacks[stack_index] stack. + */ +int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index) +{ + PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec); + int index = pec->index; + int offset = 0; + + while (index--) { + offset += pecc->num_stacks[index]; + } + + return offset + stack_index; +} + +/* * MSI/MSIX memory region implementation. * The handler handles both MSI and MSIX. */ @@ -1151,6 +1457,52 @@ static AddressSpace *pnv_phb4_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &ds->dma_as; } +static void pnv_phb4_xscom_realize(PnvPHB4 *phb) +{ + PnvPhb4PecStack *stack = phb->stack; + PnvPhb4PecState *pec = stack->pec; + PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec); + uint32_t pec_nest_base; + uint32_t pec_pci_base; + char name[64]; + + assert(pec); + + /* Initialize the XSCOM regions for the stack registers */ + snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest-stack-%d", + pec->chip_id, pec->index, stack->stack_no); + pnv_xscom_region_init(&stack->nest_regs_mr, OBJECT(stack), + &pnv_pec_stk_nest_xscom_ops, stack, name, + PHB4_PEC_NEST_STK_REGS_COUNT); + + snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d", + pec->chip_id, pec->index, stack->stack_no); + pnv_xscom_region_init(&stack->pci_regs_mr, OBJECT(stack), + &pnv_pec_stk_pci_xscom_ops, stack, name, + PHB4_PEC_PCI_STK_REGS_COUNT); + + /* PHB pass-through */ + snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d-phb", + pec->chip_id, pec->index, stack->stack_no); + pnv_xscom_region_init(&stack->phb_regs_mr, OBJECT(phb), + &pnv_phb4_xscom_ops, phb, name, 0x40); + + pec_nest_base = pecc->xscom_nest_base(pec); + pec_pci_base = pecc->xscom_pci_base(pec); + + /* Populate the XSCOM address space. */ + pnv_xscom_add_subregion(pec->chip, + pec_nest_base + 0x40 * (stack->stack_no + 1), + &stack->nest_regs_mr); + pnv_xscom_add_subregion(pec->chip, + pec_pci_base + 0x40 * (stack->stack_no + 1), + &stack->pci_regs_mr); + pnv_xscom_add_subregion(pec->chip, + pec_pci_base + PNV9_XSCOM_PEC_PCI_STK0 + + 0x40 * stack->stack_no, + &stack->phb_regs_mr); +} + static void pnv_phb4_instance_init(Object *obj) { PnvPHB4 *phb = PNV_PHB4(obj); @@ -1159,12 +1511,35 @@ static void pnv_phb4_instance_init(Object *obj) /* XIVE interrupt source object */ object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE); +} - /* Root Port */ - object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB4_ROOT_PORT); +static PnvPhb4PecStack *pnv_phb4_get_stack(PnvChip *chip, PnvPHB4 *phb, + Error **errp) +{ + Pnv9Chip *chip9 = PNV9_CHIP(chip); + int chip_id = phb->chip_id; + int index = phb->phb_id; + int i, j; + + for (i = 0; i < chip->num_pecs; i++) { + /* + * For each PEC, check the amount of stacks it supports + * and see if the given phb4 index matches a stack. + */ + PnvPhb4PecState *pec = &chip9->pecs[i]; - qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0)); - qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false); + for (j = 0; j < pec->num_stacks; j++) { + if (index == pnv_phb4_pec_get_phb_id(pec, j)) { + return &pec->stacks[j]; + } + } + } + + error_setg(errp, + "pnv-phb4 chip-id %d index %d didn't match any existing PEC", + chip_id, index); + + return NULL; } static void pnv_phb4_realize(DeviceState *dev, Error **errp) @@ -1172,10 +1547,51 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) PnvPHB4 *phb = PNV_PHB4(dev); PCIHostState *pci = PCI_HOST_BRIDGE(dev); XiveSource *xsrc = &phb->xsrc; + Error *local_err = NULL; int nr_irqs; char name[32]; - assert(phb->stack); + /* User created PHB */ + if (!phb->stack) { + PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); + PnvChip *chip = pnv_get_chip(pnv, phb->chip_id); + PnvPhb4PecClass *pecc; + BusState *s; + + if (!chip) { + error_setg(errp, "invalid chip id: %d", phb->chip_id); + return; + } + + phb->stack = pnv_phb4_get_stack(chip, phb, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* All other phb properties but 'version' are already set */ + pecc = PNV_PHB4_PEC_GET_CLASS(phb->stack->pec); + object_property_set_int(OBJECT(phb), "version", pecc->version, + &error_fatal); + + /* + * Assign stack->phb since pnv_phb4_update_regions() uses it + * to access the phb. + */ + phb->stack->phb = phb; + + /* + * Reparent user created devices to the chip to build + * correctly the device tree. + */ + pnv_chip_parent_fixup(chip, OBJECT(phb), phb->phb_id); + + s = qdev_get_parent_bus(DEVICE(chip)); + if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) { + error_propagate(errp, local_err); + return; + } + } /* Set the "big_phb" flag */ phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3; @@ -1208,10 +1624,11 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb); pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; - /* Add a single Root port */ - qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id); - qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id); - qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal); + /* Add a single Root port if running with defaults */ + if (defaults_enabled()) { + pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), + TYPE_PNV_PHB4_ROOT_PORT); + } /* Setup XIVE Source */ if (phb->big_phb) { @@ -1228,6 +1645,8 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) pnv_phb4_update_xsrc(phb); phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs); + + pnv_phb4_xscom_realize(phb); } static const char *pnv_phb4_root_bus_path(PCIHostState *host_bridge, @@ -1277,7 +1696,7 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data) dc->realize = pnv_phb4_realize; device_class_set_props(dc, pnv_phb4_properties); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->user_creatable = false; + dc->user_creatable = true; xfc->notify = pnv_phb4_xive_notify; } @@ -1338,8 +1757,23 @@ static void pnv_phb4_root_port_reset(DeviceState *dev) static void pnv_phb4_root_port_realize(DeviceState *dev, Error **errp) { PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + PCIDevice *pci = PCI_DEVICE(dev); + PCIBus *bus = pci_get_bus(pci); + PnvPHB4 *phb = NULL; Error *local_err = NULL; + phb = (PnvPHB4 *) object_dynamic_cast(OBJECT(bus->qbus.parent), + TYPE_PNV_PHB4); + + if (!phb) { + error_setg(errp, "%s must be connected to pnv-phb4 buses", dev->id); + return; + } + + /* Set unique chassis/slot values for the root port */ + qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id); + qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id); + rpc->parent_realize(dev, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -1354,7 +1788,7 @@ static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data) PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass); dc->desc = "IBM PHB4 PCIE Root Port"; - dc->user_creatable = false; + dc->user_creatable = true; device_class_set_parent_realize(dc, pnv_phb4_root_port_realize, &rpc->parent_realize); @@ -1388,32 +1822,6 @@ static void pnv_phb4_register_types(void) type_init(pnv_phb4_register_types); -void pnv_phb4_update_regions(PnvPhb4PecStack *stack) -{ - PnvPHB4 *phb = &stack->phb; - - /* Unmap first always */ - if (memory_region_is_mapped(&phb->mr_regs)) { - memory_region_del_subregion(&stack->phbbar, &phb->mr_regs); - } - if (memory_region_is_mapped(&phb->xsrc.esb_mmio)) { - memory_region_del_subregion(&stack->intbar, &phb->xsrc.esb_mmio); - } - - /* Map registers if enabled */ - if (memory_region_is_mapped(&stack->phbbar)) { - memory_region_add_subregion(&stack->phbbar, 0, &phb->mr_regs); - } - - /* Map ESB if enabled */ - if (memory_region_is_mapped(&stack->intbar)) { - memory_region_add_subregion(&stack->intbar, 0, &phb->xsrc.esb_mmio); - } - - /* Check/update m32 */ - pnv_phb4_check_all_mbt(phb); -} - void pnv_phb4_pic_print_info(PnvPHB4 *phb, Monitor *mon) { uint32_t offset = phb->regs[PHB_INT_NOTIFY_INDEX >> 3]; diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index f3e4fa0c82..7fe7f1f007 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -19,6 +19,7 @@ #include "hw/pci/pci_bus.h" #include "hw/ppc/pnv.h" #include "hw/qdev-properties.h" +#include "sysemu/sysemu.h" #include <libfdt.h> @@ -111,258 +112,6 @@ static const MemoryRegionOps pnv_pec_pci_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static uint64_t pnv_pec_stk_nest_xscom_read(void *opaque, hwaddr addr, - unsigned size) -{ - PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); - uint32_t reg = addr >> 3; - - /* TODO: add list of allowed registers and error out if not */ - return stack->nest_regs[reg]; -} - -static void pnv_pec_stk_update_map(PnvPhb4PecStack *stack) -{ - PnvPhb4PecState *pec = stack->pec; - MemoryRegion *sysmem = get_system_memory(); - uint64_t bar_en = stack->nest_regs[PEC_NEST_STK_BAR_EN]; - uint64_t bar, mask, size; - char name[64]; - - /* - * NOTE: This will really not work well if those are remapped - * after the PHB has created its sub regions. We could do better - * if we had a way to resize regions but we don't really care - * that much in practice as the stuff below really only happens - * once early during boot - */ - - /* Handle unmaps */ - if (memory_region_is_mapped(&stack->mmbar0) && - !(bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) { - memory_region_del_subregion(sysmem, &stack->mmbar0); - } - if (memory_region_is_mapped(&stack->mmbar1) && - !(bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) { - memory_region_del_subregion(sysmem, &stack->mmbar1); - } - if (memory_region_is_mapped(&stack->phbbar) && - !(bar_en & PEC_NEST_STK_BAR_EN_PHB)) { - memory_region_del_subregion(sysmem, &stack->phbbar); - } - if (memory_region_is_mapped(&stack->intbar) && - !(bar_en & PEC_NEST_STK_BAR_EN_INT)) { - memory_region_del_subregion(sysmem, &stack->intbar); - } - - /* Update PHB */ - pnv_phb4_update_regions(stack); - - /* Handle maps */ - if (!memory_region_is_mapped(&stack->mmbar0) && - (bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) { - bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0] >> 8; - mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0_MASK]; - size = ((~mask) >> 8) + 1; - snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio0", - pec->chip_id, pec->index, stack->stack_no); - memory_region_init(&stack->mmbar0, OBJECT(stack), name, size); - memory_region_add_subregion(sysmem, bar, &stack->mmbar0); - stack->mmio0_base = bar; - stack->mmio0_size = size; - } - if (!memory_region_is_mapped(&stack->mmbar1) && - (bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) { - bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1] >> 8; - mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1_MASK]; - size = ((~mask) >> 8) + 1; - snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio1", - pec->chip_id, pec->index, stack->stack_no); - memory_region_init(&stack->mmbar1, OBJECT(stack), name, size); - memory_region_add_subregion(sysmem, bar, &stack->mmbar1); - stack->mmio1_base = bar; - stack->mmio1_size = size; - } - if (!memory_region_is_mapped(&stack->phbbar) && - (bar_en & PEC_NEST_STK_BAR_EN_PHB)) { - bar = stack->nest_regs[PEC_NEST_STK_PHB_REGS_BAR] >> 8; - size = PNV_PHB4_NUM_REGS << 3; - snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-phb", - pec->chip_id, pec->index, stack->stack_no); - memory_region_init(&stack->phbbar, OBJECT(stack), name, size); - memory_region_add_subregion(sysmem, bar, &stack->phbbar); - } - if (!memory_region_is_mapped(&stack->intbar) && - (bar_en & PEC_NEST_STK_BAR_EN_INT)) { - bar = stack->nest_regs[PEC_NEST_STK_INT_BAR] >> 8; - size = PNV_PHB4_MAX_INTs << 16; - snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-int", - stack->pec->chip_id, stack->pec->index, stack->stack_no); - memory_region_init(&stack->intbar, OBJECT(stack), name, size); - memory_region_add_subregion(sysmem, bar, &stack->intbar); - } - - /* Update PHB */ - pnv_phb4_update_regions(stack); -} - -static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); - PnvPhb4PecState *pec = stack->pec; - uint32_t reg = addr >> 3; - - switch (reg) { - case PEC_NEST_STK_PCI_NEST_FIR: - stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] = val; - break; - case PEC_NEST_STK_PCI_NEST_FIR_CLR: - stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] &= val; - break; - case PEC_NEST_STK_PCI_NEST_FIR_SET: - stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] |= val; - break; - case PEC_NEST_STK_PCI_NEST_FIR_MSK: - stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] = val; - break; - case PEC_NEST_STK_PCI_NEST_FIR_MSKC: - stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] &= val; - break; - case PEC_NEST_STK_PCI_NEST_FIR_MSKS: - stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] |= val; - break; - case PEC_NEST_STK_PCI_NEST_FIR_ACT0: - case PEC_NEST_STK_PCI_NEST_FIR_ACT1: - stack->nest_regs[reg] = val; - break; - case PEC_NEST_STK_PCI_NEST_FIR_WOF: - stack->nest_regs[reg] = 0; - break; - case PEC_NEST_STK_ERR_REPORT_0: - case PEC_NEST_STK_ERR_REPORT_1: - case PEC_NEST_STK_PBCQ_GNRL_STATUS: - /* Flag error ? */ - break; - case PEC_NEST_STK_PBCQ_MODE: - stack->nest_regs[reg] = val & 0xff00000000000000ull; - break; - case PEC_NEST_STK_MMIO_BAR0: - case PEC_NEST_STK_MMIO_BAR0_MASK: - case PEC_NEST_STK_MMIO_BAR1: - case PEC_NEST_STK_MMIO_BAR1_MASK: - if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & - (PEC_NEST_STK_BAR_EN_MMIO0 | - PEC_NEST_STK_BAR_EN_MMIO1)) { - phb_pec_error(pec, "Changing enabled BAR unsupported\n"); - } - stack->nest_regs[reg] = val & 0xffffffffff000000ull; - break; - case PEC_NEST_STK_PHB_REGS_BAR: - if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_PHB) { - phb_pec_error(pec, "Changing enabled BAR unsupported\n"); - } - stack->nest_regs[reg] = val & 0xffffffffffc00000ull; - break; - case PEC_NEST_STK_INT_BAR: - if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_INT) { - phb_pec_error(pec, "Changing enabled BAR unsupported\n"); - } - stack->nest_regs[reg] = val & 0xfffffff000000000ull; - break; - case PEC_NEST_STK_BAR_EN: - stack->nest_regs[reg] = val & 0xf000000000000000ull; - pnv_pec_stk_update_map(stack); - break; - case PEC_NEST_STK_DATA_FRZ_TYPE: - case PEC_NEST_STK_PBCQ_TUN_BAR: - /* Not used for now */ - stack->nest_regs[reg] = val; - break; - default: - qemu_log_mask(LOG_UNIMP, "phb4_pec: nest_xscom_write 0x%"HWADDR_PRIx - "=%"PRIx64"\n", addr, val); - } -} - -static const MemoryRegionOps pnv_pec_stk_nest_xscom_ops = { - .read = pnv_pec_stk_nest_xscom_read, - .write = pnv_pec_stk_nest_xscom_write, - .valid.min_access_size = 8, - .valid.max_access_size = 8, - .impl.min_access_size = 8, - .impl.max_access_size = 8, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static uint64_t pnv_pec_stk_pci_xscom_read(void *opaque, hwaddr addr, - unsigned size) -{ - PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); - uint32_t reg = addr >> 3; - - /* TODO: add list of allowed registers and error out if not */ - return stack->pci_regs[reg]; -} - -static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque); - uint32_t reg = addr >> 3; - - switch (reg) { - case PEC_PCI_STK_PCI_FIR: - stack->nest_regs[reg] = val; - break; - case PEC_PCI_STK_PCI_FIR_CLR: - stack->nest_regs[PEC_PCI_STK_PCI_FIR] &= val; - break; - case PEC_PCI_STK_PCI_FIR_SET: - stack->nest_regs[PEC_PCI_STK_PCI_FIR] |= val; - break; - case PEC_PCI_STK_PCI_FIR_MSK: - stack->nest_regs[reg] = val; - break; - case PEC_PCI_STK_PCI_FIR_MSKC: - stack->nest_regs[PEC_PCI_STK_PCI_FIR_MSK] &= val; - break; - case PEC_PCI_STK_PCI_FIR_MSKS: - stack->nest_regs[PEC_PCI_STK_PCI_FIR_MSK] |= val; - break; - case PEC_PCI_STK_PCI_FIR_ACT0: - case PEC_PCI_STK_PCI_FIR_ACT1: - stack->nest_regs[reg] = val; - break; - case PEC_PCI_STK_PCI_FIR_WOF: - stack->nest_regs[reg] = 0; - break; - case PEC_PCI_STK_ETU_RESET: - stack->nest_regs[reg] = val & 0x8000000000000000ull; - /* TODO: Implement reset */ - break; - case PEC_PCI_STK_PBAIB_ERR_REPORT: - break; - case PEC_PCI_STK_PBAIB_TX_CMD_CRED: - case PEC_PCI_STK_PBAIB_TX_DAT_CRED: - stack->nest_regs[reg] = val; - break; - default: - qemu_log_mask(LOG_UNIMP, "phb4_pec_stk: pci_xscom_write 0x%"HWADDR_PRIx - "=%"PRIx64"\n", addr, val); - } -} - -static const MemoryRegionOps pnv_pec_stk_pci_xscom_ops = { - .read = pnv_pec_stk_pci_xscom_read, - .write = pnv_pec_stk_pci_xscom_write, - .valid.min_access_size = 8, - .valid.max_access_size = 8, - .impl.min_access_size = 8, - .impl.max_access_size = 8, - .endianness = DEVICE_BIG_ENDIAN, -}; - static void pnv_pec_instance_init(Object *obj) { PnvPhb4PecState *pec = PNV_PHB4_PEC(obj); @@ -374,19 +123,6 @@ static void pnv_pec_instance_init(Object *obj) } } -static int pnv_pec_phb_offset(PnvPhb4PecState *pec) -{ - PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec); - int index = pec->index; - int offset = 0; - - while (index--) { - offset += pecc->num_stacks[index]; - } - - return offset; -} - static void pnv_pec_realize(DeviceState *dev, Error **errp) { PnvPhb4PecState *pec = PNV_PHB4_PEC(dev); @@ -405,10 +141,8 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) for (i = 0; i < pec->num_stacks; i++) { PnvPhb4PecStack *stack = &pec->stacks[i]; Object *stk_obj = OBJECT(stack); - int phb_id = pnv_pec_phb_offset(pec) + i; object_property_set_int(stk_obj, "stack-no", i, &error_abort); - object_property_set_int(stk_obj, "phb-id", phb_id, &error_abort); object_property_set_link(stk_obj, "pec", OBJECT(pec), &error_abort); if (!qdev_realize(DEVICE(stk_obj), NULL, errp)) { return; @@ -462,8 +196,7 @@ static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt, pecc->compat_size))); for (i = 0; i < pec->num_stacks; i++) { - PnvPhb4PecStack *stack = &pec->stacks[i]; - PnvPHB4 *phb = &stack->phb; + int phb_id = pnv_phb4_pec_get_phb_id(pec, i); int stk_offset; name = g_strdup_printf("stack@%x", i); @@ -473,7 +206,7 @@ static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt, _FDT((fdt_setprop(fdt, stk_offset, "compatible", pecc->stk_compat, pecc->stk_compat_size))); _FDT((fdt_setprop_cell(fdt, stk_offset, "reg", i))); - _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index", phb->phb_id))); + _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index", phb_id))); } return 0; @@ -543,69 +276,38 @@ static const TypeInfo pnv_pec_type_info = { } }; -static void pnv_pec_stk_instance_init(Object *obj) +static void pnv_pec_stk_default_phb_realize(PnvPhb4PecStack *stack, + Error **errp) { - PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(obj); - - object_initialize_child(obj, "phb", &stack->phb, TYPE_PNV_PHB4); - object_property_add_alias(obj, "phb-id", OBJECT(&stack->phb), "index"); -} - -static void pnv_pec_stk_realize(DeviceState *dev, Error **errp) -{ - PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(dev); PnvPhb4PecState *pec = stack->pec; PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec); - PnvChip *chip = pec->chip; - uint32_t pec_nest_base; - uint32_t pec_pci_base; - char name[64]; - - assert(pec); - - /* Initialize the XSCOM regions for the stack registers */ - snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest-stack-%d", - pec->chip_id, pec->index, stack->stack_no); - pnv_xscom_region_init(&stack->nest_regs_mr, OBJECT(stack), - &pnv_pec_stk_nest_xscom_ops, stack, name, - PHB4_PEC_NEST_STK_REGS_COUNT); - - snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d", - pec->chip_id, pec->index, stack->stack_no); - pnv_xscom_region_init(&stack->pci_regs_mr, OBJECT(stack), - &pnv_pec_stk_pci_xscom_ops, stack, name, - PHB4_PEC_PCI_STK_REGS_COUNT); + int phb_id = pnv_phb4_pec_get_phb_id(pec, stack->stack_no); - /* PHB pass-through */ - snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d-phb", - pec->chip_id, pec->index, stack->stack_no); - pnv_xscom_region_init(&stack->phb_regs_mr, OBJECT(&stack->phb), - &pnv_phb4_xscom_ops, &stack->phb, name, 0x40); + stack->phb = PNV_PHB4(qdev_new(TYPE_PNV_PHB4)); - object_property_set_int(OBJECT(&stack->phb), "chip-id", pec->chip_id, + object_property_set_int(OBJECT(stack->phb), "chip-id", pec->chip_id, &error_fatal); - object_property_set_int(OBJECT(&stack->phb), "version", pecc->version, + object_property_set_int(OBJECT(stack->phb), "index", phb_id, &error_fatal); - object_property_set_link(OBJECT(&stack->phb), "stack", OBJECT(stack), + object_property_set_int(OBJECT(stack->phb), "version", pecc->version, + &error_fatal); + object_property_set_link(OBJECT(stack->phb), "stack", OBJECT(stack), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&stack->phb), errp)) { + + if (!sysbus_realize(SYS_BUS_DEVICE(stack->phb), errp)) { + return; + } +} + +static void pnv_pec_stk_realize(DeviceState *dev, Error **errp) +{ + PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(dev); + + if (!defaults_enabled()) { return; } - pec_nest_base = pecc->xscom_nest_base(pec); - pec_pci_base = pecc->xscom_pci_base(pec); - - /* Populate the XSCOM address space. */ - pnv_xscom_add_subregion(chip, - pec_nest_base + 0x40 * (stack->stack_no + 1), - &stack->nest_regs_mr); - pnv_xscom_add_subregion(chip, - pec_pci_base + 0x40 * (stack->stack_no + 1), - &stack->pci_regs_mr); - pnv_xscom_add_subregion(chip, - pec_pci_base + PNV9_XSCOM_PEC_PCI_STK0 + - 0x40 * stack->stack_no, - &stack->phb_regs_mr); + pnv_pec_stk_default_phb_realize(stack, errp); } static Property pnv_pec_stk_properties[] = { @@ -630,7 +332,6 @@ static const TypeInfo pnv_pec_stk_type_info = { .name = TYPE_PNV_PHB4_PEC_STACK, .parent = TYPE_DEVICE, .instance_size = sizeof(PnvPhb4PecStack), - .instance_init = pnv_pec_stk_instance_init, .class_init = pnv_pec_stk_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 9de8b83530..837146a2fb 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1099,7 +1099,6 @@ static void pnv_chip_power10_intc_print_info(PnvChip *chip, PowerPCCPU *cpu, static void pnv_chip_power8_instance_init(Object *obj) { - PnvChip *chip = PNV_CHIP(obj); Pnv8Chip *chip8 = PNV8_CHIP(obj); PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj); int i; @@ -1117,14 +1116,14 @@ static void pnv_chip_power8_instance_init(Object *obj) object_initialize_child(obj, "homer", &chip8->homer, TYPE_PNV8_HOMER); - for (i = 0; i < pcc->num_phbs; i++) { + if (defaults_enabled()) { + chip8->num_phbs = pcc->num_phbs; + } + + for (i = 0; i < chip8->num_phbs; i++) { object_initialize_child(obj, "phb[*]", &chip8->phbs[i], TYPE_PNV_PHB3); } - /* - * Number of PHBs is the chip default - */ - chip->num_phbs = pcc->num_phbs; } static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) @@ -1156,6 +1155,14 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) } } +/* Attach a root port device */ +void pnv_phb_attach_root_port(PCIHostState *pci, const char *name) +{ + PCIDevice *root = pci_new(PCI_DEVFN(0, 0), name); + + pci_realize_and_unref(root, pci->bus, &error_fatal); +} + static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) { PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); @@ -1239,7 +1246,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) &chip8->homer.regs); /* PHB3 controllers */ - for (i = 0; i < chip->num_phbs; i++) { + for (i = 0; i < chip8->num_phbs; i++) { PnvPHB3 *phb = &chip8->phbs[i]; object_property_set_int(OBJECT(phb), "index", i, &error_fatal); @@ -1806,6 +1813,36 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq) return NULL; } +void pnv_chip_parent_fixup(PnvChip *chip, Object *obj, int index) +{ + Object *parent = OBJECT(chip); + g_autofree char *default_id = + g_strdup_printf("%s[%d]", object_get_typename(obj), index); + + if (obj->parent == parent) { + return; + } + + object_ref(obj); + object_unparent(obj); + object_property_add_child( + parent, DEVICE(obj)->id ? DEVICE(obj)->id : default_id, obj); + object_unref(obj); +} + +PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id) +{ + int i; + + for (i = 0; i < pnv->num_chips; i++) { + PnvChip *chip = pnv->chips[i]; + if (chip->chip_id == chip_id) { + return chip; + } + } + return NULL; +} + static int pnv_ics_resend_child(Object *child, void *opaque) { PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3); @@ -1903,6 +1940,8 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) pmc->compat = compat; pmc->compat_size = sizeof(compat); + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB3); } static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) @@ -1921,6 +1960,8 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) pmc->compat = compat; pmc->compat_size = sizeof(compat); pmc->dt_power_mgt = pnv_dt_power_mgt; + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB4); } static void pnv_machine_power10_class_init(ObjectClass *oc, void *data) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8373429325..72f5dce751 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -723,10 +723,12 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, * * Only CPUs for which we create core types in spapr_cpu_core.c * are possible, and all of those have VMX */ - if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2))); - } else { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1))); + if (env->insns_flags & PPC_ALTIVEC) { + if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) { + _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2))); + } else { + _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1))); + } } /* Advertise DFP (Decimal Floating Point) if available diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 18eb824c97..29575cbaf6 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -49,51 +49,6 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) } } -static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev, - VirtQueue *vq) -{ - bool progress = false; - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - - virtio_scsi_acquire(s); - if (!s->dataplane_fenced) { - assert(s->ctx && s->dataplane_started); - progress = virtio_scsi_handle_cmd_vq(s, vq); - } - virtio_scsi_release(s); - return progress; -} - -static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev, - VirtQueue *vq) -{ - bool progress = false; - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - - virtio_scsi_acquire(s); - if (!s->dataplane_fenced) { - assert(s->ctx && s->dataplane_started); - progress = virtio_scsi_handle_ctrl_vq(s, vq); - } - virtio_scsi_release(s); - return progress; -} - -static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev, - VirtQueue *vq) -{ - bool progress = false; - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - - virtio_scsi_acquire(s); - if (!s->dataplane_fenced) { - assert(s->ctx && s->dataplane_started); - progress = virtio_scsi_handle_event_vq(s, vq); - } - virtio_scsi_release(s); - return progress; -} - static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); @@ -118,10 +73,10 @@ static void virtio_scsi_dataplane_stop_bh(void *opaque) VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); int i; - virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, NULL); - virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, NULL); + virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx); + virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx); for (i = 0; i < vs->conf.num_queues; i++) { - virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, NULL); + virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx); } } @@ -182,14 +137,11 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) memory_region_transaction_commit(); aio_context_acquire(s->ctx); - virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, - virtio_scsi_data_plane_handle_ctrl); - virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, - virtio_scsi_data_plane_handle_event); + virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx); + virtio_queue_aio_attach_host_notifier(vs->event_vq, s->ctx); for (i = 0; i < vs->conf.num_queues; i++) { - virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, - virtio_scsi_data_plane_handle_cmd); + virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx); } s->dataplane_starting = false; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 51fd09522a..34a968ecfb 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -720,7 +720,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - if (s->ctx) { + if (s->ctx && !s->dataplane_started) { virtio_device_start_ioeventfd(vdev); if (!s->dataplane_fenced) { return; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index bb5dbff68c..cd67a7bac8 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -116,8 +116,8 @@ struct SDState { int32_t state; /* current card state, one of SDCardStates */ uint32_t vhs; bool wp_switch; - unsigned long *wp_groups; - int32_t wpgrps_size; + unsigned long *wp_group_bmap; + int32_t wp_group_bits; uint64_t size; uint32_t blk_len; uint32_t multi_blk_cnt; @@ -290,12 +290,6 @@ FIELD(OCR, CARD_POWER_UP, 31, 1) | R_OCR_CARD_CAPACITY_MASK \ | R_OCR_CARD_POWER_UP_MASK) -static void sd_set_ocr(SDState *sd) -{ - /* All voltages OK */ - sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; -} - static void sd_ocr_powerup(void *opaque) { SDState *sd = opaque; @@ -311,6 +305,22 @@ static void sd_ocr_powerup(void *opaque) } } +static void sd_set_ocr(SDState *sd) +{ + /* All voltages OK */ + sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; + + if (sd->spi) { + /* + * We don't need to emulate power up sequence in SPI-mode. + * Thus, the card's power up status bit should be set to 1 when reset. + * The card's capacity status bit should also be set if SD card size + * is larger than 2GB for SDHC support. + */ + sd_ocr_powerup(sd); + } +} + static void sd_set_scr(SDState *sd) { sd->scr[0] = 0 << 4; /* SCR structure version 1.0 */ @@ -560,6 +570,7 @@ static void sd_reset(DeviceState *dev) sd->state = sd_idle_state; sd->rca = 0x0000; + sd->size = size; sd_set_ocr(sd); sd_set_scr(sd); sd_set_cid(sd); @@ -567,14 +578,13 @@ static void sd_reset(DeviceState *dev) sd_set_cardstatus(sd); sd_set_sdstatus(sd); - g_free(sd->wp_groups); + g_free(sd->wp_group_bmap); sd->wp_switch = sd->blk ? !blk_is_writable(sd->blk) : false; - sd->wpgrps_size = sect; - sd->wp_groups = bitmap_new(sd->wpgrps_size); + sd->wp_group_bits = sect; + sd->wp_group_bmap = bitmap_new(sd->wp_group_bits); memset(sd->function_group, 0, sizeof(sd->function_group)); sd->erase_start = INVALID_ADDRESS; sd->erase_end = INVALID_ADDRESS; - sd->size = size; sd->blk_len = 0x200; sd->pwd_len = 0; sd->expecting_acmd = false; @@ -673,7 +683,7 @@ static const VMStateDescription sd_vmstate = { VMSTATE_UINT32(card_status, SDState), VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1), VMSTATE_UINT32(vhs, SDState), - VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size), + VMSTATE_BITMAP(wp_group_bmap, SDState, 0, wp_group_bits), VMSTATE_UINT32(blk_len, SDState), VMSTATE_UINT32(multi_blk_cnt, SDState), VMSTATE_UINT32(erase_start, SDState), @@ -803,8 +813,8 @@ static void sd_erase(SDState *sd) if (sdsc) { /* Only SDSC cards support write protect groups */ wpnum = sd_addr_to_wpnum(erase_addr); - assert(wpnum < sd->wpgrps_size); - if (test_bit(wpnum, sd->wp_groups)) { + assert(wpnum < sd->wp_group_bits); + if (test_bit(wpnum, sd->wp_group_bmap)) { sd->card_status |= WP_ERASE_SKIP; continue; } @@ -828,8 +838,8 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr) */ continue; } - assert(wpnum < sd->wpgrps_size); - if (test_bit(wpnum, sd->wp_groups)) { + assert(wpnum < sd->wp_group_bits); + if (test_bit(wpnum, sd->wp_group_bmap)) { ret |= (1 << i); } } @@ -869,7 +879,7 @@ static void sd_function_switch(SDState *sd, uint32_t arg) static inline bool sd_wp_addr(SDState *sd, uint64_t addr) { - return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups); + return test_bit(sd_addr_to_wpnum(addr), sd->wp_group_bmap); } static void sd_lock_command(SDState *sd) @@ -897,7 +907,7 @@ static void sd_lock_command(SDState *sd) sd->card_status |= LOCK_UNLOCK_FAILED; return; } - bitmap_zero(sd->wp_groups, sd->wpgrps_size); + bitmap_zero(sd->wp_group_bmap, sd->wp_group_bits); sd->csd[14] &= ~0x10; sd->card_status &= ~CARD_IS_LOCKED; sd->pwd_len = 0; @@ -1348,7 +1358,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } sd->state = sd_programming_state; - set_bit(sd_addr_to_wpnum(addr), sd->wp_groups); + set_bit(sd_addr_to_wpnum(addr), sd->wp_group_bmap); /* Bzzzzzzztt .... Operation complete. */ sd->state = sd_transfer_state; return sd_r1b; @@ -1370,7 +1380,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } sd->state = sd_programming_state; - clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups); + clear_bit(sd_addr_to_wpnum(addr), sd->wp_group_bmap); /* Bzzzzzzztt .... Operation complete. */ sd->state = sd_transfer_state; return sd_r1b; diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 8b6eaea407..7f6cc2f99b 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -632,7 +632,8 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE)); const USBDesc *desc = usb_device_get_usb_desc(dev); const USBDescDevice *other_dev; - uint8_t buf[256]; + size_t buflen = USB_DESC_MAX_LEN; + g_autofree uint8_t *buf = g_malloc(buflen); uint8_t type = value >> 8; uint8_t index = value & 0xff; int flags, ret = -1; @@ -650,36 +651,36 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, switch(type) { case USB_DT_DEVICE: - ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf)); + ret = usb_desc_device(&desc->id, dev->device, msos, buf, buflen); trace_usb_desc_device(dev->addr, len, ret); break; case USB_DT_CONFIG: if (index < dev->device->bNumConfigurations) { ret = usb_desc_config(dev->device->confs + index, flags, - buf, sizeof(buf)); + buf, buflen); } trace_usb_desc_config(dev->addr, index, len, ret); break; case USB_DT_STRING: - ret = usb_desc_string(dev, index, buf, sizeof(buf)); + ret = usb_desc_string(dev, index, buf, buflen); trace_usb_desc_string(dev->addr, index, len, ret); break; case USB_DT_DEVICE_QUALIFIER: if (other_dev != NULL) { - ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); + ret = usb_desc_device_qualifier(other_dev, buf, buflen); } trace_usb_desc_device_qualifier(dev->addr, len, ret); break; case USB_DT_OTHER_SPEED_CONFIG: if (other_dev != NULL && index < other_dev->bNumConfigurations) { ret = usb_desc_config(other_dev->confs + index, flags, - buf, sizeof(buf)); + buf, buflen); buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; } trace_usb_desc_other_speed_config(dev->addr, index, len, ret); break; case USB_DT_BOS: - ret = usb_desc_bos(desc, buf, sizeof(buf)); + ret = usb_desc_bos(desc, buf, buflen); trace_usb_desc_bos(dev->addr, len, ret); break; diff --git a/hw/usb/desc.h b/hw/usb/desc.h index 3ac604ecfa..35babdeff6 100644 --- a/hw/usb/desc.h +++ b/hw/usb/desc.h @@ -199,6 +199,7 @@ struct USBDesc { const USBDescMSOS *msos; }; +#define USB_DESC_MAX_LEN 8192 #define USB_DESC_FLAG_SUPER (1 << 1) /* little helpers */ diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 599d6b52a0..c9f295e7e4 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -908,6 +908,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) p->status = USB_RET_STALL; break; } + return; err_stream: error_report("%s: invalid stream %d", __func__, p->stream); diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index ed687bc9f1..8323650c6a 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -69,6 +69,65 @@ static const USBDescStrings desc_strings = { [STR_SERIALNUMBER] = "1", }; +static const uint8_t qemu_wacom_hid_report_descriptor[] = { + 0x05, 0x01, /* Usage Page (Desktop) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x85, 0x01, /* Report ID (1) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (01h) */ + 0x29, 0x03, /* Usage Maximum (03h) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Constant) */ + 0x05, 0x01, /* Usage Page (Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7f, /* Logical Maximum (127) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x03, /* Report Count (3) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0x95, 0x03, /* Report Count (3) */ + 0x81, 0x01, /* Input (Constant) */ + 0xc0, /* End Collection */ + 0xc0, /* End Collection */ + 0x05, 0x0d, /* Usage Page (Digitizer) */ + 0x09, 0x01, /* Usage (Digitizer) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x85, 0x02, /* Report ID (2) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x06, 0x00, 0xff,/* Usage Page (ff00h), vendor-defined */ + 0x09, 0x01, /* Usage (01h) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x26, 0xff, 0x00,/* Logical Maximum (255) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x07, /* Report Count (7) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0xc0, /* End Collection */ + 0x09, 0x01, /* Usage (01h) */ + 0x85, 0x63, /* Report ID (99) */ + 0x95, 0x07, /* Report Count (7) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x09, 0x01, /* Usage (01h) */ + 0x85, 0x02, /* Report ID (2) */ + 0x95, 0x01, /* Report Count (1) */ + 0xb1, 0x02, /* Feature (Variable) */ + 0x09, 0x01, /* Usage (01h) */ + 0x85, 0x03, /* Report ID (3) */ + 0x95, 0x01, /* Report Count (1) */ + 0xb1, 0x02, /* Feature (Variable) */ + 0xc0 /* End Collection */ +}; + static const USBDescIface desc_iface_wacom = { .bInterfaceNumber = 0, .bNumEndpoints = 1, @@ -86,7 +145,7 @@ static const USBDescIface desc_iface_wacom = { 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ USB_DT_REPORT, /* u8 type: Report */ - 0x6e, 0, /* u16 len */ + sizeof(qemu_wacom_hid_report_descriptor), 0, /* u16 len */ }, }, }, @@ -266,6 +325,17 @@ static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p, } switch (request) { + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + switch (value >> 8) { + case 0x22: + memcpy(data, qemu_wacom_hid_report_descriptor, + sizeof(qemu_wacom_hid_report_descriptor)); + p->actual_length = sizeof(qemu_wacom_hid_report_descriptor); + break; + default: + return; + } + break; case WACOM_SET_REPORT: if (s->mouse_grabbed) { qemu_remove_mouse_event_handler(s->eh_entry); diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 595ce015ff..f7ad6be5fb 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -53,7 +53,6 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI vhost_vdpa_set_owner(void *dev) "dev: %p" vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 -vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" # virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index 9b0349922e..c595957983 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -161,9 +161,6 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, { VHostUserFS *fs = VHOST_USER_FS(vdev); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return; - } vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); } @@ -171,9 +168,6 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) { VHostUserFS *fs = VHOST_USER_FS(vdev); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return false; - } return vhost_virtqueue_pending(&fs->vhost_dev, idx); } diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index ac0cb575fb..04ea43704f 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -734,12 +734,6 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); } -static int vhost_vdpa_set_config_call(struct vhost_dev *dev, - int fd) -{ - trace_vhost_vdpa_set_config_call(dev, fd); - return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); -} static int vhost_vdpa_get_features(struct vhost_dev *dev, uint64_t *features) @@ -810,5 +804,4 @@ const VhostOps vdpa_ops = { .vhost_get_device_id = vhost_vdpa_get_device_id, .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, .vhost_force_iommu = vhost_vdpa_force_iommu, - .vhost_set_config_call = vhost_vdpa_set_config_call, }; diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index d1b9c027b6..3f3771274e 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -125,9 +125,6 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return; - } vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); } @@ -136,9 +133,6 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return false; - } return vhost_virtqueue_pending(&vvc->vhost_dev, idx); } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index cbf3b792da..7b03efccec 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1554,67 +1554,6 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, } } -bool vhost_config_pending(struct vhost_dev *hdev) -{ - assert(hdev->vhost_ops); - if ((hdev->started == false) || - (hdev->vhost_ops->vhost_set_config_call == NULL)) { - return false; - } - - EventNotifier *notifier = - &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; - return event_notifier_test_and_clear(notifier); -} - -void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) -{ - int fd; - int r; - EventNotifier *notifier = - &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; - EventNotifier *config_notifier = &vdev->config_notifier; - assert(hdev->vhost_ops); - - if ((hdev->started == false) || - (hdev->vhost_ops->vhost_set_config_call == NULL)) { - return; - } - if (mask) { - assert(vdev->use_guest_notifier_mask); - fd = event_notifier_get_fd(notifier); - } else { - fd = event_notifier_get_fd(config_notifier); - } - r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); - if (r < 0) { - VHOST_OPS_DEBUG(r, "vhost_set_config_call failed"); - } -} - -static void vhost_stop_config_intr(struct vhost_dev *dev) -{ - int fd = -1; - assert(dev->vhost_ops); - if (dev->vhost_ops->vhost_set_config_call) { - dev->vhost_ops->vhost_set_config_call(dev, fd); - } -} - -static void vhost_start_config_intr(struct vhost_dev *dev) -{ - int r; - - assert(dev->vhost_ops); - int fd = event_notifier_get_fd(&dev->vdev->config_notifier); - if (dev->vhost_ops->vhost_set_config_call) { - r = dev->vhost_ops->vhost_set_config_call(dev, fd); - if (!r) { - event_notifier_set(&dev->vdev->config_notifier); - } - } -} - uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, uint64_t features) { @@ -1827,16 +1766,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) } } - r = event_notifier_init( - &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); - if (r < 0) { - return r; - } - event_notifier_test_and_clear( - &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); - if (!vdev->use_guest_notifier_mask) { - vhost_config_mask(hdev, vdev, true); - } if (hdev->log_enabled) { uint64_t log_base; @@ -1869,7 +1798,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) vhost_device_iotlb_miss(hdev, vq->used_phys, true); } } - vhost_start_config_intr(hdev); return 0; fail_log: vhost_log_put(hdev, false); @@ -1895,9 +1823,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) /* should only be called after backend is connected */ assert(hdev->vhost_ops); - event_notifier_test_and_clear( - &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); - event_notifier_test_and_clear(&vdev->config_notifier); if (hdev->vhost_ops->vhost_dev_start) { hdev->vhost_ops->vhost_dev_start(hdev, false); @@ -1915,7 +1840,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) } memory_listener_unregister(&hdev->iommu_listener); } - vhost_stop_config_intr(hdev); vhost_log_put(hdev, true); hdev->started = false; hdev->vdev = NULL; diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 1d5192f8b4..54f9bbb789 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -948,9 +948,6 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, assert(vcrypto->vhost_started); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return; - } cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); } @@ -961,9 +958,6 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) assert(vcrypto->vhost_started); - if (idx == VIRTIO_CONFIG_IRQ_IDX) { - return false; - } return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); } diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 809132018b..72da12fea5 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -673,30 +673,7 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, return 0; } -static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign) -{ - VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); - bool with_irqfd = false; - EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); - int r = 0; - if (assign) { - r = event_notifier_init(notifier, 0); - if (r < 0) { - return r; - } - virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); - } else { - virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); - event_notifier_cleanup(notifier); - } - if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { - vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); - } - return r; -} static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) { @@ -718,10 +695,6 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, goto assign_error; } } - r = virtio_mmio_set_config_guest_notifier(d, assign); - if (r < 0) { - goto assign_error; - } return 0; diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 98fb5493ae..750aa47ec1 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -677,6 +677,7 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, } static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, + unsigned int queue_no, unsigned int vector) { VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; @@ -703,160 +704,112 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, } static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, - EventNotifier *n, + unsigned int queue_no, unsigned int vector) { VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_get_queue(vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); } static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, - EventNotifier *n , + unsigned int queue_no, unsigned int vector) { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_get_queue(vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; int ret; ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); assert(ret == 0); } -static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, - EventNotifier **n, unsigned int *vector) -{ - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - VirtQueue *vq; - if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { - *n = virtio_config_get_guest_notifier(vdev); - *vector = vdev->config_vector; - } else { - if (!virtio_queue_get_num(vdev, queue_no)) { - return -1; - } - *vector = virtio_queue_vector(vdev, queue_no); - vq = virtio_get_queue(vdev, queue_no); - *n = virtio_queue_get_guest_notifier(vq); - } - return 0; -} - -static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) +static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) { - unsigned int vector; - int ret; - EventNotifier *n; PCIDevice *dev = &proxy->pci_dev; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + unsigned int vector; + int ret, queue_no; - ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); - if (ret < 0) { - return ret; - } - if (vector >= msix_nr_vectors_allocated(dev)) { - return 0; - } - ret = kvm_virtio_pci_vq_vector_use(proxy, vector); - if (ret < 0) { - goto undo; - } - /* - * If guest supports masking, set up irqfd now. - * Otherwise, delay until unmasked in the frontend. - */ - if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { - ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } + vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } + ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); if (ret < 0) { - kvm_virtio_pci_vq_vector_release(proxy, vector); goto undo; } + /* If guest supports masking, set up irqfd now. + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } + } } - return 0; -undo: - vector = virtio_queue_vector(vdev, queue_no); - if (vector >= msix_nr_vectors_allocated(dev)) { - return ret; - } - if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { - ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); - if (ret < 0) { - return ret; +undo: + while (--queue_no >= 0) { + vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; } - kvm_virtio_pci_irqfd_release(proxy, n, vector); - } - return ret; -} -static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) -{ - int queue_no; - int ret = 0; - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - - for (queue_no = 0; queue_no < nvqs; queue_no++) { - if (!virtio_queue_get_num(vdev, queue_no)) { - return -1; + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } - ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); + kvm_virtio_pci_vq_vector_release(proxy, vector); } return ret; } -static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) -{ - return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); -} - -static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, - int queue_no) +static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) { + PCIDevice *dev = &proxy->pci_dev; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); unsigned int vector; - EventNotifier *n; - int ret; - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - PCIDevice *dev = &proxy->pci_dev; - - ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); - if (ret < 0) { - return; - } - if (vector >= msix_nr_vectors_allocated(dev)) { - return; - } - if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { - kvm_virtio_pci_irqfd_release(proxy, n, vector); - } - kvm_virtio_pci_vq_vector_release(proxy, vector); -} - -static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) -{ int queue_no; - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); for (queue_no = 0; queue_no < nvqs; queue_no++) { if (!virtio_queue_get_num(vdev, queue_no)) { break; } - kvm_virtio_pci_vector_release_one(proxy, queue_no); + vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } + /* If guest supports masking, clean up irqfd now. + * Otherwise, it was cleaned when masked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); } } -static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) -{ - kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); -} - -static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, +static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, unsigned int queue_no, unsigned int vector, - MSIMessage msg, - EventNotifier *n) + MSIMessage msg) { VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + VirtQueue *vq = virtio_get_queue(vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd; int ret = 0; @@ -883,15 +836,14 @@ static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, event_notifier_set(n); } } else { - ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); } return ret; } -static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, +static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, unsigned int queue_no, - unsigned int vector, - EventNotifier *n) + unsigned int vector) { VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); @@ -902,7 +854,7 @@ static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { k->guest_notifier_mask(vdev, queue_no, true); } else { - kvm_virtio_pci_irqfd_release(proxy, n, vector); + kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } } @@ -912,7 +864,6 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtQueue *vq = virtio_vector_first_queue(vdev, vector); - EventNotifier *n; int ret, index, unmasked = 0; while (vq) { @@ -921,8 +872,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, break; } if (index < proxy->nvqs_with_notifiers) { - n = virtio_queue_get_guest_notifier(vq); - ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); + ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); if (ret < 0) { goto undo; } @@ -930,24 +880,15 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, } vq = virtio_vector_next_queue(vq); } - /* unmask config intr */ - n = virtio_config_get_guest_notifier(vdev); - ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, - msg, n); - if (ret < 0) { - goto undo_config; - } + return 0; -undo_config: - n = virtio_config_get_guest_notifier(vdev); - virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + undo: vq = virtio_vector_first_queue(vdev, vector); while (vq && unmasked >= 0) { index = virtio_get_queue_index(vq); if (index < proxy->nvqs_with_notifiers) { - n = virtio_queue_get_guest_notifier(vq); - virtio_pci_one_vector_mask(proxy, index, vector, n); + virtio_pci_vq_vector_mask(proxy, index, vector); --unmasked; } vq = virtio_vector_next_queue(vq); @@ -960,22 +901,18 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtQueue *vq = virtio_vector_first_queue(vdev, vector); - EventNotifier *n; int index; while (vq) { index = virtio_get_queue_index(vq); - n = virtio_queue_get_guest_notifier(vq); if (!virtio_queue_get_num(vdev, index)) { break; } if (index < proxy->nvqs_with_notifiers) { - virtio_pci_one_vector_mask(proxy, index, vector, n); + virtio_pci_vq_vector_mask(proxy, index, vector); } vq = virtio_vector_next_queue(vq); } - n = virtio_config_get_guest_notifier(vdev); - virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); } static void virtio_pci_vector_poll(PCIDevice *dev, @@ -988,17 +925,19 @@ static void virtio_pci_vector_poll(PCIDevice *dev, int queue_no; unsigned int vector; EventNotifier *notifier; - int ret; + VirtQueue *vq; for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { - ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); - if (ret < 0) { + if (!virtio_queue_get_num(vdev, queue_no)) { break; } + vector = virtio_queue_vector(vdev, queue_no); if (vector < vector_start || vector >= vector_end || !msix_is_masked(dev, vector)) { continue; } + vq = virtio_get_queue(vdev, queue_no); + notifier = virtio_queue_get_guest_notifier(vq); if (k->guest_notifier_pending) { if (k->guest_notifier_pending(vdev, queue_no)) { msix_set_pending(dev, vector); @@ -1007,34 +946,6 @@ static void virtio_pci_vector_poll(PCIDevice *dev, msix_set_pending(dev, vector); } } - /* poll the config intr */ - ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, - &vector); - if (ret < 0) { - return; - } - if (vector < vector_start || vector >= vector_end || - !msix_is_masked(dev, vector)) { - return; - } - if (k->guest_notifier_pending) { - if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { - msix_set_pending(dev, vector); - } - } else if (event_notifier_test_and_clear(notifier)) { - msix_set_pending(dev, vector); - } -} - -void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, - int n, bool assign, - bool with_irqfd) -{ - if (n == VIRTIO_CONFIG_IRQ_IDX) { - virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); - } else { - virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); - } } static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, @@ -1043,25 +954,17 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); - VirtQueue *vq = NULL; - EventNotifier *notifier = NULL; - - if (n == VIRTIO_CONFIG_IRQ_IDX) { - notifier = virtio_config_get_guest_notifier(vdev); - } else { - vq = virtio_get_queue(vdev, n); - notifier = virtio_queue_get_guest_notifier(vq); - } + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); if (assign) { int r = event_notifier_init(notifier, 0); if (r < 0) { return r; } - virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); + virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); } else { - virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, - with_irqfd); + virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); event_notifier_cleanup(notifier); } @@ -1103,7 +1006,6 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) msix_unset_vector_notifiers(&proxy->pci_dev); if (proxy->vector_irqfd) { kvm_virtio_pci_vector_release(proxy, nvqs); - kvm_virtio_pci_vector_config_release(proxy); g_free(proxy->vector_irqfd); proxy->vector_irqfd = NULL; } @@ -1119,11 +1021,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) goto assign_error; } } - r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, - with_irqfd); - if (r < 0) { - goto config_assign_error; - } + /* Must set vector notifier after guest notifier has been assigned */ if ((with_irqfd || k->guest_notifier_mask) && assign) { if (with_irqfd) { @@ -1132,14 +1030,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) msix_nr_vectors_allocated(&proxy->pci_dev)); r = kvm_virtio_pci_vector_use(proxy, nvqs); if (r < 0) { - goto config_assign_error; + goto assign_error; } } - r = kvm_virtio_pci_vector_config_use(proxy); - if (r < 0) { - goto config_error; - } - r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, + r = msix_set_vector_notifiers(&proxy->pci_dev, + virtio_pci_vector_unmask, virtio_pci_vector_mask, virtio_pci_vector_poll); if (r < 0) { @@ -1154,11 +1049,7 @@ notifiers_error: assert(assign); kvm_virtio_pci_vector_release(proxy, nvqs); } -config_error: - kvm_virtio_pci_vector_config_release(proxy); -config_assign_error: - virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, - with_irqfd); + assign_error: /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ assert(assign); diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index b704acc5a8..2446dcd9ae 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -251,7 +251,5 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); * @fixed_queues. */ unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); -void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, - int n, bool assign, - bool with_irqfd); + #endif diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 971e59a663..aae72fb8b7 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -125,7 +125,6 @@ struct VirtQueue uint16_t vector; VirtIOHandleOutput handle_output; - VirtIOHandleAIOOutput handle_aio_output; VirtIODevice *vdev; EventNotifier guest_notifier; EventNotifier host_notifier; @@ -2303,24 +2302,6 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align) } } -static bool virtio_queue_notify_aio_vq(VirtQueue *vq) -{ - bool ret = false; - - if (vq->vring.desc && vq->handle_aio_output) { - VirtIODevice *vdev = vq->vdev; - - trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); - ret = vq->handle_aio_output(vdev, vq); - - if (unlikely(vdev->start_on_kick)) { - virtio_set_started(vdev, true); - } - } - - return ret; -} - static void virtio_queue_notify_vq(VirtQueue *vq) { if (vq->vring.desc && vq->handle_output) { @@ -2399,7 +2380,6 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, vdev->vq[i].vring.num_default = queue_size; vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN; vdev->vq[i].handle_output = handle_output; - vdev->vq[i].handle_aio_output = NULL; vdev->vq[i].used_elems = g_malloc0(sizeof(VirtQueueElement) * queue_size); @@ -2411,7 +2391,6 @@ void virtio_delete_queue(VirtQueue *vq) vq->vring.num = 0; vq->vring.num_default = 0; vq->handle_output = NULL; - vq->handle_aio_output = NULL; g_free(vq->used_elems); vq->used_elems = NULL; virtio_virtqueue_reset_region_cache(vq); @@ -3494,14 +3473,7 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) virtio_irq(vq); } } -static void virtio_config_guest_notifier_read(EventNotifier *n) -{ - VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); - if (event_notifier_test_and_clear(n)) { - virtio_notify_config(vdev); - } -} void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, bool with_irqfd) { @@ -3518,36 +3490,11 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, } } -void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, - bool assign, bool with_irqfd) -{ - EventNotifier *n; - n = &vdev->config_notifier; - if (assign && !with_irqfd) { - event_notifier_set_handler(n, virtio_config_guest_notifier_read); - } else { - event_notifier_set_handler(n, NULL); - } - if (!assign) { - /* Test and clear notifier before closing it,*/ - /* in case poll callback didn't have time to run. */ - virtio_config_guest_notifier_read(n); - } -} - EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) { return &vq->guest_notifier; } -static void virtio_queue_host_notifier_aio_read(EventNotifier *n) -{ - VirtQueue *vq = container_of(n, VirtQueue, host_notifier); - if (event_notifier_test_and_clear(n)) { - virtio_queue_notify_aio_vq(vq); - } -} - static void virtio_queue_host_notifier_aio_poll_begin(EventNotifier *n) { VirtQueue *vq = container_of(n, VirtQueue, host_notifier); @@ -3560,11 +3507,14 @@ static bool virtio_queue_host_notifier_aio_poll(void *opaque) EventNotifier *n = opaque; VirtQueue *vq = container_of(n, VirtQueue, host_notifier); - if (!vq->vring.desc || virtio_queue_empty(vq)) { - return false; - } + return vq->vring.desc && !virtio_queue_empty(vq); +} - return virtio_queue_notify_aio_vq(vq); +static void virtio_queue_host_notifier_aio_poll_ready(EventNotifier *n) +{ + VirtQueue *vq = container_of(n, VirtQueue, host_notifier); + + virtio_queue_notify_vq(vq); } static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) @@ -3575,24 +3525,23 @@ static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) virtio_queue_set_notification(vq, 1); } -void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, - VirtIOHandleAIOOutput handle_output) +void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx) { - if (handle_output) { - vq->handle_aio_output = handle_output; - aio_set_event_notifier(ctx, &vq->host_notifier, true, - virtio_queue_host_notifier_aio_read, - virtio_queue_host_notifier_aio_poll); - aio_set_event_notifier_poll(ctx, &vq->host_notifier, - virtio_queue_host_notifier_aio_poll_begin, - virtio_queue_host_notifier_aio_poll_end); - } else { - aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL); - /* Test and clear notifier before after disabling event, - * in case poll callback didn't have time to run. */ - virtio_queue_host_notifier_aio_read(&vq->host_notifier); - vq->handle_aio_output = NULL; - } + aio_set_event_notifier(ctx, &vq->host_notifier, true, + virtio_queue_host_notifier_read, + virtio_queue_host_notifier_aio_poll, + virtio_queue_host_notifier_aio_poll_ready); + aio_set_event_notifier_poll(ctx, &vq->host_notifier, + virtio_queue_host_notifier_aio_poll_begin, + virtio_queue_host_notifier_aio_poll_end); +} + +void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx) +{ + aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL); + /* Test and clear notifier before after disabling event, + * in case poll callback didn't have time to run. */ + virtio_queue_host_notifier_read(&vq->host_notifier); } void virtio_queue_host_notifier_read(EventNotifier *n) @@ -3608,11 +3557,6 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) return &vq->host_notifier; } -EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) -{ - return &vdev->config_notifier; -} - void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) { vq->host_notifier_enabled = enabled; diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 416583f130..645a29a5a0 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1115,11 +1115,11 @@ void xen_device_set_event_channel_context(XenDevice *xendev, if (channel->ctx) aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); channel->ctx = ctx; aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, - xen_device_event, NULL, xen_device_poll, channel); + xen_device_event, NULL, xen_device_poll, NULL, channel); } XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev, @@ -1193,7 +1193,7 @@ void xen_device_unbind_event_channel(XenDevice *xendev, QLIST_REMOVE(channel, list); aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) { error_setg_errno(errp, errno, "xenevtchn_unbind failed"); |