diff options
author | Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> | 2023-10-10 11:40:56 +0000 |
---|---|---|
committer | Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> | 2023-10-10 11:40:56 +0000 |
commit | e02cda008591317b1625707ff8e115a4841aa889 (patch) | |
tree | aee302e3cf8b59ec2d32ec481be3d1afddfc8968 /include/hw/ppc | |
parent | cc668e6b7e0ffd8c9d130513d12053cf5eda1d3b (diff) |
Introduce Virtio-loopback epsilon release:
Epsilon release introduces a new compatibility layer which make virtio-loopback
design to work with QEMU and rust-vmm vhost-user backend without require any
changes.
Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
Change-Id: I52e57563e08a7d0bdc002f8e928ee61ba0c53dd9
Diffstat (limited to 'include/hw/ppc')
33 files changed, 4600 insertions, 0 deletions
diff --git a/include/hw/ppc/fdt.h b/include/hw/ppc/fdt.h new file mode 100644 index 000000000..a8cd85069 --- /dev/null +++ b/include/hw/ppc/fdt.h @@ -0,0 +1,29 @@ +/* + * QEMU PowerPC helper routines for the device tree. + * + * Copyright (C) 2016 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_FDT_H +#define PPC_FDT_H + +#include "qemu/error-report.h" +#include "target/ppc/cpu-qom.h" + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + error_report("error creating device tree: %s: %s", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + +size_t ppc_create_page_sizes_prop(PowerPCCPU *cpu, uint32_t *prop, + size_t maxsize); + +#endif /* PPC_FDT_H */ diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h new file mode 100644 index 000000000..4a3f64451 --- /dev/null +++ b/include/hw/ppc/mac_dbdma.h @@ -0,0 +1,183 @@ +/* + * 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 + +#include "exec/memory.h" +#include "qemu/iov.h" +#include "sysemu/dma.h" +#include "hw/sysbus.h" +#include "qom/object.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; + /* DMA request */ + void *dma_mem; + dma_addr_t dma_len; + DMADirection dir; +}; + +/* + * 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; + +struct DBDMAState { + SysBusDevice parent_obj; + + MemoryRegion mem; + DBDMA_channel channels[DBDMA_CHANNELS]; + QEMUBH *bh; +}; +typedef struct DBDMAState 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); + +#define TYPE_MAC_DBDMA "mac-dbdma" +OBJECT_DECLARE_SIMPLE_TYPE(DBDMAState, MAC_DBDMA) + +#endif diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h new file mode 100644 index 000000000..ebdaf8a49 --- /dev/null +++ b/include/hw/ppc/openpic.h @@ -0,0 +1,176 @@ +#ifndef OPENPIC_H +#define OPENPIC_H + +#include "hw/sysbus.h" +#include "hw/core/cpu.h" +#include "qom/object.h" + +#define MAX_CPU 32 +#define MAX_MSI 8 +#define VID 0x03 /* MPIC version ID */ + +/* 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, +}; + +typedef struct IrqLines { qemu_irq irq[OPENPIC_OUTPUT_NB]; } IrqLines; + +#define OPENPIC_MODEL_FSL_MPIC_20 1 +#define OPENPIC_MODEL_FSL_MPIC_42 2 +#define OPENPIC_MODEL_KEYLARGO 3 + +#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) + +/* KeyLargo */ +#define KEYLARGO_MAX_CPU 4 +#define KEYLARGO_MAX_EXT 64 +#define KEYLARGO_MAX_IPI 4 +#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI) +#define KEYLARGO_MAX_TMR 0 +#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */ +/* Timers don't exist but this makes the code happy... */ +#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI) + +typedef struct FslMpicInfo { + int max_ext; +} FslMpicInfo; + +typedef enum IRQType { + IRQ_TYPE_NORMAL = 0, + IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ + IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ +} IRQType; + +/* + * Round up to the nearest 64 IRQs so that the queue length + * won't change when moving between 32 and 64 bit hosts. + */ +#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63) + +typedef struct IRQQueue { + unsigned long *queue; + int32_t queue_size; /* Only used for VMSTATE_BITMAP */ + int next; + int priority; +} IRQQueue; + +typedef struct IRQSource { + uint32_t ivpr; /* IRQ vector/priority register */ + uint32_t idr; /* IRQ destination register */ + uint32_t destmask; /* bitmap of CPU destinations */ + int last_cpu; + int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ + int pending; /* TRUE if IRQ is pending */ + IRQType type; + bool level:1; /* level-triggered */ + bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ +} IRQSource; + +#define IVPR_MASK_SHIFT 31 +#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT) +#define IVPR_ACTIVITY_SHIFT 30 +#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT) +#define IVPR_MODE_SHIFT 29 +#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT) +#define IVPR_POLARITY_SHIFT 23 +#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT) +#define IVPR_SENSE_SHIFT 22 +#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT) + +#define IVPR_PRIORITY_MASK (0xFU << 16) +#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) +#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) + +/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ +#define IDR_EP 0x80000000 /* external pin */ +#define IDR_CI 0x40000000 /* critical interrupt */ + +typedef struct OpenPICTimer { + uint32_t tccr; /* Global timer current count register */ + uint32_t tbcr; /* Global timer base count register */ + int n_IRQ; + bool qemu_timer_active; /* Is the qemu_timer is running? */ + struct QEMUTimer *qemu_timer; + struct OpenPICState *opp; /* Device timer is part of. */ + /* + * The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last + * current_count written or read, only defined if qemu_timer_active. + */ + uint64_t origin_time; +} OpenPICTimer; + +typedef struct OpenPICMSI { + uint32_t msir; /* Shared Message Signaled Interrupt Register */ +} OpenPICMSI; + +typedef struct IRQDest { + int32_t ctpr; /* CPU current task priority */ + IRQQueue raised; + IRQQueue servicing; + qemu_irq *irqs; + + /* Count of IRQ sources asserting on non-INT outputs */ + uint32_t outputs_active[OPENPIC_OUTPUT_NB]; +} IRQDest; + +#define TYPE_OPENPIC "openpic" +OBJECT_DECLARE_SIMPLE_TYPE(OpenPICState, OPENPIC) + +struct OpenPICState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion mem; + + /* Behavior control */ + FslMpicInfo *fsl; + uint32_t model; + uint32_t flags; + uint32_t nb_irqs; + uint32_t vid; + uint32_t vir; /* Vendor identification register */ + uint32_t vector_mask; + uint32_t tfrr_reset; + uint32_t ivpr_reset; + uint32_t idr_reset; + uint32_t brr1; + uint32_t mpic_mode_mask; + + /* Sub-regions */ + MemoryRegion sub_io_mem[6]; + + /* Global registers */ + uint32_t frr; /* Feature reporting register */ + uint32_t gcr; /* Global configuration register */ + uint32_t pir; /* Processor initialization register */ + uint32_t spve; /* Spurious vector register */ + uint32_t tfrr; /* Timer frequency reporting register */ + /* Source registers */ + IRQSource src[OPENPIC_MAX_IRQ]; + /* Local registers per output pin */ + IRQDest dst[MAX_CPU]; + uint32_t nb_cpus; + /* Timer registers */ + OpenPICTimer timers[OPENPIC_MAX_TMR]; + uint32_t max_tmr; + + /* Shared MSI registers */ + OpenPICMSI msi[MAX_MSI]; + uint32_t max_irq; + uint32_t irq_ipi0; + uint32_t irq_tim0; + uint32_t irq_msi; +}; + +#endif /* OPENPIC_H */ diff --git a/include/hw/ppc/openpic_kvm.h b/include/hw/ppc/openpic_kvm.h new file mode 100644 index 000000000..9ef421525 --- /dev/null +++ b/include/hw/ppc/openpic_kvm.h @@ -0,0 +1,7 @@ +#ifndef OPENPIC_KVM_H +#define OPENPIC_KVM_H + +#define TYPE_KVM_OPENPIC "kvm-openpic" +int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs); + +#endif /* OPENPIC_KVM_H */ diff --git a/include/hw/ppc/pef.h b/include/hw/ppc/pef.h new file mode 100644 index 000000000..707dbe524 --- /dev/null +++ b/include/hw/ppc/pef.h @@ -0,0 +1,17 @@ +/* + * PEF (Protected Execution Facility) for POWER support + * + * Copyright Red Hat. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_PPC_PEF_H +#define HW_PPC_PEF_H + +int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); +int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp); + +#endif /* HW_PPC_PEF_H */ diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h new file mode 100644 index 000000000..aa08d79d2 --- /dev/null +++ b/include/hw/ppc/pnv.h @@ -0,0 +1,332 @@ +/* + * QEMU PowerPC PowerNV various definitions + * + * Copyright (c) 2014-2016 BenH, IBM Corporation. + * + * 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.1 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/>. + */ + +#ifndef PPC_PNV_H +#define PPC_PNV_H + +#include "hw/boards.h" +#include "hw/sysbus.h" +#include "hw/ipmi/ipmi.h" +#include "hw/ppc/pnv_lpc.h" +#include "hw/ppc/pnv_pnor.h" +#include "hw/ppc/pnv_psi.h" +#include "hw/ppc/pnv_occ.h" +#include "hw/ppc/pnv_homer.h" +#include "hw/ppc/pnv_xive.h" +#include "hw/ppc/pnv_core.h" +#include "hw/pci-host/pnv_phb3.h" +#include "hw/pci-host/pnv_phb4.h" +#include "qom/object.h" + +#define TYPE_PNV_CHIP "pnv-chip" +OBJECT_DECLARE_TYPE(PnvChip, PnvChipClass, + PNV_CHIP) + +struct PnvChip { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + uint32_t chip_id; + uint64_t ram_start; + uint64_t ram_size; + + uint32_t nr_cores; + uint32_t nr_threads; + uint64_t cores_mask; + PnvCore **cores; + + uint32_t num_phbs; + + MemoryRegion xscom_mmio; + MemoryRegion xscom; + AddressSpace xscom_as; + + MemoryRegion *fw_mr; + gchar *dt_isa_nodename; +}; + +#define TYPE_PNV8_CHIP "pnv8-chip" +typedef struct Pnv8Chip Pnv8Chip; +DECLARE_INSTANCE_CHECKER(Pnv8Chip, PNV8_CHIP, + TYPE_PNV8_CHIP) + +struct Pnv8Chip { + /*< private >*/ + PnvChip parent_obj; + + /*< public >*/ + MemoryRegion icp_mmio; + + PnvLpcController lpc; + Pnv8Psi psi; + PnvOCC occ; + PnvHomer homer; + +#define PNV8_CHIP_PHB3_MAX 4 + PnvPHB3 phbs[PNV8_CHIP_PHB3_MAX]; + + XICSFabric *xics; +}; + +#define TYPE_PNV9_CHIP "pnv9-chip" +typedef struct Pnv9Chip Pnv9Chip; +DECLARE_INSTANCE_CHECKER(Pnv9Chip, PNV9_CHIP, + TYPE_PNV9_CHIP) + +struct Pnv9Chip { + /*< private >*/ + PnvChip parent_obj; + + /*< public >*/ + PnvXive xive; + Pnv9Psi psi; + PnvLpcController lpc; + PnvOCC occ; + PnvHomer homer; + + uint32_t nr_quads; + PnvQuad *quads; + +#define PNV9_CHIP_MAX_PEC 3 + PnvPhb4PecState pecs[PNV9_CHIP_MAX_PEC]; +}; + +/* + * A SMT8 fused core is a pair of SMT4 cores. + */ +#define PNV9_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf) +#define PNV9_PIR2CHIP(pir) (((pir) >> 8) & 0x7f) + +#define TYPE_PNV10_CHIP "pnv10-chip" +typedef struct Pnv10Chip Pnv10Chip; +DECLARE_INSTANCE_CHECKER(Pnv10Chip, PNV10_CHIP, + TYPE_PNV10_CHIP) + +struct Pnv10Chip { + /*< private >*/ + PnvChip parent_obj; + + /*< public >*/ + Pnv9Psi psi; + PnvLpcController lpc; +}; + +struct PnvChipClass { + /*< private >*/ + SysBusDeviceClass parent_class; + + /*< public >*/ + uint64_t chip_cfam_id; + uint64_t cores_mask; + uint32_t num_phbs; + + DeviceRealize parent_realize; + + uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id); + void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp); + void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu); + void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu); + void (*intc_print_info)(PnvChip *chip, PowerPCCPU *cpu, Monitor *mon); + ISABus *(*isa_create)(PnvChip *chip, Error **errp); + void (*dt_populate)(PnvChip *chip, void *fdt); + void (*pic_print_info)(PnvChip *chip, Monitor *mon); + uint64_t (*xscom_core_base)(PnvChip *chip, uint32_t core_id); + uint32_t (*xscom_pcba)(PnvChip *chip, uint64_t addr); +}; + +#define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP +#define PNV_CHIP_TYPE_NAME(cpu_model) cpu_model PNV_CHIP_TYPE_SUFFIX + +#define TYPE_PNV_CHIP_POWER8E PNV_CHIP_TYPE_NAME("power8e_v2.1") +DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER8E, + TYPE_PNV_CHIP_POWER8E) + +#define TYPE_PNV_CHIP_POWER8 PNV_CHIP_TYPE_NAME("power8_v2.0") +DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER8, + TYPE_PNV_CHIP_POWER8) + +#define TYPE_PNV_CHIP_POWER8NVL PNV_CHIP_TYPE_NAME("power8nvl_v1.0") +DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER8NVL, + TYPE_PNV_CHIP_POWER8NVL) + +#define TYPE_PNV_CHIP_POWER9 PNV_CHIP_TYPE_NAME("power9_v2.0") +DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER9, + TYPE_PNV_CHIP_POWER9) + +#define TYPE_PNV_CHIP_POWER10 PNV_CHIP_TYPE_NAME("power10_v2.0") +DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10, + TYPE_PNV_CHIP_POWER10) + +PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir); + +#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv") +typedef struct PnvMachineClass PnvMachineClass; +typedef struct PnvMachineState PnvMachineState; +DECLARE_OBJ_CHECKERS(PnvMachineState, PnvMachineClass, + PNV_MACHINE, TYPE_PNV_MACHINE) + + +struct PnvMachineClass { + /*< private >*/ + MachineClass parent_class; + + /*< public >*/ + const char *compat; + int compat_size; + + void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt); +}; + +struct PnvMachineState { + /*< private >*/ + MachineState parent_obj; + + uint32_t initrd_base; + long initrd_size; + + uint32_t num_chips; + PnvChip **chips; + + ISABus *isa_bus; + uint32_t cpld_irqstate; + + IPMIBmc *bmc; + Notifier powerdown_notifier; + + PnvPnor *pnor; + + hwaddr fw_load_addr; +}; + +#define PNV_FDT_ADDR 0x01000000 +#define PNV_TIMEBASE_FREQ 512000000ULL + +/* + * BMC helpers + */ +void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt); +void pnv_bmc_powerdown(IPMIBmc *bmc); +IPMIBmc *pnv_bmc_create(PnvPnor *pnor); +IPMIBmc *pnv_bmc_find(Error **errp); +void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor); + +/* + * POWER8 MMIO base addresses + */ +#define PNV_XSCOM_SIZE 0x800000000ull +#define PNV_XSCOM_BASE(chip) \ + (0x0003fc0000000000ull + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE) + +#define PNV_OCC_COMMON_AREA_SIZE 0x0000000000800000ull +#define PNV_OCC_COMMON_AREA_BASE 0x7fff800000ull +#define PNV_OCC_SENSOR_BASE(chip) (PNV_OCC_COMMON_AREA_BASE + \ + PNV_OCC_SENSOR_DATA_BLOCK_BASE((chip)->chip_id)) + +#define PNV_HOMER_SIZE 0x0000000000400000ull +#define PNV_HOMER_BASE(chip) \ + (0x7ffd800000ull + ((uint64_t)(chip)->chip_id) * PNV_HOMER_SIZE) + + +/* + * XSCOM 0x20109CA defines the ICP BAR: + * + * 0:29 : bits 14 to 43 of address to define 1 MB region. + * 30 : 1 to enable ICP to receive loads/stores against its BAR region + * 31:63 : Constant 0 + * + * Usually defined as : + * + * 0xffffe00200000000 -> 0x0003ffff80000000 + * 0xffffe00600000000 -> 0x0003ffff80100000 + * 0xffffe02200000000 -> 0x0003ffff80800000 + * 0xffffe02600000000 -> 0x0003ffff80900000 + */ +#define PNV_ICP_SIZE 0x0000000000100000ull +#define PNV_ICP_BASE(chip) \ + (0x0003ffff80000000ull + (uint64_t) (chip)->chip_id * PNV_ICP_SIZE) + + +#define PNV_PSIHB_SIZE 0x0000000000100000ull +#define PNV_PSIHB_BASE(chip) \ + (0x0003fffe80000000ull + (uint64_t)(chip)->chip_id * PNV_PSIHB_SIZE) + +#define PNV_PSIHB_FSP_SIZE 0x0000000100000000ull +#define PNV_PSIHB_FSP_BASE(chip) \ + (0x0003ffe000000000ull + (uint64_t)(chip)->chip_id * \ + PNV_PSIHB_FSP_SIZE) + +/* + * POWER9 MMIO base addresses + */ +#define PNV9_CHIP_BASE(chip, base) \ + ((base) + ((uint64_t) (chip)->chip_id << 42)) + +#define PNV9_XIVE_VC_SIZE 0x0000008000000000ull +#define PNV9_XIVE_VC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006010000000000ull) + +#define PNV9_XIVE_PC_SIZE 0x0000001000000000ull +#define PNV9_XIVE_PC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006018000000000ull) + +#define PNV9_LPCM_SIZE 0x0000000100000000ull +#define PNV9_LPCM_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030000000000ull) + +#define PNV9_PSIHB_SIZE 0x0000000000100000ull +#define PNV9_PSIHB_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203000000ull) + +#define PNV9_XIVE_IC_SIZE 0x0000000000080000ull +#define PNV9_XIVE_IC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203100000ull) + +#define PNV9_XIVE_TM_SIZE 0x0000000000040000ull +#define PNV9_XIVE_TM_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203180000ull) + +#define PNV9_PSIHB_ESB_SIZE 0x0000000000010000ull +#define PNV9_PSIHB_ESB_BASE(chip) PNV9_CHIP_BASE(chip, 0x00060302031c0000ull) + +#define PNV9_XSCOM_SIZE 0x0000000400000000ull +#define PNV9_XSCOM_BASE(chip) PNV9_CHIP_BASE(chip, 0x00603fc00000000ull) + +#define PNV9_OCC_COMMON_AREA_SIZE 0x0000000000800000ull +#define PNV9_OCC_COMMON_AREA_BASE 0x203fff800000ull +#define PNV9_OCC_SENSOR_BASE(chip) (PNV9_OCC_COMMON_AREA_BASE + \ + PNV_OCC_SENSOR_DATA_BLOCK_BASE((chip)->chip_id)) + +#define PNV9_HOMER_SIZE 0x0000000000400000ull +#define PNV9_HOMER_BASE(chip) \ + (0x203ffd800000ull + ((uint64_t)(chip)->chip_id) * PNV9_HOMER_SIZE) + +/* + * POWER10 MMIO base addresses - 16TB stride per chip + */ +#define PNV10_CHIP_BASE(chip, base) \ + ((base) + ((uint64_t) (chip)->chip_id << 44)) + +#define PNV10_XSCOM_SIZE 0x0000000400000000ull +#define PNV10_XSCOM_BASE(chip) PNV10_CHIP_BASE(chip, 0x00603fc00000000ull) + +#define PNV10_LPCM_SIZE 0x0000000100000000ull +#define PNV10_LPCM_BASE(chip) PNV10_CHIP_BASE(chip, 0x0006030000000000ull) + +#define PNV10_PSIHB_ESB_SIZE 0x0000000000100000ull +#define PNV10_PSIHB_ESB_BASE(chip) PNV10_CHIP_BASE(chip, 0x0006030202000000ull) + +#define PNV10_PSIHB_SIZE 0x0000000000100000ull +#define PNV10_PSIHB_BASE(chip) PNV10_CHIP_BASE(chip, 0x0006030203000000ull) + +#endif /* PPC_PNV_H */ diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h new file mode 100644 index 000000000..c22eab2e1 --- /dev/null +++ b/include/hw/ppc/pnv_core.h @@ -0,0 +1,73 @@ +/* + * QEMU PowerPC PowerNV CPU Core model + * + * Copyright (c) 2016, IBM Corporation. + * + * 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.1 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/>. + */ + +#ifndef PPC_PNV_CORE_H +#define PPC_PNV_CORE_H + +#include "hw/cpu/core.h" +#include "target/ppc/cpu.h" +#include "qom/object.h" + +#define TYPE_PNV_CORE "powernv-cpu-core" +OBJECT_DECLARE_TYPE(PnvCore, PnvCoreClass, + PNV_CORE) + +typedef struct PnvChip PnvChip; + +struct PnvCore { + /*< private >*/ + CPUCore parent_obj; + + /*< public >*/ + PowerPCCPU **threads; + uint32_t pir; + uint64_t hrmor; + PnvChip *chip; + + MemoryRegion xscom_regs; +}; + +struct PnvCoreClass { + DeviceClass parent_class; + + const MemoryRegionOps *xscom_ops; +}; + +#define PNV_CORE_TYPE_SUFFIX "-" TYPE_PNV_CORE +#define PNV_CORE_TYPE_NAME(cpu_model) cpu_model PNV_CORE_TYPE_SUFFIX + +typedef struct PnvCPUState { + Object *intc; +} PnvCPUState; + +static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu) +{ + return (PnvCPUState *)cpu->machine_data; +} + +#define TYPE_PNV_QUAD "powernv-cpu-quad" +OBJECT_DECLARE_SIMPLE_TYPE(PnvQuad, PNV_QUAD) + +struct PnvQuad { + DeviceState parent_obj; + + uint32_t quad_id; + MemoryRegion xscom_regs; +}; +#endif /* PPC_PNV_CORE_H */ diff --git a/include/hw/ppc/pnv_homer.h b/include/hw/ppc/pnv_homer.h new file mode 100644 index 000000000..1889e3083 --- /dev/null +++ b/include/hw/ppc/pnv_homer.h @@ -0,0 +1,56 @@ +/* + * QEMU PowerPC PowerNV Emulation of a few HOMER related registers + * + * Copyright (c) 2019, IBM Corporation. + * + * 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.1 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/>. + */ + +#ifndef PPC_PNV_HOMER_H +#define PPC_PNV_HOMER_H + +#include "hw/ppc/pnv.h" +#include "qom/object.h" + +#define TYPE_PNV_HOMER "pnv-homer" +OBJECT_DECLARE_TYPE(PnvHomer, PnvHomerClass, + PNV_HOMER) +#define TYPE_PNV8_HOMER TYPE_PNV_HOMER "-POWER8" +DECLARE_INSTANCE_CHECKER(PnvHomer, PNV8_HOMER, + TYPE_PNV8_HOMER) +#define TYPE_PNV9_HOMER TYPE_PNV_HOMER "-POWER9" +DECLARE_INSTANCE_CHECKER(PnvHomer, PNV9_HOMER, + TYPE_PNV9_HOMER) + +struct PnvHomer { + DeviceState parent; + + struct PnvChip *chip; + MemoryRegion pba_regs; + MemoryRegion regs; +}; + + +struct PnvHomerClass { + DeviceClass parent_class; + + int pba_size; + const MemoryRegionOps *pba_ops; + int homer_size; + const MemoryRegionOps *homer_ops; + + hwaddr core_max_base; +}; + +#endif /* PPC_PNV_HOMER_H */ diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h new file mode 100644 index 000000000..e893e763d --- /dev/null +++ b/include/hw/ppc/pnv_lpc.h @@ -0,0 +1,108 @@ +/* + * QEMU PowerPC PowerNV LPC controller + * + * Copyright (c) 2016, IBM Corporation. + * + * 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.1 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/>. + */ + +#ifndef PPC_PNV_LPC_H +#define PPC_PNV_LPC_H + +#include "hw/ppc/pnv_psi.h" +#include "qom/object.h" + +#define TYPE_PNV_LPC "pnv-lpc" +typedef struct PnvLpcClass PnvLpcClass; +typedef struct PnvLpcController PnvLpcController; +DECLARE_OBJ_CHECKERS(PnvLpcController, PnvLpcClass, + PNV_LPC, TYPE_PNV_LPC) +#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8" +DECLARE_INSTANCE_CHECKER(PnvLpcController, PNV8_LPC, + TYPE_PNV8_LPC) + +#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9" +DECLARE_INSTANCE_CHECKER(PnvLpcController, PNV9_LPC, + TYPE_PNV9_LPC) + +#define TYPE_PNV10_LPC TYPE_PNV_LPC "-POWER10" +DECLARE_INSTANCE_CHECKER(PnvLpcController, PNV10_LPC, + TYPE_PNV10_LPC) + +struct PnvLpcController { + DeviceState parent; + + uint64_t eccb_stat_reg; + uint32_t eccb_data_reg; + + /* OPB bus */ + MemoryRegion opb_mr; + AddressSpace opb_as; + + /* ISA IO and Memory space */ + MemoryRegion isa_io; + MemoryRegion isa_mem; + MemoryRegion isa_fw; + + /* Windows from OPB to ISA (aliases) */ + MemoryRegion opb_isa_io; + MemoryRegion opb_isa_mem; + MemoryRegion opb_isa_fw; + + /* Registers */ + MemoryRegion lpc_hc_regs; + MemoryRegion opb_master_regs; + + /* OPB Master LS registers */ + uint32_t opb_irq_route0; + uint32_t opb_irq_route1; + uint32_t opb_irq_stat; + uint32_t opb_irq_mask; + uint32_t opb_irq_pol; + uint32_t opb_irq_input; + + /* LPC HC registers */ + uint32_t lpc_hc_fw_seg_idsel; + uint32_t lpc_hc_fw_rd_acc_size; + uint32_t lpc_hc_irqser_ctrl; + uint32_t lpc_hc_irqmask; + uint32_t lpc_hc_irqstat; + uint32_t lpc_hc_error_addr; + + /* XSCOM registers */ + MemoryRegion xscom_regs; + + /* PSI to generate interrupts */ + PnvPsi *psi; +}; + + +struct PnvLpcClass { + DeviceClass parent_class; + + int psi_irq; + + DeviceRealize parent_realize; +}; + +/* + * Old compilers error on typdef forward declarations. Keep them happy. + */ +struct PnvChip; + +ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp); +int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset, + uint64_t lpcm_addr, uint64_t lpcm_size); + +#endif /* PPC_PNV_LPC_H */ diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h new file mode 100644 index 000000000..b78185aec --- /dev/null +++ b/include/hw/ppc/pnv_occ.h @@ -0,0 +1,63 @@ +/* + * QEMU PowerPC PowerNV Emulation of a few OCC related registers + * + * Copyright (c) 2015-2017, IBM Corporation. + * + * 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.1 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/>. + */ + +#ifndef PPC_PNV_OCC_H +#define PPC_PNV_OCC_H + +#include "hw/ppc/pnv_psi.h" +#include "qom/object.h" + +#define TYPE_PNV_OCC "pnv-occ" +OBJECT_DECLARE_TYPE(PnvOCC, PnvOCCClass, + PNV_OCC) +#define TYPE_PNV8_OCC TYPE_PNV_OCC "-POWER8" +DECLARE_INSTANCE_CHECKER(PnvOCC, PNV8_OCC, + TYPE_PNV8_OCC) +#define TYPE_PNV9_OCC TYPE_PNV_OCC "-POWER9" +DECLARE_INSTANCE_CHECKER(PnvOCC, PNV9_OCC, + TYPE_PNV9_OCC) + +#define PNV_OCC_SENSOR_DATA_BLOCK_OFFSET 0x00580000 +#define PNV_OCC_SENSOR_DATA_BLOCK_SIZE 0x00025800 + +struct PnvOCC { + DeviceState xd; + + /* OCC Misc interrupt */ + uint64_t occmisc; + + PnvPsi *psi; + + MemoryRegion xscom_regs; + MemoryRegion sram_regs; +}; + + +struct PnvOCCClass { + DeviceClass parent_class; + + int xscom_size; + const MemoryRegionOps *xscom_ops; + int psi_irq; +}; + +#define PNV_OCC_SENSOR_DATA_BLOCK_BASE(i) \ + (PNV_OCC_SENSOR_DATA_BLOCK_OFFSET + (i) * PNV_OCC_SENSOR_DATA_BLOCK_SIZE) + +#endif /* PPC_PNV_OCC_H */ diff --git a/include/hw/ppc/pnv_pnor.h b/include/hw/ppc/pnv_pnor.h new file mode 100644 index 000000000..99f9a3adf --- /dev/null +++ b/include/hw/ppc/pnv_pnor.h @@ -0,0 +1,31 @@ +/* + * QEMU PowerNV PNOR simple model + * + * Copyright (c) 2019, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ +#ifndef _PPC_PNV_PNOR_H +#define _PPC_PNV_PNOR_H +#include "qom/object.h" + +/* + * PNOR offset on the LPC FW address space + */ +#define PNOR_SPI_OFFSET 0x0c000000UL + +#define TYPE_PNV_PNOR "pnv-pnor" +OBJECT_DECLARE_SIMPLE_TYPE(PnvPnor, PNV_PNOR) + +struct PnvPnor { + SysBusDevice parent_obj; + + BlockBackend *blk; + + uint8_t *storage; + int64_t size; + MemoryRegion mmio; +}; + +#endif /* _PPC_PNV_PNOR_H */ diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h new file mode 100644 index 000000000..eb841b34a --- /dev/null +++ b/include/hw/ppc/pnv_psi.h @@ -0,0 +1,120 @@ +/* + * QEMU PowerPC PowerNV Processor Service Interface (PSI) model + * + * Copyright (c) 2015-2017, IBM Corporation. + * + * 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.1 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/>. + */ + +#ifndef PPC_PNV_PSI_H +#define PPC_PNV_PSI_H + +#include "hw/sysbus.h" +#include "hw/ppc/xics.h" +#include "hw/ppc/xive.h" +#include "qom/object.h" + +#define TYPE_PNV_PSI "pnv-psi" +OBJECT_DECLARE_TYPE(PnvPsi, PnvPsiClass, + PNV_PSI) + +#define PSIHB_XSCOM_MAX 0x20 + +struct PnvPsi { + DeviceState parent; + + MemoryRegion regs_mr; + uint64_t bar; + + /* FSP region not supported */ + /* MemoryRegion fsp_mr; */ + uint64_t fsp_bar; + + /* Interrupt generation */ + qemu_irq *qirqs; + + /* Registers */ + uint64_t regs[PSIHB_XSCOM_MAX]; + + MemoryRegion xscom_regs; +}; + +#define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8" +OBJECT_DECLARE_SIMPLE_TYPE(Pnv8Psi, PNV8_PSI) + +struct Pnv8Psi { + PnvPsi parent; + + ICSState ics; +}; + +#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9" +OBJECT_DECLARE_SIMPLE_TYPE(Pnv9Psi, PNV9_PSI) + +struct Pnv9Psi { + PnvPsi parent; + + XiveSource source; +}; + +#define TYPE_PNV10_PSI TYPE_PNV_PSI "-POWER10" + + +struct PnvPsiClass { + SysBusDeviceClass parent_class; + + uint32_t xscom_pcba; + uint32_t xscom_size; + uint64_t bar_mask; + const char *compat; + int compat_size; + + void (*irq_set)(PnvPsi *psi, int, bool state); +}; + +/* The PSI and FSP interrupts are muxed on the same IRQ number */ +typedef enum PnvPsiIrq { + PSIHB_IRQ_PSI, /* internal use only */ + PSIHB_IRQ_FSP, /* internal use only */ + PSIHB_IRQ_OCC, + PSIHB_IRQ_FSI, + PSIHB_IRQ_LPC_I2C, + PSIHB_IRQ_LOCAL_ERR, + PSIHB_IRQ_EXTERNAL, +} PnvPsiIrq; + +#define PSI_NUM_INTERRUPTS 6 + +void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state); + +/* P9 PSI Interrupts */ +#define PSIHB9_IRQ_PSI 0 +#define PSIHB9_IRQ_OCC 1 +#define PSIHB9_IRQ_FSI 2 +#define PSIHB9_IRQ_LPCHC 3 +#define PSIHB9_IRQ_LOCAL_ERR 4 +#define PSIHB9_IRQ_GLOBAL_ERR 5 +#define PSIHB9_IRQ_TPM 6 +#define PSIHB9_IRQ_LPC_SIRQ0 7 +#define PSIHB9_IRQ_LPC_SIRQ1 8 +#define PSIHB9_IRQ_LPC_SIRQ2 9 +#define PSIHB9_IRQ_LPC_SIRQ3 10 +#define PSIHB9_IRQ_SBE_I2C 11 +#define PSIHB9_IRQ_DIO 12 +#define PSIHB9_IRQ_PSU 13 +#define PSIHB9_NUM_IRQS 14 + +void pnv_psi_pic_print_info(Pnv9Psi *psi, Monitor *mon); + +#endif /* PPC_PNV_PSI_H */ diff --git a/include/hw/ppc/pnv_xive.h b/include/hw/ppc/pnv_xive.h new file mode 100644 index 000000000..7928e2796 --- /dev/null +++ b/include/hw/ppc/pnv_xive.h @@ -0,0 +1,98 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * Copyright (c) 2017-2019, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_PNV_XIVE_H +#define PPC_PNV_XIVE_H + +#include "hw/ppc/xive.h" +#include "qom/object.h" + +struct PnvChip; + +#define TYPE_PNV_XIVE "pnv-xive" +OBJECT_DECLARE_TYPE(PnvXive, PnvXiveClass, + PNV_XIVE) + +#define XIVE_BLOCK_MAX 16 + +#define XIVE_TABLE_BLK_MAX 16 /* Block Scope Table (0-15) */ +#define XIVE_TABLE_MIG_MAX 16 /* Migration Register Table (1-15) */ +#define XIVE_TABLE_VDT_MAX 16 /* VDT Domain Table (0-15) */ +#define XIVE_TABLE_EDT_MAX 64 /* EDT Domain Table (0-63) */ + +struct PnvXive { + XiveRouter parent_obj; + + /* Owning chip */ + struct PnvChip *chip; + + /* XSCOM addresses giving access to the controller registers */ + MemoryRegion xscom_regs; + + /* Main MMIO regions that can be configured by FW */ + MemoryRegion ic_mmio; + MemoryRegion ic_reg_mmio; + MemoryRegion ic_notify_mmio; + MemoryRegion ic_lsi_mmio; + MemoryRegion tm_indirect_mmio; + MemoryRegion vc_mmio; + MemoryRegion pc_mmio; + MemoryRegion tm_mmio; + + /* + * IPI and END address spaces modeling the EDT segmentation in the + * VC region + */ + AddressSpace ipi_as; + MemoryRegion ipi_mmio; + MemoryRegion ipi_edt_mmio; + + AddressSpace end_as; + MemoryRegion end_mmio; + MemoryRegion end_edt_mmio; + + /* Shortcut values for the Main MMIO regions */ + hwaddr ic_base; + uint32_t ic_shift; + hwaddr vc_base; + uint32_t vc_shift; + hwaddr pc_base; + uint32_t pc_shift; + hwaddr tm_base; + uint32_t tm_shift; + + /* Our XIVE source objects for IPIs and ENDs */ + XiveSource ipi_source; + XiveENDSource end_source; + + /* Interrupt controller registers */ + uint64_t regs[0x300]; + + /* + * Virtual Structure Descriptor tables : EAT, SBE, ENDT, NVTT, IRQ + * These are in a SRAM protected by ECC. + */ + uint64_t vsds[5][XIVE_BLOCK_MAX]; + + /* Translation tables */ + uint64_t blk[XIVE_TABLE_BLK_MAX]; + uint64_t mig[XIVE_TABLE_MIG_MAX]; + uint64_t vdt[XIVE_TABLE_VDT_MAX]; + uint64_t edt[XIVE_TABLE_EDT_MAX]; +}; + +struct PnvXiveClass { + XiveRouterClass parent_class; + + DeviceRealize parent_realize; +}; + +void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon); + +#endif /* PPC_PNV_XIVE_H */ diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h new file mode 100644 index 000000000..2ff9f7a8d --- /dev/null +++ b/include/hw/ppc/pnv_xscom.h @@ -0,0 +1,148 @@ +/* + * QEMU PowerPC PowerNV XSCOM bus definitions + * + * Copyright (c) 2016, IBM Corporation. + * + * 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.1 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/>. + */ + +#ifndef PPC_PNV_XSCOM_H +#define PPC_PNV_XSCOM_H + +#include "qom/object.h" + +typedef struct PnvXScomInterface PnvXScomInterface; + +#define TYPE_PNV_XSCOM_INTERFACE "pnv-xscom-interface" +#define PNV_XSCOM_INTERFACE(obj) \ + INTERFACE_CHECK(PnvXScomInterface, (obj), TYPE_PNV_XSCOM_INTERFACE) +typedef struct PnvXScomInterfaceClass PnvXScomInterfaceClass; +DECLARE_CLASS_CHECKERS(PnvXScomInterfaceClass, PNV_XSCOM_INTERFACE, + TYPE_PNV_XSCOM_INTERFACE) + +struct PnvXScomInterfaceClass { + InterfaceClass parent; + int (*dt_xscom)(PnvXScomInterface *dev, void *fdt, int offset); +}; + +/* + * Layout of the XSCOM PCB addresses of EX core 1 (POWER 8) + * + * GPIO 0x1100xxxx + * SCOM 0x1101xxxx + * OHA 0x1102xxxx + * CLOCK CTL 0x1103xxxx + * FIR 0x1104xxxx + * THERM 0x1105xxxx + * <reserved> 0x1106xxxx + * .. + * 0x110Exxxx + * PCB SLAVE 0x110Fxxxx + */ + +#define PNV_XSCOM_EX_CORE_BASE 0x10000000ull + +#define PNV_XSCOM_EX_BASE(core) \ + (PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24)) +#define PNV_XSCOM_EX_SIZE 0x100000 + +#define PNV_XSCOM_LPC_BASE 0xb0020 +#define PNV_XSCOM_LPC_SIZE 0x4 + +#define PNV_XSCOM_PSIHB_BASE 0x2010900 +#define PNV_XSCOM_PSIHB_SIZE 0x20 + +#define PNV_XSCOM_OCC_BASE 0x0066000 +#define PNV_XSCOM_OCC_SIZE 0x6000 + +#define PNV_XSCOM_PBA_BASE 0x2013f00 +#define PNV_XSCOM_PBA_SIZE 0x40 + +#define PNV_XSCOM_PBCQ_NEST_BASE 0x2012000 +#define PNV_XSCOM_PBCQ_NEST_SIZE 0x46 + +#define PNV_XSCOM_PBCQ_PCI_BASE 0x9012000 +#define PNV_XSCOM_PBCQ_PCI_SIZE 0x15 + +#define PNV_XSCOM_PBCQ_SPCI_BASE 0x9013c00 +#define PNV_XSCOM_PBCQ_SPCI_SIZE 0x5 + +/* + * Layout of the XSCOM PCB addresses (POWER 9) + */ +#define PNV9_XSCOM_EC_BASE(core) \ + ((uint64_t)(((core) & 0x1F) + 0x20) << 24) +#define PNV9_XSCOM_EC_SIZE 0x100000 + +#define PNV9_XSCOM_EQ_BASE(core) \ + ((uint64_t)(((core) & 0x1C) + 0x40) << 22) +#define PNV9_XSCOM_EQ_SIZE 0x100000 + +#define PNV9_XSCOM_OCC_BASE PNV_XSCOM_OCC_BASE +#define PNV9_XSCOM_OCC_SIZE 0x8000 + +#define PNV9_XSCOM_PBA_BASE 0x5012b00 +#define PNV9_XSCOM_PBA_SIZE 0x40 + +#define PNV9_XSCOM_PSIHB_BASE 0x5012900 +#define PNV9_XSCOM_PSIHB_SIZE 0x100 + +#define PNV9_XSCOM_XIVE_BASE 0x5013000 +#define PNV9_XSCOM_XIVE_SIZE 0x300 + +#define PNV9_XSCOM_PEC_NEST_BASE 0x4010c00 +#define PNV9_XSCOM_PEC_NEST_SIZE 0x100 + +#define PNV9_XSCOM_PEC_PCI_BASE 0xd010800 +#define PNV9_XSCOM_PEC_PCI_SIZE 0x200 + +/* XSCOM PCI "pass-through" window to PHB SCOM */ +#define PNV9_XSCOM_PEC_PCI_STK0 0x100 +#define PNV9_XSCOM_PEC_PCI_STK1 0x140 +#define PNV9_XSCOM_PEC_PCI_STK2 0x180 + +/* + * Layout of the XSCOM PCB addresses (POWER 10) + */ +#define PNV10_XSCOM_EQ_CHIPLET(core) (0x20 + ((core) >> 2)) +#define PNV10_XSCOM_EQ(chiplet) ((chiplet) << 24) +#define PNV10_XSCOM_EC(proc) \ + ((0x2 << 16) | ((1 << (3 - (proc))) << 12)) + +#define PNV10_XSCOM_EQ_BASE(core) \ + ((uint64_t) PNV10_XSCOM_EQ(PNV10_XSCOM_EQ_CHIPLET(core))) +#define PNV10_XSCOM_EQ_SIZE 0x100000 + +#define PNV10_XSCOM_EC_BASE(core) \ + ((uint64_t) PNV10_XSCOM_EQ_BASE(core) | PNV10_XSCOM_EC(core & 0x3)) +#define PNV10_XSCOM_EC_SIZE 0x100000 + +#define PNV10_XSCOM_PSIHB_BASE 0x3011D00 +#define PNV10_XSCOM_PSIHB_SIZE 0x100 + +void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp); +int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, + uint64_t xscom_base, uint64_t xscom_size, + const char *compat, int compat_size); + +void pnv_xscom_add_subregion(PnvChip *chip, hwaddr offset, + MemoryRegion *mr); +void pnv_xscom_region_init(MemoryRegion *mr, + Object *owner, + const MemoryRegionOps *ops, + void *opaque, + const char *name, + uint64_t size); + +#endif /* PPC_PNV_XSCOM_H */ diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h new file mode 100644 index 000000000..93e614cff --- /dev/null +++ b/include/hw/ppc/ppc.h @@ -0,0 +1,115 @@ +#ifndef HW_PPC_H +#define HW_PPC_H + +#include "target/ppc/cpu-qom.h" + +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); +PowerPCCPU *ppc_get_vcpu_by_pir(int pir); +int ppc_cpu_pir(PowerPCCPU *cpu); + +/* 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 */ + int64_t vtb_offset; + 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; + int64_t purr_offset; + 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); + +#if defined(CONFIG_USER_ONLY) +static inline void ppc40x_irq_init(PowerPCCPU *cpu) {} +static inline void ppc6xx_irq_init(PowerPCCPU *cpu) {} +static inline void ppc970_irq_init(PowerPCCPU *cpu) {} +static inline void ppcPOWER7_irq_init(PowerPCCPU *cpu) {} +static inline void ppcPOWER9_irq_init(PowerPCCPU *cpu) {} +static inline void ppce500_irq_init(PowerPCCPU *cpu) {} +static inline void ppc_irq_reset(PowerPCCPU *cpu) {} +#else +void ppc40x_irq_init(PowerPCCPU *cpu); +void ppce500_irq_init(PowerPCCPU *cpu); +void ppc6xx_irq_init(PowerPCCPU *cpu); +void ppc970_irq_init(PowerPCCPU *cpu); +void ppcPOWER7_irq_init(PowerPCCPU *cpu); +void ppcPOWER9_irq_init(PowerPCCPU *cpu); +void ppc_irq_reset(PowerPCCPU *cpu); +#endif + +/* 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 FW_CFG_PPC_NVRAM_FLAT (FW_CFG_ARCH_LOCAL + 0x0a) +#define FW_CFG_PPC_VIACONFIG (FW_CFG_ARCH_LOCAL + 0x0b) + +#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/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h new file mode 100644 index 000000000..980f964b5 --- /dev/null +++ b/include/hw/ppc/ppc4xx.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef PPC4XX_H +#define PPC4XX_H + +#include "hw/ppc/ppc.h" +#include "exec/memory.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); + +void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, + MemoryRegion ram_memories[], + hwaddr ram_bases[], hwaddr ram_sizes[], + const ram_addr_t 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); + +void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, + qemu_irq irqs[4]); + +#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" + +#endif /* PPC4XX_H */ diff --git a/include/hw/ppc/ppc_e500.h b/include/hw/ppc/ppc_e500.h new file mode 100644 index 000000000..b66c0e3ee --- /dev/null +++ b/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/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h new file mode 100644 index 000000000..ee7504b97 --- /dev/null +++ b/include/hw/ppc/spapr.h @@ -0,0 +1,991 @@ +#ifndef HW_SPAPR_H +#define HW_SPAPR_H + +#include "qemu/units.h" +#include "sysemu/dma.h" +#include "hw/boards.h" +#include "hw/ppc/spapr_drc.h" +#include "hw/mem/pc-dimm.h" +#include "hw/ppc/spapr_ovec.h" +#include "hw/ppc/spapr_irq.h" +#include "qom/object.h" +#include "hw/ppc/spapr_xive.h" /* For SpaprXive */ +#include "hw/ppc/xics.h" /* For ICSState */ +#include "hw/ppc/spapr_tpm_proxy.h" +#include "hw/ppc/vof.h" + +struct SpaprVioBus; +struct SpaprPhbState; +struct SpaprNvram; + +typedef struct SpaprEventLogEntry SpaprEventLogEntry; +typedef struct SpaprEventSource SpaprEventSource; +typedef struct SpaprPendingHpt SpaprPendingHpt; + +#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL +#define SPAPR_ENTRY_POINT 0x100 + +#define SPAPR_TIMEBASE_FREQ 512000000ULL + +#define TYPE_SPAPR_RTC "spapr-rtc" + +OBJECT_DECLARE_SIMPLE_TYPE(SpaprRtcState, SPAPR_RTC) + +struct SpaprRtcState { + /*< private >*/ + DeviceState parent_obj; + int64_t ns_offset; +}; + +typedef struct SpaprDimmState SpaprDimmState; + +#define TYPE_SPAPR_MACHINE "spapr-machine" +OBJECT_DECLARE_TYPE(SpaprMachineState, SpaprMachineClass, SPAPR_MACHINE) + +typedef enum { + SPAPR_RESIZE_HPT_DEFAULT = 0, + SPAPR_RESIZE_HPT_DISABLED, + SPAPR_RESIZE_HPT_ENABLED, + SPAPR_RESIZE_HPT_REQUIRED, +} SpaprResizeHpt; + +/** + * Capabilities + */ + +/* Hardware Transactional Memory */ +#define SPAPR_CAP_HTM 0x00 +/* Vector Scalar Extensions */ +#define SPAPR_CAP_VSX 0x01 +/* Decimal Floating Point */ +#define SPAPR_CAP_DFP 0x02 +/* Cache Flush on Privilege Change */ +#define SPAPR_CAP_CFPC 0x03 +/* Speculation Barrier Bounds Checking */ +#define SPAPR_CAP_SBBC 0x04 +/* Indirect Branch Serialisation */ +#define SPAPR_CAP_IBS 0x05 +/* HPT Maximum Page Size (encoded as a shift) */ +#define SPAPR_CAP_HPT_MAXPAGESIZE 0x06 +/* Nested KVM-HV */ +#define SPAPR_CAP_NESTED_KVM_HV 0x07 +/* Large Decrementer */ +#define SPAPR_CAP_LARGE_DECREMENTER 0x08 +/* Count Cache Flush Assist HW Instruction */ +#define SPAPR_CAP_CCF_ASSIST 0x09 +/* Implements PAPR FWNMI option */ +#define SPAPR_CAP_FWNMI 0x0A +/* Support H_RPT_INVALIDATE */ +#define SPAPR_CAP_RPT_INVALIDATE 0x0B +/* Num Caps */ +#define SPAPR_CAP_NUM (SPAPR_CAP_RPT_INVALIDATE + 1) + +/* + * Capability Values + */ +/* Bool Caps */ +#define SPAPR_CAP_OFF 0x00 +#define SPAPR_CAP_ON 0x01 + +/* Custom Caps */ + +/* Generic */ +#define SPAPR_CAP_BROKEN 0x00 +#define SPAPR_CAP_WORKAROUND 0x01 +#define SPAPR_CAP_FIXED 0x02 +/* SPAPR_CAP_IBS (cap-ibs) */ +#define SPAPR_CAP_FIXED_IBS 0x02 +#define SPAPR_CAP_FIXED_CCD 0x03 +#define SPAPR_CAP_FIXED_NA 0x10 /* Lets leave a bit of a gap... */ + +#define FDT_MAX_SIZE 0x200000 + +/* Max number of GPUs per system */ +#define NVGPU_MAX_NUM 6 + +/* Max number of NUMA nodes */ +#define NUMA_NODES_MAX_NUM (MAX_NODES + NVGPU_MAX_NUM) + +/* + * NUMA FORM1 macros. FORM1_DIST_REF_POINTS was taken from + * MAX_DISTANCE_REF_POINTS in arch/powerpc/mm/numa.h from Linux + * kernel source. It represents the amount of associativity domains + * for non-CPU resources. + * + * FORM1_NUMA_ASSOC_SIZE is the base array size of an ibm,associativity + * array for any non-CPU resource. + */ +#define FORM1_DIST_REF_POINTS 4 +#define FORM1_NUMA_ASSOC_SIZE (FORM1_DIST_REF_POINTS + 1) + +/* + * FORM2 NUMA affinity has a single associativity domain, giving + * us a assoc size of 2. + */ +#define FORM2_DIST_REF_POINTS 1 +#define FORM2_NUMA_ASSOC_SIZE (FORM2_DIST_REF_POINTS + 1) + +typedef struct SpaprCapabilities SpaprCapabilities; +struct SpaprCapabilities { + uint8_t caps[SPAPR_CAP_NUM]; +}; + +/** + * SpaprMachineClass: + */ +struct SpaprMachineClass { + /*< private >*/ + MachineClass parent_class; + + /*< public >*/ + bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ + bool dr_phb_enabled; /* enable dynamic-reconfig/hotplug of PHBs */ + bool update_dt_enabled; /* enable KVMPPC_H_UPDATE_DT */ + bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ + bool pre_2_10_has_unused_icps; + bool legacy_irq_allocation; + uint32_t nr_xirqs; + bool broken_host_serial_model; /* present real host info to the guest */ + bool pre_4_1_migration; /* don't migrate hpt-max-page-size */ + bool linux_pci_probe; + bool smp_threads_vsmt; /* set VSMT to smp_threads by default */ + hwaddr rma_limit; /* clamp the RMA to this size */ + bool pre_5_1_assoc_refpoints; + bool pre_5_2_numa_associativity; + bool pre_6_2_numa_affinity; + + bool (*phb_placement)(SpaprMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, + hwaddr *mmio32, hwaddr *mmio64, + unsigned n_dma, uint32_t *liobns, hwaddr *nv2gpa, + hwaddr *nv2atsd, Error **errp); + SpaprResizeHpt resize_hpt_default; + SpaprCapabilities default_caps; + SpaprIrq *irq; +}; + +/** + * SpaprMachineState: + */ +struct SpaprMachineState { + /*< private >*/ + MachineState parent_obj; + + struct SpaprVioBus *vio_bus; + QLIST_HEAD(, SpaprPhbState) phbs; + struct SpaprNvram *nvram; + SpaprRtcState rtc; + + SpaprResizeHpt resize_hpt; + void *htab; + uint32_t htab_shift; + uint64_t patb_entry; /* Process tbl registed in H_REGISTER_PROC_TBL */ + SpaprPendingHpt *pending_hpt; /* in-progress resize */ + + hwaddr rma_size; + uint32_t fdt_size; + uint32_t fdt_initial_size; + void *fdt_blob; + long kernel_size; + bool kernel_le; + uint64_t kernel_addr; + uint32_t initrd_base; + long initrd_size; + Vof *vof; + uint64_t rtc_offset; /* Now used only during incoming migration */ + struct PPCTimebase tb; + bool has_graphics; + uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */ + + Notifier epow_notifier; + QTAILQ_HEAD(, SpaprEventLogEntry) pending_events; + bool use_hotplug_event_source; + SpaprEventSource *event_sources; + + /* ibm,client-architecture-support option negotiation */ + bool cas_pre_isa3_guest; + SpaprOptionVector *ov5; /* QEMU-supported option vectors */ + SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */ + uint32_t max_compat_pvr; + + /* Migration state */ + int htab_save_index; + bool htab_first_pass; + int htab_fd; + + /* Pending DIMM unplug cache. It is populated when a LMB + * unplug starts. It can be regenerated if a migration + * occurs during the unplug process. */ + QTAILQ_HEAD(, SpaprDimmState) pending_dimm_unplugs; + + /* State related to FWNMI option */ + + /* System Reset and Machine Check Notification Routine addresses + * registered by "ibm,nmi-register" RTAS call. + */ + target_ulong fwnmi_system_reset_addr; + target_ulong fwnmi_machine_check_addr; + + /* Machine Check FWNMI synchronization, fwnmi_machine_check_interlock is + * set to -1 if a FWNMI machine check is not in progress, else is set to + * the CPU that was delivered the machine check, and is set back to -1 + * when that CPU makes an "ibm,nmi-interlock" RTAS call. The cond is used + * to synchronize other CPUs. + */ + int fwnmi_machine_check_interlock; + QemuCond fwnmi_machine_check_interlock_cond; + + /* Set by -boot */ + char *boot_device; + + /*< public >*/ + char *kvm_type; + char *host_model; + char *host_serial; + + int32_t irq_map_nr; + unsigned long *irq_map; + SpaprIrq *irq; + qemu_irq *qirqs; + SpaprInterruptController *active_intc; + ICSState *ics; + SpaprXive *xive; + + bool cmd_line_caps[SPAPR_CAP_NUM]; + SpaprCapabilities def, eff, mig; + + unsigned gpu_numa_id; + SpaprTpmProxy *tpm_proxy; + + uint32_t FORM1_assoc_array[NUMA_NODES_MAX_NUM][FORM1_NUMA_ASSOC_SIZE]; + uint32_t FORM2_assoc_array[NUMA_NODES_MAX_NUM][FORM2_NUMA_ASSOC_SIZE]; + + Error *fwnmi_migration_blocker; +}; + +#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_OVERLAP -68 +#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_DAWR0 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 + +/* 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)) + +/* Values for KVM_PPC_GET_CPU_CHAR & H_GET_CPU_CHARACTERISTICS */ +#define H_CPU_CHAR_SPEC_BAR_ORI31 PPC_BIT(0) +#define H_CPU_CHAR_BCCTRL_SERIALISED PPC_BIT(1) +#define H_CPU_CHAR_L1D_FLUSH_ORI30 PPC_BIT(2) +#define H_CPU_CHAR_L1D_FLUSH_TRIG2 PPC_BIT(3) +#define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4) +#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5) +#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6) +#define H_CPU_CHAR_CACHE_COUNT_DIS PPC_BIT(7) +#define H_CPU_CHAR_BCCTR_FLUSH_ASSIST PPC_BIT(9) + +#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0) +#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1) +#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2) +#define H_CPU_BEHAV_FLUSH_COUNT_CACHE PPC_BIT(5) +#define H_CPU_BEHAV_NO_L1D_FLUSH_ENTRY PPC_BIT(7) +#define H_CPU_BEHAV_NO_L1D_FLUSH_UACCESS PPC_BIT(8) + +/* 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_GET_CPU_CHARACTERISTICS 0x1C8 +#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_HOME_NODE_ASSOCIATIVITY 0x2EC +#define H_XIRR_X 0x2FC +#define H_RANDOM 0x300 +#define H_SET_MODE 0x31C +#define H_RESIZE_HPT_PREPARE 0x36C +#define H_RESIZE_HPT_COMMIT 0x370 +#define H_CLEAN_SLB 0x374 +#define H_INVALIDATE_PID 0x378 +#define H_REGISTER_PROC_TBL 0x37C +#define H_SIGNAL_SYS_RESET 0x380 + +#define H_INT_GET_SOURCE_INFO 0x3A8 +#define H_INT_SET_SOURCE_CONFIG 0x3AC +#define H_INT_GET_SOURCE_CONFIG 0x3B0 +#define H_INT_GET_QUEUE_INFO 0x3B4 +#define H_INT_SET_QUEUE_CONFIG 0x3B8 +#define H_INT_GET_QUEUE_CONFIG 0x3BC +#define H_INT_SET_OS_REPORTING_LINE 0x3C0 +#define H_INT_GET_OS_REPORTING_LINE 0x3C4 +#define H_INT_ESB 0x3C8 +#define H_INT_SYNC 0x3CC +#define H_INT_RESET 0x3D0 +#define H_SCM_READ_METADATA 0x3E4 +#define H_SCM_WRITE_METADATA 0x3E8 +#define H_SCM_BIND_MEM 0x3EC +#define H_SCM_UNBIND_MEM 0x3F0 +#define H_SCM_UNBIND_ALL 0x3FC +#define H_SCM_HEALTH 0x400 +#define H_RPT_INVALIDATE 0x448 + +#define MAX_HCALL_OPCODE H_RPT_INVALIDATE + +/* 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. + * 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_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3) +/* 0x4 was used for KVMPPC_H_UPDATE_PHANDLE in SLOF */ +#define KVMPPC_H_VOF_CLIENT (KVMPPC_HCALL_BASE + 0x5) +#define KVMPPC_HCALL_MAX KVMPPC_H_VOF_CLIENT + +/* + * The hcall range 0xEF00 to 0xEF80 is reserved for use in facilitating + * Secure VM mode via an Ultravisor / Protected Execution Facility + */ +#define SVM_HCALL_BASE 0xEF00 +#define SVM_H_TPM_COMM 0xEF10 +#define SVM_HCALL_MAX SVM_H_TPM_COMM + + +typedef struct SpaprDeviceTreeUpdateHeader { + uint32_t version_id; +} SpaprDeviceTreeUpdateHeader; + +#define hcall_dprintf(fmt, ...) \ + do { \ + qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt, __func__, ## __VA_ARGS__); \ + } while (0) + +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); +target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong shift); +target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong flags, target_ulong shift); +bool is_ram_address(SpaprMachineState *spapr, hwaddr addr); +void push_sregs_to_kvm_pr(SpaprMachineState *spapr); + +/* Virtual Processor Area structure constants */ +#define VPA_MIN_SIZE 640 +#define VPA_SIZE_OFFSET 0x4 +#define VPA_SHARED_PROC_OFFSET 0x9 +#define VPA_SHARED_PROC_VAL 0x2 +#define VPA_DISPATCH_COUNTER 0x100 + +/* 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_NO_SUCH_INDICATOR -3 +#define RTAS_OUT_NOT_AUTHORIZED -9002 +#define RTAS_OUT_SYSPARM_PARAM_ERROR -9999 + +/* DDW pagesize mask values from ibm,query-pe-dma-window */ +#define RTAS_DDW_PGSIZE_4K 0x01 +#define RTAS_DDW_PGSIZE_64K 0x02 +#define RTAS_DDW_PGSIZE_16M 0x04 +#define RTAS_DDW_PGSIZE_32M 0x08 +#define RTAS_DDW_PGSIZE_64M 0x10 +#define RTAS_DDW_PGSIZE_128M 0x20 +#define RTAS_DDW_PGSIZE_256M 0x40 +#define RTAS_DDW_PGSIZE_16G 0x80 + +/* 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_IBM_QUERY_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x26) +#define RTAS_IBM_CREATE_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x27) +#define RTAS_IBM_REMOVE_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x28) +#define RTAS_IBM_RESET_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x29) +#define RTAS_IBM_SUSPEND_ME (RTAS_TOKEN_BASE + 0x2A) +#define RTAS_IBM_NMI_REGISTER (RTAS_TOKEN_BASE + 0x2B) +#define RTAS_IBM_NMI_INTERLOCK (RTAS_TOKEN_BASE + 0x2C) + +#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x2D) + +/* 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 uint64_t rtas_ldq(target_ulong phys, int n) +{ + return (uint64_t)rtas_ld(phys, n) << 32 | rtas_ld(phys, n + 1); +} + +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); +} + +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); +void spapr_dt_rtas_tokens(void *fdt, int rtas); +void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr); + +#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_MIN_SIZE 20 /* hv_rtas_size in SLOF */ +#define RTAS_ERROR_LOG_MAX 2048 + +/* Offset from rtas-base where error log is placed */ +#define RTAS_ERROR_LOG_OFFSET 0x30 + +#define RTAS_EVENT_SCAN_RATE 1 + +/* This helper should be used to encode interrupt specifiers when the related + * "interrupt-controller" node has its "#interrupt-cells" property set to 2 (ie, + * VIO devices, RTAS event sources and PHBs). + */ +static inline void spapr_dt_irq(uint32_t *intspec, int irq, bool is_lsi) +{ + intspec[0] = cpu_to_be32(irq); + intspec[1] = is_lsi ? cpu_to_be32(1) : 0; +} + + +#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table" +OBJECT_DECLARE_SIMPLE_TYPE(SpaprTceTable, SPAPR_TCE_TABLE) + +#define TYPE_SPAPR_IOMMU_MEMORY_REGION "spapr-iommu-memory-region" +DECLARE_INSTANCE_CHECKER(IOMMUMemoryRegion, SPAPR_IOMMU_MEMORY_REGION, + TYPE_SPAPR_IOMMU_MEMORY_REGION) + +struct SpaprTceTable { + DeviceState parent; + uint32_t liobn; + uint32_t nb_table; + uint64_t bus_offset; + uint32_t page_shift; + uint64_t *table; + uint32_t mig_nb_table; + uint64_t *mig_table; + bool bypass; + bool need_vfio; + bool skipping_replay; + int fd; + MemoryRegion root; + IOMMUMemoryRegion iommu; + struct SpaprVioDevice *vdev; /* for @bypass migration compatibility only */ + QLIST_ENTRY(SpaprTceTable) list; +}; + +SpaprTceTable *spapr_tce_find_by_liobn(target_ulong liobn); + +struct SpaprEventLogEntry { + uint32_t summary; + uint32_t extended_length; + void *extended_log; + QTAILQ_ENTRY(SpaprEventLogEntry) next; +}; + +void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space); +void spapr_events_init(SpaprMachineState *sm); +void spapr_dt_events(SpaprMachineState *sm, void *fdt); +void close_htab_fd(SpaprMachineState *spapr); +void spapr_setup_hpt(SpaprMachineState *spapr); +void spapr_free_hpt(SpaprMachineState *spapr); +void spapr_check_mmu_mode(bool guest_radix); +SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn); +void spapr_tce_table_enable(SpaprTceTable *tcet, + uint32_t page_shift, uint64_t bus_offset, + uint32_t nb_table); +void spapr_tce_table_disable(SpaprTceTable *tcet); +void spapr_tce_set_need_vfio(SpaprTceTable *tcet, bool need_vfio); + +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(SpaprMachineState *spapr, bool big_endian); +void spapr_hotplug_req_add_by_index(SpaprDrc *drc); +void spapr_hotplug_req_remove_by_index(SpaprDrc *drc); +void spapr_hotplug_req_add_by_count(SpaprDrcType drc_type, + uint32_t count); +void spapr_hotplug_req_remove_by_count(SpaprDrcType drc_type, + uint32_t count); +void spapr_hotplug_req_add_by_count_indexed(SpaprDrcType drc_type, + uint32_t count, uint32_t index); +void spapr_hotplug_req_remove_by_count_indexed(SpaprDrcType drc_type, + uint32_t count, uint32_t index); +int spapr_hpt_shift_for_ramsize(uint64_t ramsize); +int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp); +void spapr_clear_pending_events(SpaprMachineState *spapr); +void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr); +void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev); +int spapr_max_server_number(SpaprMachineState *spapr); +void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex, + uint64_t pte0, uint64_t pte1); +void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered); + +/* DRC callbacks. */ +void spapr_core_release(DeviceState *dev); +int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); +void spapr_lmb_release(DeviceState *dev); +int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); +void spapr_phb_release(DeviceState *dev); +int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); + +void spapr_rtc_read(SpaprRtcState *rtc, struct tm *tm, uint32_t *ns); +int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset); + +#define TYPE_SPAPR_RNG "spapr-rng" + +#define SPAPR_MEMORY_BLOCK_SIZE ((hwaddr)1 << 28) /* 256MB */ + +/* + * This defines the maximum number of DIMM slots we can have for sPAPR + * guest. This is not defined by sPAPR but we are defining it to 32 slots + * based on default number of slots provided by PowerPC kernel. + */ +#define SPAPR_MAX_RAM_SLOTS 32 + +/* 1GB alignment for hotplug memory region */ +#define SPAPR_DEVICE_MEM_ALIGN (1 * GiB) + +/* + * Number of 32 bit words in each LMB list entry in ibm,dynamic-memory + * property under ibm,dynamic-reconfiguration-memory node. + */ +#define SPAPR_DR_LMB_LIST_ENTRY_SIZE 6 + +/* + * Defines for flag value in ibm,dynamic-memory property under + * ibm,dynamic-reconfiguration-memory node. + */ +#define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008 +#define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020 +#define SPAPR_LMB_FLAGS_RESERVED 0x00000080 +#define SPAPR_LMB_FLAGS_HOTREMOVABLE 0x00000100 + +void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg); + +#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) + +int spapr_get_vcpu_id(PowerPCCPU *cpu); +bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp); +PowerPCCPU *spapr_find_cpu(int vcpu_id); + +int spapr_caps_pre_load(void *opaque); +int spapr_caps_pre_save(void *opaque); + +/* + * Handling of optional capabilities + */ +extern const VMStateDescription vmstate_spapr_cap_htm; +extern const VMStateDescription vmstate_spapr_cap_vsx; +extern const VMStateDescription vmstate_spapr_cap_dfp; +extern const VMStateDescription vmstate_spapr_cap_cfpc; +extern const VMStateDescription vmstate_spapr_cap_sbbc; +extern const VMStateDescription vmstate_spapr_cap_ibs; +extern const VMStateDescription vmstate_spapr_cap_hpt_maxpagesize; +extern const VMStateDescription vmstate_spapr_cap_nested_kvm_hv; +extern const VMStateDescription vmstate_spapr_cap_large_decr; +extern const VMStateDescription vmstate_spapr_cap_ccf_assist; +extern const VMStateDescription vmstate_spapr_cap_fwnmi; +extern const VMStateDescription vmstate_spapr_cap_rpt_invalidate; + +static inline uint8_t spapr_get_cap(SpaprMachineState *spapr, int cap) +{ + return spapr->eff.caps[cap]; +} + +void spapr_caps_init(SpaprMachineState *spapr); +void spapr_caps_apply(SpaprMachineState *spapr); +void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu); +void spapr_caps_add_properties(SpaprMachineClass *smc); +int spapr_caps_post_migration(SpaprMachineState *spapr); + +bool spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize, + Error **errp); +/* + * XIVE definitions + */ +#define SPAPR_OV5_XIVE_LEGACY 0x0 +#define SPAPR_OV5_XIVE_EXPLOIT 0x40 +#define SPAPR_OV5_XIVE_BOTH 0x80 /* Only to advertise on the platform */ + +void spapr_set_all_lpcrs(target_ulong value, target_ulong mask); +hwaddr spapr_get_rtas_addr(void); +bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr); + +void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp); +void spapr_vof_quiesce(MachineState *ms); +bool spapr_vof_setprop(MachineState *ms, const char *path, const char *propname, + void *val, int vallen); +target_ulong spapr_h_vof_client(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args); +target_ulong spapr_vof_client_architecture_support(MachineState *ms, + CPUState *cs, + target_ulong ovec_addr); +void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt); + +#endif /* HW_SPAPR_H */ diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h new file mode 100644 index 000000000..dab3dfc76 --- /dev/null +++ b/include/hw/ppc/spapr_cpu_core.h @@ -0,0 +1,58 @@ +/* + * sPAPR CPU core device. + * + * Copyright (C) 2016 Bharata B Rao <bharata@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. + */ +#ifndef HW_SPAPR_CPU_CORE_H +#define HW_SPAPR_CPU_CORE_H + +#include "hw/cpu/core.h" +#include "hw/qdev-core.h" +#include "target/ppc/cpu-qom.h" +#include "target/ppc/cpu.h" +#include "qom/object.h" + +#define TYPE_SPAPR_CPU_CORE "spapr-cpu-core" +OBJECT_DECLARE_TYPE(SpaprCpuCore, SpaprCpuCoreClass, + SPAPR_CPU_CORE) + +#define SPAPR_CPU_CORE_TYPE_NAME(model) model "-" TYPE_SPAPR_CPU_CORE + +struct SpaprCpuCore { + /*< private >*/ + CPUCore parent_obj; + + /*< public >*/ + PowerPCCPU **threads; + int node_id; + bool pre_3_0_migration; /* older machine don't know about SpaprCpuState */ +}; + +struct SpaprCpuCoreClass { + DeviceClass parent_class; + const char *cpu_type; +}; + +const char *spapr_get_cpu_core_type(const char *cpu_type); +void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, + target_ulong r1, target_ulong r3, + target_ulong r4); + +typedef struct SpaprCpuState { + uint64_t vpa_addr; + uint64_t slb_shadow_addr, slb_shadow_size; + uint64_t dtl_addr, dtl_size; + bool prod; /* not migrated, only used to improve dispatch latencies */ + struct ICPState *icp; + struct XiveTCTX *tctx; +} SpaprCpuState; + +static inline SpaprCpuState *spapr_cpu_state(PowerPCCPU *cpu) +{ + return (SpaprCpuState *)cpu->machine_data; +} + +#endif diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h new file mode 100644 index 000000000..02a63b366 --- /dev/null +++ b/include/hw/ppc/spapr_drc.h @@ -0,0 +1,259 @@ +/* + * 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. + */ + +#ifndef HW_SPAPR_DRC_H +#define HW_SPAPR_DRC_H + +#include <libfdt.h> +#include "qom/object.h" +#include "sysemu/runstate.h" +#include "hw/qdev-core.h" +#include "qapi/error.h" + +#define TYPE_SPAPR_DR_CONNECTOR "spapr-dr-connector" +#define SPAPR_DR_CONNECTOR_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DR_CONNECTOR) +#define SPAPR_DR_CONNECTOR_CLASS(klass) \ + OBJECT_CLASS_CHECK(SpaprDrcClass, klass, \ + TYPE_SPAPR_DR_CONNECTOR) +#define SPAPR_DR_CONNECTOR(obj) OBJECT_CHECK(SpaprDrc, (obj), \ + TYPE_SPAPR_DR_CONNECTOR) + +#define TYPE_SPAPR_DRC_PHYSICAL "spapr-drc-physical" +#define SPAPR_DRC_PHYSICAL(obj) OBJECT_CHECK(SpaprDrcPhysical, (obj), \ + TYPE_SPAPR_DRC_PHYSICAL) + +#define TYPE_SPAPR_DRC_LOGICAL "spapr-drc-logical" + +#define TYPE_SPAPR_DRC_CPU "spapr-drc-cpu" + +#define TYPE_SPAPR_DRC_PCI "spapr-drc-pci" + +#define TYPE_SPAPR_DRC_LMB "spapr-drc-lmb" + +#define TYPE_SPAPR_DRC_PHB "spapr-drc-phb" + +#define TYPE_SPAPR_DRC_PMEM "spapr-drc-pmem" + +/* + * Various hotplug types managed by SpaprDrc + * + * 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, + SPAPR_DR_CONNECTOR_TYPE_SHIFT_PMEM = 9, +} SpaprDrcTypeShift; + +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, + SPAPR_DR_CONNECTOR_TYPE_PMEM = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PMEM, +} SpaprDrcType; + +/* + * 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; + +/* + * DR-indicator (LED/visual indicator) + * + * 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_INACTIVE = 0, + SPAPR_DR_INDICATOR_ACTIVE = 1, + SPAPR_DR_INDICATOR_IDENTIFY = 2, + SPAPR_DR_INDICATOR_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, + SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE = -9003, +} SpaprDRCCResponse; + +typedef enum { + /* + * Values come from Fig. 12 in LoPAPR section 13.4 + * + * These are exposed in the migration stream, so don't change + * them. + */ + SPAPR_DRC_STATE_INVALID = 0, + SPAPR_DRC_STATE_LOGICAL_UNUSABLE = 1, + SPAPR_DRC_STATE_LOGICAL_AVAILABLE = 2, + SPAPR_DRC_STATE_LOGICAL_UNISOLATE = 3, + SPAPR_DRC_STATE_LOGICAL_CONFIGURED = 4, + SPAPR_DRC_STATE_PHYSICAL_AVAILABLE = 5, + SPAPR_DRC_STATE_PHYSICAL_POWERON = 6, + SPAPR_DRC_STATE_PHYSICAL_UNISOLATE = 7, + SPAPR_DRC_STATE_PHYSICAL_CONFIGURED = 8, +} SpaprDrcState; + +typedef struct SpaprDrc { + /*< private >*/ + DeviceState parent; + + uint32_t id; + Object *owner; + + uint32_t state; + + /* RTAS ibm,configure-connector state */ + /* (only valid in UNISOLATE state) */ + int ccs_offset; + int ccs_depth; + + /* device pointer, via link property */ + DeviceState *dev; + bool unplug_requested; + void *fdt; + int fdt_start_offset; +} SpaprDrc; + +struct SpaprMachineState; + +typedef struct SpaprDrcClass { + /*< private >*/ + DeviceClass parent; + SpaprDrcState empty_state; + SpaprDrcState ready_state; + + /*< public >*/ + SpaprDrcTypeShift typeshift; + const char *typename; /* used in device tree, PAPR 13.5.2.6 & C.6.1 */ + const char *drc_name_prefix; /* used other places in device tree */ + + SpaprDREntitySense (*dr_entity_sense)(SpaprDrc *drc); + uint32_t (*isolate)(SpaprDrc *drc); + uint32_t (*unisolate)(SpaprDrc *drc); + void (*release)(DeviceState *dev); + + int (*dt_populate)(SpaprDrc *drc, struct SpaprMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); +} SpaprDrcClass; + +typedef struct SpaprDrcPhysical { + /*< private >*/ + SpaprDrc parent; + + /* DR-indicator */ + uint32_t dr_indicator; +} SpaprDrcPhysical; + +static inline bool spapr_drc_hotplugged(DeviceState *dev) +{ + return dev->hotplugged && !runstate_check(RUN_STATE_INMIGRATE); +} + +/* Returns true if an unplug request completed */ +bool spapr_drc_reset(SpaprDrc *drc); + +uint32_t spapr_drc_index(SpaprDrc *drc); +SpaprDrcType spapr_drc_type(SpaprDrc *drc); + +SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type, + uint32_t id); +SpaprDrc *spapr_drc_by_index(uint32_t index); +SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id); +int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask); + +/* + * These functions respectively abort if called with a device already + * attached or no device attached. In the case of spapr_drc_attach(), + * this means that the attachability of the DRC *must* be checked + * beforehand (eg. check drc->dev at pre-plug). + */ +void spapr_drc_attach(SpaprDrc *drc, DeviceState *d); +void spapr_drc_unplug_request(SpaprDrc *drc); + +/* + * Reset all DRCs, causing pending hot-plug/unplug requests to complete. + * Safely handles potential DRC removal (eg. PHBs or PCI bridges). + */ +void spapr_drc_reset_all(struct SpaprMachineState *spapr); + +static inline bool spapr_drc_unplug_requested(SpaprDrc *drc) +{ + return drc->unplug_requested; +} + +#endif /* HW_SPAPR_DRC_H */ diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h new file mode 100644 index 000000000..c22a72c9e --- /dev/null +++ b/include/hw/ppc/spapr_irq.h @@ -0,0 +1,117 @@ +/* + * QEMU PowerPC sPAPR IRQ backend definitions + * + * Copyright (c) 2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef HW_SPAPR_IRQ_H +#define HW_SPAPR_IRQ_H + +#include "target/ppc/cpu-qom.h" +#include "qom/object.h" + +/* + * IRQ range offsets per device type + */ +#define SPAPR_IRQ_IPI 0x0 + +#define SPAPR_XIRQ_BASE XICS_IRQ_BASE /* 0x1000 */ +#define SPAPR_IRQ_EPOW (SPAPR_XIRQ_BASE + 0x0000) +#define SPAPR_IRQ_HOTPLUG (SPAPR_XIRQ_BASE + 0x0001) +#define SPAPR_IRQ_VIO (SPAPR_XIRQ_BASE + 0x0100) /* 256 VIO devices */ +#define SPAPR_IRQ_PCI_LSI (SPAPR_XIRQ_BASE + 0x0200) /* 32+ PHBs devices */ + +/* Offset of the dynamic range covered by the bitmap allocator */ +#define SPAPR_IRQ_MSI (SPAPR_XIRQ_BASE + 0x0300) + +#define SPAPR_NR_XIRQS 0x1000 + +struct SpaprMachineState; + +typedef struct SpaprInterruptController SpaprInterruptController; + +#define TYPE_SPAPR_INTC "spapr-interrupt-controller" +#define SPAPR_INTC(obj) \ + INTERFACE_CHECK(SpaprInterruptController, (obj), TYPE_SPAPR_INTC) +typedef struct SpaprInterruptControllerClass SpaprInterruptControllerClass; +DECLARE_CLASS_CHECKERS(SpaprInterruptControllerClass, SPAPR_INTC, + TYPE_SPAPR_INTC) + +struct SpaprInterruptControllerClass { + InterfaceClass parent; + + int (*activate)(SpaprInterruptController *intc, uint32_t nr_servers, + Error **errp); + void (*deactivate)(SpaprInterruptController *intc); + + /* + * These methods will typically be called on all intcs, active and + * inactive + */ + int (*cpu_intc_create)(SpaprInterruptController *intc, + PowerPCCPU *cpu, Error **errp); + void (*cpu_intc_reset)(SpaprInterruptController *intc, PowerPCCPU *cpu); + void (*cpu_intc_destroy)(SpaprInterruptController *intc, PowerPCCPU *cpu); + int (*claim_irq)(SpaprInterruptController *intc, int irq, bool lsi, + Error **errp); + void (*free_irq)(SpaprInterruptController *intc, int irq); + + /* These methods should only be called on the active intc */ + void (*set_irq)(SpaprInterruptController *intc, int irq, int val); + void (*print_info)(SpaprInterruptController *intc, Monitor *mon); + void (*dt)(SpaprInterruptController *intc, uint32_t nr_servers, + void *fdt, uint32_t phandle); + int (*post_load)(SpaprInterruptController *intc, int version_id); +}; + +void spapr_irq_update_active_intc(struct SpaprMachineState *spapr); + +int spapr_irq_cpu_intc_create(struct SpaprMachineState *spapr, + PowerPCCPU *cpu, Error **errp); +void spapr_irq_cpu_intc_reset(struct SpaprMachineState *spapr, PowerPCCPU *cpu); +void spapr_irq_cpu_intc_destroy(struct SpaprMachineState *spapr, PowerPCCPU *cpu); +void spapr_irq_print_info(struct SpaprMachineState *spapr, Monitor *mon); +void spapr_irq_dt(struct SpaprMachineState *spapr, uint32_t nr_servers, + void *fdt, uint32_t phandle); + +uint32_t spapr_irq_nr_msis(struct SpaprMachineState *spapr); +int spapr_irq_msi_alloc(struct SpaprMachineState *spapr, uint32_t num, bool align, + Error **errp); +void spapr_irq_msi_free(struct SpaprMachineState *spapr, int irq, uint32_t num); + +typedef struct SpaprIrq { + bool xics; + bool xive; +} SpaprIrq; + +extern SpaprIrq spapr_irq_xics; +extern SpaprIrq spapr_irq_xics_legacy; +extern SpaprIrq spapr_irq_xive; +extern SpaprIrq spapr_irq_dual; + +void spapr_irq_init(struct SpaprMachineState *spapr, Error **errp); +int spapr_irq_claim(struct SpaprMachineState *spapr, int irq, bool lsi, Error **errp); +void spapr_irq_free(struct SpaprMachineState *spapr, int irq, int num); +qemu_irq spapr_qirq(struct SpaprMachineState *spapr, int irq); +int spapr_irq_post_load(struct SpaprMachineState *spapr, int version_id); +void spapr_irq_reset(struct SpaprMachineState *spapr, Error **errp); +int spapr_irq_get_phandle(struct SpaprMachineState *spapr, void *fdt, Error **errp); + +typedef int (*SpaprInterruptControllerInitKvm)(SpaprInterruptController *, + uint32_t, Error **); + +int spapr_irq_init_kvm(SpaprInterruptControllerInitKvm fn, + SpaprInterruptController *intc, + uint32_t nr_servers, + Error **errp); + +/* + * XICS legacy routines + */ +int spapr_irq_find(struct SpaprMachineState *spapr, int num, bool align, Error **errp); +#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp) + +#endif diff --git a/include/hw/ppc/spapr_numa.h b/include/hw/ppc/spapr_numa.h new file mode 100644 index 000000000..7cb336740 --- /dev/null +++ b/include/hw/ppc/spapr_numa.h @@ -0,0 +1,37 @@ +/* + * QEMU PowerPC pSeries Logical Partition NUMA associativity handling + * + * Copyright IBM Corp. 2020 + * + * Authors: + * Daniel Henrique Barboza <danielhb413@gmail.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. + */ + +#ifndef HW_SPAPR_NUMA_H +#define HW_SPAPR_NUMA_H + +#include "hw/boards.h" +#include "hw/ppc/spapr.h" + +/* + * Having both SpaprMachineState and MachineState as arguments + * feels odd, but it will spare a MACHINE() call inside the + * function. spapr_machine_init() is the only caller for it, and + * it has both pointers resolved already. + */ +void spapr_numa_associativity_init(SpaprMachineState *spapr, + MachineState *machine); +void spapr_numa_associativity_check(SpaprMachineState *spapr); +void spapr_numa_write_rtas_dt(SpaprMachineState *spapr, void *fdt, int rtas); +void spapr_numa_write_associativity_dt(SpaprMachineState *spapr, void *fdt, + int offset, int nodeid); +int spapr_numa_fixup_cpu_dt(SpaprMachineState *spapr, void *fdt, + int offset, PowerPCCPU *cpu); +int spapr_numa_write_assoc_lookup_arrays(SpaprMachineState *spapr, void *fdt, + int offset); +unsigned int spapr_numa_initial_nvgpu_numa_id(MachineState *machine); + +#endif /* HW_SPAPR_NUMA_H */ diff --git a/include/hw/ppc/spapr_nvdimm.h b/include/hw/ppc/spapr_nvdimm.h new file mode 100644 index 000000000..764f999f5 --- /dev/null +++ b/include/hw/ppc/spapr_nvdimm.h @@ -0,0 +1,25 @@ +/* + * QEMU PowerPC PAPR SCM backend definitions + * + * Copyright (c) 2020, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef HW_SPAPR_NVDIMM_H +#define HW_SPAPR_NVDIMM_H + +#include "hw/mem/nvdimm.h" + +typedef struct SpaprDrc SpaprDrc; +typedef struct SpaprMachineState SpaprMachineState; + +int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); +void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt); +bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, + uint64_t size, Error **errp); +void spapr_add_nvdimm(DeviceState *dev, uint64_t slot); + +#endif diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h new file mode 100644 index 000000000..c3e8b98e7 --- /dev/null +++ b/include/hw/ppc/spapr_ovec.h @@ -0,0 +1,83 @@ +/* + * QEMU SPAPR Option/Architecture Vector Definitions + * + * Each architecture option is organized/documented by the following + * in LoPAPR 1.1, Table 244: + * + * <vector number>: the bit-vector in which the option is located + * <vector byte>: the byte offset of the vector entry + * <vector bit>: the bit offset within the vector entry + * + * where each vector entry can be one or more bytes. + * + * Firmware expects a somewhat literal encoding of this bit-vector + * structure, where each entry is stored in little-endian so that the + * byte ordering reflects that of the documentation, but where each bit + * offset is from "left-to-right" in the traditional representation of + * a byte value where the MSB is the left-most bit. Thus, each + * individual byte encodes the option bits in reverse order of the + * documented bit. + * + * These definitions/helpers attempt to abstract away this internal + * representation so that we can define/set/test for individual option + * bits using only the documented values. This is done mainly by relying + * on a bitmap to approximate the documented "bit-vector" structure and + * handling conversations to-from the internal representation under the + * covers. + * + * Copyright IBM Corp. 2016 + * + * 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. + */ + +#ifndef SPAPR_OVEC_H +#define SPAPR_OVEC_H + +#include "cpu.h" + +typedef struct SpaprOptionVector SpaprOptionVector; + +#define OV_BIT(byte, bit) ((byte - 1) * BITS_PER_BYTE + bit) + +/* option vector 1 */ +#define OV1_PPC_3_00 OV_BIT(3, 0) /* guest supports PowerPC 3.00? */ + +/* option vector 5 */ +#define OV5_DRCONF_MEMORY OV_BIT(2, 2) +#define OV5_FORM1_AFFINITY OV_BIT(5, 0) +#define OV5_FORM2_AFFINITY OV_BIT(5, 2) +#define OV5_HP_EVT OV_BIT(6, 5) +#define OV5_HPT_RESIZE OV_BIT(6, 7) +#define OV5_DRMEM_V2 OV_BIT(22, 0) +#define OV5_XIVE_BOTH OV_BIT(23, 0) +#define OV5_XIVE_EXPLOIT OV_BIT(23, 1) /* 1=exploitation 0=legacy */ + +/* ISA 3.00 MMU features: */ +#define OV5_MMU_BOTH OV_BIT(24, 0) /* Radix and hash */ +#define OV5_MMU_RADIX_300 OV_BIT(24, 1) /* 1=Radix only, 0=Hash only */ +#define OV5_MMU_RADIX_GTSE OV_BIT(26, 1) /* Radix GTSE */ + +/* interfaces */ +SpaprOptionVector *spapr_ovec_new(void); +SpaprOptionVector *spapr_ovec_clone(SpaprOptionVector *ov_orig); +void spapr_ovec_intersect(SpaprOptionVector *ov, + SpaprOptionVector *ov1, + SpaprOptionVector *ov2); +bool spapr_ovec_subset(SpaprOptionVector *ov1, SpaprOptionVector *ov2); +void spapr_ovec_cleanup(SpaprOptionVector *ov); +void spapr_ovec_set(SpaprOptionVector *ov, long bitnr); +void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr); +bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr); +bool spapr_ovec_empty(SpaprOptionVector *ov); +SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector); +int spapr_dt_ovec(void *fdt, int fdt_offset, + SpaprOptionVector *ov, const char *name); + +/* migration */ +extern const VMStateDescription vmstate_spapr_ovec; + +#endif /* SPAPR_OVEC_H */ diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h new file mode 100644 index 000000000..383611f10 --- /dev/null +++ b/include/hw/ppc/spapr_rtas.h @@ -0,0 +1,10 @@ +#ifndef HW_SPAPR_RTAS_H +#define HW_SPAPR_RTAS_H +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t rets); +#endif /* HW_SPAPR_RTAS_H */ diff --git a/include/hw/ppc/spapr_tpm_proxy.h b/include/hw/ppc/spapr_tpm_proxy.h new file mode 100644 index 000000000..96d2a9697 --- /dev/null +++ b/include/hw/ppc/spapr_tpm_proxy.h @@ -0,0 +1,30 @@ +/* + * SPAPR TPM Proxy/Hypercall + * + * Copyright IBM Corp. 2019 + * + * 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. + */ + +#ifndef HW_SPAPR_TPM_PROXY_H +#define HW_SPAPR_TPM_PROXY_H + +#include "qom/object.h" +#include "hw/qdev-core.h" + +#define TYPE_SPAPR_TPM_PROXY "spapr-tpm-proxy" +OBJECT_DECLARE_SIMPLE_TYPE(SpaprTpmProxy, SPAPR_TPM_PROXY) + +struct SpaprTpmProxy { + /*< private >*/ + DeviceState parent; + + char *host_path; + int host_fd; +}; + +#endif /* HW_SPAPR_TPM_PROXY_H */ diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h new file mode 100644 index 000000000..4bea87f39 --- /dev/null +++ b/include/hw/ppc/spapr_vio.h @@ -0,0 +1,141 @@ +#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.1 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 "hw/ppc/spapr.h" +#include "sysemu/dma.h" +#include "hw/irq.h" +#include "qom/object.h" + +#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" +OBJECT_DECLARE_TYPE(SpaprVioDevice, SpaprVioDeviceClass, + VIO_SPAPR_DEVICE) + +#define TYPE_SPAPR_VIO_BUS "spapr-vio-bus" +OBJECT_DECLARE_SIMPLE_TYPE(SpaprVioBus, SPAPR_VIO_BUS) + +#define TYPE_SPAPR_VIO_BRIDGE "spapr-vio-bridge" + +typedef struct SpaprVioCrq { + uint64_t qladdr; + uint32_t qsize; + uint32_t qnext; + int(*SendFunc)(struct SpaprVioDevice *vdev, uint8_t *crq); +} SpaprVioCrq; + + +struct SpaprVioDeviceClass { + DeviceClass parent_class; + + const char *dt_name, *dt_type, *dt_compatible; + target_ulong signal_mask; + uint32_t rtce_window_size; + void (*realize)(SpaprVioDevice *dev, Error **errp); + void (*reset)(SpaprVioDevice *dev); + int (*devnode)(SpaprVioDevice *dev, void *fdt, int node_off); + const char *(*get_dt_compatible)(SpaprVioDevice *dev); +}; + +struct SpaprVioDevice { + DeviceState qdev; + uint32_t reg; + uint32_t irq; + uint64_t signal_state; + SpaprVioCrq crq; + AddressSpace as; + MemoryRegion mrroot; + MemoryRegion mrbypass; + SpaprTceTable *tcet; +}; + +#define DEFINE_SPAPR_PROPERTIES(type, field) \ + DEFINE_PROP_UINT32("reg", type, field.reg, -1) + +struct SpaprVioBus { + BusState bus; + uint32_t next_reg; +}; + +SpaprVioBus *spapr_vio_bus_init(void); +SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg); +void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt); +gchar *spapr_vio_stdout_path(SpaprVioBus *bus); + +static inline void spapr_vio_irq_pulse(SpaprVioDevice *dev) +{ + SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + + qemu_irq_pulse(spapr_qirq(spapr, dev->irq)); +} + +static inline bool spapr_vio_dma_valid(SpaprVioDevice *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(SpaprVioDevice *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(SpaprVioDevice *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(SpaprVioDevice *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(SpaprVioDevice *dev, uint8_t *crq); + +SpaprVioDevice *vty_lookup(SpaprMachineState *spapr, target_ulong reg); +void vty_putchars(SpaprVioDevice *sdev, uint8_t *buf, int len); +void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev); +void spapr_vlan_create(SpaprVioBus *bus, NICInfo *nd); +void spapr_vscsi_create(SpaprVioBus *bus); + +SpaprVioDevice *spapr_vty_get_default(SpaprVioBus *bus); + +extern const VMStateDescription vmstate_spapr_vio; + +#define VMSTATE_SPAPR_VIO(_f, _s) \ + VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, SpaprVioDevice) + +void spapr_vio_set_bypass(SpaprVioDevice *dev, bool bypass); + +#endif /* HW_SPAPR_VIO_H */ diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h new file mode 100644 index 000000000..b282960ad --- /dev/null +++ b/include/hw/ppc/spapr_xive.h @@ -0,0 +1,99 @@ +/* + * QEMU PowerPC sPAPR XIVE interrupt controller model + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_SPAPR_XIVE_H +#define PPC_SPAPR_XIVE_H + +#include "hw/ppc/spapr_irq.h" +#include "hw/ppc/xive.h" + +#define TYPE_SPAPR_XIVE "spapr-xive" +#define SPAPR_XIVE(obj) OBJECT_CHECK(SpaprXive, (obj), TYPE_SPAPR_XIVE) +#define SPAPR_XIVE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SpaprXiveClass, (klass), TYPE_SPAPR_XIVE) +#define SPAPR_XIVE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SpaprXiveClass, (obj), TYPE_SPAPR_XIVE) + +typedef struct SpaprXive { + XiveRouter parent; + + /* Internal interrupt source for IPIs and virtual devices */ + XiveSource source; + hwaddr vc_base; + + /* END ESB MMIOs */ + XiveENDSource end_source; + hwaddr end_base; + + /* DT */ + gchar *nodename; + + /* Routing table */ + XiveEAS *eat; + uint32_t nr_irqs; + XiveEND *endt; + uint32_t nr_ends; + + /* TIMA mapping address */ + hwaddr tm_base; + MemoryRegion tm_mmio; + + /* KVM support */ + int fd; + void *tm_mmap; + MemoryRegion tm_mmio_kvm; + VMChangeStateEntry *change; + + uint8_t hv_prio; +} SpaprXive; + +typedef struct SpaprXiveClass { + XiveRouterClass parent; + + DeviceRealize parent_realize; +} SpaprXiveClass; + +/* + * The sPAPR machine has a unique XIVE IC device. Assign a fixed value + * to the controller block id value. It can nevertheless be changed + * for testing purpose. + */ +#define SPAPR_XIVE_BLOCK_ID 0x0 + +struct SpaprMachineState; +void spapr_xive_hcall_init(struct SpaprMachineState *spapr); +void spapr_xive_mmio_set_enabled(SpaprXive *xive, bool enable); +void spapr_xive_map_mmio(SpaprXive *xive); + +int spapr_xive_end_to_target(uint8_t end_blk, uint32_t end_idx, + uint32_t *out_server, uint8_t *out_prio); + +/* + * KVM XIVE device helpers + */ +int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers, + Error **errp); +void kvmppc_xive_disconnect(SpaprInterruptController *intc); +void kvmppc_xive_reset(SpaprXive *xive, Error **errp); +int kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas, + Error **errp); +void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp); +uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset, + uint64_t data, bool write); +int kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk, + uint32_t end_idx, XiveEND *end, + Error **errp); +int kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk, + uint32_t end_idx, XiveEND *end, + Error **errp); +void kvmppc_xive_synchronize_state(SpaprXive *xive, Error **errp); +int kvmppc_xive_pre_save(SpaprXive *xive); +int kvmppc_xive_post_load(SpaprXive *xive, int version_id); + +#endif /* PPC_SPAPR_XIVE_H */ diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h new file mode 100644 index 000000000..97fdef758 --- /dev/null +++ b/include/hw/ppc/vof.h @@ -0,0 +1,60 @@ +/* + * Virtual Open Firmware + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_VOF_H +#define HW_VOF_H + +typedef struct Vof { + uint64_t top_addr; /* copied from rma_size */ + GArray *claimed; /* array of SpaprOfClaimed */ + uint64_t claimed_base; + GHashTable *of_instances; /* ihandle -> SpaprOfInstance */ + uint32_t of_instance_last; + char *bootargs; + long fw_size; +} Vof; + +int vof_client_call(MachineState *ms, Vof *vof, void *fdt, + target_ulong args_real); +uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size, uint64_t align); +void vof_init(Vof *vof, uint64_t top_addr, Error **errp); +void vof_cleanup(Vof *vof); +void vof_build_dt(void *fdt, Vof *vof); +uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename, + const char *prop, const char *path); + +#define TYPE_VOF_MACHINE_IF "vof-machine-if" + +typedef struct VofMachineIfClass VofMachineIfClass; +DECLARE_CLASS_CHECKERS(VofMachineIfClass, VOF_MACHINE, TYPE_VOF_MACHINE_IF) + +struct VofMachineIfClass { + InterfaceClass parent; + target_ulong (*client_architecture_support)(MachineState *ms, CPUState *cs, + target_ulong vec); + void (*quiesce)(MachineState *ms); + bool (*setprop)(MachineState *ms, const char *path, const char *propname, + void *val, int vallen); +}; + +/* + * Initial stack size is from + * https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html#REF27292 + * + * "Client programs shall be invoked with a valid stack pointer (r1) with + * at least 32K bytes of memory available for stack growth". + */ +#define VOF_STACK_SIZE 0x8000 + +#define VOF_MEM_READ(pa, buf, size) \ + address_space_read(&address_space_memory, \ + (pa), MEMTXATTRS_UNSPECIFIED, (buf), (size)) +#define VOF_MEM_WRITE(pa, buf, size) \ + address_space_write(&address_space_memory, \ + (pa), MEMTXATTRS_UNSPECIFIED, (buf), (size)) + +#define PROM_ERROR (~0U) + +#endif /* HW_VOF_H */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h new file mode 100644 index 000000000..00b80b08c --- /dev/null +++ b/include/hw/ppc/xics.h @@ -0,0 +1,196 @@ +/* + * 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. + * + */ + +#ifndef XICS_H +#define XICS_H + +#include "exec/memory.h" +#include "hw/qdev-core.h" +#include "qom/object.h" + +#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 PnvICPState PnvICPState; +typedef struct ICSStateClass ICSStateClass; +typedef struct ICSState ICSState; +typedef struct ICSIRQState ICSIRQState; +typedef struct XICSFabric XICSFabric; + +#define TYPE_ICP "icp" +OBJECT_DECLARE_TYPE(ICPState, ICPStateClass, + ICP) + +#define TYPE_PNV_ICP "pnv-icp" +DECLARE_INSTANCE_CHECKER(PnvICPState, PNV_ICP, + TYPE_PNV_ICP) + + +struct ICPStateClass { + DeviceClass parent_class; + + DeviceRealize parent_realize; +}; + +struct ICPState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + CPUState *cs; + ICSState *xirr_owner; + uint32_t xirr; + uint8_t pending_priority; + uint8_t mfrr; + qemu_irq output; + + XICSFabric *xics; +}; + +#define ICP_PROP_XICS "xics" +#define ICP_PROP_CPU "cpu" + +struct PnvICPState { + ICPState parent_obj; + + MemoryRegion mmio; + uint32_t links[3]; +}; + +#define TYPE_ICS "ics" +DECLARE_OBJ_CHECKERS(ICSState, ICSStateClass, + ICS, TYPE_ICS) + + +struct ICSStateClass { + DeviceClass parent_class; + + DeviceRealize parent_realize; + DeviceReset parent_reset; + + void (*reject)(ICSState *s, uint32_t irq); + void (*resend)(ICSState *s); +}; + +struct ICSState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t nr_irqs; + uint32_t offset; + ICSIRQState *irqs; + XICSFabric *xics; +}; + +#define ICS_PROP_XICS "xics" + +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; + 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 +#define XICS_STATUS_PRESENTED 0x10 +#define XICS_STATUS_QUEUED 0x20 + 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 TYPE_XICS_FABRIC "xics-fabric" +#define XICS_FABRIC(obj) \ + INTERFACE_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC) +typedef struct XICSFabricClass XICSFabricClass; +DECLARE_CLASS_CHECKERS(XICSFabricClass, XICS_FABRIC, + TYPE_XICS_FABRIC) + +struct XICSFabricClass { + InterfaceClass parent; + ICSState *(*ics_get)(XICSFabric *xi, int irq); + void (*ics_resend)(XICSFabric *xi); + ICPState *(*icp_get)(XICSFabric *xi, int server); +}; + +ICPState *xics_icp_get(XICSFabric *xi, int server); + +/* Internal XICS interfaces */ +void icp_set_cppr(ICPState *icp, uint8_t cppr); +void icp_set_mfrr(ICPState *icp, uint8_t mfrr); +uint32_t icp_accept(ICPState *ss); +uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr); +void icp_eoi(ICPState *icp, uint32_t xirr); +void icp_irq(ICSState *ics, int server, int nr, uint8_t priority); +void icp_reset(ICPState *icp); + +void ics_write_xive(ICSState *ics, int nr, int server, + uint8_t priority, uint8_t saved_priority); +void ics_set_irq(void *opaque, int srcno, int val); + +static inline bool ics_irq_free(ICSState *ics, uint32_t srcno) +{ + return !(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK); +} + +void ics_set_irq_type(ICSState *ics, int srcno, bool lsi); +void icp_pic_print_info(ICPState *icp, Monitor *mon); +void ics_pic_print_info(ICSState *ics, Monitor *mon); + +void ics_resend(ICSState *ics); +void icp_resend(ICPState *ss); + +Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, + Error **errp); +void icp_destroy(ICPState *icp); + +/* KVM */ +void icp_get_kvm_state(ICPState *icp); +int icp_set_kvm_state(ICPState *icp, Error **errp); +void icp_synchronize_state(ICPState *icp); +void icp_kvm_realize(DeviceState *dev, Error **errp); + +void ics_get_kvm_state(ICSState *ics); +int ics_set_kvm_state_one(ICSState *ics, int srcno, Error **errp); +int ics_set_kvm_state(ICSState *ics, Error **errp); +void ics_synchronize_state(ICSState *ics); +void ics_kvm_set_irq(ICSState *ics, int srcno, int val); + +#endif /* XICS_H */ diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h new file mode 100644 index 000000000..de752c0d2 --- /dev/null +++ b/include/hw/ppc/xics_spapr.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#ifndef XICS_SPAPR_H +#define XICS_SPAPR_H + +#include "hw/ppc/spapr.h" +#include "qom/object.h" + +#define TYPE_ICS_SPAPR "ics-spapr" +/* This is reusing the ICSState typedef from TYPE_ICS */ +DECLARE_INSTANCE_CHECKER(ICSState, ICS_SPAPR, + TYPE_ICS_SPAPR) + +int xics_kvm_connect(SpaprInterruptController *intc, uint32_t nr_servers, + Error **errp); +void xics_kvm_disconnect(SpaprInterruptController *intc); +bool xics_kvm_has_broken_disconnect(void); + +#endif /* XICS_SPAPR_H */ diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h new file mode 100644 index 000000000..b8ab0bf74 --- /dev/null +++ b/include/hw/ppc/xive.h @@ -0,0 +1,536 @@ +/* + * QEMU PowerPC XIVE interrupt controller model + * + * + * The POWER9 processor comes with a new interrupt controller, called + * XIVE as "eXternal Interrupt Virtualization Engine". + * + * = Overall architecture + * + * + * XIVE Interrupt Controller + * +------------------------------------+ IPIs + * | +---------+ +---------+ +--------+ | +-------+ + * | |VC | |CQ | |PC |----> | CORES | + * | | esb | | | | |----> | | + * | | eas | | Bridge | | tctx |----> | | + * | |SC end | | | | nvt | | | | + * +------+ | +---------+ +----+----+ +--------+ | +-+-+-+-+ + * | RAM | +------------------|-----------------+ | | | + * | | | | | | + * | | | | | | + * | | +--------------------v------------------------v-v-v--+ other + * | <--+ Power Bus +--> chips + * | esb | +---------+-----------------------+------------------+ + * | eas | | | + * | end | +--|------+ | + * | nvt | +----+----+ | +----+----+ + * +------+ |SC | | |SC | + * | | | | | + * | PQ-bits | | | PQ-bits | + * | local |-+ | in VC | + * +---------+ +---------+ + * PCIe NX,NPU,CAPI + * + * SC: Source Controller (aka. IVSE) + * VC: Virtualization Controller (aka. IVRE) + * PC: Presentation Controller (aka. IVPE) + * CQ: Common Queue (Bridge) + * + * PQ-bits: 2 bits source state machine (P:pending Q:queued) + * esb: Event State Buffer (Array of PQ bits in an IVSE) + * eas: Event Assignment Structure + * end: Event Notification Descriptor + * nvt: Notification Virtual Target + * tctx: Thread interrupt Context + * + * + * The XIVE IC is composed of three sub-engines : + * + * - Interrupt Virtualization Source Engine (IVSE), or Source + * Controller (SC). These are found in PCI PHBs, in the PSI host + * bridge controller, but also inside the main controller for the + * core IPIs and other sub-chips (NX, CAP, NPU) of the + * chip/processor. They are configured to feed the IVRE with events. + * + * - Interrupt Virtualization Routing Engine (IVRE) or Virtualization + * Controller (VC). Its job is to match an event source with an + * Event Notification Descriptor (END). + * + * - Interrupt Virtualization Presentation Engine (IVPE) or + * Presentation Controller (PC). It maintains the interrupt context + * state of each thread and handles the delivery of the external + * exception to the thread. + * + * In XIVE 1.0, the sub-engines used to be referred as: + * + * SC Source Controller + * VC Virtualization Controller + * PC Presentation Controller + * CQ Common Queue (PowerBUS Bridge) + * + * + * = XIVE internal tables + * + * Each of the sub-engines uses a set of tables to redirect exceptions + * from event sources to CPU threads. + * + * +-------+ + * User or OS | EQ | + * or +------>|entries| + * Hypervisor | | .. | + * Memory | +-------+ + * | ^ + * | | + * +-------------------------------------------------+ + * | | + * Hypervisor +------+ +---+--+ +---+--+ +------+ + * Memory | ESB | | EAT | | ENDT | | NVTT | + * (skiboot) +----+-+ +----+-+ +----+-+ +------+ + * ^ | ^ | ^ | ^ + * | | | | | | | + * +-------------------------------------------------+ + * | | | | | | | + * | | | | | | | + * +----|--|--------|--|--------|--|-+ +-|-----+ +------+ + * | | | | | | | | | | tctx| |Thread| + * IPI or --> | + v + v + v |---| + .. |-----> | + * HW events --> | | | | | | + * IVSE | IVRE | | IVPE | +------+ + * +---------------------------------+ +-------+ + * + * + * + * The IVSE have a 2-bits state machine, P for pending and Q for queued, + * for each source that allows events to be triggered. They are stored in + * an Event State Buffer (ESB) array and can be controlled by MMIOs. + * + * If the event is let through, the IVRE looks up in the Event Assignment + * Structure (EAS) table for an Event Notification Descriptor (END) + * configured for the source. Each Event Notification Descriptor defines + * a notification path to a CPU and an in-memory Event Queue, in which + * will be enqueued an EQ data for the OS to pull. + * + * The IVPE determines if a Notification Virtual Target (NVT) can + * handle the event by scanning the thread contexts of the VCPUs + * dispatched on the processor HW threads. It maintains the state of + * the thread interrupt context (TCTX) of each thread in a NVT table. + * + * = Acronyms + * + * Description In XIVE 1.0, used to be referred as + * + * EAS Event Assignment Structure IVE Interrupt Virt. Entry + * EAT Event Assignment Table IVT Interrupt Virt. Table + * ENDT Event Notif. Descriptor Table EQDT Event Queue Desc. Table + * EQ Event Queue same + * ESB Event State Buffer SBE State Bit Entry + * NVT Notif. Virtual Target VPD Virtual Processor Desc. + * NVTT Notif. Virtual Target Table VPDT Virtual Processor Desc. Table + * TCTX Thread interrupt Context + * + * + * Copyright (c) 2017-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + * + */ + +#ifndef PPC_XIVE_H +#define PPC_XIVE_H + +#include "sysemu/kvm.h" +#include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" +#include "qom/object.h" + +/* + * XIVE Notifier (Interface between Source and Router) + */ + +typedef struct XiveNotifier XiveNotifier; + +#define TYPE_XIVE_NOTIFIER "xive-notifier" +#define XIVE_NOTIFIER(obj) \ + INTERFACE_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER) +typedef struct XiveNotifierClass XiveNotifierClass; +DECLARE_CLASS_CHECKERS(XiveNotifierClass, XIVE_NOTIFIER, + TYPE_XIVE_NOTIFIER) + +struct XiveNotifierClass { + InterfaceClass parent; + void (*notify)(XiveNotifier *xn, uint32_t lisn); +}; + +/* + * XIVE Interrupt Source + */ + +#define TYPE_XIVE_SOURCE "xive-source" +OBJECT_DECLARE_SIMPLE_TYPE(XiveSource, XIVE_SOURCE) + +/* + * XIVE Interrupt Source characteristics, which define how the ESB are + * controlled. + */ +#define XIVE_SRC_H_INT_ESB 0x1 /* ESB managed with hcall H_INT_ESB */ +#define XIVE_SRC_STORE_EOI 0x2 /* Store EOI supported */ + +struct XiveSource { + DeviceState parent; + + /* IRQs */ + uint32_t nr_irqs; + unsigned long *lsi_map; + + /* PQ bits and LSI assertion bit */ + uint8_t *status; + + /* ESB memory region */ + uint64_t esb_flags; + uint32_t esb_shift; + MemoryRegion esb_mmio; + MemoryRegion esb_mmio_emulated; + + /* KVM support */ + void *esb_mmap; + MemoryRegion esb_mmio_kvm; + + XiveNotifier *xive; +}; + +/* + * ESB MMIO setting. Can be one page, for both source triggering and + * source management, or two different pages. See below for magic + * values. + */ +#define XIVE_ESB_4K 12 /* PSI HB only */ +#define XIVE_ESB_4K_2PAGE 13 +#define XIVE_ESB_64K 16 +#define XIVE_ESB_64K_2PAGE 17 + +static inline bool xive_source_esb_has_2page(XiveSource *xsrc) +{ + return xsrc->esb_shift == XIVE_ESB_64K_2PAGE || + xsrc->esb_shift == XIVE_ESB_4K_2PAGE; +} + +static inline size_t xive_source_esb_len(XiveSource *xsrc) +{ + return (1ull << xsrc->esb_shift) * xsrc->nr_irqs; +} + +/* The trigger page is always the first/even page */ +static inline hwaddr xive_source_esb_page(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + return (1ull << xsrc->esb_shift) * srcno; +} + +/* In a two pages ESB MMIO setting, the odd page is for management */ +static inline hwaddr xive_source_esb_mgmt(XiveSource *xsrc, int srcno) +{ + hwaddr addr = xive_source_esb_page(xsrc, srcno); + + if (xive_source_esb_has_2page(xsrc)) { + addr += (1 << (xsrc->esb_shift - 1)); + } + + return addr; +} + +/* + * Each interrupt source has a 2-bit state machine which can be + * controlled by MMIO. P indicates that an interrupt is pending (has + * been sent to a queue and is waiting for an EOI). Q indicates that + * the interrupt has been triggered while pending. + * + * This acts as a coalescing mechanism in order to guarantee that a + * given interrupt only occurs at most once in a queue. + * + * When doing an EOI, the Q bit will indicate if the interrupt + * needs to be re-triggered. + */ +#define XIVE_STATUS_ASSERTED 0x4 /* Extra bit for LSI */ +#define XIVE_ESB_VAL_P 0x2 +#define XIVE_ESB_VAL_Q 0x1 + +#define XIVE_ESB_RESET 0x0 +#define XIVE_ESB_PENDING XIVE_ESB_VAL_P +#define XIVE_ESB_QUEUED (XIVE_ESB_VAL_P | XIVE_ESB_VAL_Q) +#define XIVE_ESB_OFF XIVE_ESB_VAL_Q + +bool xive_esb_trigger(uint8_t *pq); +bool xive_esb_eoi(uint8_t *pq); +uint8_t xive_esb_set(uint8_t *pq, uint8_t value); + +/* + * "magic" Event State Buffer (ESB) MMIO offsets. + * + * The following offsets into the ESB MMIO allow to read or manipulate + * the PQ bits. They must be used with an 8-byte load instruction. + * They all return the previous state of the interrupt (atomically). + * + * Additionally, some ESB pages support doing an EOI via a store and + * some ESBs support doing a trigger via a separate trigger page. + */ +#define XIVE_ESB_STORE_EOI 0x400 /* Store */ +#define XIVE_ESB_LOAD_EOI 0x000 /* Load */ +#define XIVE_ESB_GET 0x800 /* Load */ +#define XIVE_ESB_SET_PQ_00 0xc00 /* Load */ +#define XIVE_ESB_SET_PQ_01 0xd00 /* Load */ +#define XIVE_ESB_SET_PQ_10 0xe00 /* Load */ +#define XIVE_ESB_SET_PQ_11 0xf00 /* Load */ + +uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno); +uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq); + +/* + * Source status helpers + */ +static inline void xive_source_set_status(XiveSource *xsrc, uint32_t srcno, + uint8_t status, bool enable) +{ + if (enable) { + xsrc->status[srcno] |= status; + } else { + xsrc->status[srcno] &= ~status; + } +} + +static inline void xive_source_set_asserted(XiveSource *xsrc, uint32_t srcno, + bool enable) +{ + xive_source_set_status(xsrc, srcno, XIVE_STATUS_ASSERTED, enable); +} + +static inline bool xive_source_is_asserted(XiveSource *xsrc, uint32_t srcno) +{ + return xsrc->status[srcno] & XIVE_STATUS_ASSERTED; +} + +void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset, + Monitor *mon); + +static inline bool xive_source_irq_is_lsi(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + return test_bit(srcno, xsrc->lsi_map); +} + +static inline void xive_source_irq_set_lsi(XiveSource *xsrc, uint32_t srcno) +{ + assert(srcno < xsrc->nr_irqs); + bitmap_set(xsrc->lsi_map, srcno, 1); +} + +void xive_source_set_irq(void *opaque, int srcno, int val); + +/* + * XIVE Thread interrupt Management (TM) context + */ + +#define TYPE_XIVE_TCTX "xive-tctx" +OBJECT_DECLARE_SIMPLE_TYPE(XiveTCTX, XIVE_TCTX) + +/* + * XIVE Thread interrupt Management register rings : + * + * QW-0 User event-based exception state + * QW-1 O/S OS context for priority management, interrupt acks + * QW-2 Pool hypervisor pool context for virtual processors dispatched + * QW-3 Physical physical thread context and security context + */ +#define XIVE_TM_RING_COUNT 4 +#define XIVE_TM_RING_SIZE 0x10 + +typedef struct XivePresenter XivePresenter; + +struct XiveTCTX { + DeviceState parent_obj; + + CPUState *cs; + qemu_irq hv_output; + qemu_irq os_output; + + uint8_t regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE]; + + XivePresenter *xptr; +}; + +static inline uint32_t xive_tctx_word2(uint8_t *ring) +{ + return *((uint32_t *) &ring[TM_WORD2]); +} + +/* + * XIVE Router + */ +typedef struct XiveFabric XiveFabric; + +struct XiveRouter { + SysBusDevice parent; + + XiveFabric *xfb; +}; + +#define TYPE_XIVE_ROUTER "xive-router" +OBJECT_DECLARE_TYPE(XiveRouter, XiveRouterClass, + XIVE_ROUTER) + +struct XiveRouterClass { + SysBusDeviceClass parent; + + /* XIVE table accessors */ + int (*get_eas)(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx, + XiveEAS *eas); + int (*get_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx, + XiveEND *end); + int (*write_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx, + XiveEND *end, uint8_t word_number); + int (*get_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx, + XiveNVT *nvt); + int (*write_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx, + XiveNVT *nvt, uint8_t word_number); + uint8_t (*get_block_id)(XiveRouter *xrtr); +}; + +int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx, + XiveEAS *eas); +int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx, + XiveEND *end); +int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx, + XiveEND *end, uint8_t word_number); +int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx, + XiveNVT *nvt); +int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx, + XiveNVT *nvt, uint8_t word_number); +void xive_router_notify(XiveNotifier *xn, uint32_t lisn); + +/* + * XIVE Presenter + */ + +typedef struct XiveTCTXMatch { + XiveTCTX *tctx; + uint8_t ring; +} XiveTCTXMatch; + +#define TYPE_XIVE_PRESENTER "xive-presenter" +#define XIVE_PRESENTER(obj) \ + INTERFACE_CHECK(XivePresenter, (obj), TYPE_XIVE_PRESENTER) +typedef struct XivePresenterClass XivePresenterClass; +DECLARE_CLASS_CHECKERS(XivePresenterClass, XIVE_PRESENTER, + TYPE_XIVE_PRESENTER) + +struct XivePresenterClass { + InterfaceClass parent; + int (*match_nvt)(XivePresenter *xptr, uint8_t format, + uint8_t nvt_blk, uint32_t nvt_idx, + bool cam_ignore, uint8_t priority, + uint32_t logic_serv, XiveTCTXMatch *match); + bool (*in_kernel)(const XivePresenter *xptr); +}; + +int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx, + uint8_t format, + uint8_t nvt_blk, uint32_t nvt_idx, + bool cam_ignore, uint32_t logic_serv); +bool xive_presenter_notify(XiveFabric *xfb, uint8_t format, + uint8_t nvt_blk, uint32_t nvt_idx, + bool cam_ignore, uint8_t priority, + uint32_t logic_serv); + +/* + * XIVE Fabric (Interface between Interrupt Controller and Machine) + */ + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC(obj) \ + INTERFACE_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +typedef struct XiveFabricClass XiveFabricClass; +DECLARE_CLASS_CHECKERS(XiveFabricClass, XIVE_FABRIC, + TYPE_XIVE_FABRIC) + +struct XiveFabricClass { + InterfaceClass parent; + int (*match_nvt)(XiveFabric *xfb, uint8_t format, + uint8_t nvt_blk, uint32_t nvt_idx, + bool cam_ignore, uint8_t priority, + uint32_t logic_serv, XiveTCTXMatch *match); +}; + +/* + * XIVE END ESBs + */ + +#define TYPE_XIVE_END_SOURCE "xive-end-source" +OBJECT_DECLARE_SIMPLE_TYPE(XiveENDSource, XIVE_END_SOURCE) + +struct XiveENDSource { + DeviceState parent; + + uint32_t nr_ends; + + /* ESB memory region */ + uint32_t esb_shift; + MemoryRegion esb_mmio; + + XiveRouter *xrtr; +}; + +/* + * For legacy compatibility, the exceptions define up to 256 different + * priorities. P9 implements only 9 levels : 8 active levels [0 - 7] + * and the least favored level 0xFF. + */ +#define XIVE_PRIORITY_MAX 7 + +/* + * Convert a priority number to an Interrupt Pending Buffer (IPB) + * register, which indicates a pending interrupt at the priority + * corresponding to the bit number + */ +static inline uint8_t xive_priority_to_ipb(uint8_t priority) +{ + return priority > XIVE_PRIORITY_MAX ? + 0 : 1 << (XIVE_PRIORITY_MAX - priority); +} + +/* + * XIVE Thread Interrupt Management Aera (TIMA) + * + * This region gives access to the registers of the thread interrupt + * management context. It is four page wide, each page providing a + * different view of the registers. The page with the lower offset is + * the most privileged and gives access to the entire context. + */ +#define XIVE_TM_HW_PAGE 0x0 +#define XIVE_TM_HV_PAGE 0x1 +#define XIVE_TM_OS_PAGE 0x2 +#define XIVE_TM_USER_PAGE 0x3 + +void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset, + uint64_t value, unsigned size); +uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset, + unsigned size); + +void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon); +Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp); +void xive_tctx_reset(XiveTCTX *tctx); +void xive_tctx_destroy(XiveTCTX *tctx); +void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb); + +/* + * KVM XIVE device helpers + */ + +int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp); +void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val); +int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp); +int kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp); +int kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp); +int kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp); + +#endif /* PPC_XIVE_H */ diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h new file mode 100644 index 000000000..b7fde2354 --- /dev/null +++ b/include/hw/ppc/xive_regs.h @@ -0,0 +1,301 @@ +/* + * QEMU PowerPC XIVE internal structure definitions + * + * + * The XIVE structures are accessed by the HW and their format is + * architected to be big-endian. Some macros are provided to ease + * access to the different fields. + * + * + * Copyright (c) 2016-2018, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_XIVE_REGS_H +#define PPC_XIVE_REGS_H + +#include "qemu/bswap.h" +#include "qemu/host-utils.h" + +/* + * Interrupt source number encoding on PowerBUS + */ +/* + * Trigger data definition + * + * The trigger definition is used for triggers both for HW source + * interrupts (PHB, PSI), as well as for rerouting interrupts between + * Interrupt Controller. + * + * HW source controllers set bit0 of word0 to ‘0’ as they provide EAS + * information (EAS block + EAS index) in the 8 byte data and not END + * information, which is use for rerouting interrupts. + * + * bit1 of word0 to ‘1’ signals that the state bit check has been + * performed. + */ +#define XIVE_TRIGGER_END PPC_BIT(0) +#define XIVE_TRIGGER_PQ PPC_BIT(1) + +/* + * QEMU macros to manipulate the trigger payload in native endian + */ +#define XIVE_EAS_BLOCK(n) (((n) >> 28) & 0xf) +#define XIVE_EAS_INDEX(n) ((n) & 0x0fffffff) +#define XIVE_EAS(blk, idx) ((uint32_t)(blk) << 28 | (idx)) + +#define TM_SHIFT 16 + +/* TM register offsets */ +#define TM_QW0_USER 0x000 /* All rings */ +#define TM_QW1_OS 0x010 /* Ring 0..2 */ +#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */ +#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */ + +/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */ +#define TM_NSR 0x0 /* + + - + */ +#define TM_CPPR 0x1 /* - + - + */ +#define TM_IPB 0x2 /* - + + + */ +#define TM_LSMFB 0x3 /* - + + + */ +#define TM_ACK_CNT 0x4 /* - + - - */ +#define TM_INC 0x5 /* - + - + */ +#define TM_AGE 0x6 /* - + - + */ +#define TM_PIPR 0x7 /* - + - + */ + +#define TM_WORD0 0x0 +#define TM_WORD1 0x4 + +/* + * QW word 2 contains the valid bit at the top and other fields + * depending on the QW. + */ +#define TM_WORD2 0x8 +#define TM_QW0W2_VU PPC_BIT32(0) +#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1, 31) /* XX 2,31 ? */ +#define TM_QW1W2_VO PPC_BIT32(0) +#define TM_QW1W2_OS_CAM PPC_BITMASK32(8, 31) +#define TM_QW2W2_VP PPC_BIT32(0) +#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8, 31) +#define TM_QW3W2_VT PPC_BIT32(0) +#define TM_QW3W2_LP PPC_BIT32(6) +#define TM_QW3W2_LE PPC_BIT32(7) +#define TM_QW3W2_T PPC_BIT32(31) + +/* + * In addition to normal loads to "peek" and writes (only when invalid) + * using 4 and 8 bytes accesses, the above registers support these + * "special" byte operations: + * + * - Byte load from QW0[NSR] - User level NSR (EBB) + * - Byte store to QW0[NSR] - User level NSR (EBB) + * - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access + * - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0 + * otherwise VT||0000000 + * - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present) + * + * Then we have all these "special" CI ops at these offset that trigger + * all sorts of side effects: + */ +#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/ +#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */ +#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user context */ +#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user + * context */ +#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */ +#define TM_SPC_PULL_OS_CTX 0x818 /* Load32/Load64 Pull/Invalidate OS + * context to reg */ +#define TM_SPC_PULL_POOL_CTX 0x828 /* Load32/Load64 Pull/Invalidate Pool + * context to reg*/ +#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */ +#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd + * line */ +#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line */ +#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even + * line */ +#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line */ +/* XXX more... */ + +/* NSR fields for the various QW ack types */ +#define TM_QW0_NSR_EB PPC_BIT8(0) +#define TM_QW1_NSR_EO PPC_BIT8(0) +#define TM_QW3_NSR_HE PPC_BITMASK8(0, 1) +#define TM_QW3_NSR_HE_NONE 0 +#define TM_QW3_NSR_HE_POOL 1 +#define TM_QW3_NSR_HE_PHYS 2 +#define TM_QW3_NSR_HE_LSI 3 +#define TM_QW3_NSR_I PPC_BIT8(2) +#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3, 7) + +/* + * EAS (Event Assignment Structure) + * + * One per interrupt source. Targets an interrupt to a given Event + * Notification Descriptor (END) and provides the corresponding + * logical interrupt number (END data) + */ +typedef struct XiveEAS { + /* + * Use a single 64-bit definition to make it easier to perform + * atomic updates + */ + uint64_t w; +#define EAS_VALID PPC_BIT(0) +#define EAS_END_BLOCK PPC_BITMASK(4, 7) /* Destination END block# */ +#define EAS_END_INDEX PPC_BITMASK(8, 31) /* Destination END index */ +#define EAS_MASKED PPC_BIT(32) /* Masked */ +#define EAS_END_DATA PPC_BITMASK(33, 63) /* Data written to the END */ +} XiveEAS; + +#define xive_eas_is_valid(eas) (be64_to_cpu((eas)->w) & EAS_VALID) +#define xive_eas_is_masked(eas) (be64_to_cpu((eas)->w) & EAS_MASKED) + +void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon); + +static inline uint64_t xive_get_field64(uint64_t mask, uint64_t word) +{ + return (be64_to_cpu(word) & mask) >> ctz64(mask); +} + +static inline uint64_t xive_set_field64(uint64_t mask, uint64_t word, + uint64_t value) +{ + uint64_t tmp = + (be64_to_cpu(word) & ~mask) | ((value << ctz64(mask)) & mask); + return cpu_to_be64(tmp); +} + +static inline uint32_t xive_get_field32(uint32_t mask, uint32_t word) +{ + return (be32_to_cpu(word) & mask) >> ctz32(mask); +} + +static inline uint32_t xive_set_field32(uint32_t mask, uint32_t word, + uint32_t value) +{ + uint32_t tmp = + (be32_to_cpu(word) & ~mask) | ((value << ctz32(mask)) & mask); + return cpu_to_be32(tmp); +} + +/* Event Notification Descriptor (END) */ +typedef struct XiveEND { + uint32_t w0; +#define END_W0_VALID PPC_BIT32(0) /* "v" bit */ +#define END_W0_ENQUEUE PPC_BIT32(1) /* "q" bit */ +#define END_W0_UCOND_NOTIFY PPC_BIT32(2) /* "n" bit */ +#define END_W0_BACKLOG PPC_BIT32(3) /* "b" bit */ +#define END_W0_PRECL_ESC_CTL PPC_BIT32(4) /* "p" bit */ +#define END_W0_ESCALATE_CTL PPC_BIT32(5) /* "e" bit */ +#define END_W0_UNCOND_ESCALATE PPC_BIT32(6) /* "u" bit - DD2.0 */ +#define END_W0_SILENT_ESCALATE PPC_BIT32(7) /* "s" bit - DD2.0 */ +#define END_W0_QSIZE PPC_BITMASK32(12, 15) +#define END_W0_SW0 PPC_BIT32(16) +#define END_W0_FIRMWARE END_W0_SW0 /* Owned by FW */ +#define END_QSIZE_4K 0 +#define END_QSIZE_64K 4 +#define END_W0_HWDEP PPC_BITMASK32(24, 31) + uint32_t w1; +#define END_W1_ESn PPC_BITMASK32(0, 1) +#define END_W1_ESn_P PPC_BIT32(0) +#define END_W1_ESn_Q PPC_BIT32(1) +#define END_W1_ESe PPC_BITMASK32(2, 3) +#define END_W1_ESe_P PPC_BIT32(2) +#define END_W1_ESe_Q PPC_BIT32(3) +#define END_W1_GENERATION PPC_BIT32(9) +#define END_W1_PAGE_OFF PPC_BITMASK32(10, 31) + uint32_t w2; +#define END_W2_MIGRATION_REG PPC_BITMASK32(0, 3) +#define END_W2_OP_DESC_HI PPC_BITMASK32(4, 31) + uint32_t w3; +#define END_W3_OP_DESC_LO PPC_BITMASK32(0, 31) + uint32_t w4; +#define END_W4_ESC_END_BLOCK PPC_BITMASK32(4, 7) +#define END_W4_ESC_END_INDEX PPC_BITMASK32(8, 31) + uint32_t w5; +#define END_W5_ESC_END_DATA PPC_BITMASK32(1, 31) + uint32_t w6; +#define END_W6_FORMAT_BIT PPC_BIT32(8) +#define END_W6_NVT_BLOCK PPC_BITMASK32(9, 12) +#define END_W6_NVT_INDEX PPC_BITMASK32(13, 31) + uint32_t w7; +#define END_W7_F0_IGNORE PPC_BIT32(0) +#define END_W7_F0_BLK_GROUPING PPC_BIT32(1) +#define END_W7_F0_PRIORITY PPC_BITMASK32(8, 15) +#define END_W7_F1_WAKEZ PPC_BIT32(0) +#define END_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31) +} XiveEND; + +#define xive_end_is_valid(end) (be32_to_cpu((end)->w0) & END_W0_VALID) +#define xive_end_is_enqueue(end) (be32_to_cpu((end)->w0) & END_W0_ENQUEUE) +#define xive_end_is_notify(end) (be32_to_cpu((end)->w0) & END_W0_UCOND_NOTIFY) +#define xive_end_is_backlog(end) (be32_to_cpu((end)->w0) & END_W0_BACKLOG) +#define xive_end_is_escalate(end) (be32_to_cpu((end)->w0) & END_W0_ESCALATE_CTL) +#define xive_end_is_uncond_escalation(end) \ + (be32_to_cpu((end)->w0) & END_W0_UNCOND_ESCALATE) +#define xive_end_is_silent_escalation(end) \ + (be32_to_cpu((end)->w0) & END_W0_SILENT_ESCALATE) +#define xive_end_is_firmware(end) \ + (be32_to_cpu((end)->w0) & END_W0_FIRMWARE) + +static inline uint64_t xive_end_qaddr(XiveEND *end) +{ + return ((uint64_t) be32_to_cpu(end->w2) & 0x0fffffff) << 32 | + be32_to_cpu(end->w3); +} + +void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon); +void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon); +void xive_end_eas_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon); + +/* Notification Virtual Target (NVT) */ +typedef struct XiveNVT { + uint32_t w0; +#define NVT_W0_VALID PPC_BIT32(0) + uint32_t w1; +#define NVT_W1_EQ_BLOCK PPC_BITMASK32(0, 3) +#define NVT_W1_EQ_INDEX PPC_BITMASK32(4, 31) + uint32_t w2; + uint32_t w3; + uint32_t w4; +#define NVT_W4_IPB PPC_BITMASK32(16, 23) + uint32_t w5; + uint32_t w6; + uint32_t w7; + uint32_t w8; +#define NVT_W8_GRP_VALID PPC_BIT32(0) + uint32_t w9; + uint32_t wa; + uint32_t wb; + uint32_t wc; + uint32_t wd; + uint32_t we; + uint32_t wf; +} XiveNVT; + +#define xive_nvt_is_valid(nvt) (be32_to_cpu((nvt)->w0) & NVT_W0_VALID) + +/* + * The VP number space in a block is defined by the END_W6_NVT_INDEX + * field of the XIVE END + */ +#define XIVE_NVT_SHIFT 19 +#define XIVE_NVT_COUNT (1 << XIVE_NVT_SHIFT) + +static inline uint32_t xive_nvt_cam_line(uint8_t nvt_blk, uint32_t nvt_idx) +{ + return (nvt_blk << XIVE_NVT_SHIFT) | nvt_idx; +} + +static inline uint32_t xive_nvt_idx(uint32_t cam_line) +{ + return cam_line & ((1 << XIVE_NVT_SHIFT) - 1); +} + +static inline uint32_t xive_nvt_blk(uint32_t cam_line) +{ + return (cam_line >> XIVE_NVT_SHIFT) & 0xf; +} + +#endif /* PPC_XIVE_REGS_H */ |