diff options
Diffstat (limited to 'hw/intc')
-rw-r--r-- | hw/intc/xics.c | 461 | ||||
-rw-r--r-- | hw/intc/xics_kvm.c | 184 | ||||
-rw-r--r-- | hw/intc/xics_spapr.c | 128 |
3 files changed, 256 insertions, 517 deletions
diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 095c16a300..ffc0747c7f 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -49,40 +49,41 @@ int xics_get_cpu_index_by_dt_id(int cpu_dt_id) return -1; } -void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu) +void xics_cpu_destroy(XICSFabric *xi, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); - ICPState *ss = &xics->ss[cs->cpu_index]; + ICPState *icp = xics_icp_get(xi, cs->cpu_index); - assert(cs->cpu_index < xics->nr_servers); - assert(cs == ss->cs); + assert(icp); + assert(cs == icp->cs); - ss->output = NULL; - ss->cs = NULL; + icp->output = NULL; + icp->cs = NULL; } -void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) +void xics_cpu_setup(XICSFabric *xi, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - ICPState *ss = &xics->ss[cs->cpu_index]; - XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); + ICPState *icp = xics_icp_get(xi, cs->cpu_index); + ICPStateClass *icpc; - assert(cs->cpu_index < xics->nr_servers); + assert(icp); - ss->cs = cs; + icp->cs = cs; - if (info->cpu_setup) { - info->cpu_setup(xics, cpu); + icpc = ICP_GET_CLASS(icp); + if (icpc->cpu_setup) { + icpc->cpu_setup(icp, cpu); } switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_POWER7: - ss->output = env->irq_inputs[POWER7_INPUT_INT]; + icp->output = env->irq_inputs[POWER7_INPUT_INT]; break; case PPC_FLAGS_INPUT_970: - ss->output = env->irq_inputs[PPC970_INPUT_INT]; + icp->output = env->irq_inputs[PPC970_INPUT_INT]; break; default: @@ -92,185 +93,43 @@ void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) } } -static void xics_common_pic_print_info(InterruptStatsProvider *obj, - Monitor *mon) +void icp_pic_print_info(ICPState *icp, Monitor *mon) { - XICSState *xics = XICS_COMMON(obj); - ICSState *ics; - uint32_t i; - - for (i = 0; i < xics->nr_servers; i++) { - ICPState *icp = &xics->ss[i]; - - if (!icp->output) { - continue; - } - monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n", - i, icp->xirr, icp->xirr_owner, - icp->pending_priority, icp->mfrr); - } - - QLIST_FOREACH(ics, &xics->ics, list) { - monitor_printf(mon, "ICS %4x..%4x %p\n", - ics->offset, ics->offset + ics->nr_irqs - 1, ics); - - if (!ics->irqs) { - continue; - } - - for (i = 0; i < ics->nr_irqs; i++) { - ICSIRQState *irq = ics->irqs + i; - - if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) { - continue; - } - monitor_printf(mon, " %4x %s %02x %02x\n", - ics->offset + i, - (irq->flags & XICS_FLAGS_IRQ_LSI) ? - "LSI" : "MSI", - irq->priority, irq->status); - } - } -} - -/* - * XICS Common class - parent for emulated XICS and KVM-XICS - */ -static void xics_common_reset(DeviceState *d) -{ - XICSState *xics = XICS_COMMON(d); - ICSState *ics; - int i; - - for (i = 0; i < xics->nr_servers; i++) { - device_reset(DEVICE(&xics->ss[i])); - } - - QLIST_FOREACH(ics, &xics->ics, list) { - device_reset(DEVICE(ics)); - } -} - -static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - XICSState *xics = XICS_COMMON(obj); - int64_t value = xics->nr_irqs; + int cpu_index = icp->cs ? icp->cs->cpu_index : -1; - visit_type_int(v, name, &value, errp); -} - -static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - XICSState *xics = XICS_COMMON(obj); - XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); - Error *error = NULL; - int64_t value; - - visit_type_int(v, name, &value, &error); - if (error) { - error_propagate(errp, error); + if (!icp->output) { return; } - if (xics->nr_irqs) { - error_setg(errp, "Number of interrupts is already set to %u", - xics->nr_irqs); - return; - } - - assert(info->set_nr_irqs); - info->set_nr_irqs(xics, value, errp); -} - -void xics_set_nr_servers(XICSState *xics, uint32_t nr_servers, - const char *typename, Error **errp) -{ - int i; - - xics->nr_servers = nr_servers; - - xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); - for (i = 0; i < xics->nr_servers; i++) { - char name[32]; - ICPState *icp = &xics->ss[i]; - - object_initialize(icp, sizeof(*icp), typename); - snprintf(name, sizeof(name), "icp[%d]", i); - object_property_add_child(OBJECT(xics), name, OBJECT(icp), errp); - icp->xics = xics; - } + monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n", + cpu_index, icp->xirr, icp->xirr_owner, + icp->pending_priority, icp->mfrr); } -static void xics_prop_get_nr_servers(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) +void ics_pic_print_info(ICSState *ics, Monitor *mon) { - XICSState *xics = XICS_COMMON(obj); - int64_t value = xics->nr_servers; - - visit_type_int(v, name, &value, errp); -} + uint32_t i; -static void xics_prop_set_nr_servers(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - XICSState *xics = XICS_COMMON(obj); - XICSStateClass *xsc = XICS_COMMON_GET_CLASS(xics); - Error *error = NULL; - int64_t value; + monitor_printf(mon, "ICS %4x..%4x %p\n", + ics->offset, ics->offset + ics->nr_irqs - 1, ics); - visit_type_int(v, name, &value, &error); - if (error) { - error_propagate(errp, error); + if (!ics->irqs) { return; } - if (xics->nr_servers) { - error_setg(errp, "Number of servers is already set to %u", - xics->nr_servers); - return; - } - - assert(xsc->set_nr_servers); - xsc->set_nr_servers(xics, value, errp); -} - -static void xics_common_initfn(Object *obj) -{ - XICSState *xics = XICS_COMMON(obj); - QLIST_INIT(&xics->ics); - object_property_add(obj, "nr_irqs", "int", - xics_prop_get_nr_irqs, xics_prop_set_nr_irqs, - NULL, NULL, NULL); - object_property_add(obj, "nr_servers", "int", - xics_prop_get_nr_servers, xics_prop_set_nr_servers, - NULL, NULL, NULL); -} - -static void xics_common_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); + for (i = 0; i < ics->nr_irqs; i++) { + ICSIRQState *irq = ics->irqs + i; - dc->reset = xics_common_reset; - ic->print_info = xics_common_pic_print_info; + if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) { + continue; + } + monitor_printf(mon, " %4x %s %02x %02x\n", + ics->offset + i, + (irq->flags & XICS_FLAGS_IRQ_LSI) ? + "LSI" : "MSI", + irq->priority, irq->status); + } } -static const TypeInfo xics_common_info = { - .name = TYPE_XICS_COMMON, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(XICSState), - .class_size = sizeof(XICSStateClass), - .instance_init = xics_common_initfn, - .class_init = xics_common_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_INTERRUPT_STATS_PROVIDER }, - { } - }, -}; - /* * ICP: Presentation layer */ @@ -278,8 +137,8 @@ static const TypeInfo xics_common_info = { #define XISR_MASK 0x00ffffff #define CPPR_MASK 0xff000000 -#define XISR(ss) (((ss)->xirr) & XISR_MASK) -#define CPPR(ss) (((ss)->xirr) >> 24) +#define XISR(icp) (((icp)->xirr) & XISR_MASK) +#define CPPR(icp) (((icp)->xirr) >> 24) static void ics_reject(ICSState *ics, uint32_t nr) { @@ -290,7 +149,7 @@ static void ics_reject(ICSState *ics, uint32_t nr) } } -static void ics_resend(ICSState *ics) +void ics_resend(ICSState *ics) { ICSStateClass *k = ICS_BASE_GET_CLASS(ics); @@ -308,151 +167,152 @@ static void ics_eoi(ICSState *ics, int nr) } } -static void icp_check_ipi(ICPState *ss) +static void icp_check_ipi(ICPState *icp) { - if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { + if (XISR(icp) && (icp->pending_priority <= icp->mfrr)) { return; } - trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr); + trace_xics_icp_check_ipi(icp->cs->cpu_index, icp->mfrr); - if (XISR(ss) && ss->xirr_owner) { - ics_reject(ss->xirr_owner, XISR(ss)); + if (XISR(icp) && icp->xirr_owner) { + ics_reject(icp->xirr_owner, XISR(icp)); } - ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; - ss->pending_priority = ss->mfrr; - ss->xirr_owner = NULL; - qemu_irq_raise(ss->output); + icp->xirr = (icp->xirr & ~XISR_MASK) | XICS_IPI; + icp->pending_priority = icp->mfrr; + icp->xirr_owner = NULL; + qemu_irq_raise(icp->output); } -static void icp_resend(ICPState *ss) +void icp_resend(ICPState *icp) { - ICSState *ics; + XICSFabric *xi = icp->xics; + XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi); - if (ss->mfrr < CPPR(ss)) { - icp_check_ipi(ss); - } - QLIST_FOREACH(ics, &ss->xics->ics, list) { - ics_resend(ics); + if (icp->mfrr < CPPR(icp)) { + icp_check_ipi(icp); } + + xic->ics_resend(xi); } -void icp_set_cppr(ICPState *ss, uint8_t cppr) +void icp_set_cppr(ICPState *icp, uint8_t cppr) { uint8_t old_cppr; uint32_t old_xisr; - old_cppr = CPPR(ss); - ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24); + old_cppr = CPPR(icp); + icp->xirr = (icp->xirr & ~CPPR_MASK) | (cppr << 24); if (cppr < old_cppr) { - if (XISR(ss) && (cppr <= ss->pending_priority)) { - old_xisr = XISR(ss); - ss->xirr &= ~XISR_MASK; /* Clear XISR */ - ss->pending_priority = 0xff; - qemu_irq_lower(ss->output); - if (ss->xirr_owner) { - ics_reject(ss->xirr_owner, old_xisr); - ss->xirr_owner = NULL; + if (XISR(icp) && (cppr <= icp->pending_priority)) { + old_xisr = XISR(icp); + icp->xirr &= ~XISR_MASK; /* Clear XISR */ + icp->pending_priority = 0xff; + qemu_irq_lower(icp->output); + if (icp->xirr_owner) { + ics_reject(icp->xirr_owner, old_xisr); + icp->xirr_owner = NULL; } } } else { - if (!XISR(ss)) { - icp_resend(ss); + if (!XISR(icp)) { + icp_resend(icp); } } } -void icp_set_mfrr(ICPState *ss, uint8_t mfrr) +void icp_set_mfrr(ICPState *icp, uint8_t mfrr) { - ss->mfrr = mfrr; - if (mfrr < CPPR(ss)) { - icp_check_ipi(ss); + icp->mfrr = mfrr; + if (mfrr < CPPR(icp)) { + icp_check_ipi(icp); } } -uint32_t icp_accept(ICPState *ss) +uint32_t icp_accept(ICPState *icp) { - uint32_t xirr = ss->xirr; + uint32_t xirr = icp->xirr; - qemu_irq_lower(ss->output); - ss->xirr = ss->pending_priority << 24; - ss->pending_priority = 0xff; - ss->xirr_owner = NULL; + qemu_irq_lower(icp->output); + icp->xirr = icp->pending_priority << 24; + icp->pending_priority = 0xff; + icp->xirr_owner = NULL; - trace_xics_icp_accept(xirr, ss->xirr); + trace_xics_icp_accept(xirr, icp->xirr); return xirr; } -uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr) +uint32_t icp_ipoll(ICPState *icp, uint32_t *mfrr) { if (mfrr) { - *mfrr = ss->mfrr; + *mfrr = icp->mfrr; } - return ss->xirr; + return icp->xirr; } -void icp_eoi(ICPState *ss, uint32_t xirr) +void icp_eoi(ICPState *icp, uint32_t xirr) { + XICSFabric *xi = icp->xics; + XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi); ICSState *ics; uint32_t irq; /* Send EOI -> ICS */ - ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); - trace_xics_icp_eoi(ss->cs->cpu_index, xirr, ss->xirr); + icp->xirr = (icp->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); + trace_xics_icp_eoi(icp->cs->cpu_index, xirr, icp->xirr); irq = xirr & XISR_MASK; - QLIST_FOREACH(ics, &ss->xics->ics, list) { - if (ics_valid_irq(ics, irq)) { - ics_eoi(ics, irq); - } + + ics = xic->ics_get(xi, irq); + if (ics) { + ics_eoi(ics, irq); } - if (!XISR(ss)) { - icp_resend(ss); + if (!XISR(icp)) { + icp_resend(icp); } } static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority) { - XICSState *xics = ics->xics; - ICPState *ss = xics->ss + server; + ICPState *icp = xics_icp_get(ics->xics, server); trace_xics_icp_irq(server, nr, priority); - if ((priority >= CPPR(ss)) - || (XISR(ss) && (ss->pending_priority <= priority))) { + if ((priority >= CPPR(icp)) + || (XISR(icp) && (icp->pending_priority <= priority))) { ics_reject(ics, nr); } else { - if (XISR(ss) && ss->xirr_owner) { - ics_reject(ss->xirr_owner, XISR(ss)); - ss->xirr_owner = NULL; + if (XISR(icp) && icp->xirr_owner) { + ics_reject(icp->xirr_owner, XISR(icp)); + icp->xirr_owner = NULL; } - ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); - ss->xirr_owner = ics; - ss->pending_priority = priority; - trace_xics_icp_raise(ss->xirr, ss->pending_priority); - qemu_irq_raise(ss->output); + icp->xirr = (icp->xirr & ~XISR_MASK) | (nr & XISR_MASK); + icp->xirr_owner = ics; + icp->pending_priority = priority; + trace_xics_icp_raise(icp->xirr, icp->pending_priority); + qemu_irq_raise(icp->output); } } static void icp_dispatch_pre_save(void *opaque) { - ICPState *ss = opaque; - ICPStateClass *info = ICP_GET_CLASS(ss); + ICPState *icp = opaque; + ICPStateClass *info = ICP_GET_CLASS(icp); if (info->pre_save) { - info->pre_save(ss); + info->pre_save(icp); } } static int icp_dispatch_post_load(void *opaque, int version_id) { - ICPState *ss = opaque; - ICPStateClass *info = ICP_GET_CLASS(ss); + ICPState *icp = opaque; + ICPStateClass *info = ICP_GET_CLASS(icp); if (info->post_load) { - return info->post_load(ss, version_id); + return info->post_load(icp, version_id); } return 0; @@ -485,12 +345,30 @@ static void icp_reset(DeviceState *dev) qemu_set_irq(icp->output, 0); } +static void icp_realize(DeviceState *dev, Error **errp) +{ + ICPState *icp = ICP(dev); + Object *obj; + Error *err = NULL; + + obj = object_property_get_link(OBJECT(dev), "xics", &err); + if (!obj) { + error_setg(errp, "%s: required link 'xics' not found: %s", + __func__, error_get_pretty(err)); + return; + } + + icp->xics = XICS_FABRIC(obj); +} + + static void icp_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = icp_reset; dc->vmsd = &vmstate_icp_server; + dc->realize = icp_realize; } static const TypeInfo icp_info = { @@ -663,17 +541,6 @@ static void ics_simple_reset(DeviceState *dev) } } -static int ics_simple_post_load(ICSState *ics, int version_id) -{ - int i; - - for (i = 0; i < ics->xics->nr_servers; i++) { - icp_resend(&ics->xics->ss[i]); - } - - return 0; -} - static void ics_simple_dispatch_pre_save(void *opaque) { ICSState *ics = opaque; @@ -746,15 +613,20 @@ static void ics_simple_realize(DeviceState *dev, Error **errp) ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); } +static Property ics_simple_properties[] = { + DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void ics_simple_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ICSStateClass *isc = ICS_BASE_CLASS(klass); - dc->realize = ics_simple_realize; + isc->realize = ics_simple_realize; + dc->props = ics_simple_properties; dc->vmsd = &vmstate_ics_simple; dc->reset = ics_simple_reset; - isc->post_load = ics_simple_post_load; isc->reject = ics_simple_reject; isc->resend = ics_simple_resend; isc->eoi = ics_simple_eoi; @@ -769,38 +641,69 @@ static const TypeInfo ics_simple_info = { .instance_init = ics_simple_initfn, }; +static void ics_base_realize(DeviceState *dev, Error **errp) +{ + ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev); + ICSState *ics = ICS_BASE(dev); + Object *obj; + Error *err = NULL; + + obj = object_property_get_link(OBJECT(dev), "xics", &err); + if (!obj) { + error_setg(errp, "%s: required link 'xics' not found: %s", + __func__, error_get_pretty(err)); + return; + } + ics->xics = XICS_FABRIC(obj); + + + if (icsc->realize) { + icsc->realize(dev, errp); + } +} + +static void ics_base_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = ics_base_realize; +} + static const TypeInfo ics_base_info = { .name = TYPE_ICS_BASE, .parent = TYPE_DEVICE, .abstract = true, .instance_size = sizeof(ICSState), + .class_init = ics_base_class_init, .class_size = sizeof(ICSStateClass), }; +static const TypeInfo xics_fabric_info = { + .name = TYPE_XICS_FABRIC, + .parent = TYPE_INTERFACE, + .class_size = sizeof(XICSFabricClass), +}; + /* * Exported functions */ -ICSState *xics_find_source(XICSState *xics, int irq) +qemu_irq xics_get_qirq(XICSFabric *xi, int irq) { - ICSState *ics; + XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi); + ICSState *ics = xic->ics_get(xi, irq); - QLIST_FOREACH(ics, &xics->ics, list) { - if (ics_valid_irq(ics, irq)) { - return ics; - } + if (ics) { + return ics->qirqs[irq - ics->offset]; } + return NULL; } -qemu_irq xics_get_qirq(XICSState *xics, int irq) +ICPState *xics_icp_get(XICSFabric *xi, int server) { - ICSState *ics = xics_find_source(xics, irq); + XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi); - if (ics) { - return ics->qirqs[irq - ics->offset]; - } - - return NULL; + return xic->icp_get(xi, server); } void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) @@ -813,10 +716,10 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) static void xics_register_types(void) { - type_register_static(&xics_common_info); type_register_static(&ics_simple_info); type_register_static(&ics_base_info); type_register_static(&icp_info); + type_register_static(&xics_fabric_info); } type_init(xics_register_types) diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 17694eaa87..0a3daca3bb 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -40,16 +40,12 @@ #include <sys/ioctl.h> -typedef struct KVMXICSState { - XICSState parent_obj; - - int kernel_xics_fd; -} KVMXICSState; +static int kernel_xics_fd = -1; /* * ICP-KVM */ -static void icp_get_kvm_state(ICPState *ss) +static void icp_get_kvm_state(ICPState *icp) { uint64_t state; struct kvm_one_reg reg = { @@ -59,25 +55,25 @@ static void icp_get_kvm_state(ICPState *ss) int ret; /* ICP for this CPU thread is not in use, exiting */ - if (!ss->cs) { + if (!icp->cs) { return; } - ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, ®); + ret = kvm_vcpu_ioctl(icp->cs, KVM_GET_ONE_REG, ®); if (ret != 0) { error_report("Unable to retrieve KVM interrupt controller state" - " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno)); + " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno)); exit(1); } - ss->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; - ss->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) + icp->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; + icp->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) & KVM_REG_PPC_ICP_MFRR_MASK; - ss->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) + icp->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) & KVM_REG_PPC_ICP_PPRI_MASK; } -static int icp_set_kvm_state(ICPState *ss, int version_id) +static int icp_set_kvm_state(ICPState *icp, int version_id) { uint64_t state; struct kvm_one_reg reg = { @@ -87,18 +83,18 @@ static int icp_set_kvm_state(ICPState *ss, int version_id) int ret; /* ICP for this CPU thread is not in use, exiting */ - if (!ss->cs) { + if (!icp->cs) { return 0; } - state = ((uint64_t)ss->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) - | ((uint64_t)ss->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) - | ((uint64_t)ss->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); + state = ((uint64_t)icp->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) + | ((uint64_t)icp->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) + | ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); - ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, ®); + ret = kvm_vcpu_ioctl(icp->cs, KVM_SET_ONE_REG, ®); if (ret != 0) { error_report("Unable to restore KVM interrupt controller state (0x%" - PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs), + PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(icp->cs), strerror(errno)); return ret; } @@ -122,6 +118,34 @@ static void icp_kvm_reset(DeviceState *dev) icp_set_kvm_state(icp, 1); } +static void icp_kvm_cpu_setup(ICPState *icp, PowerPCCPU *cpu) +{ + CPUState *cs = CPU(cpu); + int ret; + + if (kernel_xics_fd == -1) { + abort(); + } + + /* + * If we are reusing a parked vCPU fd corresponding to the CPU + * which was hot-removed earlier we don't have to renable + * KVM_CAP_IRQ_XICS capability again. + */ + if (icp->cap_irq_xics_enabled) { + return; + } + + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, + kvm_arch_vcpu_id(cs)); + if (ret < 0) { + error_report("Unable to connect CPU%ld to kernel XICS: %s", + kvm_arch_vcpu_id(cs), strerror(errno)); + exit(1); + } + icp->cap_irq_xics_enabled = true; +} + static void icp_kvm_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -130,6 +154,7 @@ static void icp_kvm_class_init(ObjectClass *klass, void *data) dc->reset = icp_kvm_reset; icpc->pre_save = icp_get_kvm_state; icpc->post_load = icp_set_kvm_state; + icpc->cpu_setup = icp_kvm_cpu_setup; } static const TypeInfo icp_kvm_info = { @@ -145,7 +170,6 @@ static const TypeInfo icp_kvm_info = { */ static void ics_get_kvm_state(ICSState *ics) { - KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -160,7 +184,7 @@ static void ics_get_kvm_state(ICSState *ics) attr.attr = i + ics->offset; - ret = ioctl(xicskvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); + ret = ioctl(kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); if (ret != 0) { error_report("Unable to retrieve KVM interrupt controller state" " for IRQ %d: %s", i + ics->offset, strerror(errno)); @@ -204,7 +228,6 @@ static void ics_get_kvm_state(ICSState *ics) static int ics_set_kvm_state(ICSState *ics, int version_id) { - KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -238,7 +261,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id) } } - ret = ioctl(xicskvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); + ret = ioctl(kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); if (ret != 0) { error_report("Unable to restore KVM interrupt controller state" " for IRQs %d: %s", i + ics->offset, strerror(errno)); @@ -308,7 +331,7 @@ static void ics_kvm_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); ICSStateClass *icsc = ICS_BASE_CLASS(klass); - dc->realize = ics_kvm_realize; + icsc->realize = ics_kvm_realize; dc->reset = ics_kvm_reset; icsc->pre_save = ics_get_kvm_state; icsc->post_load = ics_set_kvm_state; @@ -324,57 +347,6 @@ static const TypeInfo ics_kvm_info = { /* * XICS-KVM */ -static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) -{ - CPUState *cs; - ICPState *ss; - KVMXICSState *xicskvm = XICS_SPAPR_KVM(xics); - int ret; - - cs = CPU(cpu); - ss = &xics->ss[cs->cpu_index]; - - assert(cs->cpu_index < xics->nr_servers); - if (xicskvm->kernel_xics_fd == -1) { - abort(); - } - - /* - * If we are reusing a parked vCPU fd corresponding to the CPU - * which was hot-removed earlier we don't have to renable - * KVM_CAP_IRQ_XICS capability again. - */ - if (ss->cap_irq_xics_enabled) { - return; - } - - ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, xicskvm->kernel_xics_fd, - kvm_arch_vcpu_id(cs)); - if (ret < 0) { - error_report("Unable to connect CPU%ld to kernel XICS: %s", - kvm_arch_vcpu_id(cs), strerror(errno)); - exit(1); - } - ss->cap_irq_xics_enabled = true; -} - -static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, - Error **errp) -{ - ICSState *ics = QLIST_FIRST(&xics->ics); - - /* This needs to be deprecated ... */ - xics->nr_irqs = nr_irqs; - if (ics) { - ics->nr_irqs = nr_irqs; - } -} - -static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers, - Error **errp) -{ - xics_set_nr_servers(xics, nr_servers, TYPE_KVM_ICP, errp); -} static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t token, @@ -385,13 +357,9 @@ static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, __func__); } -static void xics_kvm_realize(DeviceState *dev, Error **errp) +int xics_kvm_init(sPAPRMachineState *spapr, Error **errp) { - KVMXICSState *xicskvm = XICS_SPAPR_KVM(dev); - XICSState *xics = XICS_COMMON(dev); - ICSState *ics; - int i, rc; - Error *error = NULL; + int rc; struct kvm_create_device xics_create_device = { .type = KVM_DEV_TYPE_XICS, .flags = 0, @@ -439,72 +407,24 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) goto fail; } - xicskvm->kernel_xics_fd = xics_create_device.fd; - - QLIST_FOREACH(ics, &xics->ics, list) { - object_property_set_bool(OBJECT(ics), true, "realized", &error); - if (error) { - error_propagate(errp, error); - goto fail; - } - } - - assert(xics->nr_servers); - for (i = 0; i < xics->nr_servers; i++) { - object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized", - &error); - if (error) { - error_propagate(errp, error); - goto fail; - } - } + kernel_xics_fd = xics_create_device.fd; kvm_kernel_irqchip = true; kvm_msi_via_irqfd_allowed = true; kvm_gsi_direct_mapping = true; - return; + return rc; fail: kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); + return -1; } -static void xics_kvm_initfn(Object *obj) -{ - XICSState *xics = XICS_COMMON(obj); - ICSState *ics; - - ics = ICS_SIMPLE(object_new(TYPE_ICS_KVM)); - object_property_add_child(obj, "ics", OBJECT(ics), NULL); - ics->xics = xics; - QLIST_INSERT_HEAD(&xics->ics, ics, list); -} - -static void xics_kvm_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - XICSStateClass *xsc = XICS_COMMON_CLASS(oc); - - dc->realize = xics_kvm_realize; - xsc->cpu_setup = xics_kvm_cpu_setup; - xsc->set_nr_irqs = xics_kvm_set_nr_irqs; - xsc->set_nr_servers = xics_kvm_set_nr_servers; -} - -static const TypeInfo xics_spapr_kvm_info = { - .name = TYPE_XICS_SPAPR_KVM, - .parent = TYPE_XICS_COMMON, - .instance_size = sizeof(KVMXICSState), - .class_init = xics_kvm_class_init, - .instance_init = xics_kvm_initfn, -}; - static void xics_kvm_register_types(void) { - type_register_static(&xics_spapr_kvm_info); type_register_static(&ics_kvm_info); type_register_static(&icp_kvm_info); } diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 2e3f1c5e95..84d24b2837 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -44,7 +44,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *icp = &spapr->xics->ss[cs->cpu_index]; + ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index); target_ulong cppr = args[0]; icp_set_cppr(icp, cppr); @@ -56,12 +56,13 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, { target_ulong server = xics_get_cpu_index_by_dt_id(args[0]); target_ulong mfrr = args[1]; + ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), server); - if (server >= spapr->xics->nr_servers) { + if (!icp) { return H_PARAMETER; } - icp_set_mfrr(spapr->xics->ss + server, mfrr); + icp_set_mfrr(icp, mfrr); return H_SUCCESS; } @@ -69,7 +70,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *icp = &spapr->xics->ss[cs->cpu_index]; + ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index); uint32_t xirr = icp_accept(icp); args[0] = xirr; @@ -80,7 +81,7 @@ static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *icp = &spapr->xics->ss[cs->cpu_index]; + ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index); uint32_t xirr = icp_accept(icp); args[0] = xirr; @@ -92,7 +93,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *icp = &spapr->xics->ss[cs->cpu_index]; + ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index); target_ulong xirr = args[0]; icp_eoi(icp, xirr); @@ -103,7 +104,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *icp = &spapr->xics->ss[cs->cpu_index]; + ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index); uint32_t mfrr; uint32_t xirr = icp_ipoll(icp, &mfrr); @@ -118,7 +119,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = QLIST_FIRST(&spapr->xics->ics); + ICSState *ics = spapr->ics; uint32_t nr, srcno, server, priority; if ((nargs != 3) || (nret != 1)) { @@ -134,7 +135,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1)); priority = rtas_ld(args, 2); - if (!ics_valid_irq(ics, nr) || (server >= ics->xics->nr_servers) + if (!ics_valid_irq(ics, nr) || !xics_icp_get(XICS_FABRIC(spapr), server) || (priority > 0xff)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; @@ -151,7 +152,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = QLIST_FIRST(&spapr->xics->ics); + ICSState *ics = spapr->ics; uint32_t nr, srcno; if ((nargs != 1) || (nret != 3)) { @@ -181,7 +182,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = QLIST_FIRST(&spapr->xics->ics); + ICSState *ics = spapr->ics; uint32_t nr, srcno; if ((nargs != 1) || (nret != 1)) { @@ -212,7 +213,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = QLIST_FIRST(&spapr->xics->ics); + ICSState *ics = spapr->ics; uint32_t nr, srcno; if ((nargs != 1) || (nret != 1)) { @@ -239,36 +240,8 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, rtas_st(rets, 0, RTAS_OUT_SUCCESS); } -static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, - Error **errp) +int xics_spapr_init(sPAPRMachineState *spapr, Error **errp) { - ICSState *ics = QLIST_FIRST(&xics->ics); - - /* This needs to be deprecated ... */ - xics->nr_irqs = nr_irqs; - if (ics) { - ics->nr_irqs = nr_irqs; - } -} - -static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers, - Error **errp) -{ - xics_set_nr_servers(xics, nr_servers, TYPE_ICP, errp); -} - -static void xics_spapr_realize(DeviceState *dev, Error **errp) -{ - XICSState *xics = XICS_SPAPR(dev); - ICSState *ics; - Error *error = NULL; - int i; - - if (!xics->nr_servers) { - error_setg(errp, "Number of servers needs to be greater 0"); - return; - } - /* Registration of global state belongs into realize */ spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); @@ -281,55 +254,9 @@ static void xics_spapr_realize(DeviceState *dev, Error **errp) spapr_register_hypercall(H_XIRR_X, h_xirr_x); spapr_register_hypercall(H_EOI, h_eoi); spapr_register_hypercall(H_IPOLL, h_ipoll); - - QLIST_FOREACH(ics, &xics->ics, list) { - object_property_set_bool(OBJECT(ics), true, "realized", &error); - if (error) { - error_propagate(errp, error); - return; - } - } - - for (i = 0; i < xics->nr_servers; i++) { - object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized", - &error); - if (error) { - error_propagate(errp, error); - return; - } - } -} - -static void xics_spapr_initfn(Object *obj) -{ - XICSState *xics = XICS_SPAPR(obj); - ICSState *ics; - - ics = ICS_SIMPLE(object_new(TYPE_ICS_SIMPLE)); - object_property_add_child(obj, "ics", OBJECT(ics), NULL); - ics->xics = xics; - QLIST_INSERT_HEAD(&xics->ics, ics, list); -} - -static void xics_spapr_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - XICSStateClass *xsc = XICS_SPAPR_CLASS(oc); - - dc->realize = xics_spapr_realize; - xsc->set_nr_irqs = xics_spapr_set_nr_irqs; - xsc->set_nr_servers = xics_spapr_set_nr_servers; + return 0; } -static const TypeInfo xics_spapr_info = { - .name = TYPE_XICS_SPAPR, - .parent = TYPE_XICS_COMMON, - .instance_size = sizeof(XICSState), - .class_size = sizeof(XICSStateClass), - .class_init = xics_spapr_class_init, - .instance_init = xics_spapr_initfn, -}; - #define ICS_IRQ_FREE(ics, srcno) \ (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) @@ -354,9 +281,8 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) return -1; } -int xics_spapr_alloc(XICSState *xics, int irq_hint, bool lsi, Error **errp) +int spapr_ics_alloc(ICSState *ics, int irq_hint, bool lsi, Error **errp) { - ICSState *ics = QLIST_FIRST(&xics->ics); int irq; if (!ics) { @@ -387,10 +313,9 @@ int xics_spapr_alloc(XICSState *xics, int irq_hint, bool lsi, Error **errp) * Allocate block of consecutive IRQs, and return the number of the first IRQ in * the block. If align==true, aligns the first IRQ number to num. */ -int xics_spapr_alloc_block(XICSState *xics, int num, bool lsi, bool align, - Error **errp) +int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi, + bool align, Error **errp) { - ICSState *ics = QLIST_FIRST(&xics->ics); int i, first = -1; if (!ics) { @@ -440,20 +365,18 @@ static void ics_free(ICSState *ics, int srcno, int num) } } -void xics_spapr_free(XICSState *xics, int irq, int num) +void spapr_ics_free(ICSState *ics, int irq, int num) { - ICSState *ics = xics_find_source(xics, irq); - - if (ics) { + if (ics_valid_irq(ics, irq)) { trace_xics_ics_free(0, irq, num); ics_free(ics, irq - ics->offset, num); } } -void spapr_dt_xics(XICSState *xics, void *fdt, uint32_t phandle) +void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle) { uint32_t interrupt_server_ranges_prop[] = { - 0, cpu_to_be32(xics->nr_servers), + 0, cpu_to_be32(nr_servers), }; int node; @@ -470,10 +393,3 @@ void spapr_dt_xics(XICSState *xics, void *fdt, uint32_t phandle) _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); } - -static void xics_spapr_register_types(void) -{ - type_register_static(&xics_spapr_info); -} - -type_init(xics_spapr_register_types) |