diff options
Diffstat (limited to 'qemu/include/hw/ppc')
-rw-r--r-- | qemu/include/hw/ppc/mac_dbdma.h | 173 | ||||
-rw-r--r-- | qemu/include/hw/ppc/openpic.h | 32 | ||||
-rw-r--r-- | qemu/include/hw/ppc/ppc.h | 103 | ||||
-rw-r--r-- | qemu/include/hw/ppc/ppc4xx.h | 64 | ||||
-rw-r--r-- | qemu/include/hw/ppc/ppc_e500.h | 6 | ||||
-rw-r--r-- | qemu/include/hw/ppc/spapr.h | 612 | ||||
-rw-r--r-- | qemu/include/hw/ppc/spapr_drc.h | 201 | ||||
-rw-r--r-- | qemu/include/hw/ppc/spapr_vio.h | 148 | ||||
-rw-r--r-- | qemu/include/hw/ppc/xics.h | 170 |
9 files changed, 1509 insertions, 0 deletions
diff --git a/qemu/include/hw/ppc/mac_dbdma.h b/qemu/include/hw/ppc/mac_dbdma.h new file mode 100644 index 000000000..c6870212e --- /dev/null +++ b/qemu/include/hw/ppc/mac_dbdma.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2009 Laurent Vivier + * + * 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. + */ +#ifndef HW_MAC_DBDMA_H +#define HW_MAC_DBDMA_H 1 + +#include "exec/memory.h" + +typedef struct DBDMA_io DBDMA_io; + +typedef void (*DBDMA_flush)(DBDMA_io *io); +typedef void (*DBDMA_rw)(DBDMA_io *io); +typedef void (*DBDMA_end)(DBDMA_io *io); +struct DBDMA_io { + void *opaque; + void *channel; + hwaddr addr; + int len; + int is_last; + int is_dma_out; + DBDMA_end dma_end; + /* DMA is in progress, don't start another one */ + bool processing; + /* unaligned last sector of a request */ + uint8_t head_remainder[0x200]; + uint8_t tail_remainder[0x200]; + QEMUIOVector iov; +}; + +/* + * DBDMA control/status registers. All little-endian. + */ + +#define DBDMA_CONTROL 0x00 +#define DBDMA_STATUS 0x01 +#define DBDMA_CMDPTR_HI 0x02 +#define DBDMA_CMDPTR_LO 0x03 +#define DBDMA_INTR_SEL 0x04 +#define DBDMA_BRANCH_SEL 0x05 +#define DBDMA_WAIT_SEL 0x06 +#define DBDMA_XFER_MODE 0x07 +#define DBDMA_DATA2PTR_HI 0x08 +#define DBDMA_DATA2PTR_LO 0x09 +#define DBDMA_RES1 0x0A +#define DBDMA_ADDRESS_HI 0x0B +#define DBDMA_BRANCH_ADDR_HI 0x0C +#define DBDMA_RES2 0x0D +#define DBDMA_RES3 0x0E +#define DBDMA_RES4 0x0F + +#define DBDMA_REGS 16 +#define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t)) + +#define DBDMA_CHANNEL_SHIFT 7 +#define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT) + +#define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT) + +/* Bits in control and status registers */ + +#define RUN 0x8000 +#define PAUSE 0x4000 +#define FLUSH 0x2000 +#define WAKE 0x1000 +#define DEAD 0x0800 +#define ACTIVE 0x0400 +#define BT 0x0100 +#define DEVSTAT 0x00ff + +/* + * DBDMA command structure. These fields are all little-endian! + */ + +typedef struct dbdma_cmd { + uint16_t req_count; /* requested byte transfer count */ + uint16_t command; /* command word (has bit-fields) */ + uint32_t phy_addr; /* physical data address */ + uint32_t cmd_dep; /* command-dependent field */ + uint16_t res_count; /* residual count after completion */ + uint16_t xfer_status; /* transfer status */ +} dbdma_cmd; + +/* DBDMA command values in command field */ + +#define COMMAND_MASK 0xf000 +#define OUTPUT_MORE 0x0000 /* transfer memory data to stream */ +#define OUTPUT_LAST 0x1000 /* ditto followed by end marker */ +#define INPUT_MORE 0x2000 /* transfer stream data to memory */ +#define INPUT_LAST 0x3000 /* ditto, expect end marker */ +#define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */ +#define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */ +#define DBDMA_NOP 0x6000 /* do nothing */ +#define DBDMA_STOP 0x7000 /* suspend processing */ + +/* Key values in command field */ + +#define KEY_MASK 0x0700 +#define KEY_STREAM0 0x0000 /* usual data stream */ +#define KEY_STREAM1 0x0100 /* control/status stream */ +#define KEY_STREAM2 0x0200 /* device-dependent stream */ +#define KEY_STREAM3 0x0300 /* device-dependent stream */ +#define KEY_STREAM4 0x0400 /* reserved */ +#define KEY_REGS 0x0500 /* device register space */ +#define KEY_SYSTEM 0x0600 /* system memory-mapped space */ +#define KEY_DEVICE 0x0700 /* device memory-mapped space */ + +/* Interrupt control values in command field */ + +#define INTR_MASK 0x0030 +#define INTR_NEVER 0x0000 /* don't interrupt */ +#define INTR_IFSET 0x0010 /* intr if condition bit is 1 */ +#define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */ +#define INTR_ALWAYS 0x0030 /* always interrupt */ + +/* Branch control values in command field */ + +#define BR_MASK 0x000c +#define BR_NEVER 0x0000 /* don't branch */ +#define BR_IFSET 0x0004 /* branch if condition bit is 1 */ +#define BR_IFCLR 0x0008 /* branch if condition bit is 0 */ +#define BR_ALWAYS 0x000c /* always branch */ + +/* Wait control values in command field */ + +#define WAIT_MASK 0x0003 +#define WAIT_NEVER 0x0000 /* don't wait */ +#define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */ +#define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */ +#define WAIT_ALWAYS 0x0003 /* always wait */ + +typedef struct DBDMA_channel { + int channel; + uint32_t regs[DBDMA_REGS]; + qemu_irq irq; + DBDMA_io io; + DBDMA_rw rw; + DBDMA_flush flush; + dbdma_cmd current; +} DBDMA_channel; + +typedef struct { + MemoryRegion mem; + DBDMA_channel channels[DBDMA_CHANNELS]; + QEMUBH *bh; +} DBDMAState; + +/* Externally callable functions */ + +void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, + DBDMA_rw rw, DBDMA_flush flush, + void *opaque); +void DBDMA_kick(DBDMAState *dbdma); +void* DBDMA_init (MemoryRegion **dbdma_mem); + +#endif diff --git a/qemu/include/hw/ppc/openpic.h b/qemu/include/hw/ppc/openpic.h new file mode 100644 index 000000000..ee67098cb --- /dev/null +++ b/qemu/include/hw/ppc/openpic.h @@ -0,0 +1,32 @@ +#if !defined(__OPENPIC_H__) +#define __OPENPIC_H__ + +#include "qemu-common.h" +#include "hw/qdev.h" + +#define TYPE_OPENPIC "openpic" + +/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ +enum { + OPENPIC_OUTPUT_INT = 0, /* IRQ */ + OPENPIC_OUTPUT_CINT, /* critical IRQ */ + OPENPIC_OUTPUT_MCK, /* Machine check event */ + OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ + OPENPIC_OUTPUT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_NB, +}; + +#define OPENPIC_MODEL_RAVEN 0 +#define OPENPIC_MODEL_FSL_MPIC_20 1 +#define OPENPIC_MODEL_FSL_MPIC_42 2 + +#define OPENPIC_MAX_SRC 256 +#define OPENPIC_MAX_TMR 4 +#define OPENPIC_MAX_IPI 4 +#define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \ + OPENPIC_MAX_TMR) + +#define TYPE_KVM_OPENPIC "kvm-openpic" +int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs); + +#endif /* __OPENPIC_H__ */ diff --git a/qemu/include/hw/ppc/ppc.h b/qemu/include/hw/ppc/ppc.h new file mode 100644 index 000000000..14efd0ca3 --- /dev/null +++ b/qemu/include/hw/ppc/ppc.h @@ -0,0 +1,103 @@ +#ifndef HW_PPC_H +#define HW_PPC_H 1 + +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); + +/* PowerPC hardware exceptions management helpers */ +typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); +typedef struct clk_setup_t clk_setup_t; +struct clk_setup_t { + clk_setup_cb cb; + void *opaque; +}; +static inline void clk_setup (clk_setup_t *clk, uint32_t freq) +{ + if (clk->cb != NULL) + (*clk->cb)(clk->opaque, freq); +} + +struct ppc_tb_t { + /* Time base management */ + int64_t tb_offset; /* Compensation */ + int64_t atb_offset; /* Compensation */ + uint32_t tb_freq; /* TB frequency */ + /* Decrementer management */ + uint64_t decr_next; /* Tick for next decr interrupt */ + uint32_t decr_freq; /* decrementer frequency */ + QEMUTimer *decr_timer; + /* Hypervisor decrementer management */ + uint64_t hdecr_next; /* Tick for next hdecr interrupt */ + QEMUTimer *hdecr_timer; + uint64_t purr_load; + uint64_t purr_start; + void *opaque; + uint32_t flags; +}; + +/* PPC Timers flags */ +#define PPC_TIMER_BOOKE (1 << 0) /* Enable Booke support */ +#define PPC_TIMER_E500 (1 << 1) /* Enable e500 support */ +#define PPC_DECR_UNDERFLOW_TRIGGERED (1 << 2) /* Decr interrupt triggered when + * the most significant bit + * changes from 0 to 1. + */ +#define PPC_DECR_ZERO_TRIGGERED (1 << 3) /* Decr interrupt triggered when + * the decrementer reaches zero. + */ +#define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when + * the most significant bit is 1. + */ + +uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset); +clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); +/* Embedded PowerPC DCR management */ +typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn); +typedef void (*dcr_write_cb)(void *opaque, int dcrn, uint32_t val); +int ppc_dcr_init (CPUPPCState *env, int (*dcr_read_error)(int dcrn), + int (*dcr_write_error)(int dcrn)); +int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, + dcr_read_cb drc_read, dcr_write_cb dcr_write); +clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, + unsigned int decr_excp); + +/* Embedded PowerPC reset */ +void ppc40x_core_reset(PowerPCCPU *cpu); +void ppc40x_chip_reset(PowerPCCPU *cpu); +void ppc40x_system_reset(PowerPCCPU *cpu); +void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); + +extern CPUWriteMemoryFunc * const PPC_io_write[]; +extern CPUReadMemoryFunc * const PPC_io_read[]; +void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); + +void ppc40x_irq_init (CPUPPCState *env); +void ppce500_irq_init (CPUPPCState *env); +void ppc6xx_irq_init (CPUPPCState *env); +void ppc970_irq_init (CPUPPCState *env); +void ppcPOWER7_irq_init (CPUPPCState *env); + +/* PPC machines for OpenBIOS */ +enum { + ARCH_PREP = 0, + ARCH_MAC99, + ARCH_HEATHROW, + ARCH_MAC99_U3, +}; + +#define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) +#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) +#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) +#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03) +#define FW_CFG_PPC_CLOCKFREQ (FW_CFG_ARCH_LOCAL + 0x04) +#define FW_CFG_PPC_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05) +#define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06) +#define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07) +#define FW_CFG_PPC_NVRAM_ADDR (FW_CFG_ARCH_LOCAL + 0x08) +#define FW_CFG_PPC_BUSFREQ (FW_CFG_ARCH_LOCAL + 0x09) + +#define PPC_SERIAL_MM_BAUDBASE 399193 + +/* ppc_booke.c */ +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags); + +#endif diff --git a/qemu/include/hw/ppc/ppc4xx.h b/qemu/include/hw/ppc/ppc4xx.h new file mode 100644 index 000000000..91d84bad6 --- /dev/null +++ b/qemu/include/hw/ppc/ppc4xx.h @@ -0,0 +1,64 @@ +/* + * QEMU PowerPC 4xx emulation shared definitions + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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. + */ + +#if !defined(PPC_4XX_H) +#define PPC_4XX_H + +#include "hw/pci/pci.h" + +/* PowerPC 4xx core initialization */ +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk); + +/* PowerPC 4xx universal interrupt controller */ +enum { + PPCUIC_OUTPUT_INT = 0, + PPCUIC_OUTPUT_CINT = 1, + PPCUIC_OUTPUT_NB, +}; +qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, + uint32_t dcr_base, int has_ssr, int has_vr); + +ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, + MemoryRegion ram_memories[], + hwaddr ram_bases[], + hwaddr ram_sizes[], + const unsigned int sdram_bank_sizes[]); + +void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, + MemoryRegion ram_memories[], + hwaddr *ram_bases, + hwaddr *ram_sizes, + int do_init); + +#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" + +PCIBus *ppc4xx_pci_init(CPUPPCState *env, qemu_irq pci_irqs[4], + hwaddr config_space, + hwaddr int_ack, + hwaddr special_cycle, + hwaddr registers); + +#endif /* !defined(PPC_4XX_H) */ diff --git a/qemu/include/hw/ppc/ppc_e500.h b/qemu/include/hw/ppc/ppc_e500.h new file mode 100644 index 000000000..b66c0e3ee --- /dev/null +++ b/qemu/include/hw/ppc/ppc_e500.h @@ -0,0 +1,6 @@ +#ifndef HW_PPC_E500_H +#define HW_PPC_E500_H + +void ppce500_set_mpic_proxy(bool enabled); + +#endif diff --git a/qemu/include/hw/ppc/spapr.h b/qemu/include/hw/ppc/spapr.h new file mode 100644 index 000000000..91a61abbc --- /dev/null +++ b/qemu/include/hw/ppc/spapr.h @@ -0,0 +1,612 @@ +#if !defined(__HW_SPAPR_H__) +#define __HW_SPAPR_H__ + +#include "sysemu/dma.h" +#include "hw/boards.h" +#include "hw/ppc/xics.h" +#include "hw/ppc/spapr_drc.h" + +struct VIOsPAPRBus; +struct sPAPRPHBState; +struct sPAPRNVRAM; +typedef struct sPAPRConfigureConnectorState sPAPRConfigureConnectorState; +typedef struct sPAPREventLogEntry sPAPREventLogEntry; + +#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL +#define SPAPR_ENTRY_POINT 0x100 + +typedef struct sPAPRMachineClass sPAPRMachineClass; +typedef struct sPAPRMachineState sPAPRMachineState; + +#define TYPE_SPAPR_MACHINE "spapr-machine" +#define SPAPR_MACHINE(obj) \ + OBJECT_CHECK(sPAPRMachineState, (obj), TYPE_SPAPR_MACHINE) +#define SPAPR_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(sPAPRMachineClass, obj, TYPE_SPAPR_MACHINE) +#define SPAPR_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(sPAPRMachineClass, klass, TYPE_SPAPR_MACHINE) + +/** + * sPAPRMachineClass: + */ +struct sPAPRMachineClass { + /*< private >*/ + MachineClass parent_class; + + /*< public >*/ +}; + +/** + * sPAPRMachineState: + */ +struct sPAPRMachineState { + /*< private >*/ + MachineState parent_obj; + + struct VIOsPAPRBus *vio_bus; + QLIST_HEAD(, sPAPRPHBState) phbs; + struct sPAPRNVRAM *nvram; + XICSState *icp; + DeviceState *rtc; + + void *htab; + uint32_t htab_shift; + hwaddr rma_size; + int vrma_adjust; + hwaddr fdt_addr, rtas_addr; + ssize_t rtas_size; + void *rtas_blob; + void *fdt_skel; + uint64_t rtc_offset; /* Now used only during incoming migration */ + struct PPCTimebase tb; + bool has_graphics; + + uint32_t check_exception_irq; + Notifier epow_notifier; + QTAILQ_HEAD(, sPAPREventLogEntry) pending_events; + + /* Migration state */ + int htab_save_index; + bool htab_first_pass; + int htab_fd; + bool htab_fd_stale; + + /* RTAS state */ + QTAILQ_HEAD(, sPAPRConfigureConnectorState) ccs_list; + + /*< public >*/ + char *kvm_type; +}; + +#define H_SUCCESS 0 +#define H_BUSY 1 /* Hardware busy -- retry later */ +#define H_CLOSED 2 /* Resource closed */ +#define H_NOT_AVAILABLE 3 +#define H_CONSTRAINED 4 /* Resource request constrained to max allowed */ +#define H_PARTIAL 5 +#define H_IN_PROGRESS 14 /* Kind of like busy */ +#define H_PAGE_REGISTERED 15 +#define H_PARTIAL_STORE 16 +#define H_PENDING 17 /* returned from H_POLL_PENDING */ +#define H_CONTINUE 18 /* Returned from H_Join on success */ +#define H_LONG_BUSY_START_RANGE 9900 /* Start of long busy range */ +#define H_LONG_BUSY_ORDER_1_MSEC 9900 /* Long busy, hint that 1msec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_10_MSEC 9901 /* Long busy, hint that 10msec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_100_MSEC 9902 /* Long busy, hint that 100msec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_1_SEC 9903 /* Long busy, hint that 1sec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_10_SEC 9904 /* Long busy, hint that 10sec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_100_SEC 9905 /* Long busy, hint that 100sec \ + is a good time to retry */ +#define H_LONG_BUSY_END_RANGE 9905 /* End of long busy range */ +#define H_HARDWARE -1 /* Hardware error */ +#define H_FUNCTION -2 /* Function not supported */ +#define H_PRIVILEGE -3 /* Caller not privileged */ +#define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting */ +#define H_BAD_MODE -5 /* Illegal msr value */ +#define H_PTEG_FULL -6 /* PTEG is full */ +#define H_NOT_FOUND -7 /* PTE was not found" */ +#define H_RESERVED_DABR -8 /* DABR address is reserved by the hypervisor on this processor" */ +#define H_NO_MEM -9 +#define H_AUTHORITY -10 +#define H_PERMISSION -11 +#define H_DROPPED -12 +#define H_SOURCE_PARM -13 +#define H_DEST_PARM -14 +#define H_REMOTE_PARM -15 +#define H_RESOURCE -16 +#define H_ADAPTER_PARM -17 +#define H_RH_PARM -18 +#define H_RCQ_PARM -19 +#define H_SCQ_PARM -20 +#define H_EQ_PARM -21 +#define H_RT_PARM -22 +#define H_ST_PARM -23 +#define H_SIGT_PARM -24 +#define H_TOKEN_PARM -25 +#define H_MLENGTH_PARM -27 +#define H_MEM_PARM -28 +#define H_MEM_ACCESS_PARM -29 +#define H_ATTR_PARM -30 +#define H_PORT_PARM -31 +#define H_MCG_PARM -32 +#define H_VL_PARM -33 +#define H_TSIZE_PARM -34 +#define H_TRACE_PARM -35 + +#define H_MASK_PARM -37 +#define H_MCG_FULL -38 +#define H_ALIAS_EXIST -39 +#define H_P_COUNTER -40 +#define H_TABLE_FULL -41 +#define H_ALT_TABLE -42 +#define H_MR_CONDITION -43 +#define H_NOT_ENOUGH_RESOURCES -44 +#define H_R_STATE -45 +#define H_RESCINDEND -46 +#define H_P2 -55 +#define H_P3 -56 +#define H_P4 -57 +#define H_P5 -58 +#define H_P6 -59 +#define H_P7 -60 +#define H_P8 -61 +#define H_P9 -62 +#define H_UNSUPPORTED_FLAG -256 +#define H_MULTI_THREADS_ACTIVE -9005 + + +/* Long Busy is a condition that can be returned by the firmware + * when a call cannot be completed now, but the identical call + * should be retried later. This prevents calls blocking in the + * firmware for long periods of time. Annoyingly the firmware can return + * a range of return codes, hinting at how long we should wait before + * retrying. If you don't care for the hint, the macro below is a good + * way to check for the long_busy return codes + */ +#define H_IS_LONG_BUSY(x) ((x >= H_LONG_BUSY_START_RANGE) \ + && (x <= H_LONG_BUSY_END_RANGE)) + +/* Flags */ +#define H_LARGE_PAGE (1ULL<<(63-16)) +#define H_EXACT (1ULL<<(63-24)) /* Use exact PTE or return H_PTEG_FULL */ +#define H_R_XLATE (1ULL<<(63-25)) /* include a valid logical page num in the pte if the valid bit is set */ +#define H_READ_4 (1ULL<<(63-26)) /* Return 4 PTEs */ +#define H_PAGE_STATE_CHANGE (1ULL<<(63-28)) +#define H_PAGE_UNUSED ((1ULL<<(63-29)) | (1ULL<<(63-30))) +#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED) +#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31))) +#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE +#define H_AVPN (1ULL<<(63-32)) /* An avpn is provided as a sanity test */ +#define H_ANDCOND (1ULL<<(63-33)) +#define H_ICACHE_INVALIDATE (1ULL<<(63-40)) /* icbi, etc. (ignored for IO pages) */ +#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */ +#define H_ZERO_PAGE (1ULL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */ +#define H_COPY_PAGE (1ULL<<(63-49)) +#define H_N (1ULL<<(63-61)) +#define H_PP1 (1ULL<<(63-62)) +#define H_PP2 (1ULL<<(63-63)) + +/* Values for 2nd argument to H_SET_MODE */ +#define H_SET_MODE_RESOURCE_SET_CIABR 1 +#define H_SET_MODE_RESOURCE_SET_DAWR 2 +#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3 +#define H_SET_MODE_RESOURCE_LE 4 + +/* Flags for H_SET_MODE_RESOURCE_LE */ +#define H_SET_MODE_ENDIAN_BIG 0 +#define H_SET_MODE_ENDIAN_LITTLE 1 + +/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */ +#define H_SET_MODE_ADDR_TRANS_NONE 0 +#define H_SET_MODE_ADDR_TRANS_0001_8000 2 +#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000 3 + +/* VASI States */ +#define H_VASI_INVALID 0 +#define H_VASI_ENABLED 1 +#define H_VASI_ABORTED 2 +#define H_VASI_SUSPENDING 3 +#define H_VASI_SUSPENDED 4 +#define H_VASI_RESUMED 5 +#define H_VASI_COMPLETED 6 + +/* DABRX flags */ +#define H_DABRX_HYPERVISOR (1ULL<<(63-61)) +#define H_DABRX_KERNEL (1ULL<<(63-62)) +#define H_DABRX_USER (1ULL<<(63-63)) + +/* Each control block has to be on a 4K boundary */ +#define H_CB_ALIGNMENT 4096 + +/* pSeries hypervisor opcodes */ +#define H_REMOVE 0x04 +#define H_ENTER 0x08 +#define H_READ 0x0c +#define H_CLEAR_MOD 0x10 +#define H_CLEAR_REF 0x14 +#define H_PROTECT 0x18 +#define H_GET_TCE 0x1c +#define H_PUT_TCE 0x20 +#define H_SET_SPRG0 0x24 +#define H_SET_DABR 0x28 +#define H_PAGE_INIT 0x2c +#define H_SET_ASR 0x30 +#define H_ASR_ON 0x34 +#define H_ASR_OFF 0x38 +#define H_LOGICAL_CI_LOAD 0x3c +#define H_LOGICAL_CI_STORE 0x40 +#define H_LOGICAL_CACHE_LOAD 0x44 +#define H_LOGICAL_CACHE_STORE 0x48 +#define H_LOGICAL_ICBI 0x4c +#define H_LOGICAL_DCBF 0x50 +#define H_GET_TERM_CHAR 0x54 +#define H_PUT_TERM_CHAR 0x58 +#define H_REAL_TO_LOGICAL 0x5c +#define H_HYPERVISOR_DATA 0x60 +#define H_EOI 0x64 +#define H_CPPR 0x68 +#define H_IPI 0x6c +#define H_IPOLL 0x70 +#define H_XIRR 0x74 +#define H_PERFMON 0x7c +#define H_MIGRATE_DMA 0x78 +#define H_REGISTER_VPA 0xDC +#define H_CEDE 0xE0 +#define H_CONFER 0xE4 +#define H_PROD 0xE8 +#define H_GET_PPP 0xEC +#define H_SET_PPP 0xF0 +#define H_PURR 0xF4 +#define H_PIC 0xF8 +#define H_REG_CRQ 0xFC +#define H_FREE_CRQ 0x100 +#define H_VIO_SIGNAL 0x104 +#define H_SEND_CRQ 0x108 +#define H_COPY_RDMA 0x110 +#define H_REGISTER_LOGICAL_LAN 0x114 +#define H_FREE_LOGICAL_LAN 0x118 +#define H_ADD_LOGICAL_LAN_BUFFER 0x11C +#define H_SEND_LOGICAL_LAN 0x120 +#define H_BULK_REMOVE 0x124 +#define H_MULTICAST_CTRL 0x130 +#define H_SET_XDABR 0x134 +#define H_STUFF_TCE 0x138 +#define H_PUT_TCE_INDIRECT 0x13C +#define H_CHANGE_LOGICAL_LAN_MAC 0x14C +#define H_VTERM_PARTNER_INFO 0x150 +#define H_REGISTER_VTERM 0x154 +#define H_FREE_VTERM 0x158 +#define H_RESET_EVENTS 0x15C +#define H_ALLOC_RESOURCE 0x160 +#define H_FREE_RESOURCE 0x164 +#define H_MODIFY_QP 0x168 +#define H_QUERY_QP 0x16C +#define H_REREGISTER_PMR 0x170 +#define H_REGISTER_SMR 0x174 +#define H_QUERY_MR 0x178 +#define H_QUERY_MW 0x17C +#define H_QUERY_HCA 0x180 +#define H_QUERY_PORT 0x184 +#define H_MODIFY_PORT 0x188 +#define H_DEFINE_AQP1 0x18C +#define H_GET_TRACE_BUFFER 0x190 +#define H_DEFINE_AQP0 0x194 +#define H_RESIZE_MR 0x198 +#define H_ATTACH_MCQP 0x19C +#define H_DETACH_MCQP 0x1A0 +#define H_CREATE_RPT 0x1A4 +#define H_REMOVE_RPT 0x1A8 +#define H_REGISTER_RPAGES 0x1AC +#define H_DISABLE_AND_GETC 0x1B0 +#define H_ERROR_DATA 0x1B4 +#define H_GET_HCA_INFO 0x1B8 +#define H_GET_PERF_COUNT 0x1BC +#define H_MANAGE_TRACE 0x1C0 +#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 +#define H_QUERY_INT_STATE 0x1E4 +#define H_POLL_PENDING 0x1D8 +#define H_ILLAN_ATTRIBUTES 0x244 +#define H_MODIFY_HEA_QP 0x250 +#define H_QUERY_HEA_QP 0x254 +#define H_QUERY_HEA 0x258 +#define H_QUERY_HEA_PORT 0x25C +#define H_MODIFY_HEA_PORT 0x260 +#define H_REG_BCMC 0x264 +#define H_DEREG_BCMC 0x268 +#define H_REGISTER_HEA_RPAGES 0x26C +#define H_DISABLE_AND_GET_HEA 0x270 +#define H_GET_HEA_INFO 0x274 +#define H_ALLOC_HEA_RESOURCE 0x278 +#define H_ADD_CONN 0x284 +#define H_DEL_CONN 0x288 +#define H_JOIN 0x298 +#define H_VASI_STATE 0x2A4 +#define H_ENABLE_CRQ 0x2B0 +#define H_GET_EM_PARMS 0x2B8 +#define H_SET_MPP 0x2D0 +#define H_GET_MPP 0x2D4 +#define H_XIRR_X 0x2FC +#define H_SET_MODE 0x31C +#define MAX_HCALL_OPCODE H_SET_MODE + +/* The hcalls above are standardized in PAPR and implemented by pHyp + * as well. + * + * We also need some hcalls which are specific to qemu / KVM-on-POWER. + * So far we just need one for H_RTAS, but in future we'll need more + * for extensions like virtio. We put those into the 0xf000-0xfffc + * range which is reserved by PAPR for "platform-specific" hcalls. + */ +#define KVMPPC_HCALL_BASE 0xf000 +#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) +#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1) +/* Client Architecture support */ +#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2) +#define KVMPPC_HCALL_MAX KVMPPC_H_CAS + +typedef struct sPAPRDeviceTreeUpdateHeader { + uint32_t version_id; +} sPAPRDeviceTreeUpdateHeader; + +/*#define DEBUG_SPAPR_HCALLS*/ + +#ifdef DEBUG_SPAPR_HCALLS +#define hcall_dprintf(fmt, ...) \ + do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0) +#else +#define hcall_dprintf(fmt, ...) \ + do { } while (0) +#endif + +typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPRMachineState *sm, + target_ulong opcode, + target_ulong *args); + +void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); +target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, + target_ulong *args); + +int spapr_allocate_irq(int hint, bool lsi); +int spapr_allocate_irq_block(int num, bool lsi, bool msi); + +/* ibm,set-eeh-option */ +#define RTAS_EEH_DISABLE 0 +#define RTAS_EEH_ENABLE 1 +#define RTAS_EEH_THAW_IO 2 +#define RTAS_EEH_THAW_DMA 3 + +/* ibm,get-config-addr-info2 */ +#define RTAS_GET_PE_ADDR 0 +#define RTAS_GET_PE_MODE 1 +#define RTAS_PE_MODE_NONE 0 +#define RTAS_PE_MODE_NOT_SHARED 1 +#define RTAS_PE_MODE_SHARED 2 + +/* ibm,read-slot-reset-state2 */ +#define RTAS_EEH_PE_STATE_NORMAL 0 +#define RTAS_EEH_PE_STATE_RESET 1 +#define RTAS_EEH_PE_STATE_STOPPED_IO_DMA 2 +#define RTAS_EEH_PE_STATE_STOPPED_DMA 4 +#define RTAS_EEH_PE_STATE_UNAVAIL 5 +#define RTAS_EEH_NOT_SUPPORT 0 +#define RTAS_EEH_SUPPORT 1 +#define RTAS_EEH_PE_UNAVAIL_INFO 1000 +#define RTAS_EEH_PE_RECOVER_INFO 0 + +/* ibm,set-slot-reset */ +#define RTAS_SLOT_RESET_DEACTIVATE 0 +#define RTAS_SLOT_RESET_HOT 1 +#define RTAS_SLOT_RESET_FUNDAMENTAL 3 + +/* ibm,slot-error-detail */ +#define RTAS_SLOT_TEMP_ERR_LOG 1 +#define RTAS_SLOT_PERM_ERR_LOG 2 + +/* RTAS return codes */ +#define RTAS_OUT_SUCCESS 0 +#define RTAS_OUT_NO_ERRORS_FOUND 1 +#define RTAS_OUT_HW_ERROR -1 +#define RTAS_OUT_BUSY -2 +#define RTAS_OUT_PARAM_ERROR -3 +#define RTAS_OUT_NOT_SUPPORTED -3 +#define RTAS_OUT_NOT_AUTHORIZED -9002 + +/* RTAS tokens */ +#define RTAS_TOKEN_BASE 0x2000 + +#define RTAS_DISPLAY_CHARACTER (RTAS_TOKEN_BASE + 0x00) +#define RTAS_GET_TIME_OF_DAY (RTAS_TOKEN_BASE + 0x01) +#define RTAS_SET_TIME_OF_DAY (RTAS_TOKEN_BASE + 0x02) +#define RTAS_POWER_OFF (RTAS_TOKEN_BASE + 0x03) +#define RTAS_SYSTEM_REBOOT (RTAS_TOKEN_BASE + 0x04) +#define RTAS_QUERY_CPU_STOPPED_STATE (RTAS_TOKEN_BASE + 0x05) +#define RTAS_START_CPU (RTAS_TOKEN_BASE + 0x06) +#define RTAS_STOP_SELF (RTAS_TOKEN_BASE + 0x07) +#define RTAS_IBM_GET_SYSTEM_PARAMETER (RTAS_TOKEN_BASE + 0x08) +#define RTAS_IBM_SET_SYSTEM_PARAMETER (RTAS_TOKEN_BASE + 0x09) +#define RTAS_IBM_SET_XIVE (RTAS_TOKEN_BASE + 0x0A) +#define RTAS_IBM_GET_XIVE (RTAS_TOKEN_BASE + 0x0B) +#define RTAS_IBM_INT_OFF (RTAS_TOKEN_BASE + 0x0C) +#define RTAS_IBM_INT_ON (RTAS_TOKEN_BASE + 0x0D) +#define RTAS_CHECK_EXCEPTION (RTAS_TOKEN_BASE + 0x0E) +#define RTAS_EVENT_SCAN (RTAS_TOKEN_BASE + 0x0F) +#define RTAS_IBM_SET_TCE_BYPASS (RTAS_TOKEN_BASE + 0x10) +#define RTAS_QUIESCE (RTAS_TOKEN_BASE + 0x11) +#define RTAS_NVRAM_FETCH (RTAS_TOKEN_BASE + 0x12) +#define RTAS_NVRAM_STORE (RTAS_TOKEN_BASE + 0x13) +#define RTAS_READ_PCI_CONFIG (RTAS_TOKEN_BASE + 0x14) +#define RTAS_WRITE_PCI_CONFIG (RTAS_TOKEN_BASE + 0x15) +#define RTAS_IBM_READ_PCI_CONFIG (RTAS_TOKEN_BASE + 0x16) +#define RTAS_IBM_WRITE_PCI_CONFIG (RTAS_TOKEN_BASE + 0x17) +#define RTAS_IBM_QUERY_INTERRUPT_SOURCE_NUMBER (RTAS_TOKEN_BASE + 0x18) +#define RTAS_IBM_CHANGE_MSI (RTAS_TOKEN_BASE + 0x19) +#define RTAS_SET_INDICATOR (RTAS_TOKEN_BASE + 0x1A) +#define RTAS_SET_POWER_LEVEL (RTAS_TOKEN_BASE + 0x1B) +#define RTAS_GET_POWER_LEVEL (RTAS_TOKEN_BASE + 0x1C) +#define RTAS_GET_SENSOR_STATE (RTAS_TOKEN_BASE + 0x1D) +#define RTAS_IBM_CONFIGURE_CONNECTOR (RTAS_TOKEN_BASE + 0x1E) +#define RTAS_IBM_OS_TERM (RTAS_TOKEN_BASE + 0x1F) +#define RTAS_IBM_SET_EEH_OPTION (RTAS_TOKEN_BASE + 0x20) +#define RTAS_IBM_GET_CONFIG_ADDR_INFO2 (RTAS_TOKEN_BASE + 0x21) +#define RTAS_IBM_READ_SLOT_RESET_STATE2 (RTAS_TOKEN_BASE + 0x22) +#define RTAS_IBM_SET_SLOT_RESET (RTAS_TOKEN_BASE + 0x23) +#define RTAS_IBM_CONFIGURE_PE (RTAS_TOKEN_BASE + 0x24) +#define RTAS_IBM_SLOT_ERROR_DETAIL (RTAS_TOKEN_BASE + 0x25) + +#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x26) + +/* RTAS ibm,get-system-parameter token values */ +#define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20 +#define RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE 42 +#define RTAS_SYSPARM_UUID 48 + +/* RTAS indicator/sensor types + * + * as defined by PAPR+ 2.7 7.3.5.4, Table 41 + * + * NOTE: currently only DR-related sensors are implemented here + */ +#define RTAS_SENSOR_TYPE_ISOLATION_STATE 9001 +#define RTAS_SENSOR_TYPE_DR 9002 +#define RTAS_SENSOR_TYPE_ALLOCATION_STATE 9003 +#define RTAS_SENSOR_TYPE_ENTITY_SENSE RTAS_SENSOR_TYPE_ALLOCATION_STATE + +/* Possible values for the platform-processor-diagnostics-run-mode parameter + * of the RTAS ibm,get-system-parameter call. + */ +#define DIAGNOSTICS_RUN_MODE_DISABLED 0 +#define DIAGNOSTICS_RUN_MODE_STAGGERED 1 +#define DIAGNOSTICS_RUN_MODE_IMMEDIATE 2 +#define DIAGNOSTICS_RUN_MODE_PERIODIC 3 + +static inline uint64_t ppc64_phys_to_real(uint64_t addr) +{ + return addr & ~0xF000000000000000ULL; +} + +static inline uint32_t rtas_ld(target_ulong phys, int n) +{ + return ldl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n)); +} + +static inline void rtas_st(target_ulong phys, int n, uint32_t val) +{ + stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val); +} + +static inline void rtas_st_buffer_direct(target_ulong phys, + target_ulong phys_len, + uint8_t *buffer, uint16_t buffer_len) +{ + cpu_physical_memory_write(ppc64_phys_to_real(phys), buffer, + MIN(buffer_len, phys_len)); +} + +static inline void rtas_st_buffer(target_ulong phys, target_ulong phys_len, + uint8_t *buffer, uint16_t buffer_len) +{ + if (phys_len < 2) { + return; + } + stw_be_phys(&address_space_memory, + ppc64_phys_to_real(phys), buffer_len); + rtas_st_buffer_direct(phys + 2, phys_len - 2, buffer, buffer_len); +} + +typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, sPAPRMachineState *sm, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets); +void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn); +target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *sm, + uint32_t token, uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets); +int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, + hwaddr rtas_size); + +#define SPAPR_TCE_PAGE_SHIFT 12 +#define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT) +#define SPAPR_TCE_PAGE_MASK (SPAPR_TCE_PAGE_SIZE - 1) + +#define SPAPR_VIO_BASE_LIOBN 0x00000000 +#define SPAPR_VIO_LIOBN(reg) (0x00000000 | (reg)) +#define SPAPR_PCI_LIOBN(phb_index, window_num) \ + (0x80000000 | ((phb_index) << 8) | (window_num)) +#define SPAPR_IS_PCI_LIOBN(liobn) (!!((liobn) & 0x80000000)) +#define SPAPR_PCI_DMA_WINDOW_NUM(liobn) ((liobn) & 0xff) + +#define RTAS_ERROR_LOG_MAX 2048 + +#define RTAS_EVENT_SCAN_RATE 1 + +typedef struct sPAPRTCETable sPAPRTCETable; + +#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table" +#define SPAPR_TCE_TABLE(obj) \ + OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE) + +struct sPAPRTCETable { + DeviceState parent; + uint32_t liobn; + uint32_t nb_table; + uint64_t bus_offset; + uint32_t page_shift; + uint64_t *table; + bool bypass; + bool vfio_accel; + int fd; + MemoryRegion iommu; + struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */ + QLIST_ENTRY(sPAPRTCETable) list; +}; + +sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn); + +struct sPAPREventLogEntry { + int log_type; + bool exception; + void *data; + QTAILQ_ENTRY(sPAPREventLogEntry) next; +}; + +void spapr_events_init(sPAPRMachineState *sm); +void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq); +int spapr_h_cas_compose_response(sPAPRMachineState *sm, + target_ulong addr, target_ulong size); +sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, + uint64_t bus_offset, + uint32_t page_shift, + uint32_t nb_table, + bool vfio_accel); +MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet); +int spapr_dma_dt(void *fdt, int node_off, const char *propname, + uint32_t liobn, uint64_t window, uint32_t size); +int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, + sPAPRTCETable *tcet); +void spapr_pci_switch_vga(bool big_endian); +void spapr_hotplug_req_add_event(sPAPRDRConnector *drc); +void spapr_hotplug_req_remove_event(sPAPRDRConnector *drc); + +/* rtas-configure-connector state */ +struct sPAPRConfigureConnectorState { + uint32_t drc_index; + int fdt_offset; + int fdt_depth; + QTAILQ_ENTRY(sPAPRConfigureConnectorState) next; +}; + +void spapr_ccs_reset_hook(void *opaque); + +#define TYPE_SPAPR_RTC "spapr-rtc" + +void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns); +int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset); + +#define SPAPR_MEMORY_BLOCK_SIZE (1 << 28) /* 256MB */ + +#endif /* !defined (__HW_SPAPR_H__) */ diff --git a/qemu/include/hw/ppc/spapr_drc.h b/qemu/include/hw/ppc/spapr_drc.h new file mode 100644 index 000000000..60cda35ed --- /dev/null +++ b/qemu/include/hw/ppc/spapr_drc.h @@ -0,0 +1,201 @@ +/* + * QEMU SPAPR Dynamic Reconfiguration Connector Implementation + * + * Copyright IBM Corp. 2014 + * + * Authors: + * Michael Roth <mdroth@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#if !defined(__HW_SPAPR_DRC_H__) +#define __HW_SPAPR_DRC_H__ + +#include "qom/object.h" +#include "hw/qdev.h" +#include "libfdt.h" + +#define TYPE_SPAPR_DR_CONNECTOR "spapr-dr-connector" +#define SPAPR_DR_CONNECTOR_GET_CLASS(obj) \ + OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DR_CONNECTOR) +#define SPAPR_DR_CONNECTOR_CLASS(klass) \ + OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, \ + TYPE_SPAPR_DR_CONNECTOR) +#define SPAPR_DR_CONNECTOR(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \ + TYPE_SPAPR_DR_CONNECTOR) + +/* + * Various hotplug types managed by sPAPRDRConnector + * + * these are somewhat arbitrary, but to make things easier + * when generating DRC indexes later we've aligned the bit + * positions with the values used to assign DRC indexes on + * pSeries. we use those values as bit shifts to allow for + * the OR'ing of these values in various QEMU routines, but + * for values exposed to the guest (via DRC indexes for + * instance) we will use the shift amounts. + */ +typedef enum { + SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU = 1, + SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB = 2, + SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO = 3, + SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI = 4, + SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB = 8, +} sPAPRDRConnectorTypeShift; + +typedef enum { + SPAPR_DR_CONNECTOR_TYPE_ANY = ~0, + SPAPR_DR_CONNECTOR_TYPE_CPU = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU, + SPAPR_DR_CONNECTOR_TYPE_PHB = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB, + SPAPR_DR_CONNECTOR_TYPE_VIO = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO, + SPAPR_DR_CONNECTOR_TYPE_PCI = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI, + SPAPR_DR_CONNECTOR_TYPE_LMB = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB, +} sPAPRDRConnectorType; + +/* + * set via set-indicator RTAS calls + * as documented by PAPR+ 2.7 13.5.3.4, Table 177 + * + * isolated: put device under firmware control + * unisolated: claim OS control of device (may or may not be in use) + */ +typedef enum { + SPAPR_DR_ISOLATION_STATE_ISOLATED = 0, + SPAPR_DR_ISOLATION_STATE_UNISOLATED = 1 +} sPAPRDRIsolationState; + +/* + * set via set-indicator RTAS calls + * as documented by PAPR+ 2.7 13.5.3.4, Table 177 + * + * unusable: mark device as unavailable to OS + * usable: mark device as available to OS + * exchange: (currently unused) + * recover: (currently unused) + */ +typedef enum { + SPAPR_DR_ALLOCATION_STATE_UNUSABLE = 0, + SPAPR_DR_ALLOCATION_STATE_USABLE = 1, + SPAPR_DR_ALLOCATION_STATE_EXCHANGE = 2, + SPAPR_DR_ALLOCATION_STATE_RECOVER = 3 +} sPAPRDRAllocationState; + +/* + * LED/visual indicator state + * + * set via set-indicator RTAS calls + * as documented by PAPR+ 2.7 13.5.3.4, Table 177, + * and PAPR+ 2.7 13.5.4.1, Table 180 + * + * inactive: hotpluggable entity inactive and safely removable + * active: hotpluggable entity in use and not safely removable + * identify: (currently unused) + * action: (currently unused) + */ +typedef enum { + SPAPR_DR_INDICATOR_STATE_INACTIVE = 0, + SPAPR_DR_INDICATOR_STATE_ACTIVE = 1, + SPAPR_DR_INDICATOR_STATE_IDENTIFY = 2, + SPAPR_DR_INDICATOR_STATE_ACTION = 3, +} sPAPRDRIndicatorState; + +/* + * returned via get-sensor-state RTAS calls + * as documented by PAPR+ 2.7 13.5.3.3, Table 175: + * + * empty: connector slot empty (e.g. empty hotpluggable PCI slot) + * present: connector slot populated and device available to OS + * unusable: device not currently available to OS + * exchange: (currently unused) + * recover: (currently unused) + */ +typedef enum { + SPAPR_DR_ENTITY_SENSE_EMPTY = 0, + SPAPR_DR_ENTITY_SENSE_PRESENT = 1, + SPAPR_DR_ENTITY_SENSE_UNUSABLE = 2, + SPAPR_DR_ENTITY_SENSE_EXCHANGE = 3, + SPAPR_DR_ENTITY_SENSE_RECOVER = 4, +} sPAPRDREntitySense; + +typedef enum { + SPAPR_DR_CC_RESPONSE_NEXT_SIB = 1, /* currently unused */ + SPAPR_DR_CC_RESPONSE_NEXT_CHILD = 2, + SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY = 3, + SPAPR_DR_CC_RESPONSE_PREV_PARENT = 4, + SPAPR_DR_CC_RESPONSE_SUCCESS = 0, + SPAPR_DR_CC_RESPONSE_ERROR = -1, + SPAPR_DR_CC_RESPONSE_CONTINUE = -2, +} sPAPRDRCCResponse; + +typedef void (spapr_drc_detach_cb)(DeviceState *d, void *opaque); + +typedef struct sPAPRDRConnector { + /*< private >*/ + DeviceState parent; + + sPAPRDRConnectorType type; + uint32_t id; + Object *owner; + const char *name; + + /* sensor/indicator states */ + uint32_t isolation_state; + uint32_t allocation_state; + uint32_t indicator_state; + + /* configure-connector state */ + void *fdt; + int fdt_start_offset; + bool configured; + + bool awaiting_release; + + /* device pointer, via link property */ + DeviceState *dev; + spapr_drc_detach_cb *detach_cb; + void *detach_cb_opaque; +} sPAPRDRConnector; + +typedef struct sPAPRDRConnectorClass { + /*< private >*/ + DeviceClass parent; + + /*< public >*/ + + /* accessors for guest-visible (generally via RTAS) DR state */ + int (*set_isolation_state)(sPAPRDRConnector *drc, + sPAPRDRIsolationState state); + int (*set_indicator_state)(sPAPRDRConnector *drc, + sPAPRDRIndicatorState state); + int (*set_allocation_state)(sPAPRDRConnector *drc, + sPAPRDRAllocationState state); + uint32_t (*get_index)(sPAPRDRConnector *drc); + uint32_t (*get_type)(sPAPRDRConnector *drc); + const char *(*get_name)(sPAPRDRConnector *drc); + + sPAPRDREntitySense (*entity_sense)(sPAPRDRConnector *drc); + + /* QEMU interfaces for managing FDT/configure-connector */ + const void *(*get_fdt)(sPAPRDRConnector *drc, int *fdt_start_offset); + void (*set_configured)(sPAPRDRConnector *drc); + + /* QEMU interfaces for managing hotplug operations */ + void (*attach)(sPAPRDRConnector *drc, DeviceState *d, void *fdt, + int fdt_start_offset, bool coldplug, Error **errp); + void (*detach)(sPAPRDRConnector *drc, DeviceState *d, + spapr_drc_detach_cb *detach_cb, + void *detach_cb_opaque, Error **errp); + bool (*release_pending)(sPAPRDRConnector *drc); +} sPAPRDRConnectorClass; + +sPAPRDRConnector *spapr_dr_connector_new(Object *owner, + sPAPRDRConnectorType type, + uint32_t id); +sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index); +sPAPRDRConnector *spapr_dr_connector_by_id(sPAPRDRConnectorType type, + uint32_t id); +int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, + uint32_t drc_type_mask); + +#endif /* __HW_SPAPR_DRC_H__ */ diff --git a/qemu/include/hw/ppc/spapr_vio.h b/qemu/include/hw/ppc/spapr_vio.h new file mode 100644 index 000000000..2299a5405 --- /dev/null +++ b/qemu/include/hw/ppc/spapr_vio.h @@ -0,0 +1,148 @@ +#ifndef _HW_SPAPR_VIO_H +#define _HW_SPAPR_VIO_H +/* + * QEMU sPAPR VIO bus definitions + * + * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au> + * Based on the s390 virtio bus definitions: + * Copyright (c) 2009 Alexander Graf <agraf@suse.de> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "sysemu/dma.h" + +#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" +#define VIO_SPAPR_DEVICE(obj) \ + OBJECT_CHECK(VIOsPAPRDevice, (obj), TYPE_VIO_SPAPR_DEVICE) +#define VIO_SPAPR_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VIOsPAPRDeviceClass, (klass), TYPE_VIO_SPAPR_DEVICE) +#define VIO_SPAPR_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VIOsPAPRDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE) + +#define TYPE_SPAPR_VIO_BUS "spapr-vio-bus" +#define SPAPR_VIO_BUS(obj) OBJECT_CHECK(VIOsPAPRBus, (obj), TYPE_SPAPR_VIO_BUS) + +struct VIOsPAPRDevice; + +typedef struct VIOsPAPR_CRQ { + uint64_t qladdr; + uint32_t qsize; + uint32_t qnext; + int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq); +} VIOsPAPR_CRQ; + +typedef struct VIOsPAPRDevice VIOsPAPRDevice; +typedef struct VIOsPAPRBus VIOsPAPRBus; + +typedef struct VIOsPAPRDeviceClass { + DeviceClass parent_class; + + const char *dt_name, *dt_type, *dt_compatible; + target_ulong signal_mask; + uint32_t rtce_window_size; + void (*realize)(VIOsPAPRDevice *dev, Error **errp); + void (*reset)(VIOsPAPRDevice *dev); + int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); +} VIOsPAPRDeviceClass; + +struct VIOsPAPRDevice { + DeviceState qdev; + uint32_t reg; + uint32_t irq; + target_ulong signal_state; + VIOsPAPR_CRQ crq; + AddressSpace as; + MemoryRegion mrroot; + MemoryRegion mrbypass; + sPAPRTCETable *tcet; +}; + +#define DEFINE_SPAPR_PROPERTIES(type, field) \ + DEFINE_PROP_UINT32("reg", type, field.reg, -1) + +struct VIOsPAPRBus { + BusState bus; + uint32_t next_reg; + int (*init)(VIOsPAPRDevice *dev); + int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); +}; + +extern VIOsPAPRBus *spapr_vio_bus_init(void); +extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); +extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); +extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus); + +extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); + +static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + + return xics_get_qirq(spapr->icp, dev->irq); +} + +static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr, + uint32_t size, DMADirection dir) +{ + return dma_memory_valid(&dev->as, taddr, size, dir); +} + +static inline int spapr_vio_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, + void *buf, uint32_t size) +{ + return (dma_memory_read(&dev->as, taddr, buf, size) != 0) ? + H_DEST_PARM : H_SUCCESS; +} + +static inline int spapr_vio_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, + const void *buf, uint32_t size) +{ + return (dma_memory_write(&dev->as, taddr, buf, size) != 0) ? + H_DEST_PARM : H_SUCCESS; +} + +static inline int spapr_vio_dma_set(VIOsPAPRDevice *dev, uint64_t taddr, + uint8_t c, uint32_t size) +{ + return (dma_memory_set(&dev->as, taddr, c, size) != 0) ? + H_DEST_PARM : H_SUCCESS; +} + +#define vio_stb(_dev, _addr, _val) (stb_dma(&(_dev)->as, (_addr), (_val))) +#define vio_sth(_dev, _addr, _val) (stw_be_dma(&(_dev)->as, (_addr), (_val))) +#define vio_stl(_dev, _addr, _val) (stl_be_dma(&(_dev)->as, (_addr), (_val))) +#define vio_stq(_dev, _addr, _val) (stq_be_dma(&(_dev)->as, (_addr), (_val))) +#define vio_ldq(_dev, _addr) (ldq_be_dma(&(_dev)->as, (_addr))) + +int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq); + +VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg); +void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); +void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev); +void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd); +void spapr_vscsi_create(VIOsPAPRBus *bus); + +VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); + +void spapr_vio_quiesce(void); + +extern const VMStateDescription vmstate_spapr_vio; + +#define VMSTATE_SPAPR_VIO(_f, _s) \ + VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, VIOsPAPRDevice) + +void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass); + +#endif /* _HW_SPAPR_VIO_H */ diff --git a/qemu/include/hw/ppc/xics.h b/qemu/include/hw/ppc/xics.h new file mode 100644 index 000000000..355a96623 --- /dev/null +++ b/qemu/include/hw/ppc/xics.h @@ -0,0 +1,170 @@ +/* + * 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. + * + */ +#if !defined(__XICS_H__) +#define __XICS_H__ + +#include "hw/sysbus.h" + +#define TYPE_XICS_COMMON "xics-common" +#define XICS_COMMON(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_COMMON) + +#define TYPE_XICS "xics" +#define XICS(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS) + +#define TYPE_KVM_XICS "xics-kvm" +#define KVM_XICS(obj) OBJECT_CHECK(KVMXICSState, (obj), TYPE_KVM_XICS) + +#define XICS_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_COMMON) +#define XICS_CLASS(klass) \ + OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS) +#define XICS_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_COMMON) +#define XICS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS) + +#define XICS_IPI 0x2 +#define XICS_BUID 0x1 +#define XICS_IRQ_BASE (XICS_BUID << 12) + +/* + * We currently only support one BUID which is our interrupt base + * (the kernel implementation supports more but we don't exploit + * that yet) + */ +typedef struct XICSStateClass XICSStateClass; +typedef struct XICSState XICSState; +typedef struct ICPStateClass ICPStateClass; +typedef struct ICPState ICPState; +typedef struct ICSStateClass ICSStateClass; +typedef struct ICSState ICSState; +typedef struct ICSIRQState ICSIRQState; + +struct XICSStateClass { + DeviceClass parent_class; + + void (*cpu_setup)(XICSState *icp, PowerPCCPU *cpu); + void (*set_nr_irqs)(XICSState *icp, uint32_t nr_irqs, Error **errp); + void (*set_nr_servers)(XICSState *icp, uint32_t nr_servers, Error **errp); +}; + +struct XICSState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + uint32_t nr_servers; + uint32_t nr_irqs; + ICPState *ss; + ICSState *ics; +}; + +#define TYPE_ICP "icp" +#define ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_ICP) + +#define TYPE_KVM_ICP "icp-kvm" +#define KVM_ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_KVM_ICP) + +#define ICP_CLASS(klass) \ + OBJECT_CLASS_CHECK(ICPStateClass, (klass), TYPE_ICP) +#define ICP_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ICPStateClass, (obj), TYPE_ICP) + +struct ICPStateClass { + DeviceClass parent_class; + + void (*pre_save)(ICPState *s); + int (*post_load)(ICPState *s, int version_id); +}; + +struct ICPState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + CPUState *cs; + uint32_t xirr; + uint8_t pending_priority; + uint8_t mfrr; + qemu_irq output; + bool cap_irq_xics_enabled; +}; + +#define TYPE_ICS "ics" +#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS) + +#define TYPE_KVM_ICS "icskvm" +#define KVM_ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_KVM_ICS) + +#define ICS_CLASS(klass) \ + OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS) +#define ICS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS) + +struct ICSStateClass { + DeviceClass parent_class; + + void (*pre_save)(ICSState *s); + int (*post_load)(ICSState *s, int version_id); +}; + +struct ICSState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t nr_irqs; + uint32_t offset; + qemu_irq *qirqs; + ICSIRQState *irqs; + XICSState *icp; +}; + +struct ICSIRQState { + uint32_t server; + uint8_t priority; + uint8_t saved_priority; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; +/* (flags & XICS_FLAGS_IRQ_MASK) == 0 means the interrupt is not allocated */ +#define XICS_FLAGS_IRQ_LSI 0x1 +#define XICS_FLAGS_IRQ_MSI 0x2 +#define XICS_FLAGS_IRQ_MASK 0x3 + uint8_t flags; +}; + +#define XICS_IRQS 1024 + +qemu_irq xics_get_qirq(XICSState *icp, int irq); +void xics_set_irq_type(XICSState *icp, int irq, bool lsi); +int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi); +int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align); +void xics_free(XICSState *icp, int irq, int num); + +void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu); + +#endif /* __XICS_H__ */ |