aboutsummaryrefslogtreecommitdiffstats
path: root/hw/spapr.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2011-04-01 15:15:25 +1100
committerAlexander Graf <agraf@suse.de>2011-04-01 18:34:56 +0200
commitb5cec4c5f294ca3af24e7edf4f37cc2de0ae0e03 (patch)
tree9bf9d4a35459792308fc4566331f5871bff350c0 /hw/spapr.c
parent821303f59b63ab832f0921f070db55e95bb21858 (diff)
Implement the PAPR (pSeries) virtualized interrupt controller (xics)
PAPR defines an interrupt control architecture which is logically divided into ICS (Interrupt Control Presentation, each unit is responsible for presenting interrupts to a particular "interrupt server", i.e. CPU) and ICS (Interrupt Control Source, each unit responsible for one or more hardware interrupts as numbered globally across the system). All PAPR virtual IO devices expect to deliver interrupts via this mechanism. In Linux, this interrupt controller system is handled by the "xics" driver. On pSeries systems, access to the interrupt controller is virtualized via hypercalls and RTAS methods. However, the virtualized interface is very similar to the underlying interrupt controller hardware, and similar PICs exist un-virtualized in some other systems. This patch implements both the ICP and ICS sides of the PAPR interrupt controller. For now, only the hypercall virtualized interface is provided, however it would be relatively straightforward to graft an emulated register interface onto the underlying interrupt logic if we want to add a machine with a hardware ICS/ICP system in the future. There are some limitations in this implementation: it is assumed for now that only one instance of the ICS exists, although a full xics system can have several, each responsible for a different group of hardware irqs. ICP/ICS can handle both level-sensitve (LSI) and message signalled (MSI) interrupt inputs. For now, this implementation supports only MSI interrupts, since that is used by PAPR virtual IO devices. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/spapr.c')
-rw-r--r--hw/spapr.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/hw/spapr.c b/hw/spapr.c
index 6c64de82d..b5aefd72c 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -34,6 +34,7 @@
#include "hw/spapr.h"
#include "hw/spapr_vio.h"
+#include "hw/xics.h"
#include <libfdt.h>
@@ -45,6 +46,7 @@
#define TIMEBASE_FREQ 512000000ULL
#define MAX_CPUS 32
+#define XICS_IRQS 1024
sPAPREnvironment *spapr;
@@ -64,6 +66,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr";
+ uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
int i;
char *modelname;
int ret;
@@ -125,6 +128,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
for (i = 0; i < smp_cpus; i++) {
CPUState *env = envs[i];
+ uint32_t gserver_prop[] = {cpu_to_be32(i), 0}; /* HACK! */
char *nodename;
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
0xffffffff, 0xffffffff};
@@ -155,6 +159,9 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
pft_size_prop, sizeof(pft_size_prop))));
_FDT((fdt_property_string(fdt, "status", "okay")));
_FDT((fdt_property(fdt, "64-bit", NULL, 0)));
+ _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", i)));
+ _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
+ gserver_prop, sizeof(gserver_prop))));
if (envs[i]->mmu_model & POWERPC_MMU_1TSEG) {
_FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
@@ -176,6 +183,20 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
_FDT((fdt_end_node(fdt)));
+ /* interrupt controller */
+ _FDT((fdt_begin_node(fdt, "interrupt-controller@0")));
+
+ _FDT((fdt_property_string(fdt, "device_type",
+ "PowerPC-External-Interrupt-Presentation")));
+ _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
+ _FDT((fdt_property_cell(fdt, "reg", 0)));
+ _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+ _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
+ interrupt_server_ranges_prop,
+ sizeof(interrupt_server_ranges_prop))));
+
+ _FDT((fdt_end_node(fdt)));
+
/* vdevice */
_FDT((fdt_begin_node(fdt, "vdevice")));
@@ -183,6 +204,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
_FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
_FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
_FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+ _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
+ _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
_FDT((fdt_end_node(fdt)));
@@ -296,6 +319,10 @@ static void ppc_spapr_init(ram_addr_t ram_size,
}
qemu_free(filename);
+ /* Set up Interrupt Controller */
+ spapr->icp = xics_system_init(smp_cpus, envs, XICS_IRQS);
+
+ /* Set up VIO bus */
spapr->vio_bus = spapr_vio_bus_init();
for (i = 0; i < MAX_SERIAL_PORTS; i++) {