[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v1 02/11] ppc/xics: Move SPAPR specific code to
From: |
David Gibson |
Subject: |
Re: [Qemu-devel] [PATCH v1 02/11] ppc/xics: Move SPAPR specific code to a separate file |
Date: |
Fri, 24 Jun 2016 15:19:51 +1000 |
User-agent: |
Mutt/1.6.1 (2016-04-27) |
On Thu, Jun 23, 2016 at 11:17:21PM +0530, Nikunj A Dadhania wrote:
> From: Benjamin Herrenschmidt <address@hidden>
>
> Leave the core ICP/ICS logic in xics.c and move the top level
> class wrapper, hypercall and RTAS handlers to xics_spapr.c
>
> Signed-off-by: Benjamin Herrenschmidt <address@hidden>
> [add cpu.h in xics_spapr.c, move set_nr_irqs and set_nr_servers to
> xics_spapr.c]
> Signed-off-by: Nikunj A Dadhania <address@hidden>
> ---
> default-configs/ppc64-softmmu.mak | 1 +
> hw/intc/Makefile.objs | 1 +
> hw/intc/xics.c | 418 +-----------------------------------
> hw/intc/xics_spapr.c | 432
> ++++++++++++++++++++++++++++++++++++++
> include/hw/ppc/xics.h | 21 ++
> 5 files changed, 464 insertions(+), 409 deletions(-)
> create mode 100644 hw/intc/xics_spapr.c
>
> diff --git a/default-configs/ppc64-softmmu.mak
> b/default-configs/ppc64-softmmu.mak
> index bb71b23..c4be59f 100644
> --- a/default-configs/ppc64-softmmu.mak
> +++ b/default-configs/ppc64-softmmu.mak
> @@ -49,6 +49,7 @@ CONFIG_ETSEC=y
> CONFIG_LIBDECNUMBER=y
> # For pSeries
> CONFIG_XICS=$(CONFIG_PSERIES)
> +CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
> CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
> # For PReP
> CONFIG_MC146818RTC=y
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index c7bbf88..530df2e 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -30,6 +30,7 @@ obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
> obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o
> obj-$(CONFIG_SH4) += sh_intc.o
> obj-$(CONFIG_XICS) += xics.o
> +obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
> obj-$(CONFIG_XICS_KVM) += xics_kvm.o
> obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
> obj-$(CONFIG_S390_FLIC) += s390_flic.o
> diff --git a/hw/intc/xics.c b/hw/intc/xics.c
> index a715532..6ca391f 100644
> --- a/hw/intc/xics.c
> +++ b/hw/intc/xics.c
> @@ -32,12 +32,11 @@
> #include "hw/hw.h"
> #include "trace.h"
> #include "qemu/timer.h"
> -#include "hw/ppc/spapr.h"
> #include "hw/ppc/xics.h"
> #include "qemu/error-report.h"
> #include "qapi/visitor.h"
>
> -static int get_cpu_index_by_dt_id(int cpu_dt_id)
> +int get_cpu_index_by_dt_id(int cpu_dt_id)
If this is made public it needs xics_*() name the current one is too
generic for a global symbol.
> {
> PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
>
> @@ -242,7 +241,7 @@ static void icp_resend(XICSState *icp, int server)
> ics_resend(icp->ics);
> }
>
> -static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr)
> +void icp_set_cppr(XICSState *icp, int server, uint8_t cppr)
> {
> ICPState *ss = icp->ss + server;
> uint8_t old_cppr;
> @@ -266,7 +265,7 @@ static void icp_set_cppr(XICSState *icp, int server,
> uint8_t cppr)
> }
> }
>
> -static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr)
> +void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr)
> {
> ICPState *ss = icp->ss + server;
>
> @@ -276,7 +275,7 @@ static void icp_set_mfrr(XICSState *icp, int server,
> uint8_t mfrr)
> }
> }
>
> -static uint32_t icp_accept(ICPState *ss)
> +uint32_t icp_accept(ICPState *ss)
> {
> uint32_t xirr = ss->xirr;
>
> @@ -289,7 +288,7 @@ static uint32_t icp_accept(ICPState *ss)
> return xirr;
> }
>
> -static void icp_eoi(XICSState *icp, int server, uint32_t xirr)
> +void icp_eoi(XICSState *icp, int server, uint32_t xirr)
> {
> ICPState *ss = icp->ss + server;
>
> @@ -390,12 +389,6 @@ static const TypeInfo icp_info = {
> /*
> * ICS: Source layer
> */
> -static int ics_valid_irq(ICSState *ics, uint32_t nr)
> -{
> - return (nr >= ics->offset)
> - && (nr < (ics->offset + ics->nr_irqs));
> -}
> -
> static void resend_msi(ICSState *ics, int srcno)
> {
> ICSIRQState *irq = ics->irqs + srcno;
> @@ -480,8 +473,8 @@ static void write_xive_lsi(ICSState *ics, int srcno)
> resend_lsi(ics, srcno);
> }
>
> -static void ics_write_xive(ICSState *ics, int nr, int server,
> - uint8_t priority, uint8_t saved_priority)
> +void ics_write_xive(ICSState *ics, int nr, int server,
> + uint8_t priority, uint8_t saved_priority)
> {
> int srcno = nr - ics->offset;
> ICSIRQState *irq = ics->irqs + srcno;
> @@ -658,7 +651,7 @@ static const TypeInfo ics_info = {
> /*
> * Exported functions
> */
> -static int xics_find_source(XICSState *icp, int irq)
> +int xics_find_source(XICSState *icp, int irq)
> {
> int sources = 1;
> int src;
> @@ -686,7 +679,7 @@ qemu_irq xics_get_qirq(XICSState *icp, int irq)
> return NULL;
> }
>
> -static void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
> +void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
> {
> assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
>
> @@ -705,402 +698,9 @@ void xics_set_irq_type(XICSState *icp, int irq, bool
> lsi)
> ics_set_irq_type(ics, irq - ics->offset, lsi);
> }
>
> -#define ICS_IRQ_FREE(ics, srcno) \
> - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
> -
> -static int ics_find_free_block(ICSState *ics, int num, int alignnum)
> -{
> - int first, i;
> -
> - for (first = 0; first < ics->nr_irqs; first += alignnum) {
> - if (num > (ics->nr_irqs - first)) {
> - return -1;
> - }
> - for (i = first; i < first + num; ++i) {
> - if (!ICS_IRQ_FREE(ics, i)) {
> - break;
> - }
> - }
> - if (i == (first + num)) {
> - return first;
> - }
> - }
> -
> - return -1;
> -}
> -
> -int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi,
> - Error **errp)
> -{
> - ICSState *ics = &icp->ics[src];
> - int irq;
> -
> - if (irq_hint) {
> - assert(src == xics_find_source(icp, irq_hint));
> - if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
> - error_setg(errp, "can't allocate IRQ %d: already in use",
> irq_hint);
> - return -1;
> - }
> - irq = irq_hint;
> - } else {
> - irq = ics_find_free_block(ics, 1, 1);
> - if (irq < 0) {
> - error_setg(errp, "can't allocate IRQ: no IRQ left");
> - return -1;
> - }
> - irq += ics->offset;
> - }
> -
> - ics_set_irq_type(ics, irq - ics->offset, lsi);
> - trace_xics_alloc(src, irq);
> -
> - return irq;
> -}
> -
> -/*
> - * 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 *icp, int src, int num, bool lsi,
> - bool align, Error **errp)
> -{
> - int i, first = -1;
> - ICSState *ics = &icp->ics[src];
> -
> - assert(src == 0);
> - /*
> - * MSIMesage::data is used for storing VIRQ so
> - * it has to be aligned to num to support multiple
> - * MSI vectors. MSI-X is not affected by this.
> - * The hint is used for the first IRQ, the rest should
> - * be allocated continuously.
> - */
> - if (align) {
> - assert((num == 1) || (num == 2) || (num == 4) ||
> - (num == 8) || (num == 16) || (num == 32));
> - first = ics_find_free_block(ics, num, num);
> - } else {
> - first = ics_find_free_block(ics, num, 1);
> - }
> - if (first < 0) {
> - error_setg(errp, "can't find a free %d-IRQ block", num);
> - return -1;
> - }
> -
> - if (first >= 0) {
> - for (i = first; i < first + num; ++i) {
> - ics_set_irq_type(ics, i, lsi);
> - }
> - }
> - first += ics->offset;
> -
> - trace_xics_alloc_block(src, first, num, lsi, align);
> -
> - return first;
> -}
> -
> -static void ics_free(ICSState *ics, int srcno, int num)
> -{
> - int i;
> -
> - for (i = srcno; i < srcno + num; ++i) {
> - if (ICS_IRQ_FREE(ics, i)) {
> - trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset);
> - }
> - memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
> - }
> -}
> -
> -void xics_spapr_free(XICSState *icp, int irq, int num)
> -{
> - int src = xics_find_source(icp, irq);
> -
> - if (src >= 0) {
> - ICSState *ics = &icp->ics[src];
> -
> - /* FIXME: implement multiple sources */
> - assert(src == 0);
> -
> - trace_xics_ics_free(ics - icp->ics, irq, num);
> - ics_free(ics, irq - ics->offset, num);
> - }
> -}
> -
> -/*
> - * Guest interfaces
> - */
> -
> -static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - target_ulong opcode, target_ulong *args)
> -{
> - CPUState *cs = CPU(cpu);
> - target_ulong cppr = args[0];
> -
> - icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
> - return H_SUCCESS;
> -}
> -
> -static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - target_ulong opcode, target_ulong *args)
> -{
> - target_ulong server = get_cpu_index_by_dt_id(args[0]);
> - target_ulong mfrr = args[1];
> -
> - if (server >= spapr->icp->nr_servers) {
> - return H_PARAMETER;
> - }
> -
> - icp_set_mfrr(spapr->icp, server, mfrr);
> - return H_SUCCESS;
> -}
> -
> -static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - target_ulong opcode, target_ulong *args)
> -{
> - CPUState *cs = CPU(cpu);
> - uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
> -
> - args[0] = xirr;
> - return H_SUCCESS;
> -}
> -
> -static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - target_ulong opcode, target_ulong *args)
> -{
> - CPUState *cs = CPU(cpu);
> - ICPState *ss = &spapr->icp->ss[cs->cpu_index];
> - uint32_t xirr = icp_accept(ss);
> -
> - args[0] = xirr;
> - args[1] = cpu_get_host_ticks();
> - return H_SUCCESS;
> -}
> -
> -static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - target_ulong opcode, target_ulong *args)
> -{
> - CPUState *cs = CPU(cpu);
> - target_ulong xirr = args[0];
> -
> - icp_eoi(spapr->icp, cs->cpu_index, xirr);
> - return H_SUCCESS;
> -}
> -
> -static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - target_ulong opcode, target_ulong *args)
> -{
> - CPUState *cs = CPU(cpu);
> - ICPState *ss = &spapr->icp->ss[cs->cpu_index];
> -
> - args[0] = ss->xirr;
> - args[1] = ss->mfrr;
> -
> - return H_SUCCESS;
> -}
> -
> -static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - uint32_t token,
> - uint32_t nargs, target_ulong args,
> - uint32_t nret, target_ulong rets)
> -{
> - ICSState *ics = spapr->icp->ics;
> - uint32_t nr, server, priority;
> -
> - if ((nargs != 3) || (nret != 1)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - nr = rtas_ld(args, 0);
> - server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
> - priority = rtas_ld(args, 2);
> -
> - if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
> - || (priority > 0xff)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - ics_write_xive(ics, nr, server, priority, priority);
> -
> - rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> -}
> -
> -static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - uint32_t token,
> - uint32_t nargs, target_ulong args,
> - uint32_t nret, target_ulong rets)
> -{
> - ICSState *ics = spapr->icp->ics;
> - uint32_t nr;
> -
> - if ((nargs != 1) || (nret != 3)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - nr = rtas_ld(args, 0);
> -
> - if (!ics_valid_irq(ics, nr)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> - rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
> - rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
> -}
> -
> -static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - uint32_t token,
> - uint32_t nargs, target_ulong args,
> - uint32_t nret, target_ulong rets)
> -{
> - ICSState *ics = spapr->icp->ics;
> - uint32_t nr;
> -
> - if ((nargs != 1) || (nret != 1)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - nr = rtas_ld(args, 0);
> -
> - if (!ics_valid_irq(ics, nr)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
> - ics->irqs[nr - ics->offset].priority);
> -
> - rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> -}
> -
> -static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> - uint32_t token,
> - uint32_t nargs, target_ulong args,
> - uint32_t nret, target_ulong rets)
> -{
> - ICSState *ics = spapr->icp->ics;
> - uint32_t nr;
> -
> - if ((nargs != 1) || (nret != 1)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - nr = rtas_ld(args, 0);
> -
> - if (!ics_valid_irq(ics, nr)) {
> - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> - return;
> - }
> -
> - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
> - ics->irqs[nr - ics->offset].saved_priority,
> - ics->irqs[nr - ics->offset].saved_priority);
> -
> - rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> -}
> -
> -/*
> - * XICS
> - */
> -
> -static void xics_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp)
> -{
> - icp->nr_irqs = icp->ics->nr_irqs = nr_irqs;
> -}
> -
> -static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers,
> - Error **errp)
> -{
> - int i;
> -
> - icp->nr_servers = nr_servers;
> -
> - icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState));
> - for (i = 0; i < icp->nr_servers; i++) {
> - char buffer[32];
> - object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP);
> - snprintf(buffer, sizeof(buffer), "icp[%d]", i);
> - object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]),
> - errp);
> - }
> -}
> -
> -static void xics_spapr_realize(DeviceState *dev, Error **errp)
> -{
> - XICSState *icp = XICS(dev);
> - Error *error = NULL;
> - int i;
> -
> - if (!icp->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);
> - spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
> - spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
> -
> - spapr_register_hypercall(H_CPPR, h_cppr);
> - spapr_register_hypercall(H_IPI, h_ipi);
> - spapr_register_hypercall(H_XIRR, h_xirr);
> - spapr_register_hypercall(H_XIRR_X, h_xirr_x);
> - spapr_register_hypercall(H_EOI, h_eoi);
> - spapr_register_hypercall(H_IPOLL, h_ipoll);
> -
> - object_property_set_bool(OBJECT(icp->ics), true, "realized", &error);
> - if (error) {
> - error_propagate(errp, error);
> - return;
> - }
> -
> - for (i = 0; i < icp->nr_servers; i++) {
> - object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized",
> &error);
> - if (error) {
> - error_propagate(errp, error);
> - return;
> - }
> - }
> -}
> -
> -static void xics_spapr_initfn(Object *obj)
> -{
> - XICSState *xics = XICS(obj);
> -
> - xics->ics = ICS(object_new(TYPE_ICS));
> - object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
> - xics->ics->icp = xics;
> -}
> -
> -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_set_nr_irqs;
> - xsc->set_nr_servers = xics_set_nr_servers;
> -}
> -
> -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,
> -};
> -
> static void xics_register_types(void)
> {
> type_register_static(&xics_common_info);
> - type_register_static(&xics_spapr_info);
> type_register_static(&ics_info);
> type_register_static(&icp_info);
> }
> diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
> new file mode 100644
> index 0000000..48d458a
> --- /dev/null
> +++ b/hw/intc/xics_spapr.c
> @@ -0,0 +1,432 @@
> +/*
> + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System
> Emulator
> + *
> + * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
> + *
> + * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
> + *
> + * 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 "cpu.h"
> +#include "hw/hw.h"
> +#include "trace.h"
> +#include "qemu/timer.h"
> +#include "hw/ppc/spapr.h"
> +#include "hw/ppc/xics.h"
> +#include "qapi/visitor.h"
> +#include "qapi/error.h"
> +
> +/*
> + * Guest interfaces
> + */
> +
> +static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + target_ulong opcode, target_ulong *args)
> +{
> + CPUState *cs = CPU(cpu);
> + target_ulong cppr = args[0];
> +
> + icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
> + return H_SUCCESS;
> +}
> +
> +static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + target_ulong opcode, target_ulong *args)
> +{
> + target_ulong server = get_cpu_index_by_dt_id(args[0]);
> + target_ulong mfrr = args[1];
> +
> + if (server >= spapr->icp->nr_servers) {
> + return H_PARAMETER;
> + }
> +
> + icp_set_mfrr(spapr->icp, server, mfrr);
> + return H_SUCCESS;
> +}
> +
> +static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + target_ulong opcode, target_ulong *args)
> +{
> + CPUState *cs = CPU(cpu);
> + uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
> +
> + args[0] = xirr;
> + return H_SUCCESS;
> +}
> +
> +static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + target_ulong opcode, target_ulong *args)
> +{
> + CPUState *cs = CPU(cpu);
> + ICPState *ss = &spapr->icp->ss[cs->cpu_index];
> + uint32_t xirr = icp_accept(ss);
> +
> + args[0] = xirr;
> + args[1] = cpu_get_host_ticks();
> + return H_SUCCESS;
> +}
> +
> +static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + target_ulong opcode, target_ulong *args)
> +{
> + CPUState *cs = CPU(cpu);
> + target_ulong xirr = args[0];
> +
> + icp_eoi(spapr->icp, cs->cpu_index, xirr);
> + return H_SUCCESS;
> +}
> +
> +static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + target_ulong opcode, target_ulong *args)
> +{
> + CPUState *cs = CPU(cpu);
> + ICPState *ss = &spapr->icp->ss[cs->cpu_index];
> +
> + args[0] = ss->xirr;
> + args[1] = ss->mfrr;
> +
> + return H_SUCCESS;
> +}
> +
> +static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + uint32_t token,
> + uint32_t nargs, target_ulong args,
> + uint32_t nret, target_ulong rets)
> +{
> + ICSState *ics = spapr->icp->ics;
> + uint32_t nr, server, priority;
> +
> + if ((nargs != 3) || (nret != 1)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + nr = rtas_ld(args, 0);
> + server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
> + priority = rtas_ld(args, 2);
> +
> + if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
> + || (priority > 0xff)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + ics_write_xive(ics, nr, server, priority, priority);
> +
> + rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> +}
> +
> +static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + uint32_t token,
> + uint32_t nargs, target_ulong args,
> + uint32_t nret, target_ulong rets)
> +{
> + ICSState *ics = spapr->icp->ics;
> + uint32_t nr;
> +
> + if ((nargs != 1) || (nret != 3)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + nr = rtas_ld(args, 0);
> +
> + if (!ics_valid_irq(ics, nr)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> + rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
> + rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
> +}
> +
> +static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + uint32_t token,
> + uint32_t nargs, target_ulong args,
> + uint32_t nret, target_ulong rets)
> +{
> + ICSState *ics = spapr->icp->ics;
> + uint32_t nr;
> +
> + if ((nargs != 1) || (nret != 1)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + nr = rtas_ld(args, 0);
> +
> + if (!ics_valid_irq(ics, nr)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
> + ics->irqs[nr - ics->offset].priority);
> +
> + rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> +}
> +
> +static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> + uint32_t token,
> + uint32_t nargs, target_ulong args,
> + uint32_t nret, target_ulong rets)
> +{
> + ICSState *ics = spapr->icp->ics;
> + uint32_t nr;
> +
> + if ((nargs != 1) || (nret != 1)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + nr = rtas_ld(args, 0);
> +
> + if (!ics_valid_irq(ics, nr)) {
> + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> + return;
> + }
> +
> + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
> + ics->irqs[nr - ics->offset].saved_priority,
> + ics->irqs[nr - ics->offset].saved_priority);
> +
> + rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> +}
> +
> +static void xics_spapr_set_nr_irqs(XICSState *icp, uint32_t nr_irqs,
> + Error **errp)
> +{
> + icp->nr_irqs = icp->ics->nr_irqs = nr_irqs;
> +}
> +
> +static void xics_spapr_set_nr_servers(XICSState *icp, uint32_t nr_servers,
> + Error **errp)
> +{
> + int i;
> +
> + icp->nr_servers = nr_servers;
> +
> + icp->ss = g_malloc0(icp->nr_servers * sizeof(ICPState));
> + for (i = 0; i < icp->nr_servers; i++) {
> + char buffer[32];
> + object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP);
> + snprintf(buffer, sizeof(buffer), "icp[%d]", i);
> + object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]),
> + errp);
> + }
> +}
> +
> +static void xics_spapr_realize(DeviceState *dev, Error **errp)
> +{
> + XICSState *icp = XICS(dev);
> + Error *error = NULL;
> + int i;
> +
> + if (!icp->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);
> + spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
> + spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
> +
> + spapr_register_hypercall(H_CPPR, h_cppr);
> + spapr_register_hypercall(H_IPI, h_ipi);
> + spapr_register_hypercall(H_XIRR, h_xirr);
> + spapr_register_hypercall(H_XIRR_X, h_xirr_x);
> + spapr_register_hypercall(H_EOI, h_eoi);
> + spapr_register_hypercall(H_IPOLL, h_ipoll);
> +
> + object_property_set_bool(OBJECT(icp->ics), true, "realized", &error);
> + if (error) {
> + error_propagate(errp, error);
> + return;
> + }
> +
> + for (i = 0; i < icp->nr_servers; i++) {
> + object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized",
> &error);
> + if (error) {
> + error_propagate(errp, error);
> + return;
> + }
> + }
> +}
> +
> +static void xics_spapr_initfn(Object *obj)
> +{
> + XICSState *xics = XICS(obj);
> +
> + xics->ics = ICS(object_new(TYPE_ICS));
> + object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
> + xics->ics->icp = xics;
> +}
> +
> +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;
> +}
> +
> +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)))
> +
> +static int ics_find_free_block(ICSState *ics, int num, int alignnum)
> +{
> + int first, i;
> +
> + for (first = 0; first < ics->nr_irqs; first += alignnum) {
> + if (num > (ics->nr_irqs - first)) {
> + return -1;
> + }
> + for (i = first; i < first + num; ++i) {
> + if (!ICS_IRQ_FREE(ics, i)) {
> + break;
> + }
> + }
> + if (i == (first + num)) {
> + return first;
> + }
> + }
> +
> + return -1;
> +}
> +
> +int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi,
> + Error **errp)
> +{
> + ICSState *ics = &icp->ics[src];
> + int irq;
> +
> + if (irq_hint) {
> + assert(src == xics_find_source(icp, irq_hint));
> + if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
> + error_setg(errp, "can't allocate IRQ %d: already in use",
> irq_hint);
> + return -1;
> + }
> + irq = irq_hint;
> + } else {
> + irq = ics_find_free_block(ics, 1, 1);
> + if (irq < 0) {
> + error_setg(errp, "can't allocate IRQ: no IRQ left");
> + return -1;
> + }
> + irq += ics->offset;
> + }
> +
> + ics_set_irq_type(ics, irq - ics->offset, lsi);
> + trace_xics_alloc(src, irq);
> +
> + return irq;
> +}
> +
> +/*
> + * 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 *icp, int src, int num, bool lsi,
> + bool align, Error **errp)
> +{
> + int i, first = -1;
> + ICSState *ics = &icp->ics[src];
> +
> + assert(src == 0);
> + /*
> + * MSIMesage::data is used for storing VIRQ so
> + * it has to be aligned to num to support multiple
> + * MSI vectors. MSI-X is not affected by this.
> + * The hint is used for the first IRQ, the rest should
> + * be allocated continuously.
> + */
> + if (align) {
> + assert((num == 1) || (num == 2) || (num == 4) ||
> + (num == 8) || (num == 16) || (num == 32));
> + first = ics_find_free_block(ics, num, num);
> + } else {
> + first = ics_find_free_block(ics, num, 1);
> + }
> + if (first < 0) {
> + error_setg(errp, "can't find a free %d-IRQ block", num);
> + return -1;
> + }
> +
> + if (first >= 0) {
> + for (i = first; i < first + num; ++i) {
> + ics_set_irq_type(ics, i, lsi);
> + }
> + }
> + first += ics->offset;
> +
> + trace_xics_alloc_block(src, first, num, lsi, align);
> +
> + return first;
> +}
> +
> +static void ics_free(ICSState *ics, int srcno, int num)
> +{
> + int i;
> +
> + for (i = srcno; i < srcno + num; ++i) {
> + if (ICS_IRQ_FREE(ics, i)) {
> + trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset);
> + }
> + memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
> + }
> +}
> +
> +void xics_spapr_free(XICSState *icp, int irq, int num)
> +{
> + int src = xics_find_source(icp, irq);
> +
> + if (src >= 0) {
> + ICSState *ics = &icp->ics[src];
> +
> + /* FIXME: implement multiple sources */
> + assert(src == 0);
> +
> + trace_xics_ics_free(ics - icp->ics, irq, num);
> + ics_free(ics, irq - ics->offset, num);
> + }
> +}
> +
> +static void xics_spapr_register_types(void)
> +{
> + type_register_static(&xics_spapr_info);
> +}
> +
> +type_init(xics_spapr_register_types)
> diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
> index 452a978..76b45ef 100644
> --- a/include/hw/ppc/xics.h
> +++ b/include/hw/ppc/xics.h
> @@ -145,6 +145,12 @@ struct ICSState {
> XICSState *icp;
> };
>
> +static inline bool ics_valid_irq(ICSState *ics, uint32_t nr)
> +{
> + return (nr >= ics->offset)
> + && (nr < (ics->offset + ics->nr_irqs));
> +}
> +
> struct ICSIRQState {
> uint32_t server;
> uint8_t priority;
> @@ -174,4 +180,19 @@ void xics_spapr_free(XICSState *icp, int irq, int num);
> void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu);
> void xics_cpu_destroy(XICSState *icp, PowerPCCPU *cpu);
>
> +/* Internal XICS interfaces */
> +int get_cpu_index_by_dt_id(int cpu_dt_id);
> +
> +void icp_set_cppr(XICSState *icp, int server, uint8_t cppr);
> +void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr);
> +uint32_t icp_accept(ICPState *ss);
> +void icp_eoi(XICSState *icp, int server, uint32_t xirr);
> +
> +void ics_write_xive(ICSState *ics, int nr, int server,
> + uint8_t priority, uint8_t saved_priority);
> +
> +void ics_set_irq_type(ICSState *ics, int srcno, bool lsi);
> +
> +int xics_find_source(XICSState *icp, int irq);
> +
> #endif /* __XICS_H__ */
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature
- [Qemu-devel] [PATCH v1 00/11] sPAPR xics rework/cleanup, Nikunj A Dadhania, 2016/06/23
- [Qemu-devel] [PATCH v1 01/11] ppc/xics: Rename existing xics to xics_spapr, Nikunj A Dadhania, 2016/06/23
- [Qemu-devel] [PATCH v1 04/11] ppc/xics: Remove unused xics_set_irq_type(), Nikunj A Dadhania, 2016/06/23
- [Qemu-devel] [PATCH v1 05/11] ppc/xics: Replace "icp" with "xics" in most places, Nikunj A Dadhania, 2016/06/23
- [Qemu-devel] [PATCH v1 08/11] ppc/xics: Use a helper to add a new ICS, Nikunj A Dadhania, 2016/06/23