summaryrefslogtreecommitdiffstats
path: root/hw/intc
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-06-29 11:59:00 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-06-29 11:59:00 +0100
commit2d80e0ab4b4326e340df7e0bcc687b2bc63c68d8 (patch)
tree199100356df3871e308e6aacba40170d962cea38 /hw/intc
parentde6793e8c2a4d34e28e5ea385276249fc98109ec (diff)
parent79c0ff2cae1f24cb7e041ac2dbdcc329d2a86ba2 (diff)
downloadhqemu-2d80e0ab4b4326e340df7e0bcc687b2bc63c68d8.zip
hqemu-2d80e0ab4b4326e340df7e0bcc687b2bc63c68d8.tar.gz
Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging
Patch queue for ppc - 2014-06-27 Changes include: - instruction emulation fixes - linux-user fixes - mac99: layout fixes - pseries: Initial VFIO support - pseries: support for UUID - pseries: support for -boot m # gpg: Signature made Fri 27 Jun 2014 12:51:01 BST using RSA key ID 03FEDC60 # gpg: Can't check signature: public key not found * remotes/agraf/tags/signed-ppc-for-upstream: (32 commits) PPC: e500: Only create dt entries for existing serial ports spapr_pci: Use XICS interrupt allocator and do not cache interrupts in PHB vmstate: Add preallocation for migrating arrays (VMS_ALLOC flag) xics: Implement xics_ics_free() spapr: Remove @next_irq spapr: Move interrupt allocator to xics xics: Disable flags reset on xics reset xics: Add xics_find_source() xics: Add flags for interrupts spapr: Add RTAS sysparm SPLPAR Characteristics spapr: Add RTAS sysparm UUID spapr: Fix RTAS sysparm DIAGNOSTICS_RUN_MODE spapr: Add rtas_st_buffer utility function spapr: Define a 2.1 pseries machine spapr: Fix code design style (s/SPAPRMachine/sPAPRMachineState) target-ppc: Add support for POWER8 pvr 0x4D0000 uninorth: Fix PCI hole size mac99: Add motherboard devices before PCI cards target-ppc: Remove unused gen_qemu_ld8s() target-ppc: Remove unused IMM and d extract helpers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/xics.c182
-rw-r--r--hw/intc/xics_kvm.c34
2 files changed, 184 insertions, 32 deletions
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 76dd6f5..0fd2a84 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -437,7 +437,7 @@ static void ics_set_irq(void *opaque, int srcno, int val)
{
ICSState *ics = (ICSState *)opaque;
- if (ics->islsi[srcno]) {
+ if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
set_irq_lsi(ics, srcno, val);
} else {
set_irq_msi(ics, srcno, val);
@@ -474,7 +474,7 @@ static void ics_write_xive(ICSState *ics, int nr, int server,
trace_xics_ics_write_xive(nr, srcno, server, priority);
- if (ics->islsi[srcno]) {
+ if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
write_xive_lsi(ics, srcno);
} else {
write_xive_msi(ics, srcno);
@@ -496,7 +496,7 @@ static void ics_resend(ICSState *ics)
for (i = 0; i < ics->nr_irqs; i++) {
/* FIXME: filter by server#? */
- if (ics->islsi[i]) {
+ if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
resend_lsi(ics, i);
} else {
resend_msi(ics, i);
@@ -511,7 +511,7 @@ static void ics_eoi(ICSState *ics, int nr)
trace_xics_ics_eoi(nr);
- if (ics->islsi[srcno]) {
+ if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
irq->status &= ~XICS_STATUS_SENT;
}
}
@@ -520,11 +520,18 @@ static void ics_reset(DeviceState *dev)
{
ICSState *ics = ICS(dev);
int i;
+ uint8_t flags[ics->nr_irqs];
+
+ for (i = 0; i < ics->nr_irqs; i++) {
+ flags[i] = ics->irqs[i].flags;
+ }
memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
+
for (i = 0; i < ics->nr_irqs; i++) {
ics->irqs[i].priority = 0xff;
ics->irqs[i].saved_priority = 0xff;
+ ics->irqs[i].flags = flags[i];
}
}
@@ -563,13 +570,14 @@ static int ics_dispatch_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_ics_irq = {
.name = "ics/irq",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(server, ICSIRQState),
VMSTATE_UINT8(priority, ICSIRQState),
VMSTATE_UINT8(saved_priority, ICSIRQState),
VMSTATE_UINT8(status, ICSIRQState),
+ VMSTATE_UINT8(flags, ICSIRQState),
VMSTATE_END_OF_LIST()
},
};
@@ -606,7 +614,6 @@ static void ics_realize(DeviceState *dev, Error **errp)
return;
}
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
- ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool));
ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
}
@@ -633,21 +640,166 @@ static const TypeInfo ics_info = {
/*
* Exported functions
*/
+static int xics_find_source(XICSState *icp, int irq)
+{
+ int sources = 1;
+ int src;
+
+ /* FIXME: implement multiple sources */
+ for (src = 0; src < sources; ++src) {
+ ICSState *ics = &icp->ics[src];
+ if (ics_valid_irq(ics, irq)) {
+ return src;
+ }
+ }
+
+ return -1;
+}
qemu_irq xics_get_qirq(XICSState *icp, int irq)
{
- if (!ics_valid_irq(icp->ics, irq)) {
- return NULL;
+ int src = xics_find_source(icp, irq);
+
+ if (src >= 0) {
+ ICSState *ics = &icp->ics[src];
+ return ics->qirqs[irq - ics->offset];
}
- return icp->ics->qirqs[irq - icp->ics->offset];
+ return NULL;
+}
+
+static void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
+{
+ assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
+
+ ics->irqs[srcno].flags |=
+ lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
}
void xics_set_irq_type(XICSState *icp, int irq, bool lsi)
{
- assert(ics_valid_irq(icp->ics, irq));
+ int src = xics_find_source(icp, irq);
+ ICSState *ics;
- icp->ics->islsi[irq - icp->ics->offset] = lsi;
+ assert(src >= 0);
+
+ ics = &icp->ics[src];
+ 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_alloc(XICSState *icp, int src, int irq_hint, bool lsi)
+{
+ 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)) {
+ trace_xics_alloc_failed_hint(src, irq_hint);
+ return -1;
+ }
+ irq = irq_hint;
+ } else {
+ irq = ics_find_free_block(ics, 1, 1);
+ if (irq < 0) {
+ trace_xics_alloc_failed_no_left(src);
+ return -1;
+ }
+ irq += ics->offset;
+ }
+
+ ics_set_irq_type(ics, irq - ics->offset, lsi);
+ trace_xics_alloc(src, irq);
+
+ return irq;
+}
+
+/*
+ * Allocate block of consequtive IRQs, returns a number of the first.
+ * If align==true, aligns the first IRQ number to num.
+ */
+int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align)
+{
+ 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) {
+ 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_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);
+ }
}
/*
@@ -866,10 +1018,10 @@ static void xics_realize(DeviceState *dev, Error **errp)
}
/* Registration of global state belongs into realize */
- spapr_rtas_register("ibm,set-xive", rtas_set_xive);
- spapr_rtas_register("ibm,get-xive", rtas_get_xive);
- spapr_rtas_register("ibm,int-off", rtas_int_off);
- spapr_rtas_register("ibm,int-on", rtas_int_on);
+ 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);
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 09476ae..20b19e9 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -38,10 +38,6 @@
typedef struct KVMXICSState {
XICSState parent_obj;
- uint32_t set_xive_token;
- uint32_t get_xive_token;
- uint32_t int_off_token;
- uint32_t int_on_token;
int kernel_xics_fd;
} KVMXICSState;
@@ -224,7 +220,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
state |= KVM_XICS_MASKED;
}
- if (ics->islsi[i]) {
+ if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
state |= KVM_XICS_LEVEL_SENSITIVE;
if (irq->status & XICS_STATUS_ASSERTED) {
state |= KVM_XICS_PENDING;
@@ -253,7 +249,7 @@ static void ics_kvm_set_irq(void *opaque, int srcno, int val)
int rc;
args.irq = srcno + ics->offset;
- if (!ics->islsi[srcno]) {
+ if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) {
if (!val) {
return;
}
@@ -271,11 +267,18 @@ static void ics_kvm_reset(DeviceState *dev)
{
ICSState *ics = ICS(dev);
int i;
+ uint8_t flags[ics->nr_irqs];
+
+ for (i = 0; i < ics->nr_irqs; i++) {
+ flags[i] = ics->irqs[i].flags;
+ }
memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
+
for (i = 0; i < ics->nr_irqs; i++) {
ics->irqs[i].priority = 0xff;
ics->irqs[i].saved_priority = 0xff;
+ ics->irqs[i].flags = flags[i];
}
ics_set_kvm_state(ics, 1);
@@ -290,7 +293,6 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp)
return;
}
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
- ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool));
ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs);
}
@@ -392,32 +394,30 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp)
goto fail;
}
- icpkvm->set_xive_token = spapr_rtas_register("ibm,set-xive", rtas_dummy);
- icpkvm->get_xive_token = spapr_rtas_register("ibm,get-xive", rtas_dummy);
- icpkvm->int_off_token = spapr_rtas_register("ibm,int-off", rtas_dummy);
- icpkvm->int_on_token = spapr_rtas_register("ibm,int-on", rtas_dummy);
+ spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy);
+ spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy);
+ spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy);
+ spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy);
- rc = kvmppc_define_rtas_kernel_token(icpkvm->set_xive_token,
- "ibm,set-xive");
+ rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive");
if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive");
goto fail;
}
- rc = kvmppc_define_rtas_kernel_token(icpkvm->get_xive_token,
- "ibm,get-xive");
+ rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive");
if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive");
goto fail;
}
- rc = kvmppc_define_rtas_kernel_token(icpkvm->int_on_token, "ibm,int-on");
+ rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on");
if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on");
goto fail;
}
- rc = kvmppc_define_rtas_kernel_token(icpkvm->int_off_token, "ibm,int-off");
+ rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off");
if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off");
goto fail;
OpenPOWER on IntegriCloud