diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2012-04-16 12:50:12 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2012-04-16 12:50:12 -0500 |
commit | 8a6b8708e37a4df064aa3b36d7baa786110871f4 (patch) | |
tree | dbb00258c2a3ec5738801279a1d40ed2f3f8b131 | |
parent | e6f5d0be730a41bacb10edba19d1369ec2949486 (diff) | |
parent | fda1f7684935ae7290c8a31e3ba9fdb30eead4ed (diff) |
Merge remote-tracking branch 'sstabellini/for_anthony' into staging
* sstabellini/for_anthony:
xen: introduce an event channel for buffered io event notifications
xen-mapcache: don't unmap locked entry during mapcache invalidation
Xen, mapcache: Fix the compute of the size of bucket.
xen: handle backend deletion from xenstore
Xen: Add xen-apic support and hook it up.
Xen: basic HVM MSI injection support.
-rw-r--r-- | Makefile.target | 2 | ||||
-rw-r--r-- | hw/pc.c | 8 | ||||
-rw-r--r-- | hw/xen.h | 1 | ||||
-rw-r--r-- | hw/xen_apic.c | 90 | ||||
-rw-r--r-- | hw/xen_backend.c | 17 | ||||
-rw-r--r-- | hw/xen_disk.c | 4 | ||||
-rw-r--r-- | xen-all.c | 50 | ||||
-rw-r--r-- | xen-mapcache.c | 15 | ||||
-rw-r--r-- | xen-stub.c | 4 |
9 files changed, 171 insertions, 20 deletions
diff --git a/Makefile.target b/Makefile.target index 61dfe3b79f..84951a09ec 100644 --- a/Makefile.target +++ b/Makefile.target @@ -239,7 +239,7 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS) obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o obj-$(CONFIG_NO_XEN) += xen-stub.o -obj-i386-$(CONFIG_XEN) += xen_platform.o +obj-i386-$(CONFIG_XEN) += xen_platform.o xen_apic.o # Inter-VM PCI shared memory CONFIG_IVSHMEM = @@ -42,6 +42,7 @@ #include "sysbus.h" #include "sysemu.h" #include "kvm.h" +#include "xen.h" #include "blockdev.h" #include "ui/qemu-spice.h" #include "memory.h" @@ -891,9 +892,12 @@ static DeviceState *apic_init(void *env, uint8_t apic_id) if (kvm_irqchip_in_kernel()) { dev = qdev_create(NULL, "kvm-apic"); + } else if (xen_enabled()) { + dev = qdev_create(NULL, "xen-apic"); } else { dev = qdev_create(NULL, "apic"); } + qdev_prop_set_uint8(dev, "id", apic_id); qdev_prop_set_ptr(dev, "cpu_env", env); qdev_init_nofail(dev); @@ -912,6 +916,10 @@ static DeviceState *apic_init(void *env, uint8_t apic_id) msi_supported = true; } + if (xen_enabled()) { + msi_supported = true; + } + return dev; } @@ -34,6 +34,7 @@ static inline int xen_enabled(void) int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); void xen_piix3_set_irq(void *opaque, int irq_num, int level); void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len); +void xen_hvm_inject_msi(uint64_t addr, uint32_t data); void xen_cmos_set_s3_resume(void *opaque, int irq, int level); qemu_irq *xen_interrupt_controller_init(void); diff --git a/hw/xen_apic.c b/hw/xen_apic.c new file mode 100644 index 0000000000..1725ff67dd --- /dev/null +++ b/hw/xen_apic.c @@ -0,0 +1,90 @@ +/* + * Xen basic APIC support + * + * Copyright (c) 2012 Citrix + * + * Authors: + * Wei Liu <wei.liu2@citrix.com> + * + * This work is licensed under the terms of the GNU GPL version 2 or + * later. See the COPYING file in the top-level directory. + */ +#include "hw/apic_internal.h" +#include "hw/msi.h" +#include "xen.h" + +static uint64_t xen_apic_mem_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + return ~(uint64_t)0; +} + +static void xen_apic_mem_write(void *opaque, target_phys_addr_t addr, + uint64_t data, unsigned size) +{ + if (size != sizeof(uint32_t)) { + fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size); + return; + } + + xen_hvm_inject_msi(addr, data); +} + +static const MemoryRegionOps xen_apic_io_ops = { + .read = xen_apic_mem_read, + .write = xen_apic_mem_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void xen_apic_init(APICCommonState *s) +{ + memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi", + MSI_SPACE_SIZE); +} + +static void xen_apic_set_base(APICCommonState *s, uint64_t val) +{ +} + +static void xen_apic_set_tpr(APICCommonState *s, uint8_t val) +{ +} + +static uint8_t xen_apic_get_tpr(APICCommonState *s) +{ + return 0; +} + +static void xen_apic_vapic_base_update(APICCommonState *s) +{ +} + +static void xen_apic_external_nmi(APICCommonState *s) +{ +} + +static void xen_apic_class_init(ObjectClass *klass, void *data) +{ + APICCommonClass *k = APIC_COMMON_CLASS(klass); + + k->init = xen_apic_init; + k->set_base = xen_apic_set_base; + k->set_tpr = xen_apic_set_tpr; + k->get_tpr = xen_apic_get_tpr; + k->vapic_base_update = xen_apic_vapic_base_update; + k->external_nmi = xen_apic_external_nmi; +} + +static TypeInfo xen_apic_info = { + .name = "xen-apic", + .parent = TYPE_APIC_COMMON, + .instance_size = sizeof(APICCommonState), + .class_init = xen_apic_class_init, +}; + +static void xen_apic_register_types(void) +{ + type_register_static(&xen_apic_info); +} + +type_init(xen_apic_register_types) diff --git a/hw/xen_backend.c b/hw/xen_backend.c index 2673ace185..66cb144397 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -592,7 +592,7 @@ static void xenstore_update_be(char *watch, char *type, int dom, struct XenDevOps *ops) { struct XenDevice *xendev; - char path[XEN_BUFSIZE], *dom0; + char path[XEN_BUFSIZE], *dom0, *bepath; unsigned int len, dev; dom0 = xs_get_domain_path(xenstore, 0); @@ -611,15 +611,16 @@ static void xenstore_update_be(char *watch, char *type, int dom, return; } - if (0) { - /* FIXME: detect devices being deleted from xenstore ... */ - xen_be_del_xendev(dom, dev); - } - xendev = xen_be_get_xendev(type, dom, dev, ops); if (xendev != NULL) { - xen_be_backend_changed(xendev, path); - xen_be_check_state(xendev); + bepath = xs_read(xenstore, 0, xendev->be, &len); + if (bepath == NULL) { + xen_be_del_xendev(dom, dev); + } else { + free(bepath); + xen_be_backend_changed(xendev, path); + xen_be_check_state(xendev); + } } } diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 9719395b09..22dbd10303 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -745,6 +745,10 @@ static int blk_free(struct XenDevice *xendev) struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); struct ioreq *ioreq; + if (blkdev->bs || blkdev->sring) { + blk_disconnect(xendev); + } + while (!QLIST_EMPTY(&blkdev->freelist)) { ioreq = QLIST_FIRST(&blkdev->freelist); QLIST_REMOVE(ioreq, list); @@ -59,6 +59,9 @@ static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu) } # define FMT_ioreq_size "u" #endif +#ifndef HVM_PARAM_BUFIOREQ_EVTCHN +#define HVM_PARAM_BUFIOREQ_EVTCHN 26 +#endif #define BUFFER_IO_MAX_DELAY 100 @@ -77,6 +80,8 @@ typedef struct XenIOState { QEMUTimer *buffered_io_timer; /* the evtchn port for polling the notification, */ evtchn_port_t *ioreq_local_port; + /* evtchn local port for buffered io */ + evtchn_port_t bufioreq_local_port; /* the evtchn fd for polling */ XenEvtchn xce_handle; /* which vcpu we are serving */ @@ -122,6 +127,11 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) } } +void xen_hvm_inject_msi(uint64_t addr, uint32_t data) +{ + xc_hvm_inject_msi(xen_xc, xen_domid, addr, data); +} + static void xen_suspend_notifier(Notifier *notifier, void *data) { xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3); @@ -624,6 +634,12 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state) evtchn_port_t port; port = xc_evtchn_pending(state->xce_handle); + if (port == state->bufioreq_local_port) { + qemu_mod_timer(state->buffered_io_timer, + BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock)); + return NULL; + } + if (port != -1) { for (i = 0; i < smp_cpus; i++) { if (state->ioreq_local_port[i] == port) { @@ -772,16 +788,18 @@ static void handle_ioreq(ioreq_t *req) } } -static void handle_buffered_iopage(XenIOState *state) +static int handle_buffered_iopage(XenIOState *state) { buf_ioreq_t *buf_req = NULL; ioreq_t req; int qw; if (!state->buffered_io_page) { - return; + return 0; } + memset(&req, 0x00, sizeof(req)); + while (state->buffered_io_page->read_pointer != state->buffered_io_page->write_pointer) { buf_req = &state->buffered_io_page->buf_ioreq[ state->buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM]; @@ -806,15 +824,21 @@ static void handle_buffered_iopage(XenIOState *state) xen_mb(); state->buffered_io_page->read_pointer += qw ? 2 : 1; } + + return req.count; } static void handle_buffered_io(void *opaque) { XenIOState *state = opaque; - handle_buffered_iopage(state); - qemu_mod_timer(state->buffered_io_timer, - BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock)); + if (handle_buffered_iopage(state)) { + qemu_mod_timer(state->buffered_io_timer, + BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock)); + } else { + qemu_del_timer(state->buffered_io_timer); + xc_evtchn_unmask(state->xce_handle, state->bufioreq_local_port); + } } static void cpu_handle_ioreq(void *opaque) @@ -944,7 +968,6 @@ static void xen_main_loop_prepare(XenIOState *state) state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io, state); - qemu_mod_timer(state->buffered_io_timer, qemu_get_clock_ms(rt_clock)); if (evtchn_fd != -1) { qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state); @@ -1045,6 +1068,7 @@ int xen_hvm_init(void) { int i, rc; unsigned long ioreq_pfn; + unsigned long bufioreq_evtchn; XenIOState *state; state = g_malloc0(sizeof (XenIOState)); @@ -1097,6 +1121,20 @@ int xen_hvm_init(void) state->ioreq_local_port[i] = rc; } + rc = xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_EVTCHN, + &bufioreq_evtchn); + if (rc < 0) { + fprintf(stderr, "failed to get HVM_PARAM_BUFIOREQ_EVTCHN\n"); + return -1; + } + rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid, + (uint32_t)bufioreq_evtchn); + if (rc == -1) { + fprintf(stderr, "bind interdomain ioctl error %d\n", errno); + return -1; + } + state->bufioreq_local_port = rc; + /* Init RAM management */ xen_map_cache_init(xen_phys_offset_to_gaddr, state); xen_ram_init(ram_size); diff --git a/xen-mapcache.c b/xen-mapcache.c index a456479363..59ba085b62 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -216,12 +216,14 @@ tryagain: } /* size is always a multiple of MCACHE_BUCKET_SIZE */ - if ((address_offset + (__size % MCACHE_BUCKET_SIZE)) > MCACHE_BUCKET_SIZE) - __size += MCACHE_BUCKET_SIZE; - if (__size % MCACHE_BUCKET_SIZE) - __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE); - if (!__size) + if (size) { + __size = size + address_offset; + if (__size % MCACHE_BUCKET_SIZE) { + __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE); + } + } else { __size = MCACHE_BUCKET_SIZE; + } entry = &mapcache->entry[address_index % mapcache->nr_buckets]; @@ -385,6 +387,9 @@ void xen_invalidate_map_cache(void) if (entry->vaddr_base == NULL) { continue; } + if (entry->lock > 0) { + continue; + } if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); diff --git a/xen-stub.c b/xen-stub.c index 9ea02d435e..8ff2b79ac6 100644 --- a/xen-stub.c +++ b/xen-stub.c @@ -29,6 +29,10 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) { } +void xen_hvm_inject_msi(uint64_t addr, uint32_t data) +{ +} + void xen_cmos_set_s3_resume(void *opaque, int irq, int level) { } |