This patch is for testing only and goes along with other two patches for priodrop and dev passthrough, it should apply against 1.4.5. diff --git a/cpus.c b/cpus.c index c15ff6c..0c19214 100644 --- a/cpus.c +++ b/cpus.c @@ -737,6 +737,26 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) CPUState *cpu = ENV_GET_CPU(env); int r; + /* For now just do a 1:1 vCPU binding as they come online for device + * pass through + */ + cpu_set_t cpuset; + int ret, i; + unsigned long cpu_index = kvm_arch_vcpu_id(cpu); + + CPU_ZERO(&cpuset); + CPU_SET(cpu_index, &cpuset); + ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if(ret != 0) { + printf("pthread_setaffinity_np failed to setaffinity to CPU 0\n"); + exit(-1); + } + + CPU_ZERO(&cpuset); + pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if(CPU_ISSET(cpu_index,&cpuset)) + printf("Binding: vCPU %ld --> CPU %d\n", cpu_index, i); + qemu_mutex_lock(&qemu_global_mutex); qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index caca979..46c2c59 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -904,6 +904,8 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) /* Available with KVM_CAP_ARM_SET_DEVICE_ADDR */ #define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr) +#define KVM_ARM_GET_DEVICE_RESOURCES _IOW(KVMIO, 0xe1, struct kvm_arm_get_device_resources) +#define KVM_ARM_ASSIGN_DEVICE _IOW(KVMIO, 0xe2, struct kvm_arm_assigned_device) /* * ioctls for vcpu fds @@ -1013,6 +1015,7 @@ struct kvm_assigned_irq { }; }; + struct kvm_assigned_msix_nr { __u32 assigned_dev_id; __u16 entry_nr; @@ -1027,4 +1030,33 @@ struct kvm_assigned_msix_entry { __u16 padding[3]; }; + +/* MAX 6 MMIO resources per device */ +#define MAX_RES_PER_DEVICE 6 +struct kvm_arm_get_device_resources { + char devname[128]; + __u32 resource_cnt; + struct { + __u64 hpa; + __u32 size; + __u32 attr; + char host_name[64]; + } host_resources[MAX_RES_PER_DEVICE]; + struct { + __u32 hwirq; + __u32 attr; + char host_name[64]; + } hostirq; +}; + +struct kvm_guest_device_resources { + __u64 gpa[MAX_RES_PER_DEVICE]; + __u32 girq; +}; + +struct kvm_arm_assigned_device { + struct kvm_arm_get_device_resources dev_res; + struct kvm_guest_device_resources guest_res; +}; + #endif /* __LINUX_KVM_H */ diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs index d89b57c..9aee84e 100644 --- a/target-arm/Makefile.objs +++ b/target-arm/Makefile.objs @@ -1,5 +1,5 @@ obj-y += arm-semi.o obj-$(CONFIG_SOFTMMU) += machine.o -obj-$(CONFIG_KVM) += kvm.o +obj-$(CONFIG_KVM) += kvm.o device-assign.o obj-y += translate.o op_helper.o helper.o cpu.o obj-y += neon_helper.o iwmmxt_helper.o diff --git a/target-arm/device-assign.c b/target-arm/device-assign.c new file mode 100644 index 0000000..e4d0e97 --- /dev/null +++ b/target-arm/device-assign.c @@ -0,0 +1,118 @@ + +#include "hw/sysbus.h" +#include "qemu-common.h" +#include "hw/qdev.h" +#include "hw/ptimer.h" +#include "kvm_arm.h" +#include "qemu/error-report.h" + +#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */ +#define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */ +#define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_REG 0x00000300 /* Register offsets */ +#define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_DMA 0x00000800 + +#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */ +#define IORESOURCE_READONLY 0x00004000 +#define IORESOURCE_CACHEABLE 0x00008000 + +typedef struct { + SysBusDevice busdev; + char *devname; + uint64_t hpa, gpa; + uint32_t dev_size; + uint32_t hirq,girq; +} AssignedDevice; + +static Property device_assign_properties[] = { + DEFINE_PROP_STRING("host", AssignedDevice, devname), + DEFINE_PROP_UINT64("hpa", AssignedDevice, hpa, 0), + DEFINE_PROP_UINT64("gpa", AssignedDevice, gpa, 0), + DEFINE_PROP_UINT32("size", AssignedDevice, dev_size, 0), + DEFINE_PROP_UINT32("hostirq", AssignedDevice, hirq, 0), + DEFINE_PROP_UINT32("guestirq", AssignedDevice, girq, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static int assign_device(AssignedDevice *dev) +{ + int ret,i; + struct kvm_arm_get_device_resources dev_res; + struct kvm_arm_assigned_device dev_assigned; + char *p, c='-'; + + memset(&dev_res,0,sizeof(dev_res)); + memset(&dev_assigned,0,sizeof(dev_assigned)); + + if((p = strstr(dev->devname, (char *)&c)) != (char *) NULL) + *p = ','; + if(dev->devname) + strcpy(dev_res.devname, dev->devname); + else + goto assign_failed; + + ret = kvm_vm_ioctl(kvm_state, KVM_ARM_GET_DEVICE_RESOURCES, &dev_res); + if(ret) + goto assign_failed; + + dev_assigned.dev_res = dev_res; + /* + * Assigning GPA to same value as HPA and Guest IRQ to same value as + * Host IRQ. The machine model is the same as host, it can be done. + * Proposed Solution is: + * - Get the values from Guest device tree, this would assume the + * passthrough device has been configured for the guest. + */ + + for(i=0; i < dev_res.resource_cnt; i++) { + dev_assigned.guest_res.gpa[i] = dev_res.host_resources[i].hpa; + } + dev_assigned.guest_res.girq = dev_res.hostirq.hwirq; + ret = kvm_vm_ioctl(kvm_state, KVM_ARM_ASSIGN_DEVICE, &dev_assigned); + return ret; +assign_failed: + return -1; +} + +static int assign_devinit(SysBusDevice *dev) +{ + AssignedDevice *d = FROM_SYSBUS(AssignedDevice, dev); + int ret; + + if (!kvm_enabled()) { + error_report("device-assign: error: requires KVM support"); + } + ret = assign_device(d); + if(ret) { + error_report("device-assign: error: internal error"); + exit(-1); + } + return 0; +} + +static void device_assign_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *k = DEVICE_CLASS(klass); + sdc->init = assign_devinit; + /* need to add - exit, and reset */ + k->props = device_assign_properties; + k->desc = "KVM-based ARM Device Passthrouhg"; +} + + + +static const TypeInfo dev_assign_info = { + .name = "kvm-device-assign", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AssignedDevice), + .class_init = device_assign_class_init, +}; + +static void assign_device_init(void) +{ + type_register_static(&dev_assign_info); +} + +type_init(assign_device_init) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index d8acace..5e9bcd0 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -22,6 +22,7 @@ #include "kvm_arm.h" #include "cpu.h" #include "hw/arm/arm.h" +#include "qemu/error-report.h" const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index b1c54ff..8cb94e3 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -29,4 +29,6 @@ */ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid); +int kvm_device_assign(KVMState *s, char *, ...); + #endif -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html