Commit ab711e21 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.9-20170301' into staging



ppc patch queue for 2017-03-01

I was hoping to get this pull request squeezed in before the soft
freeze, but I ran into some difficulties during testing.  Everything
here was at least posted before the soft freeze, so I'm hoping we can
still merge it for 2.9.

The biggest things here are:
    * Cleanups to handling of hashed page tables, that will make
      adding support for the POWER9 MMU easier
    * Cleanups to the XICS interrupt controller that will make
      implementing the powernv machine easier
    * TCG implementation of extended overflow and carry handling for
      POWER9

It also includes:
    * Increasing the CPU limit for pseries to 1024 vCPUs
    * Generating proper OF node names in qemu (making hotplug and
      coldplug logic closer together)

# gpg: Signature made Wed 01 Mar 2017 04:43:06 GMT
# gpg:                using RSA key 0x6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-2.9-20170301: (50 commits)
  Add PowerPC 32-bit guest memory dump support
  ppc/xics: rename 'ICPState *' variables to 'icp'
  ppc/xics: move InterruptStatsProvider to the sPAPR machine
  ppc/xics: move ics-simple post_load under the machine
  ppc/xics: remove the XICSState classes
  ppc/xics: export the XICS init routines
  ppc/xics: move the ICP array under the sPAPR machine
  ppc/xics: register the reset handler of ICP objects
  ppc/xics: simplify spapr_dt_xics() interface
  ppc/xics: use the QOM interface to grab an ICP
  ppc/xics: move the cpu_setup() handler under the ICPState class
  ppc/xics: simplify the cpu_setup() handler
  ppc/xics: move kernel_xics_fd out of KVMXICSState
  ppc/xics: extend the QOM interface to handle ICPs
  ppc/xics: remove the XICS list of ICS
  ppc/xics: register the reset handler of ICS objects
  ppc/xics: remove xics_find_source()
  ppc/xics: use the QOM interface to resend irqs
  ppc/xics: use the QOM interface to get irqs
  ppc/xics: use the QOM interface under the sPAPR machine
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 4bc0d39a 356bb70e
Loading
Loading
Loading
Loading
+182 −279
Original line number Diff line number Diff line
@@ -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,30 +93,27 @@ 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];
    int cpu_index = icp->cs ? icp->cs->cpu_index : -1;

    if (!icp->output) {
            continue;
        return;
    }
    monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n",
                       i, icp->xirr, icp->xirr_owner,
                   cpu_index, icp->xirr, icp->xirr_owner,
                   icp->pending_priority, icp->mfrr);
}

    QLIST_FOREACH(ics, &xics->ics, list) {
void ics_pic_print_info(ICSState *ics, Monitor *mon)
{
    uint32_t i;

    monitor_printf(mon, "ICS %4x..%4x %p\n",
                   ics->offset, ics->offset + ics->nr_irqs - 1, ics);

    if (!ics->irqs) {
            continue;
        return;
    }

    for (i = 0; i < ics->nr_irqs; i++) {
@@ -131,145 +129,6 @@ static void xics_common_pic_print_info(InterruptStatsProvider *obj,
                       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;

    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);
        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;
    }
}

static void xics_prop_get_nr_servers(Object *obj, Visitor *v,
                                     const char *name, void *opaque,
                                     Error **errp)
{
    XICSState *xics = XICS_COMMON(obj);
    int64_t value = xics->nr_servers;

    visit_type_int(v, name, &value, errp);
}

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;

    visit_type_int(v, name, &value, &error);
    if (error) {
        error_propagate(errp, error);
        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);

    dc->reset = xics_common_reset;
    ic->print_info = xics_common_pic_print_info;
}

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 = 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)
+52 −132

File changed.

Preview size limit exceeded, changes collapsed.

+22 −106
Original line number Diff line number Diff line
@@ -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)
+28 −0
Original line number Diff line number Diff line
@@ -1530,6 +1530,34 @@ static const pci_class_desc pci_class_descriptions[] =
    { 0, NULL}
};

static void pci_for_each_device_under_bus_reverse(PCIBus *bus,
                                                  void (*fn)(PCIBus *b,
                                                             PCIDevice *d,
                                                             void *opaque),
                                                  void *opaque)
{
    PCIDevice *d;
    int devfn;

    for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
        d = bus->devices[ARRAY_SIZE(bus->devices) - 1 - devfn];
        if (d) {
            fn(bus, d, opaque);
        }
    }
}

void pci_for_each_device_reverse(PCIBus *bus, int bus_num,
                         void (*fn)(PCIBus *b, PCIDevice *d, void *opaque),
                         void *opaque)
{
    bus = pci_find_bus_nr(bus, bus_num);

    if (bus) {
        pci_for_each_device_under_bus_reverse(bus, fn, opaque);
    }
}

static void pci_for_each_device_under_bus(PCIBus *bus,
                                          void (*fn)(PCIBus *b, PCIDevice *d,
                                                     void *opaque),
+169 −27

File changed.

Preview size limit exceeded, changes collapsed.

Loading