mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.1-20180821' into staging
ppc patch queue 2018-08-21
Here's my first ppc & spapr pull request for qemu-3.1. This contains
a bunch of things that have accumulated while 3.0 was in freeze.
Highlights are:
* SLOF firmware update
* A number of floating point cleanups from Richard Henderson and
Yasmin Beatriz
* A new model for assigning irq numbers on spapr, this is an
important preliminary step towards implementing the POWER9
"XIVE" interrupt controller
# gpg: Signature made Tue 21 Aug 2018 05:32:44 BST
# gpg: using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-3.1-20180821: (26 commits)
ppc: add DBCR based debugging
spapr_pci: factorize the use of SPAPR_MACHINE_GET_CLASS()
mac_newworld: don't use legacy fw_cfg_init_mem() function
mac_oldworld: don't use legacy fw_cfg_init_mem() function
40p: don't use legacy fw_cfg_init_mem() function
qemu-doc: mark ppc/prep machine as deprecated
hw/ppc: deprecate the machine type 'prep', replaced by '40p'
spapr: introduce a IRQ controller backend to the machine
hw/ppc/ppc405_uc: Convert away from old_mmio
hw/ppc/ppc_boards: Don't use old_mmio for ref405ep_fpga
hw/ppc/prep: Remove ifdeffed-out stub of XCSR code
spapr: introduce a fixed IRQ number space
spapr: Add a pseries-3.1 machine type
target/ppc: simplify bcdadd/sub functions
xics: don't include "target/ppc/cpu-qom.h" in "hw/ppc/xics.h"
vfio/spapr: Allow backing bigger guest IOMMU pages with smaller physical pages
target/ppc: bcdsub fix sign when result is zero
target/ppc: Use non-arithmetic conversions for fp load/store
target/ppc: Honor fpscr_ze semantics and tidy fre, fresqrt
target/ppc: Tidy helper_fsqrt
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -4,7 +4,7 @@ obj-y += ppc.o ppc_booke.o fdt.o
|
||||
obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o spapr_irq.o
|
||||
# IBM PowerNV
|
||||
obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o
|
||||
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
|
||||
|
||||
+11
-1
@@ -454,7 +454,17 @@ static void ppc_core99_init(MachineState *machine)
|
||||
pmac_format_nvram_partition(nvr, 0x2000);
|
||||
/* No PCI init: the BIOS will do it */
|
||||
|
||||
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
|
||||
fw_cfg = FW_CFG(dev);
|
||||
qdev_prop_set_uint32(dev, "data_width", 1);
|
||||
qdev_prop_set_bit(dev, "dma_enabled", false);
|
||||
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
|
||||
OBJECT(fw_cfg), NULL);
|
||||
qdev_init_nofail(dev);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(s, 0, CFG_ADDR);
|
||||
sysbus_mmio_map(s, 1, CFG_ADDR + 2);
|
||||
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
|
||||
+11
-1
@@ -309,7 +309,17 @@ static void ppc_heathrow_init(MachineState *machine)
|
||||
|
||||
/* No PCI init: the BIOS will do it */
|
||||
|
||||
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
|
||||
fw_cfg = FW_CFG(dev);
|
||||
qdev_prop_set_uint32(dev, "data_width", 1);
|
||||
qdev_prop_set_bit(dev, "dma_enabled", false);
|
||||
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
|
||||
OBJECT(fw_cfg), NULL);
|
||||
qdev_init_nofail(dev);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(s, 0, CFG_ADDR);
|
||||
sysbus_mmio_map(s, 1, CFG_ADDR + 2);
|
||||
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
|
||||
+10
-50
@@ -66,7 +66,7 @@ struct ref405ep_fpga_t {
|
||||
uint8_t reg1;
|
||||
};
|
||||
|
||||
static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
|
||||
static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
ref405ep_fpga_t *fpga;
|
||||
uint32_t ret;
|
||||
@@ -87,8 +87,8 @@ static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ref405ep_fpga_writeb (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
ref405ep_fpga_t *fpga;
|
||||
|
||||
@@ -105,54 +105,14 @@ static void ref405ep_fpga_writeb (void *opaque,
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = ref405ep_fpga_readb(opaque, addr) << 8;
|
||||
ret |= ref405ep_fpga_readb(opaque, addr + 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ref405ep_fpga_writew (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
|
||||
ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
|
||||
}
|
||||
|
||||
static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = ref405ep_fpga_readb(opaque, addr) << 24;
|
||||
ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
|
||||
ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
|
||||
ret |= ref405ep_fpga_readb(opaque, addr + 3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ref405ep_fpga_writel (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF);
|
||||
ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF);
|
||||
ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF);
|
||||
ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ref405ep_fpga_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl,
|
||||
},
|
||||
.write = {
|
||||
ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel,
|
||||
},
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.read = ref405ep_fpga_readb,
|
||||
.write = ref405ep_fpga_writeb,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 1,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void ref405ep_fpga_reset (void *opaque)
|
||||
|
||||
+25
-148
@@ -283,7 +283,7 @@ struct ppc4xx_opba_t {
|
||||
uint8_t pr;
|
||||
};
|
||||
|
||||
static uint32_t opba_readb (void *opaque, hwaddr addr)
|
||||
static uint64_t opba_readb(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
ppc4xx_opba_t *opba;
|
||||
uint32_t ret;
|
||||
@@ -307,8 +307,8 @@ static uint32_t opba_readb (void *opaque, hwaddr addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void opba_writeb (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
static void opba_writeb(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
ppc4xx_opba_t *opba;
|
||||
|
||||
@@ -328,61 +328,14 @@ static void opba_writeb (void *opaque,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t opba_readw (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
#ifdef DEBUG_OPBA
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
ret = opba_readb(opaque, addr) << 8;
|
||||
ret |= opba_readb(opaque, addr + 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void opba_writew (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_OPBA
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
opba_writeb(opaque, addr, value >> 8);
|
||||
opba_writeb(opaque, addr + 1, value);
|
||||
}
|
||||
|
||||
static uint32_t opba_readl (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
#ifdef DEBUG_OPBA
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
ret = opba_readb(opaque, addr) << 24;
|
||||
ret |= opba_readb(opaque, addr + 1) << 16;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void opba_writel (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_OPBA
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
opba_writeb(opaque, addr, value >> 24);
|
||||
opba_writeb(opaque, addr + 1, value >> 16);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps opba_ops = {
|
||||
.old_mmio = {
|
||||
.read = { opba_readb, opba_readw, opba_readl, },
|
||||
.write = { opba_writeb, opba_writew, opba_writel, },
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.read = opba_readb,
|
||||
.write = opba_writeb,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 1,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void ppc4xx_opba_reset (void *opaque)
|
||||
@@ -750,65 +703,27 @@ struct ppc405_gpio_t {
|
||||
uint32_t isr1l;
|
||||
};
|
||||
|
||||
static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr)
|
||||
static uint64_t ppc405_gpio_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
#ifdef DEBUG_GPIO
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
printf("%s: addr " TARGET_FMT_plx " size %d\n", __func__, addr, size);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ppc405_gpio_writeb (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
static void ppc405_gpio_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
#ifdef DEBUG_GPIO
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr)
|
||||
{
|
||||
#ifdef DEBUG_GPIO
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ppc405_gpio_writew (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_GPIO
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr)
|
||||
{
|
||||
#ifdef DEBUG_GPIO
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ppc405_gpio_writel (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_GPIO
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
printf("%s: addr " TARGET_FMT_plx " size %d val %08" PRIx32 "\n",
|
||||
__func__, addr, size, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ppc405_gpio_ops = {
|
||||
.old_mmio = {
|
||||
.read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, },
|
||||
.write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, },
|
||||
},
|
||||
.read = ppc405_gpio_read,
|
||||
.write = ppc405_gpio_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
@@ -1017,44 +932,6 @@ struct ppc4xx_gpt_t {
|
||||
uint32_t mask[5];
|
||||
};
|
||||
|
||||
static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr)
|
||||
{
|
||||
#ifdef DEBUG_GPT
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
/* XXX: generate a bus fault */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ppc4xx_gpt_writeb (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
/* XXX: generate a bus fault */
|
||||
}
|
||||
|
||||
static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr)
|
||||
{
|
||||
#ifdef DEBUG_GPT
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
/* XXX: generate a bus fault */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ppc4xx_gpt_writew (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
/* XXX: generate a bus fault */
|
||||
}
|
||||
|
||||
static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
|
||||
{
|
||||
/* XXX: TODO */
|
||||
@@ -1107,7 +984,7 @@ static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
|
||||
/* XXX: TODO */
|
||||
}
|
||||
|
||||
static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
|
||||
static uint64_t ppc4xx_gpt_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
ppc4xx_gpt_t *gpt;
|
||||
uint32_t ret;
|
||||
@@ -1162,8 +1039,8 @@ static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ppc4xx_gpt_writel (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
static void ppc4xx_gpt_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
ppc4xx_gpt_t *gpt;
|
||||
int idx;
|
||||
@@ -1225,10 +1102,10 @@ static void ppc4xx_gpt_writel (void *opaque,
|
||||
}
|
||||
|
||||
static const MemoryRegionOps gpt_ops = {
|
||||
.old_mmio = {
|
||||
.read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, },
|
||||
.write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, },
|
||||
},
|
||||
.read = ppc4xx_gpt_read,
|
||||
.write = ppc4xx_gpt_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
+16
-95
@@ -78,94 +78,6 @@ static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
|
||||
/* ISA IO ports bridge */
|
||||
#define PPC_IO_BASE 0x80000000
|
||||
|
||||
/* PowerPC control and status registers */
|
||||
#if 0 // Not used
|
||||
static struct {
|
||||
/* IDs */
|
||||
uint32_t veni_devi;
|
||||
uint32_t revi;
|
||||
/* Control and status */
|
||||
uint32_t gcsr;
|
||||
uint32_t xcfr;
|
||||
uint32_t ct32;
|
||||
uint32_t mcsr;
|
||||
/* General purpose registers */
|
||||
uint32_t gprg[6];
|
||||
/* Exceptions */
|
||||
uint32_t feen;
|
||||
uint32_t fest;
|
||||
uint32_t fema;
|
||||
uint32_t fecl;
|
||||
uint32_t eeen;
|
||||
uint32_t eest;
|
||||
uint32_t eecl;
|
||||
uint32_t eeint;
|
||||
uint32_t eemck0;
|
||||
uint32_t eemck1;
|
||||
/* Error diagnostic */
|
||||
} XCSR;
|
||||
|
||||
static void PPC_XCSR_writeb (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
}
|
||||
|
||||
static void PPC_XCSR_writew (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
}
|
||||
|
||||
static void PPC_XCSR_writel (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
}
|
||||
|
||||
static uint32_t PPC_XCSR_readb (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t retval = 0;
|
||||
|
||||
printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
|
||||
retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static uint32_t PPC_XCSR_readw (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t retval = 0;
|
||||
|
||||
printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
|
||||
retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static uint32_t PPC_XCSR_readl (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t retval = 0;
|
||||
|
||||
printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
|
||||
retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps PPC_XCSR_ops = {
|
||||
.old_mmio = {
|
||||
.read = { PPC_XCSR_readb, PPC_XCSR_readw, PPC_XCSR_readl, },
|
||||
.write = { PPC_XCSR_writeb, PPC_XCSR_writew, PPC_XCSR_writel, },
|
||||
},
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* Fake super-io ports for PREP platform (Intel 82378ZB) */
|
||||
typedef struct sysctrl_t {
|
||||
qemu_irq reset_irq;
|
||||
@@ -648,11 +560,10 @@ static void ppc_prep_init(MachineState *machine)
|
||||
portio_list_init(&prep_port_list, NULL, prep_portio_list, sysctrl, "prep");
|
||||
portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0);
|
||||
|
||||
/* PowerPC control and status register group */
|
||||
#if 0
|
||||
memory_region_init_io(xcsr, NULL, &PPC_XCSR_ops, NULL, "ppc-xcsr", 0x1000);
|
||||
memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr);
|
||||
#endif
|
||||
/*
|
||||
* PowerPC control and status register group: unimplemented,
|
||||
* would be at address 0xFEFF0000.
|
||||
*/
|
||||
|
||||
if (machine_usb(machine)) {
|
||||
pci_create_simple(pci_bus, -1, "pci-ohci");
|
||||
@@ -676,6 +587,7 @@ static void ppc_prep_init(MachineState *machine)
|
||||
|
||||
static void prep_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->deprecation_reason = "use 40p machine type instead";
|
||||
mc->desc = "PowerPC PREP platform";
|
||||
mc->init = ppc_prep_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
@@ -706,7 +618,7 @@ static void ibm_40p_init(MachineState *machine)
|
||||
uint16_t cmos_checksum;
|
||||
PowerPCCPU *cpu;
|
||||
DeviceState *dev;
|
||||
SysBusDevice *pcihost;
|
||||
SysBusDevice *pcihost, *s;
|
||||
Nvram *m48t59 = NULL;
|
||||
PCIBus *pci_bus;
|
||||
ISABus *isa_bus;
|
||||
@@ -799,7 +711,16 @@ static void ibm_40p_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/* Prepare firmware configuration for OpenBIOS */
|
||||
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
|
||||
fw_cfg = FW_CFG(dev);
|
||||
qdev_prop_set_uint32(dev, "data_width", 1);
|
||||
qdev_prop_set_bit(dev, "dma_enabled", false);
|
||||
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
|
||||
OBJECT(fw_cfg), NULL);
|
||||
qdev_init_nofail(dev);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(s, 0, CFG_ADDR);
|
||||
sysbus_mmio_map(s, 1, CFG_ADDR + 2);
|
||||
|
||||
if (machine->kernel_filename) {
|
||||
/* load kernel */
|
||||
|
||||
+55
-176
@@ -54,7 +54,6 @@
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_vio.h"
|
||||
#include "hw/pci-host/spapr.h"
|
||||
#include "hw/ppc/xics.h"
|
||||
#include "hw/pci/msi.h"
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
@@ -117,33 +116,6 @@ static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
|
||||
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
|
||||
}
|
||||
|
||||
static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
|
||||
const char *type_ics,
|
||||
int nr_irqs, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
Object *obj;
|
||||
|
||||
obj = object_new(type_ics);
|
||||
object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
|
||||
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
|
||||
&error_abort);
|
||||
object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err);
|
||||
if (local_err) {
|
||||
goto error;
|
||||
}
|
||||
object_property_set_bool(obj, true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return ICS_BASE(obj);
|
||||
|
||||
error:
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
|
||||
{
|
||||
/* Dummy entries correspond to unused ICPState objects in older QEMUs,
|
||||
@@ -184,38 +156,6 @@ static int xics_max_server_number(sPAPRMachineState *spapr)
|
||||
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
|
||||
}
|
||||
|
||||
static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
if (machine_kernel_irqchip_allowed(machine) &&
|
||||
!xics_kvm_init(spapr, &local_err)) {
|
||||
spapr->icp_type = TYPE_KVM_ICP;
|
||||
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs,
|
||||
&local_err);
|
||||
}
|
||||
if (machine_kernel_irqchip_required(machine) && !spapr->ics) {
|
||||
error_prepend(&local_err,
|
||||
"kernel_irqchip requested but unavailable: ");
|
||||
goto error;
|
||||
}
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
}
|
||||
|
||||
if (!spapr->ics) {
|
||||
xics_spapr_init(spapr);
|
||||
spapr->icp_type = TYPE_ICP;
|
||||
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs,
|
||||
&local_err);
|
||||
}
|
||||
|
||||
error:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
|
||||
int smt_threads)
|
||||
{
|
||||
@@ -1636,6 +1576,10 @@ static void spapr_machine_reset(void)
|
||||
ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
|
||||
}
|
||||
|
||||
if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
|
||||
spapr_irq_msi_reset(spapr);
|
||||
}
|
||||
|
||||
qemu_devices_reset();
|
||||
|
||||
/* DRC reset may cause a device to be unplugged. This will cause troubles
|
||||
@@ -1910,6 +1854,24 @@ static const VMStateDescription vmstate_spapr_patb_entry = {
|
||||
},
|
||||
};
|
||||
|
||||
static bool spapr_irq_map_needed(void *opaque)
|
||||
{
|
||||
sPAPRMachineState *spapr = opaque;
|
||||
|
||||
return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_spapr_irq_map = {
|
||||
.name = "spapr_irq_map",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = spapr_irq_map_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BITMAP(irq_map, sPAPRMachineState, 0, irq_map_nr),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_spapr = {
|
||||
.name = "spapr",
|
||||
.version_id = 3,
|
||||
@@ -1937,6 +1899,7 @@ static const VMStateDescription vmstate_spapr = {
|
||||
&vmstate_spapr_cap_cfpc,
|
||||
&vmstate_spapr_cap_sbbc,
|
||||
&vmstate_spapr_cap_ibs,
|
||||
&vmstate_spapr_irq_map,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
@@ -2590,7 +2553,7 @@ static void spapr_machine_init(MachineState *machine)
|
||||
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
|
||||
|
||||
/* Set up Interrupt Controller before we create the VCPUs */
|
||||
xics_system_init(machine, XICS_IRQS_SPAPR, &error_fatal);
|
||||
smc->irq->init(spapr, &error_fatal);
|
||||
|
||||
/* Set up containers for ibm,client-architecture-support negotiated options
|
||||
*/
|
||||
@@ -3782,121 +3745,13 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
|
||||
return cpu ? ICP(cpu->intc) : NULL;
|
||||
}
|
||||
|
||||
#define ICS_IRQ_FREE(ics, srcno) \
|
||||
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
|
||||
|
||||
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
|
||||
{
|
||||
int first, i;
|
||||
|
||||
for (first = 0; first < ics->nr_irqs; first += alignnum) {
|
||||
if (num > (ics->nr_irqs - first)) {
|
||||
return -1;
|
||||
}
|
||||
for (i = first; i < first + num; ++i) {
|
||||
if (!ICS_IRQ_FREE(ics, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == (first + num)) {
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
int first = -1;
|
||||
|
||||
assert(ics);
|
||||
|
||||
/*
|
||||
* MSIMesage::data is used for storing VIRQ so
|
||||
* it has to be aligned to num to support multiple
|
||||
* MSI vectors. MSI-X is not affected by this.
|
||||
* The hint is used for the first IRQ, the rest should
|
||||
* be allocated continuously.
|
||||
*/
|
||||
if (align) {
|
||||
assert((num == 1) || (num == 2) || (num == 4) ||
|
||||
(num == 8) || (num == 16) || (num == 32));
|
||||
first = ics_find_free_block(ics, num, num);
|
||||
} else {
|
||||
first = ics_find_free_block(ics, num, 1);
|
||||
}
|
||||
|
||||
if (first < 0) {
|
||||
error_setg(errp, "can't find a free %d-IRQ block", num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return first + ics->offset;
|
||||
}
|
||||
|
||||
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
|
||||
assert(ics);
|
||||
|
||||
if (!ics_valid_irq(ics, irq)) {
|
||||
error_setg(errp, "IRQ %d is invalid", irq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
|
||||
error_setg(errp, "IRQ %d is not free", irq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ics_set_irq_type(ics, irq - ics->offset, lsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
int srcno = irq - ics->offset;
|
||||
int i;
|
||||
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
trace_spapr_irq_free(0, irq, num);
|
||||
for (i = srcno; i < srcno + num; ++i) {
|
||||
if (ICS_IRQ_FREE(ics, i)) {
|
||||
trace_spapr_irq_free_warn(0, i + ics->offset);
|
||||
}
|
||||
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
return ics->qirqs[irq - ics->offset];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void spapr_pic_print_info(InterruptStatsProvider *obj,
|
||||
Monitor *mon)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
CPUState *cs;
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
icp_pic_print_info(ICP(cpu->intc), mon);
|
||||
}
|
||||
|
||||
ics_pic_print_info(spapr->ics, mon);
|
||||
smc->irq->print_info(spapr, mon);
|
||||
}
|
||||
|
||||
int spapr_get_vcpu_id(PowerPCCPU *cpu)
|
||||
@@ -4009,6 +3864,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
|
||||
smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
|
||||
spapr_caps_add_properties(smc, &error_abort);
|
||||
smc->irq = &spapr_irq_xics;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_machine_info = {
|
||||
@@ -4059,19 +3915,42 @@ static const TypeInfo spapr_machine_info = {
|
||||
} \
|
||||
type_init(spapr_machine_register_##suffix)
|
||||
|
||||
/*
|
||||
* pseries-3.0
|
||||
/*
|
||||
* pseries-3.1
|
||||
*/
|
||||
static void spapr_machine_3_0_instance_options(MachineState *machine)
|
||||
static void spapr_machine_3_1_instance_options(MachineState *machine)
|
||||
{
|
||||
}
|
||||
|
||||
static void spapr_machine_3_0_class_options(MachineClass *mc)
|
||||
static void spapr_machine_3_1_class_options(MachineClass *mc)
|
||||
{
|
||||
/* Defaults for the latest behaviour inherited from the base class */
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(3_0, "3.0", true);
|
||||
DEFINE_SPAPR_MACHINE(3_1, "3.1", true);
|
||||
|
||||
/*
|
||||
* pseries-3.0
|
||||
*/
|
||||
#define SPAPR_COMPAT_3_0 \
|
||||
HW_COMPAT_3_0
|
||||
|
||||
static void spapr_machine_3_0_instance_options(MachineState *machine)
|
||||
{
|
||||
spapr_machine_3_1_instance_options(machine);
|
||||
}
|
||||
|
||||
static void spapr_machine_3_0_class_options(MachineClass *mc)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
|
||||
spapr_machine_3_1_class_options(mc);
|
||||
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_3_0);
|
||||
|
||||
smc->legacy_irq_allocation = true;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
|
||||
|
||||
/*
|
||||
* pseries-2.12
|
||||
|
||||
+33
-30
@@ -11,6 +11,7 @@
|
||||
#include "hw/ppc/spapr_cpu_core.h"
|
||||
#include "target/ppc/cpu.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/xics.h" /* for icp_create() - to be removed */
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/cpus.h"
|
||||
@@ -113,26 +114,6 @@ const char *spapr_get_cpu_core_type(const char *cpu_type)
|
||||
return object_class_get_name(oc);
|
||||
}
|
||||
|
||||
static void spapr_unrealize_vcpu(PowerPCCPU *cpu)
|
||||
{
|
||||
qemu_unregister_reset(spapr_cpu_reset, cpu);
|
||||
object_unparent(cpu->intc);
|
||||
cpu_remove_sync(CPU(cpu));
|
||||
object_unparent(OBJECT(cpu));
|
||||
}
|
||||
|
||||
static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
|
||||
CPUCore *cc = CPU_CORE(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cc->nr_threads; i++) {
|
||||
spapr_unrealize_vcpu(sc->threads[i]);
|
||||
}
|
||||
g_free(sc->threads);
|
||||
}
|
||||
|
||||
static bool slb_shadow_needed(void *opaque)
|
||||
{
|
||||
sPAPRCPUState *spapr_cpu = opaque;
|
||||
@@ -207,10 +188,34 @@ static const VMStateDescription vmstate_spapr_cpu_state = {
|
||||
}
|
||||
};
|
||||
|
||||
static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
|
||||
{
|
||||
if (!sc->pre_3_0_migration) {
|
||||
vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
|
||||
}
|
||||
qemu_unregister_reset(spapr_cpu_reset, cpu);
|
||||
object_unparent(cpu->intc);
|
||||
cpu_remove_sync(CPU(cpu));
|
||||
object_unparent(OBJECT(cpu));
|
||||
}
|
||||
|
||||
static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
|
||||
CPUCore *cc = CPU_CORE(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cc->nr_threads; i++) {
|
||||
spapr_unrealize_vcpu(sc->threads[i], sc);
|
||||
}
|
||||
g_free(sc->threads);
|
||||
}
|
||||
|
||||
static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
Error **errp)
|
||||
sPAPRCPUCore *sc, Error **errp)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
CPUState *cs = CPU(cpu);
|
||||
Error *local_err = NULL;
|
||||
|
||||
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
|
||||
@@ -233,6 +238,11 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
goto error_unregister;
|
||||
}
|
||||
|
||||
if (!sc->pre_3_0_migration) {
|
||||
vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
|
||||
cpu->machine_data);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error_unregister:
|
||||
@@ -272,10 +282,6 @@ static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
|
||||
}
|
||||
|
||||
cpu->machine_data = g_new0(sPAPRCPUState, 1);
|
||||
if (!sc->pre_3_0_migration) {
|
||||
vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
|
||||
cpu->machine_data);
|
||||
}
|
||||
|
||||
object_unref(obj);
|
||||
return cpu;
|
||||
@@ -290,9 +296,6 @@ static void spapr_delete_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
|
||||
{
|
||||
sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
|
||||
|
||||
if (!sc->pre_3_0_migration) {
|
||||
vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
|
||||
}
|
||||
cpu->machine_data = NULL;
|
||||
g_free(spapr_cpu);
|
||||
object_unparent(OBJECT(cpu));
|
||||
@@ -325,7 +328,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
for (j = 0; j < cc->nr_threads; j++) {
|
||||
spapr_realize_vcpu(sc->threads[j], spapr, &local_err);
|
||||
spapr_realize_vcpu(sc->threads[j], spapr, sc, &local_err);
|
||||
if (local_err) {
|
||||
goto err_unrealize;
|
||||
}
|
||||
@@ -334,7 +337,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
err_unrealize:
|
||||
while (--j >= 0) {
|
||||
spapr_unrealize_vcpu(sc->threads[j]);
|
||||
spapr_unrealize_vcpu(sc->threads[j], sc);
|
||||
}
|
||||
err:
|
||||
while (--i >= 0) {
|
||||
|
||||
@@ -707,9 +707,11 @@ void spapr_clear_pending_events(sPAPRMachineState *spapr)
|
||||
|
||||
void spapr_events_init(sPAPRMachineState *spapr)
|
||||
{
|
||||
int epow_irq;
|
||||
int epow_irq = SPAPR_IRQ_EPOW;
|
||||
|
||||
epow_irq = spapr_irq_findone(spapr, &error_fatal);
|
||||
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
|
||||
epow_irq = spapr_irq_findone(spapr, &error_fatal);
|
||||
}
|
||||
|
||||
spapr_irq_claim(spapr, epow_irq, false, &error_fatal);
|
||||
|
||||
@@ -729,9 +731,11 @@ void spapr_events_init(sPAPRMachineState *spapr)
|
||||
* checking that it's enabled.
|
||||
*/
|
||||
if (spapr->use_hotplug_event_source) {
|
||||
int hp_irq;
|
||||
int hp_irq = SPAPR_IRQ_HOTPLUG;
|
||||
|
||||
hp_irq = spapr_irq_findone(spapr, &error_fatal);
|
||||
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
|
||||
hp_irq = spapr_irq_findone(spapr, &error_fatal);
|
||||
}
|
||||
|
||||
spapr_irq_claim(spapr, hp_irq, false, &error_fatal);
|
||||
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* QEMU PowerPC sPAPR IRQ interface
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/xics.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
void spapr_irq_msi_init(sPAPRMachineState *spapr, uint32_t nr_msis)
|
||||
{
|
||||
spapr->irq_map_nr = nr_msis;
|
||||
spapr->irq_map = bitmap_new(spapr->irq_map_nr);
|
||||
}
|
||||
|
||||
int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
|
||||
Error **errp)
|
||||
{
|
||||
int irq;
|
||||
|
||||
/*
|
||||
* The 'align_mask' parameter of bitmap_find_next_zero_area()
|
||||
* should be one less than a power of 2; 0 means no
|
||||
* alignment. Adapt the 'align' value of the former allocator
|
||||
* to fit the requirements of bitmap_find_next_zero_area()
|
||||
*/
|
||||
align -= 1;
|
||||
|
||||
irq = bitmap_find_next_zero_area(spapr->irq_map, spapr->irq_map_nr, 0, num,
|
||||
align);
|
||||
if (irq == spapr->irq_map_nr) {
|
||||
error_setg(errp, "can't find a free %d-IRQ block", num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bitmap_set(spapr->irq_map, irq, num);
|
||||
|
||||
return irq + SPAPR_IRQ_MSI;
|
||||
}
|
||||
|
||||
void spapr_irq_msi_free(sPAPRMachineState *spapr, int irq, uint32_t num)
|
||||
{
|
||||
bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num);
|
||||
}
|
||||
|
||||
void spapr_irq_msi_reset(sPAPRMachineState *spapr)
|
||||
{
|
||||
bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* XICS IRQ backend.
|
||||
*/
|
||||
|
||||
static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
|
||||
const char *type_ics,
|
||||
int nr_irqs, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
Object *obj;
|
||||
|
||||
obj = object_new(type_ics);
|
||||
object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
|
||||
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
|
||||
&error_abort);
|
||||
object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err);
|
||||
if (local_err) {
|
||||
goto error;
|
||||
}
|
||||
object_property_set_bool(obj, true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return ICS_BASE(obj);
|
||||
|
||||
error:
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void spapr_irq_init_xics(sPAPRMachineState *spapr, Error **errp)
|
||||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
int nr_irqs = smc->irq->nr_irqs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* Initialize the MSI IRQ allocator. */
|
||||
if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
|
||||
spapr_irq_msi_init(spapr, XICS_IRQ_BASE + nr_irqs - SPAPR_IRQ_MSI);
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
if (machine_kernel_irqchip_allowed(machine) &&
|
||||
!xics_kvm_init(spapr, &local_err)) {
|
||||
spapr->icp_type = TYPE_KVM_ICP;
|
||||
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs,
|
||||
&local_err);
|
||||
}
|
||||
if (machine_kernel_irqchip_required(machine) && !spapr->ics) {
|
||||
error_prepend(&local_err,
|
||||
"kernel_irqchip requested but unavailable: ");
|
||||
goto error;
|
||||
}
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
}
|
||||
|
||||
if (!spapr->ics) {
|
||||
xics_spapr_init(spapr);
|
||||
spapr->icp_type = TYPE_ICP;
|
||||
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs,
|
||||
&local_err);
|
||||
}
|
||||
|
||||
error:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
#define ICS_IRQ_FREE(ics, srcno) \
|
||||
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
|
||||
|
||||
static int spapr_irq_claim_xics(sPAPRMachineState *spapr, int irq, bool lsi,
|
||||
Error **errp)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
|
||||
assert(ics);
|
||||
|
||||
if (!ics_valid_irq(ics, irq)) {
|
||||
error_setg(errp, "IRQ %d is invalid", irq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
|
||||
error_setg(errp, "IRQ %d is not free", irq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ics_set_irq_type(ics, irq - ics->offset, lsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spapr_irq_free_xics(sPAPRMachineState *spapr, int irq, int num)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
uint32_t srcno = irq - ics->offset;
|
||||
int i;
|
||||
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
trace_spapr_irq_free(0, irq, num);
|
||||
for (i = srcno; i < srcno + num; ++i) {
|
||||
if (ICS_IRQ_FREE(ics, i)) {
|
||||
trace_spapr_irq_free_warn(0, i);
|
||||
}
|
||||
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
uint32_t srcno = irq - ics->offset;
|
||||
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
return ics->qirqs[srcno];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
icp_pic_print_info(ICP(cpu->intc), mon);
|
||||
}
|
||||
|
||||
ics_pic_print_info(spapr->ics, mon);
|
||||
}
|
||||
|
||||
sPAPRIrq spapr_irq_xics = {
|
||||
.nr_irqs = XICS_IRQS_SPAPR,
|
||||
|
||||
.init = spapr_irq_init_xics,
|
||||
.claim = spapr_irq_claim_xics,
|
||||
.free = spapr_irq_free_xics,
|
||||
.qirq = spapr_qirq_xics,
|
||||
.print_info = spapr_irq_print_info_xics,
|
||||
};
|
||||
|
||||
/*
|
||||
* sPAPR IRQ frontend routines for devices
|
||||
*/
|
||||
|
||||
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
return smc->irq->claim(spapr, irq, lsi, errp);
|
||||
}
|
||||
|
||||
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
smc->irq->free(spapr, irq, num);
|
||||
}
|
||||
|
||||
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
return smc->irq->qirq(spapr, irq);
|
||||
}
|
||||
|
||||
/*
|
||||
* XICS legacy routines - to deprecate one day
|
||||
*/
|
||||
|
||||
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
|
||||
{
|
||||
int first, i;
|
||||
|
||||
for (first = 0; first < ics->nr_irqs; first += alignnum) {
|
||||
if (num > (ics->nr_irqs - first)) {
|
||||
return -1;
|
||||
}
|
||||
for (i = first; i < first + num; ++i) {
|
||||
if (!ICS_IRQ_FREE(ics, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == (first + num)) {
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
int first = -1;
|
||||
|
||||
assert(ics);
|
||||
|
||||
/*
|
||||
* MSIMesage::data is used for storing VIRQ so
|
||||
* it has to be aligned to num to support multiple
|
||||
* MSI vectors. MSI-X is not affected by this.
|
||||
* The hint is used for the first IRQ, the rest should
|
||||
* be allocated continuously.
|
||||
*/
|
||||
if (align) {
|
||||
assert((num == 1) || (num == 2) || (num == 4) ||
|
||||
(num == 8) || (num == 16) || (num == 32));
|
||||
first = ics_find_free_block(ics, num, num);
|
||||
} else {
|
||||
first = ics_find_free_block(ics, num, 1);
|
||||
}
|
||||
|
||||
if (first < 0) {
|
||||
error_setg(errp, "can't find a free %d-IRQ block", num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return first + ics->offset;
|
||||
}
|
||||
+24
-8
@@ -267,6 +267,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong args, uint32_t nret,
|
||||
target_ulong rets)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
uint32_t config_addr = rtas_ld(args, 0);
|
||||
uint64_t buid = rtas_ldq(args, 1);
|
||||
unsigned int func = rtas_ld(args, 3);
|
||||
@@ -334,6 +335,9 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!smc->legacy_irq_allocation) {
|
||||
spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
|
||||
}
|
||||
spapr_irq_free(spapr, msi->first_irq, msi->num);
|
||||
if (msi_present(pdev)) {
|
||||
spapr_msi_setmsg(pdev, 0, false, 0, 0);
|
||||
@@ -372,7 +376,13 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
}
|
||||
|
||||
/* Allocate MSIs */
|
||||
irq = spapr_irq_find(spapr, req_num, ret_intr_type == RTAS_TYPE_MSI, &err);
|
||||
if (smc->legacy_irq_allocation) {
|
||||
irq = spapr_irq_find(spapr, req_num, ret_intr_type == RTAS_TYPE_MSI,
|
||||
&err);
|
||||
} else {
|
||||
irq = spapr_irq_msi_alloc(spapr, req_num,
|
||||
ret_intr_type == RTAS_TYPE_MSI, &err);
|
||||
}
|
||||
if (err) {
|
||||
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
|
||||
config_addr);
|
||||
@@ -392,6 +402,9 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
|
||||
/* Release previous MSIs */
|
||||
if (msi) {
|
||||
if (!smc->legacy_irq_allocation) {
|
||||
spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
|
||||
}
|
||||
spapr_irq_free(spapr, msi->first_irq, msi->num);
|
||||
g_hash_table_remove(phb->msi, &config_addr);
|
||||
}
|
||||
@@ -1546,6 +1559,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
sPAPRMachineState *spapr =
|
||||
(sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(),
|
||||
TYPE_SPAPR_MACHINE);
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||
@@ -1563,7 +1577,6 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
if (sphb->index != (uint32_t)-1) {
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
Error *local_err = NULL;
|
||||
|
||||
smc->phb_placement(spapr, sphb->index,
|
||||
@@ -1705,14 +1718,16 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
/* Initialize the LSI table */
|
||||
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||
uint32_t irq;
|
||||
uint32_t irq = SPAPR_IRQ_PCI_LSI + sphb->index * PCI_NUM_PINS + i;
|
||||
Error *local_err = NULL;
|
||||
|
||||
irq = spapr_irq_findone(spapr, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
error_prepend(errp, "can't allocate LSIs: ");
|
||||
return;
|
||||
if (smc->legacy_irq_allocation) {
|
||||
irq = spapr_irq_findone(spapr, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
error_prepend(errp, "can't allocate LSIs: ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
spapr_irq_claim(spapr, irq, true, &local_err);
|
||||
@@ -2123,6 +2138,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
||||
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges));
|
||||
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
|
||||
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
|
||||
/* TODO: fine tune the total count of allocatable MSIs per PHB */
|
||||
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS_SPAPR));
|
||||
|
||||
/* Dynamic DMA window */
|
||||
|
||||
+60
-6
@@ -37,12 +37,13 @@
|
||||
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_vio.h"
|
||||
#include "hw/ppc/xics.h"
|
||||
#include "hw/ppc/fdt.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#define SPAPR_VIO_REG_BASE 0x71000000
|
||||
|
||||
static void spapr_vio_get_irq(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
@@ -445,6 +446,55 @@ static void spapr_vio_busdev_reset(DeviceState *qdev)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The register property of a VIO device is defined in livirt using
|
||||
* 0x1000 as a base register number plus a 0x1000 increment. For the
|
||||
* VIO tty device, the base number is changed to 0x30000000. QEMU uses
|
||||
* a base register number of 0x71000000 and then a simple increment.
|
||||
*
|
||||
* The formula below tries to compute a unique index number from the
|
||||
* register value that will be used to define the IRQ number of the
|
||||
* VIO device.
|
||||
*
|
||||
* A maximum of 256 VIO devices is covered. Collisions are possible
|
||||
* but they will be detected when the IRQ is claimed.
|
||||
*/
|
||||
static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg)
|
||||
{
|
||||
uint32_t irq;
|
||||
|
||||
if (reg >= SPAPR_VIO_REG_BASE) {
|
||||
/*
|
||||
* VIO device register values when allocated by QEMU. For
|
||||
* these, we simply mask the high bits to fit the overall
|
||||
* range: [0x00 - 0xff].
|
||||
*
|
||||
* The nvram VIO device (reg=0x71000000) is a static device of
|
||||
* the pseries machine and so is always allocated by QEMU. Its
|
||||
* IRQ number is 0x0.
|
||||
*/
|
||||
irq = reg & 0xff;
|
||||
|
||||
} else if (reg >= 0x30000000) {
|
||||
/*
|
||||
* VIO tty devices register values, when allocated by livirt,
|
||||
* are mapped in range [0xf0 - 0xff], gives us a maximum of 16
|
||||
* vtys.
|
||||
*/
|
||||
irq = 0xf0 | ((reg >> 12) & 0xf);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Other VIO devices register values, when allocated by
|
||||
* livirt, should be mapped in range [0x00 - 0xef]. Conflicts
|
||||
* will be detected when IRQ is claimed.
|
||||
*/
|
||||
irq = (reg >> 12) & 0xff;
|
||||
}
|
||||
|
||||
return SPAPR_IRQ_VIO | irq;
|
||||
}
|
||||
|
||||
static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
@@ -485,10 +535,14 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
|
||||
}
|
||||
|
||||
if (!dev->irq) {
|
||||
dev->irq = spapr_irq_findone(spapr, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
dev->irq = spapr_vio_reg_to_irq(dev->reg);
|
||||
|
||||
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
|
||||
dev->irq = spapr_irq_findone(spapr, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +611,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
|
||||
/* Create bus on bridge device */
|
||||
qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
|
||||
bus = SPAPR_VIO_BUS(qbus);
|
||||
bus->next_reg = 0x71000000;
|
||||
bus->next_reg = SPAPR_VIO_REG_BASE;
|
||||
|
||||
/* hcall-vio */
|
||||
spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
|
||||
|
||||
@@ -1136,6 +1136,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
|
||||
info.iova_pgsizes = 4096;
|
||||
}
|
||||
vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes);
|
||||
container->pgsizes = info.iova_pgsizes;
|
||||
} else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU) ||
|
||||
ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) {
|
||||
struct vfio_iommu_spapr_tce_info info;
|
||||
@@ -1200,6 +1201,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
|
||||
}
|
||||
|
||||
if (v2) {
|
||||
container->pgsizes = info.ddw.pgsizes;
|
||||
/*
|
||||
* There is a default window in just created container.
|
||||
* To make region_add/del simpler, we better remove this
|
||||
@@ -1214,6 +1216,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
|
||||
}
|
||||
} else {
|
||||
/* The default table uses 4K pages */
|
||||
container->pgsizes = 0x1000;
|
||||
vfio_host_win_add(container, info.dma32_window_start,
|
||||
info.dma32_window_start +
|
||||
info.dma32_window_size - 1,
|
||||
|
||||
+20
-1
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "hw/vfio/vfio-common.h"
|
||||
#include "hw/hw.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "trace.h"
|
||||
|
||||
@@ -144,9 +145,27 @@ int vfio_spapr_create_window(VFIOContainer *container,
|
||||
{
|
||||
int ret;
|
||||
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
|
||||
unsigned pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
|
||||
uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
|
||||
unsigned entries, pages;
|
||||
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
|
||||
long systempagesize = qemu_getrampagesize();
|
||||
|
||||
/*
|
||||
* The host might not support the guest supported IOMMU page size,
|
||||
* so we will use smaller physical IOMMU pages to back them.
|
||||
*/
|
||||
if (pagesize > systempagesize) {
|
||||
pagesize = systempagesize;
|
||||
}
|
||||
pagesize = 1ULL << (63 - clz64(container->pgsizes &
|
||||
(pagesize | (pagesize - 1))));
|
||||
if (!pagesize) {
|
||||
error_report("Host doesn't support page size 0x%"PRIx64
|
||||
", the supported mask is 0x%lx",
|
||||
memory_region_iommu_get_min_page_size(iommu_mr),
|
||||
container->pgsizes);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: For VFIO iommu types which have KVM acceleration to
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#include "qemu/units.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/ppc/xics.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"
|
||||
|
||||
struct VIOsPAPRBus;
|
||||
struct sPAPRPHBState;
|
||||
@@ -15,6 +15,7 @@ struct sPAPRNVRAM;
|
||||
typedef struct sPAPREventLogEntry sPAPREventLogEntry;
|
||||
typedef struct sPAPREventSource sPAPREventSource;
|
||||
typedef struct sPAPRPendingHPT sPAPRPendingHPT;
|
||||
typedef struct ICSState ICSState;
|
||||
|
||||
#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
|
||||
#define SPAPR_ENTRY_POINT 0x100
|
||||
@@ -101,12 +102,15 @@ struct sPAPRMachineClass {
|
||||
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
|
||||
bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
|
||||
bool pre_2_10_has_unused_icps;
|
||||
bool legacy_irq_allocation;
|
||||
|
||||
void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index,
|
||||
uint64_t *buid, hwaddr *pio,
|
||||
hwaddr *mmio32, hwaddr *mmio64,
|
||||
unsigned n_dma, uint32_t *liobns, Error **errp);
|
||||
sPAPRResizeHPT resize_hpt_default;
|
||||
sPAPRCapabilities default_caps;
|
||||
sPAPRIrq *irq;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -167,6 +171,8 @@ struct sPAPRMachineState {
|
||||
char *kvm_type;
|
||||
|
||||
const char *icp_type;
|
||||
int32_t irq_map_nr;
|
||||
unsigned long *irq_map;
|
||||
|
||||
bool cmd_line_caps[SPAPR_CAP_NUM];
|
||||
sPAPRCapabilities def, eff, mig;
|
||||
@@ -775,14 +781,6 @@ int spapr_get_vcpu_id(PowerPCCPU *cpu);
|
||||
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp);
|
||||
PowerPCCPU *spapr_find_cpu(int vcpu_id);
|
||||
|
||||
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align,
|
||||
Error **errp);
|
||||
#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp)
|
||||
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
|
||||
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
|
||||
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
|
||||
|
||||
|
||||
int spapr_caps_pre_load(void *opaque);
|
||||
int spapr_caps_pre_save(void *opaque);
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* IRQ range offsets per device type
|
||||
*/
|
||||
#define SPAPR_IRQ_EPOW 0x1000 /* XICS_IRQ_BASE offset */
|
||||
#define SPAPR_IRQ_HOTPLUG 0x1001
|
||||
#define SPAPR_IRQ_VIO 0x1100 /* 256 VIO devices */
|
||||
#define SPAPR_IRQ_PCI_LSI 0x1200 /* 32+ PHBs devices */
|
||||
|
||||
#define SPAPR_IRQ_MSI 0x1300 /* Offset of the dynamic range covered
|
||||
* by the bitmap allocator */
|
||||
|
||||
typedef struct sPAPRMachineState sPAPRMachineState;
|
||||
|
||||
void spapr_irq_msi_init(sPAPRMachineState *spapr, uint32_t nr_msis);
|
||||
int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
|
||||
Error **errp);
|
||||
void spapr_irq_msi_free(sPAPRMachineState *spapr, int irq, uint32_t num);
|
||||
void spapr_irq_msi_reset(sPAPRMachineState *spapr);
|
||||
|
||||
typedef struct sPAPRIrq {
|
||||
uint32_t nr_irqs;
|
||||
|
||||
void (*init)(sPAPRMachineState *spapr, Error **errp);
|
||||
int (*claim)(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
|
||||
void (*free)(sPAPRMachineState *spapr, int irq, int num);
|
||||
qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq);
|
||||
void (*print_info)(sPAPRMachineState *spapr, Monitor *mon);
|
||||
} sPAPRIrq;
|
||||
|
||||
extern sPAPRIrq spapr_irq_xics;
|
||||
|
||||
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
|
||||
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
|
||||
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
|
||||
|
||||
/*
|
||||
* XICS legacy routines
|
||||
*/
|
||||
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp);
|
||||
#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp)
|
||||
|
||||
#endif
|
||||
@@ -29,7 +29,6 @@
|
||||
#define XICS_H
|
||||
|
||||
#include "hw/qdev.h"
|
||||
#include "target/ppc/cpu-qom.h"
|
||||
|
||||
#define XICS_IPI 0x2
|
||||
#define XICS_BUID 0x1
|
||||
|
||||
@@ -73,6 +73,7 @@ typedef struct VFIOContainer {
|
||||
unsigned iommu_type;
|
||||
int error;
|
||||
bool initialized;
|
||||
unsigned long pgsizes;
|
||||
/*
|
||||
* This assumes the host IOMMU can support only a single
|
||||
* contiguous IOVA window. We may need to generalize that in
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||
implementation for certain IBM POWER hardware. The sources are at
|
||||
https://github.com/aik/SLOF, and the image currently in qemu is
|
||||
built from git tag qemu-slof-20180621.
|
||||
built from git tag qemu-slof-20180702.
|
||||
|
||||
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
|
||||
legacy x86 software to communicate with an attached serial console as
|
||||
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user