Patch queue for ppc - 2014-06-27
Changes include: - instruction emulation fixes - linux-user fixes - mac99: layout fixes - pseries: Initial VFIO support - pseries: support for UUID - pseries: support for -boot m -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJTrVqlAAoJECszeR4D/txgXEwP/iRn8HQ4c7LooveCK2R1maNc sXjkt/tcC4jSiG3i80s6WcVo7jGtc2wrJI0WzJlz4THBnRaT9Yv+VYOCHV4yXuUV PW7SYnLZz0X10lOjPdqCM3rY7lzoqrijTLPhUs/amjnb9v0USIOUO+MrZ1AxA6xc 78i5UvEabVIVyUbe4NJDZY7s/odF+/17JWJuzcUHpjI97nfS9pVfvNfw2YBcC+75 EW7bSFNsPbwG5yHZKkqkheovQEcX+jjMsoqKbXchSKzW3hvNmSf76WwWYbQIgmUO rbOn3UkwhUAza5bj4+b2lbVVC3TOjIyNYFNmo8g0WeUpFkEcW8Q+SEBKmLX8eFdV s0dSvgAxGi1Ia2EYCZjqZjw37QVZzs3spVeRPETN65vxDi51FRPZqK6LTJdb+aIa x8mbbb5bL5BoRKRbeTlU1EyRMhU/yuvW0wfvqhO3XJhe/PAbycvGpR/PyESDMuRr AGanQ8wtmQjBXgzmYJn5G3GP266KEzJA9ajOOni9PpkUL86W7AqIWoXDZHAYaY5+ Lu7CMrBlWOHhSxrBdMhdZXcnY3n3fZEqcENhM7xR8poLwlmGH3a/fYIaojg9zW5b dVJ/68Lr/acTloWdAb9GbIsg97CQvaesrO2+ir5nqGlTxgER6S4RPKjf5Zje8MsN 0FnftGC1WXn95QMfz9nm =lZh8 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging Patch queue for ppc - 2014-06-27 Changes include: - instruction emulation fixes - linux-user fixes - mac99: layout fixes - pseries: Initial VFIO support - pseries: support for UUID - pseries: support for -boot m # gpg: Signature made Fri 27 Jun 2014 12:51:01 BST using RSA key ID 03FEDC60 # gpg: Can't check signature: public key not found * remotes/agraf/tags/signed-ppc-for-upstream: (32 commits) PPC: e500: Only create dt entries for existing serial ports spapr_pci: Use XICS interrupt allocator and do not cache interrupts in PHB vmstate: Add preallocation for migrating arrays (VMS_ALLOC flag) xics: Implement xics_ics_free() spapr: Remove @next_irq spapr: Move interrupt allocator to xics xics: Disable flags reset on xics reset xics: Add xics_find_source() xics: Add flags for interrupts spapr: Add RTAS sysparm SPLPAR Characteristics spapr: Add RTAS sysparm UUID spapr: Fix RTAS sysparm DIAGNOSTICS_RUN_MODE spapr: Add rtas_st_buffer utility function spapr: Define a 2.1 pseries machine spapr: Fix code design style (s/SPAPRMachine/sPAPRMachineState) target-ppc: Add support for POWER8 pvr 0x4D0000 uninorth: Fix PCI hole size mac99: Add motherboard devices before PCI cards target-ppc: Remove unused gen_qemu_ld8s() target-ppc: Remove unused IMM and d extract helpers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2d80e0ab4b
182
hw/intc/xics.c
182
hw/intc/xics.c
@ -437,7 +437,7 @@ static void ics_set_irq(void *opaque, int srcno, int val)
|
||||
{
|
||||
ICSState *ics = (ICSState *)opaque;
|
||||
|
||||
if (ics->islsi[srcno]) {
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
set_irq_lsi(ics, srcno, val);
|
||||
} else {
|
||||
set_irq_msi(ics, srcno, val);
|
||||
@ -474,7 +474,7 @@ static void ics_write_xive(ICSState *ics, int nr, int server,
|
||||
|
||||
trace_xics_ics_write_xive(nr, srcno, server, priority);
|
||||
|
||||
if (ics->islsi[srcno]) {
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
write_xive_lsi(ics, srcno);
|
||||
} else {
|
||||
write_xive_msi(ics, srcno);
|
||||
@ -496,7 +496,7 @@ static void ics_resend(ICSState *ics)
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
/* FIXME: filter by server#? */
|
||||
if (ics->islsi[i]) {
|
||||
if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
resend_lsi(ics, i);
|
||||
} else {
|
||||
resend_msi(ics, i);
|
||||
@ -511,7 +511,7 @@ static void ics_eoi(ICSState *ics, int nr)
|
||||
|
||||
trace_xics_ics_eoi(nr);
|
||||
|
||||
if (ics->islsi[srcno]) {
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
irq->status &= ~XICS_STATUS_SENT;
|
||||
}
|
||||
}
|
||||
@ -520,11 +520,18 @@ static void ics_reset(DeviceState *dev)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
int i;
|
||||
uint8_t flags[ics->nr_irqs];
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
flags[i] = ics->irqs[i].flags;
|
||||
}
|
||||
|
||||
memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
ics->irqs[i].priority = 0xff;
|
||||
ics->irqs[i].saved_priority = 0xff;
|
||||
ics->irqs[i].flags = flags[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,13 +570,14 @@ static int ics_dispatch_post_load(void *opaque, int version_id)
|
||||
|
||||
static const VMStateDescription vmstate_ics_irq = {
|
||||
.name = "ics/irq",
|
||||
.version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(server, ICSIRQState),
|
||||
VMSTATE_UINT8(priority, ICSIRQState),
|
||||
VMSTATE_UINT8(saved_priority, ICSIRQState),
|
||||
VMSTATE_UINT8(status, ICSIRQState),
|
||||
VMSTATE_UINT8(flags, ICSIRQState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
@ -606,7 +614,6 @@ static void ics_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
|
||||
ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool));
|
||||
ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
|
||||
}
|
||||
|
||||
@ -633,21 +640,166 @@ static const TypeInfo ics_info = {
|
||||
/*
|
||||
* Exported functions
|
||||
*/
|
||||
static int xics_find_source(XICSState *icp, int irq)
|
||||
{
|
||||
int sources = 1;
|
||||
int src;
|
||||
|
||||
/* FIXME: implement multiple sources */
|
||||
for (src = 0; src < sources; ++src) {
|
||||
ICSState *ics = &icp->ics[src];
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
qemu_irq xics_get_qirq(XICSState *icp, int irq)
|
||||
{
|
||||
if (!ics_valid_irq(icp->ics, irq)) {
|
||||
return NULL;
|
||||
int src = xics_find_source(icp, irq);
|
||||
|
||||
if (src >= 0) {
|
||||
ICSState *ics = &icp->ics[src];
|
||||
return ics->qirqs[irq - ics->offset];
|
||||
}
|
||||
|
||||
return icp->ics->qirqs[irq - icp->ics->offset];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
|
||||
{
|
||||
assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
|
||||
|
||||
ics->irqs[srcno].flags |=
|
||||
lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
|
||||
}
|
||||
|
||||
void xics_set_irq_type(XICSState *icp, int irq, bool lsi)
|
||||
{
|
||||
assert(ics_valid_irq(icp->ics, irq));
|
||||
int src = xics_find_source(icp, irq);
|
||||
ICSState *ics;
|
||||
|
||||
icp->ics->islsi[irq - icp->ics->offset] = lsi;
|
||||
assert(src >= 0);
|
||||
|
||||
ics = &icp->ics[src];
|
||||
ics_set_irq_type(ics, irq - ics->offset, lsi);
|
||||
}
|
||||
|
||||
#define ICS_IRQ_FREE(ics, srcno) \
|
||||
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
|
||||
|
||||
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
|
||||
{
|
||||
int first, i;
|
||||
|
||||
for (first = 0; first < ics->nr_irqs; first += alignnum) {
|
||||
if (num > (ics->nr_irqs - first)) {
|
||||
return -1;
|
||||
}
|
||||
for (i = first; i < first + num; ++i) {
|
||||
if (!ICS_IRQ_FREE(ics, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == (first + num)) {
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi)
|
||||
{
|
||||
ICSState *ics = &icp->ics[src];
|
||||
int irq;
|
||||
|
||||
if (irq_hint) {
|
||||
assert(src == xics_find_source(icp, irq_hint));
|
||||
if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
|
||||
trace_xics_alloc_failed_hint(src, irq_hint);
|
||||
return -1;
|
||||
}
|
||||
irq = irq_hint;
|
||||
} else {
|
||||
irq = ics_find_free_block(ics, 1, 1);
|
||||
if (irq < 0) {
|
||||
trace_xics_alloc_failed_no_left(src);
|
||||
return -1;
|
||||
}
|
||||
irq += ics->offset;
|
||||
}
|
||||
|
||||
ics_set_irq_type(ics, irq - ics->offset, lsi);
|
||||
trace_xics_alloc(src, irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate block of consequtive IRQs, returns a number of the first.
|
||||
* If align==true, aligns the first IRQ number to num.
|
||||
*/
|
||||
int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align)
|
||||
{
|
||||
int i, first = -1;
|
||||
ICSState *ics = &icp->ics[src];
|
||||
|
||||
assert(src == 0);
|
||||
/*
|
||||
* MSIMesage::data is used for storing VIRQ so
|
||||
* it has to be aligned to num to support multiple
|
||||
* MSI vectors. MSI-X is not affected by this.
|
||||
* The hint is used for the first IRQ, the rest should
|
||||
* be allocated continuously.
|
||||
*/
|
||||
if (align) {
|
||||
assert((num == 1) || (num == 2) || (num == 4) ||
|
||||
(num == 8) || (num == 16) || (num == 32));
|
||||
first = ics_find_free_block(ics, num, num);
|
||||
} else {
|
||||
first = ics_find_free_block(ics, num, 1);
|
||||
}
|
||||
|
||||
if (first >= 0) {
|
||||
for (i = first; i < first + num; ++i) {
|
||||
ics_set_irq_type(ics, i, lsi);
|
||||
}
|
||||
}
|
||||
first += ics->offset;
|
||||
|
||||
trace_xics_alloc_block(src, first, num, lsi, align);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
static void ics_free(ICSState *ics, int srcno, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = srcno; i < srcno + num; ++i) {
|
||||
if (ICS_IRQ_FREE(ics, i)) {
|
||||
trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset);
|
||||
}
|
||||
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
|
||||
}
|
||||
}
|
||||
|
||||
void xics_free(XICSState *icp, int irq, int num)
|
||||
{
|
||||
int src = xics_find_source(icp, irq);
|
||||
|
||||
if (src >= 0) {
|
||||
ICSState *ics = &icp->ics[src];
|
||||
|
||||
/* FIXME: implement multiple sources */
|
||||
assert(src == 0);
|
||||
|
||||
trace_xics_ics_free(ics - icp->ics, irq, num);
|
||||
ics_free(ics, irq - ics->offset, num);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -866,10 +1018,10 @@ static void xics_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* Registration of global state belongs into realize */
|
||||
spapr_rtas_register("ibm,set-xive", rtas_set_xive);
|
||||
spapr_rtas_register("ibm,get-xive", rtas_get_xive);
|
||||
spapr_rtas_register("ibm,int-off", rtas_int_off);
|
||||
spapr_rtas_register("ibm,int-on", rtas_int_on);
|
||||
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
|
||||
spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
|
||||
spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
|
||||
spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
|
||||
|
||||
spapr_register_hypercall(H_CPPR, h_cppr);
|
||||
spapr_register_hypercall(H_IPI, h_ipi);
|
||||
|
@ -38,10 +38,6 @@
|
||||
typedef struct KVMXICSState {
|
||||
XICSState parent_obj;
|
||||
|
||||
uint32_t set_xive_token;
|
||||
uint32_t get_xive_token;
|
||||
uint32_t int_off_token;
|
||||
uint32_t int_on_token;
|
||||
int kernel_xics_fd;
|
||||
} KVMXICSState;
|
||||
|
||||
@ -224,7 +220,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
|
||||
state |= KVM_XICS_MASKED;
|
||||
}
|
||||
|
||||
if (ics->islsi[i]) {
|
||||
if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
state |= KVM_XICS_LEVEL_SENSITIVE;
|
||||
if (irq->status & XICS_STATUS_ASSERTED) {
|
||||
state |= KVM_XICS_PENDING;
|
||||
@ -253,7 +249,7 @@ static void ics_kvm_set_irq(void *opaque, int srcno, int val)
|
||||
int rc;
|
||||
|
||||
args.irq = srcno + ics->offset;
|
||||
if (!ics->islsi[srcno]) {
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) {
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
@ -271,11 +267,18 @@ static void ics_kvm_reset(DeviceState *dev)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
int i;
|
||||
uint8_t flags[ics->nr_irqs];
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
flags[i] = ics->irqs[i].flags;
|
||||
}
|
||||
|
||||
memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
ics->irqs[i].priority = 0xff;
|
||||
ics->irqs[i].saved_priority = 0xff;
|
||||
ics->irqs[i].flags = flags[i];
|
||||
}
|
||||
|
||||
ics_set_kvm_state(ics, 1);
|
||||
@ -290,7 +293,6 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
|
||||
ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool));
|
||||
ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs);
|
||||
}
|
||||
|
||||
@ -392,32 +394,30 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
icpkvm->set_xive_token = spapr_rtas_register("ibm,set-xive", rtas_dummy);
|
||||
icpkvm->get_xive_token = spapr_rtas_register("ibm,get-xive", rtas_dummy);
|
||||
icpkvm->int_off_token = spapr_rtas_register("ibm,int-off", rtas_dummy);
|
||||
icpkvm->int_on_token = spapr_rtas_register("ibm,int-on", rtas_dummy);
|
||||
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy);
|
||||
spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy);
|
||||
spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy);
|
||||
spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy);
|
||||
|
||||
rc = kvmppc_define_rtas_kernel_token(icpkvm->set_xive_token,
|
||||
"ibm,set-xive");
|
||||
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive");
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = kvmppc_define_rtas_kernel_token(icpkvm->get_xive_token,
|
||||
"ibm,get-xive");
|
||||
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive");
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = kvmppc_define_rtas_kernel_token(icpkvm->int_on_token, "ibm,int-on");
|
||||
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on");
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = kvmppc_define_rtas_kernel_token(icpkvm->int_off_token, "ibm,int-off");
|
||||
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off");
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off");
|
||||
goto fail;
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "qemu/range.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/misc/vfio.h"
|
||||
|
||||
/* #define DEBUG_VFIO */
|
||||
#ifdef DEBUG_VFIO
|
||||
@ -3649,6 +3650,39 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
|
||||
|
||||
container->iommu_data.type1.initialized = true;
|
||||
|
||||
} else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU)) {
|
||||
ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
|
||||
if (ret) {
|
||||
error_report("vfio: failed to set group container: %m");
|
||||
ret = -errno;
|
||||
goto free_container_exit;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_SPAPR_TCE_IOMMU);
|
||||
if (ret) {
|
||||
error_report("vfio: failed to set iommu for container: %m");
|
||||
ret = -errno;
|
||||
goto free_container_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* The host kernel code implementing VFIO_IOMMU_DISABLE is called
|
||||
* when container fd is closed so we do not call it explicitly
|
||||
* in this file.
|
||||
*/
|
||||
ret = ioctl(fd, VFIO_IOMMU_ENABLE);
|
||||
if (ret) {
|
||||
error_report("vfio: failed to enable container: %m");
|
||||
ret = -errno;
|
||||
goto free_container_exit;
|
||||
}
|
||||
|
||||
container->iommu_data.type1.listener = vfio_memory_listener;
|
||||
container->iommu_data.release = vfio_listener_release;
|
||||
|
||||
memory_listener_register(&container->iommu_data.type1.listener,
|
||||
container->space->as);
|
||||
|
||||
} else {
|
||||
error_report("vfio: No available IOMMU models");
|
||||
ret = -EINVAL;
|
||||
@ -4318,3 +4352,47 @@ static void register_vfio_pci_dev_type(void)
|
||||
}
|
||||
|
||||
type_init(register_vfio_pci_dev_type)
|
||||
|
||||
static int vfio_container_do_ioctl(AddressSpace *as, int32_t groupid,
|
||||
int req, void *param)
|
||||
{
|
||||
VFIOGroup *group;
|
||||
VFIOContainer *container;
|
||||
int ret = -1;
|
||||
|
||||
group = vfio_get_group(groupid, as);
|
||||
if (!group) {
|
||||
error_report("vfio: group %d not registered", groupid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
container = group->container;
|
||||
if (group->container) {
|
||||
ret = ioctl(container->fd, req, param);
|
||||
if (ret < 0) {
|
||||
error_report("vfio: failed to ioctl container: ret=%d, %s",
|
||||
ret, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
vfio_put_group(group);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vfio_container_ioctl(AddressSpace *as, int32_t groupid,
|
||||
int req, void *param)
|
||||
{
|
||||
/* We allow only certain ioctls to the container */
|
||||
switch (req) {
|
||||
case VFIO_CHECK_EXTENSION:
|
||||
case VFIO_IOMMU_SPAPR_TCE_GET_INFO:
|
||||
break;
|
||||
default:
|
||||
/* Return an error on unknown requests */
|
||||
error_report("vfio: unsupported ioctl %X", req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return vfio_container_do_ioctl(as, groupid, req, param);
|
||||
}
|
||||
|
@ -153,8 +153,8 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
spapr_rtas_register("nvram-fetch", rtas_nvram_fetch);
|
||||
spapr_rtas_register("nvram-store", rtas_nvram_store);
|
||||
spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
|
||||
spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
|
||||
d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
|
||||
memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL);
|
||||
memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio,
|
||||
0x80000000ULL, 0x70000000ULL);
|
||||
0x80000000ULL, 0x10000000ULL);
|
||||
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
|
||||
&d->pci_hole);
|
||||
|
||||
|
@ -4,6 +4,9 @@ obj-y += ppc.o ppc_booke.o
|
||||
obj-$(CONFIG_PSERIES) += spapr.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
|
||||
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
|
||||
obj-y += spapr_pci_vfio.o
|
||||
endif
|
||||
# PowerPC 4xx boards
|
||||
obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
|
||||
obj-y += ppc4xx_pci.o
|
||||
|
@ -316,10 +316,15 @@ static int ppce500_load_device_tree(MachineState *machine,
|
||||
* device it finds in the dt as serial output device. And we generate
|
||||
* devices in reverse order to the dt.
|
||||
*/
|
||||
if (serial_hds[1]) {
|
||||
dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
|
||||
soc, mpic, "serial1", 1, false);
|
||||
}
|
||||
|
||||
if (serial_hds[0]) {
|
||||
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
|
||||
soc, mpic, "serial0", 0, true);
|
||||
}
|
||||
|
||||
snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
|
||||
MPC8544_UTIL_OFFSET);
|
||||
|
@ -373,18 +373,11 @@ static void ppc_core99_init(MachineState *machine)
|
||||
machine_arch = ARCH_MAC99;
|
||||
}
|
||||
/* init basic PC hardware */
|
||||
pci_vga_init(pci_bus);
|
||||
|
||||
escc_mem = escc_init(0, pic[0x25], pic[0x24],
|
||||
serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
|
||||
memory_region_init_alias(escc_bar, NULL, "escc-bar",
|
||||
escc_mem, 0, memory_region_size(escc_mem));
|
||||
|
||||
for(i = 0; i < nb_nics; i++)
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
|
||||
|
||||
ide_drive_get(hd, MAX_IDE_BUS);
|
||||
|
||||
macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO);
|
||||
dev = DEVICE(macio);
|
||||
qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */
|
||||
@ -395,6 +388,8 @@ static void ppc_core99_init(MachineState *machine)
|
||||
macio_init(macio, pic_mem, escc_bar);
|
||||
|
||||
/* We only emulate 2 out of 3 IDE controllers for now */
|
||||
ide_drive_get(hd, MAX_IDE_BUS);
|
||||
|
||||
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
|
||||
"ide[0]"));
|
||||
macio_ide_init_drives(macio_ide, hd);
|
||||
@ -420,8 +415,15 @@ static void ppc_core99_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
|
||||
pci_vga_init(pci_bus);
|
||||
|
||||
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) {
|
||||
graphic_depth = 15;
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
|
||||
}
|
||||
|
||||
/* The NewWorld NVRAM is not located in the MacIO device */
|
||||
dev = qdev_create(NULL, TYPE_MACIO_NVRAM);
|
||||
|
104
hw/ppc/spapr.c
104
hw/ppc/spapr.c
@ -85,16 +85,16 @@
|
||||
|
||||
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
||||
|
||||
typedef struct sPAPRMachineState sPAPRMachineState;
|
||||
|
||||
typedef struct SPAPRMachine SPAPRMachine;
|
||||
#define TYPE_SPAPR_MACHINE "spapr-machine"
|
||||
#define SPAPR_MACHINE(obj) \
|
||||
OBJECT_CHECK(SPAPRMachine, (obj), TYPE_SPAPR_MACHINE)
|
||||
OBJECT_CHECK(sPAPRMachineState, (obj), TYPE_SPAPR_MACHINE)
|
||||
|
||||
/**
|
||||
* SPAPRMachine:
|
||||
* sPAPRMachineState:
|
||||
*/
|
||||
struct SPAPRMachine {
|
||||
struct sPAPRMachineState {
|
||||
/*< private >*/
|
||||
MachineState parent_obj;
|
||||
|
||||
@ -102,76 +102,8 @@ struct SPAPRMachine {
|
||||
char *kvm_type;
|
||||
};
|
||||
|
||||
|
||||
sPAPREnvironment *spapr;
|
||||
|
||||
int spapr_allocate_irq(int hint, bool lsi)
|
||||
{
|
||||
int irq;
|
||||
|
||||
if (hint) {
|
||||
irq = hint;
|
||||
if (hint >= spapr->next_irq) {
|
||||
spapr->next_irq = hint + 1;
|
||||
}
|
||||
/* FIXME: we should probably check for collisions somehow */
|
||||
} else {
|
||||
irq = spapr->next_irq++;
|
||||
}
|
||||
|
||||
/* Configure irq type */
|
||||
if (!xics_get_qirq(spapr->icp, irq)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
xics_set_irq_type(spapr->icp, irq, lsi);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate block of consequtive IRQs, returns a number of the first.
|
||||
* If msi==true, aligns the first IRQ number to num.
|
||||
*/
|
||||
int spapr_allocate_irq_block(int num, bool lsi, bool msi)
|
||||
{
|
||||
int first = -1;
|
||||
int i, hint = 0;
|
||||
|
||||
/*
|
||||
* MSIMesage::data is used for storing VIRQ so
|
||||
* it has to be aligned to num to support multiple
|
||||
* MSI vectors. MSI-X is not affected by this.
|
||||
* The hint is used for the first IRQ, the rest should
|
||||
* be allocated continuously.
|
||||
*/
|
||||
if (msi) {
|
||||
assert((num == 1) || (num == 2) || (num == 4) ||
|
||||
(num == 8) || (num == 16) || (num == 32));
|
||||
hint = (spapr->next_irq + num - 1) & ~(num - 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
int irq;
|
||||
|
||||
irq = spapr_allocate_irq(hint, lsi);
|
||||
if (!irq) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == i) {
|
||||
first = irq;
|
||||
hint = 0;
|
||||
}
|
||||
|
||||
/* If the above doesn't create a consecutive block then that's
|
||||
* an internal bug */
|
||||
assert(irq == (first + i));
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
static XICSState *try_create_xics(const char *type, int nr_servers,
|
||||
int nr_irqs)
|
||||
{
|
||||
@ -442,6 +374,9 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||
if (boot_device) {
|
||||
_FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
|
||||
}
|
||||
if (boot_menu) {
|
||||
_FDT((fdt_property_cell(fdt, "qemu,boot-menu", boot_menu)));
|
||||
}
|
||||
_FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
|
||||
_FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
|
||||
_FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
|
||||
@ -956,7 +891,7 @@ static const VMStateDescription vmstate_spapr = {
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(next_irq, sPAPREnvironment),
|
||||
VMSTATE_UNUSED(4), /* used to be @next_irq */
|
||||
|
||||
/* RTC offset */
|
||||
VMSTATE_UINT64(rtc_offset, sPAPREnvironment),
|
||||
@ -1360,7 +1295,6 @@ static void ppc_spapr_init(MachineState *machine)
|
||||
/* Set up Interrupt Controller before we create the VCPUs */
|
||||
spapr->icp = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads,
|
||||
XICS_IRQS);
|
||||
spapr->next_irq = XICS_IRQ_BASE;
|
||||
|
||||
/* init CPUs */
|
||||
if (cpu_model == NULL) {
|
||||
@ -1619,14 +1553,14 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
||||
|
||||
static char *spapr_get_kvm_type(Object *obj, Error **errp)
|
||||
{
|
||||
SPAPRMachine *sm = SPAPR_MACHINE(obj);
|
||||
sPAPRMachineState *sm = SPAPR_MACHINE(obj);
|
||||
|
||||
return g_strdup(sm->kvm_type);
|
||||
}
|
||||
|
||||
static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
SPAPRMachine *sm = SPAPR_MACHINE(obj);
|
||||
sPAPRMachineState *sm = SPAPR_MACHINE(obj);
|
||||
|
||||
g_free(sm->kvm_type);
|
||||
sm->kvm_type = g_strdup(value);
|
||||
@ -1660,7 +1594,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
static const TypeInfo spapr_machine_info = {
|
||||
.name = TYPE_SPAPR_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(SPAPRMachine),
|
||||
.instance_size = sizeof(sPAPRMachineState),
|
||||
.instance_init = spapr_machine_initfn,
|
||||
.class_init = spapr_machine_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
@ -1669,9 +1603,25 @@ static const TypeInfo spapr_machine_info = {
|
||||
},
|
||||
};
|
||||
|
||||
static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = "pseries-2.1";
|
||||
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
|
||||
mc->is_default = 0;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_machine_2_1_info = {
|
||||
.name = TYPE_SPAPR_MACHINE "2.1",
|
||||
.parent = TYPE_SPAPR_MACHINE,
|
||||
.class_init = spapr_machine_2_1_class_init,
|
||||
};
|
||||
|
||||
static void spapr_machine_register_types(void)
|
||||
{
|
||||
type_register_static(&spapr_machine_info);
|
||||
type_register_static(&spapr_machine_2_1_info);
|
||||
}
|
||||
|
||||
type_init(spapr_machine_register_types)
|
||||
|
@ -314,8 +314,9 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
|
||||
void spapr_events_init(sPAPREnvironment *spapr)
|
||||
{
|
||||
spapr->epow_irq = spapr_allocate_msi(0);
|
||||
spapr->epow_irq = xics_alloc(spapr->icp, 0, 0, false);
|
||||
spapr->epow_notifier.notify = spapr_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&spapr->epow_notifier);
|
||||
spapr_rtas_register("check-exception", check_exception);
|
||||
spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
|
||||
check_exception);
|
||||
}
|
||||
|
@ -118,7 +118,8 @@ static int spapr_tce_table_realize(DeviceState *dev)
|
||||
tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
|
||||
tcet->nb_table <<
|
||||
tcet->page_shift,
|
||||
&tcet->fd);
|
||||
&tcet->fd,
|
||||
tcet->vfio_accel);
|
||||
}
|
||||
|
||||
if (!tcet->table) {
|
||||
@ -142,7 +143,8 @@ static int spapr_tce_table_realize(DeviceState *dev)
|
||||
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
|
||||
uint64_t bus_offset,
|
||||
uint32_t page_shift,
|
||||
uint32_t nb_table)
|
||||
uint32_t nb_table,
|
||||
bool vfio_accel)
|
||||
{
|
||||
sPAPRTCETable *tcet;
|
||||
|
||||
@ -161,6 +163,7 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
|
||||
tcet->bus_offset = bus_offset;
|
||||
tcet->page_shift = page_shift;
|
||||
tcet->nb_table = nb_table;
|
||||
tcet->vfio_accel = vfio_accel;
|
||||
|
||||
object_property_add_child(OBJECT(owner), "tce-table", OBJECT(tcet), NULL);
|
||||
|
||||
|
@ -219,37 +219,13 @@ static void rtas_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
finish_write_pci_config(spapr, 0, addr, size, val, rets);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an entry with config_addr or returns the empty one if not found AND
|
||||
* alloc_new is set.
|
||||
* At the moment the msi_table entries are never released so there is
|
||||
* no point to look till the end of the list if we need to find the free entry.
|
||||
*/
|
||||
static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
|
||||
bool alloc_new)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) {
|
||||
if (!phb->msi_table[i].nvec) {
|
||||
break;
|
||||
}
|
||||
if (phb->msi_table[i].config_addr == config_addr) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) {
|
||||
trace_spapr_pci_msi("Allocating new MSI config", i, config_addr);
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set MSI/MSIX message data.
|
||||
* This is required for msi_notify()/msix_notify() which
|
||||
* will write at the addresses via spapr_msi_write().
|
||||
*
|
||||
* If hwaddr == 0, all entries will have .data == first_irq i.e.
|
||||
* table will be reset.
|
||||
*/
|
||||
static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
|
||||
unsigned first_irq, unsigned req_num)
|
||||
@ -263,9 +239,12 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < req_num; ++i, ++msg.data) {
|
||||
for (i = 0; i < req_num; ++i) {
|
||||
msix_set_message(pdev, i, msg);
|
||||
trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
|
||||
if (addr) {
|
||||
++msg.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,9 +259,12 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
|
||||
unsigned int seq_num = rtas_ld(args, 5);
|
||||
unsigned int ret_intr_type;
|
||||
int ndev, irq, max_irqs = 0;
|
||||
unsigned int irq, max_irqs = 0, num = 0;
|
||||
sPAPRPHBState *phb = NULL;
|
||||
PCIDevice *pdev = NULL;
|
||||
bool msix = false;
|
||||
spapr_pci_msi *msi;
|
||||
int *config_addr_key;
|
||||
|
||||
switch (func) {
|
||||
case RTAS_CHANGE_MSI_FN:
|
||||
@ -310,13 +292,18 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
|
||||
/* Releasing MSIs */
|
||||
if (!req_num) {
|
||||
ndev = spapr_msicfg_find(phb, config_addr, false);
|
||||
if (ndev < 0) {
|
||||
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
|
||||
msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
|
||||
if (!msi) {
|
||||
trace_spapr_pci_msi("Releasing wrong config", config_addr);
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
|
||||
|
||||
xics_free(spapr->icp, msi->first_irq, msi->num);
|
||||
spapr_msi_setmsg(pdev, 0, msix, 0, num);
|
||||
g_hash_table_remove(phb->msi, &config_addr);
|
||||
|
||||
trace_spapr_pci_msi("Released MSIs", config_addr);
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
rtas_st(rets, 1, 0);
|
||||
return;
|
||||
@ -324,15 +311,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
|
||||
/* Enabling MSI */
|
||||
|
||||
/* Find a device number in the map to add or reuse the existing one */
|
||||
ndev = spapr_msicfg_find(phb, config_addr, true);
|
||||
if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
|
||||
error_report("No free entry for a new MSI device");
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
|
||||
|
||||
/* Check if the device supports as many IRQs as requested */
|
||||
if (ret_intr_type == RTAS_TYPE_MSI) {
|
||||
max_irqs = msi_nr_vectors_allocated(pdev);
|
||||
@ -340,48 +318,47 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
max_irqs = pdev->msix_entries_nr;
|
||||
}
|
||||
if (!max_irqs) {
|
||||
error_report("Requested interrupt type %d is not enabled for device#%d",
|
||||
ret_intr_type, ndev);
|
||||
error_report("Requested interrupt type %d is not enabled for device %x",
|
||||
ret_intr_type, config_addr);
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
return;
|
||||
}
|
||||
/* Correct the number if the guest asked for too many */
|
||||
if (req_num > max_irqs) {
|
||||
trace_spapr_pci_msi_retry(config_addr, req_num, max_irqs);
|
||||
req_num = max_irqs;
|
||||
irq = 0; /* to avoid misleading trace */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check if there is an old config and MSI number has not changed */
|
||||
if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
|
||||
/* Unexpected behaviour */
|
||||
error_report("Cannot reuse MSI config for device#%d", ndev);
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* There is no cached config, allocate MSIs */
|
||||
if (!phb->msi_table[ndev].nvec) {
|
||||
irq = spapr_allocate_irq_block(req_num, false,
|
||||
/* Allocate MSIs */
|
||||
irq = xics_alloc_block(spapr->icp, 0, req_num, false,
|
||||
ret_intr_type == RTAS_TYPE_MSI);
|
||||
if (irq < 0) {
|
||||
error_report("Cannot allocate MSIs for device#%d", ndev);
|
||||
if (!irq) {
|
||||
error_report("Cannot allocate MSIs for device %x", config_addr);
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
phb->msi_table[ndev].irq = irq;
|
||||
phb->msi_table[ndev].nvec = req_num;
|
||||
phb->msi_table[ndev].config_addr = config_addr;
|
||||
}
|
||||
|
||||
/* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
|
||||
spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX,
|
||||
phb->msi_table[ndev].irq, req_num);
|
||||
irq, req_num);
|
||||
|
||||
/* Add MSI device to cache */
|
||||
msi = g_new(spapr_pci_msi, 1);
|
||||
msi->first_irq = irq;
|
||||
msi->num = req_num;
|
||||
config_addr_key = g_new(int, 1);
|
||||
*config_addr_key = config_addr;
|
||||
g_hash_table_insert(phb->msi, config_addr_key, msi);
|
||||
|
||||
out:
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
rtas_st(rets, 1, req_num);
|
||||
rtas_st(rets, 2, ++seq_num);
|
||||
rtas_st(rets, 3, ret_intr_type);
|
||||
|
||||
trace_spapr_pci_rtas_ibm_change_msi(func, req_num);
|
||||
trace_spapr_pci_rtas_ibm_change_msi(config_addr, func, req_num, irq);
|
||||
}
|
||||
|
||||
static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
|
||||
@ -395,25 +372,28 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
|
||||
uint32_t config_addr = rtas_ld(args, 0);
|
||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||
unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
|
||||
int ndev;
|
||||
sPAPRPHBState *phb = NULL;
|
||||
PCIDevice *pdev = NULL;
|
||||
spapr_pci_msi *msi;
|
||||
|
||||
/* Fins sPAPRPHBState */
|
||||
/* Find sPAPRPHBState */
|
||||
phb = find_phb(spapr, buid);
|
||||
if (!phb) {
|
||||
if (phb) {
|
||||
pdev = find_dev(spapr, buid, config_addr);
|
||||
}
|
||||
if (!phb || !pdev) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find device descriptor and start IRQ */
|
||||
ndev = spapr_msicfg_find(phb, config_addr, false);
|
||||
if (ndev < 0) {
|
||||
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
|
||||
msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
|
||||
if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) {
|
||||
trace_spapr_pci_msi("Failed to return vector", config_addr);
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
|
||||
intr_src_num = msi->first_irq + ioa_intr_num;
|
||||
trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
|
||||
intr_src_num);
|
||||
|
||||
@ -634,7 +614,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||
uint32_t irq;
|
||||
|
||||
irq = spapr_allocate_lsi(0);
|
||||
irq = xics_alloc_block(spapr->icp, 0, 1, true, false);
|
||||
if (!irq) {
|
||||
error_setg(errp, "spapr_allocate_lsi failed");
|
||||
return;
|
||||
@ -649,6 +629,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
info->finish_realize(sphb, errp);
|
||||
|
||||
sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
|
||||
}
|
||||
|
||||
static void spapr_phb_finish_realize(sPAPRPHBState *sphb, Error **errp)
|
||||
@ -658,7 +640,7 @@ static void spapr_phb_finish_realize(sPAPRPHBState *sphb, Error **errp)
|
||||
tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn,
|
||||
0,
|
||||
SPAPR_TCE_PAGE_SHIFT,
|
||||
0x40000000 >> SPAPR_TCE_PAGE_SHIFT);
|
||||
0x40000000 >> SPAPR_TCE_PAGE_SHIFT, false);
|
||||
if (!tcet) {
|
||||
error_setg(errp, "Unable to create TCE table for %s",
|
||||
sphb->dtbusname);
|
||||
@ -712,22 +694,69 @@ static const VMStateDescription vmstate_spapr_pci_lsi = {
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_spapr_pci_msi = {
|
||||
.name = "spapr_pci/lsi",
|
||||
.name = "spapr_pci/msi",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(config_addr, struct spapr_pci_msi),
|
||||
VMSTATE_UINT32(irq, struct spapr_pci_msi),
|
||||
VMSTATE_UINT32(nvec, struct spapr_pci_msi),
|
||||
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT32(key, spapr_pci_msi_mig),
|
||||
VMSTATE_UINT32(value.first_irq, spapr_pci_msi_mig),
|
||||
VMSTATE_UINT32(value.num, spapr_pci_msi_mig),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static void spapr_pci_pre_save(void *opaque)
|
||||
{
|
||||
sPAPRPHBState *sphb = opaque;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
int i;
|
||||
|
||||
if (sphb->msi_devs) {
|
||||
g_free(sphb->msi_devs);
|
||||
sphb->msi_devs = NULL;
|
||||
}
|
||||
sphb->msi_devs_num = g_hash_table_size(sphb->msi);
|
||||
if (!sphb->msi_devs_num) {
|
||||
return;
|
||||
}
|
||||
sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig));
|
||||
|
||||
g_hash_table_iter_init(&iter, sphb->msi);
|
||||
for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
|
||||
sphb->msi_devs[i].key = *(uint32_t *) key;
|
||||
sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
|
||||
}
|
||||
}
|
||||
|
||||
static int spapr_pci_post_load(void *opaque, int version_id)
|
||||
{
|
||||
sPAPRPHBState *sphb = opaque;
|
||||
gpointer key, value;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sphb->msi_devs_num; ++i) {
|
||||
key = g_memdup(&sphb->msi_devs[i].key,
|
||||
sizeof(sphb->msi_devs[i].key));
|
||||
value = g_memdup(&sphb->msi_devs[i].value,
|
||||
sizeof(sphb->msi_devs[i].value));
|
||||
g_hash_table_insert(sphb->msi, key, value);
|
||||
}
|
||||
if (sphb->msi_devs) {
|
||||
g_free(sphb->msi_devs);
|
||||
sphb->msi_devs = NULL;
|
||||
}
|
||||
sphb->msi_devs_num = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_spapr_pci = {
|
||||
.name = "spapr_pci",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.pre_save = spapr_pci_pre_save,
|
||||
.post_load = spapr_pci_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState),
|
||||
VMSTATE_UINT32_EQUAL(dma_liobn, sPAPRPHBState),
|
||||
@ -737,9 +766,9 @@ static const VMStateDescription vmstate_spapr_pci = {
|
||||
VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
|
||||
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
|
||||
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
|
||||
VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0,
|
||||
vmstate_spapr_pci_msi, struct spapr_pci_msi),
|
||||
|
||||
VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
|
||||
VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, sPAPRPHBState, msi_devs_num, 0,
|
||||
vmstate_spapr_pci_msi, spapr_pci_msi_mig),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
@ -909,14 +938,20 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
||||
|
||||
void spapr_pci_rtas_init(void)
|
||||
{
|
||||
spapr_rtas_register("read-pci-config", rtas_read_pci_config);
|
||||
spapr_rtas_register("write-pci-config", rtas_write_pci_config);
|
||||
spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
|
||||
spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
|
||||
spapr_rtas_register(RTAS_READ_PCI_CONFIG, "read-pci-config",
|
||||
rtas_read_pci_config);
|
||||
spapr_rtas_register(RTAS_WRITE_PCI_CONFIG, "write-pci-config",
|
||||
rtas_write_pci_config);
|
||||
spapr_rtas_register(RTAS_IBM_READ_PCI_CONFIG, "ibm,read-pci-config",
|
||||
rtas_ibm_read_pci_config);
|
||||
spapr_rtas_register(RTAS_IBM_WRITE_PCI_CONFIG, "ibm,write-pci-config",
|
||||
rtas_ibm_write_pci_config);
|
||||
if (msi_supported) {
|
||||
spapr_rtas_register("ibm,query-interrupt-source-number",
|
||||
spapr_rtas_register(RTAS_IBM_QUERY_INTERRUPT_SOURCE_NUMBER,
|
||||
"ibm,query-interrupt-source-number",
|
||||
rtas_ibm_query_interrupt_source_number);
|
||||
spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi);
|
||||
spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
|
||||
rtas_ibm_change_msi);
|
||||
}
|
||||
}
|
||||
|
||||
|
102
hw/ppc/spapr_pci_vfio.c
Normal file
102
hw/ppc/spapr_pci_vfio.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* QEMU sPAPR PCI host for VFIO
|
||||
*
|
||||
* Copyright (c) 2011-2014 Alexey Kardashevskiy, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/pci-host/spapr.h"
|
||||
#include "linux/vfio.h"
|
||||
#include "hw/misc/vfio.h"
|
||||
|
||||
static Property spapr_phb_vfio_properties[] = {
|
||||
DEFINE_PROP_INT32("iommu", sPAPRPHBVFIOState, iommugroupid, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void spapr_phb_vfio_finish_realize(sPAPRPHBState *sphb, Error **errp)
|
||||
{
|
||||
sPAPRPHBVFIOState *svphb = SPAPR_PCI_VFIO_HOST_BRIDGE(sphb);
|
||||
struct vfio_iommu_spapr_tce_info info = { .argsz = sizeof(info) };
|
||||
int ret;
|
||||
sPAPRTCETable *tcet;
|
||||
uint32_t liobn = svphb->phb.dma_liobn;
|
||||
|
||||
if (svphb->iommugroupid == -1) {
|
||||
error_setg(errp, "Wrong IOMMU group ID %d", svphb->iommugroupid);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vfio_container_ioctl(&svphb->phb.iommu_as, svphb->iommugroupid,
|
||||
VFIO_CHECK_EXTENSION,
|
||||
(void *) VFIO_SPAPR_TCE_IOMMU);
|
||||
if (ret != 1) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"spapr-vfio: SPAPR extension is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vfio_container_ioctl(&svphb->phb.iommu_as, svphb->iommugroupid,
|
||||
VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"spapr-vfio: get info from container failed");
|
||||
return;
|
||||
}
|
||||
|
||||
tcet = spapr_tce_new_table(DEVICE(sphb), liobn, info.dma32_window_start,
|
||||
SPAPR_TCE_PAGE_SHIFT,
|
||||
info.dma32_window_size >> SPAPR_TCE_PAGE_SHIFT,
|
||||
true);
|
||||
if (!tcet) {
|
||||
error_setg(errp, "spapr-vfio: failed to create VFIO TCE table");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Register default 32bit DMA window */
|
||||
memory_region_add_subregion(&sphb->iommu_root, tcet->bus_offset,
|
||||
spapr_tce_get_iommu(tcet));
|
||||
}
|
||||
|
||||
static void spapr_phb_vfio_reset(DeviceState *qdev)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_CLASS(klass);
|
||||
|
||||
dc->props = spapr_phb_vfio_properties;
|
||||
dc->reset = spapr_phb_vfio_reset;
|
||||
spc->finish_realize = spapr_phb_vfio_finish_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_phb_vfio_info = {
|
||||
.name = TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE,
|
||||
.parent = TYPE_SPAPR_PCI_HOST_BRIDGE,
|
||||
.instance_size = sizeof(sPAPRPHBVFIOState),
|
||||
.class_init = spapr_phb_vfio_class_init,
|
||||
.class_size = sizeof(sPAPRPHBClass),
|
||||
};
|
||||
|
||||
static void spapr_pci_vfio_register_types(void)
|
||||
{
|
||||
type_register_static(&spapr_phb_vfio_info);
|
||||
}
|
||||
|
||||
type_init(spapr_pci_vfio_register_types)
|
@ -36,9 +36,6 @@
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#define TOKEN_BASE 0x2000
|
||||
#define TOKEN_MAX 0x100
|
||||
|
||||
static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs,
|
||||
target_ulong args,
|
||||
@ -225,8 +222,6 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
env->msr = 0;
|
||||
}
|
||||
|
||||
#define DIAGNOSTICS_RUN_MODE 42
|
||||
|
||||
static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
|
||||
sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs,
|
||||
@ -236,16 +231,28 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
|
||||
target_ulong parameter = rtas_ld(args, 0);
|
||||
target_ulong buffer = rtas_ld(args, 1);
|
||||
target_ulong length = rtas_ld(args, 2);
|
||||
target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
|
||||
target_ulong ret = RTAS_OUT_SUCCESS;
|
||||
|
||||
switch (parameter) {
|
||||
case DIAGNOSTICS_RUN_MODE:
|
||||
if (length == 1) {
|
||||
rtas_st(buffer, 0, 0);
|
||||
ret = RTAS_OUT_SUCCESS;
|
||||
}
|
||||
case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
|
||||
char *param_val = g_strdup_printf("MaxEntCap=%d,MaxPlatProcs=%d",
|
||||
max_cpus, smp_cpus);
|
||||
rtas_st_buffer(buffer, length, (uint8_t *)param_val, strlen(param_val));
|
||||
g_free(param_val);
|
||||
break;
|
||||
}
|
||||
case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: {
|
||||
uint8_t param_val = DIAGNOSTICS_RUN_MODE_DISABLED;
|
||||
|
||||
rtas_st_buffer(buffer, length, ¶m_val, sizeof(param_val));
|
||||
break;
|
||||
}
|
||||
case RTAS_SYSPARM_UUID:
|
||||
rtas_st_buffer(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0));
|
||||
break;
|
||||
default:
|
||||
ret = RTAS_OUT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
rtas_st(rets, 0, ret);
|
||||
}
|
||||
@ -260,7 +267,9 @@ static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
|
||||
target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
|
||||
|
||||
switch (parameter) {
|
||||
case DIAGNOSTICS_RUN_MODE:
|
||||
case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS:
|
||||
case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE:
|
||||
case RTAS_SYSPARM_UUID:
|
||||
ret = RTAS_OUT_NOT_AUTHORIZED;
|
||||
break;
|
||||
}
|
||||
@ -271,17 +280,14 @@ static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
|
||||
static struct rtas_call {
|
||||
const char *name;
|
||||
spapr_rtas_fn fn;
|
||||
} rtas_table[TOKEN_MAX];
|
||||
|
||||
static struct rtas_call *rtas_next = rtas_table;
|
||||
} rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE];
|
||||
|
||||
target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
if ((token >= TOKEN_BASE)
|
||||
&& ((token - TOKEN_BASE) < TOKEN_MAX)) {
|
||||
struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
|
||||
if ((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)) {
|
||||
struct rtas_call *call = rtas_table + (token - RTAS_TOKEN_BASE);
|
||||
|
||||
if (call->fn) {
|
||||
call->fn(cpu, spapr, token, nargs, args, nret, rets);
|
||||
@ -303,23 +309,22 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
int spapr_rtas_register(const char *name, spapr_rtas_fn fn)
|
||||
void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (rtas_next - rtas_table); i++) {
|
||||
if (strcmp(name, rtas_table[i].name) == 0) {
|
||||
fprintf(stderr, "RTAS call \"%s\" registered twice\n", name);
|
||||
if (!((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX))) {
|
||||
fprintf(stderr, "RTAS invalid token 0x%x\n", token);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
token -= RTAS_TOKEN_BASE;
|
||||
if (rtas_table[token].name) {
|
||||
fprintf(stderr, "RTAS call \"%s\" is registered already as 0x%x\n",
|
||||
rtas_table[token].name, token);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
assert(rtas_next < (rtas_table + TOKEN_MAX));
|
||||
|
||||
rtas_next->name = name;
|
||||
rtas_next->fn = fn;
|
||||
|
||||
return (rtas_next++ - rtas_table) + TOKEN_BASE;
|
||||
rtas_table[token].name = name;
|
||||
rtas_table[token].fn = fn;
|
||||
}
|
||||
|
||||
int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
@ -359,7 +364,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < TOKEN_MAX; i++) {
|
||||
for (i = 0; i < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; i++) {
|
||||
struct rtas_call *call = &rtas_table[i];
|
||||
|
||||
if (!call->name) {
|
||||
@ -367,7 +372,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
}
|
||||
|
||||
ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
|
||||
i + TOKEN_BASE);
|
||||
i + RTAS_TOKEN_BASE);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
|
||||
call->name, fdt_strerror(ret));
|
||||
@ -380,18 +385,24 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
|
||||
static void core_rtas_register_types(void)
|
||||
{
|
||||
spapr_rtas_register("display-character", rtas_display_character);
|
||||
spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
|
||||
spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
|
||||
spapr_rtas_register("power-off", rtas_power_off);
|
||||
spapr_rtas_register("system-reboot", rtas_system_reboot);
|
||||
spapr_rtas_register("query-cpu-stopped-state",
|
||||
spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",
|
||||
rtas_display_character);
|
||||
spapr_rtas_register(RTAS_GET_TIME_OF_DAY, "get-time-of-day",
|
||||
rtas_get_time_of_day);
|
||||
spapr_rtas_register(RTAS_SET_TIME_OF_DAY, "set-time-of-day",
|
||||
rtas_set_time_of_day);
|
||||
spapr_rtas_register(RTAS_POWER_OFF, "power-off", rtas_power_off);
|
||||
spapr_rtas_register(RTAS_SYSTEM_REBOOT, "system-reboot",
|
||||
rtas_system_reboot);
|
||||
spapr_rtas_register(RTAS_QUERY_CPU_STOPPED_STATE, "query-cpu-stopped-state",
|
||||
rtas_query_cpu_stopped_state);
|
||||
spapr_rtas_register("start-cpu", rtas_start_cpu);
|
||||
spapr_rtas_register("stop-self", rtas_stop_self);
|
||||
spapr_rtas_register("ibm,get-system-parameter",
|
||||
spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
|
||||
spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
|
||||
spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
|
||||
"ibm,get-system-parameter",
|
||||
rtas_ibm_get_system_parameter);
|
||||
spapr_rtas_register("ibm,set-system-parameter",
|
||||
spapr_rtas_register(RTAS_IBM_SET_SYSTEM_PARAMETER,
|
||||
"ibm,set-system-parameter",
|
||||
rtas_ibm_set_system_parameter);
|
||||
}
|
||||
|
||||
|
@ -449,7 +449,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
|
||||
dev->qdev.id = id;
|
||||
}
|
||||
|
||||
dev->irq = spapr_allocate_msi(dev->irq);
|
||||
dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false);
|
||||
if (!dev->irq) {
|
||||
return -1;
|
||||
}
|
||||
@ -460,7 +460,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
|
||||
0,
|
||||
SPAPR_TCE_PAGE_SHIFT,
|
||||
pc->rtce_window_size >>
|
||||
SPAPR_TCE_PAGE_SHIFT);
|
||||
SPAPR_TCE_PAGE_SHIFT, false);
|
||||
address_space_init(&dev->as, spapr_tce_get_iommu(dev->tcet), qdev->id);
|
||||
}
|
||||
|
||||
@ -517,8 +517,9 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
|
||||
spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
|
||||
|
||||
/* RTAS calls */
|
||||
spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
|
||||
spapr_rtas_register("quiesce", rtas_quiesce);
|
||||
spapr_rtas_register(RTAS_IBM_SET_TCE_BYPASS, "ibm,set-tce-bypass",
|
||||
rtas_set_tce_bypass);
|
||||
spapr_rtas_register(RTAS_QUIESCE, "quiesce", rtas_quiesce);
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
9
include/hw/misc/vfio.h
Normal file
9
include/hw/misc/vfio.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef VFIO_API_H
|
||||
#define VFIO_API_H
|
||||
|
||||
#include "qemu/typedefs.h"
|
||||
|
||||
extern int vfio_container_ioctl(AddressSpace *as, int32_t groupid,
|
||||
int req, void *param);
|
||||
|
||||
#endif
|
@ -27,13 +27,15 @@
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/ppc/xics.h"
|
||||
|
||||
#define SPAPR_MSIX_MAX_DEVS 32
|
||||
|
||||
#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
|
||||
#define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge"
|
||||
|
||||
#define SPAPR_PCI_HOST_BRIDGE(obj) \
|
||||
OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
|
||||
|
||||
#define SPAPR_PCI_VFIO_HOST_BRIDGE(obj) \
|
||||
OBJECT_CHECK(sPAPRPHBVFIOState, (obj), TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE)
|
||||
|
||||
#define SPAPR_PCI_HOST_BRIDGE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(sPAPRPHBClass, (klass), TYPE_SPAPR_PCI_HOST_BRIDGE)
|
||||
#define SPAPR_PCI_HOST_BRIDGE_GET_CLASS(obj) \
|
||||
@ -41,6 +43,7 @@
|
||||
|
||||
typedef struct sPAPRPHBClass sPAPRPHBClass;
|
||||
typedef struct sPAPRPHBState sPAPRPHBState;
|
||||
typedef struct sPAPRPHBVFIOState sPAPRPHBVFIOState;
|
||||
|
||||
struct sPAPRPHBClass {
|
||||
PCIHostBridgeClass parent_class;
|
||||
@ -48,6 +51,16 @@ struct sPAPRPHBClass {
|
||||
void (*finish_realize)(sPAPRPHBState *sphb, Error **errp);
|
||||
};
|
||||
|
||||
typedef struct spapr_pci_msi {
|
||||
uint32_t first_irq;
|
||||
uint32_t num;
|
||||
} spapr_pci_msi;
|
||||
|
||||
typedef struct spapr_pci_msi_mig {
|
||||
uint32_t key;
|
||||
spapr_pci_msi value;
|
||||
} spapr_pci_msi_mig;
|
||||
|
||||
struct sPAPRPHBState {
|
||||
PCIHostState parent_obj;
|
||||
|
||||
@ -67,15 +80,20 @@ struct sPAPRPHBState {
|
||||
uint32_t irq;
|
||||
} lsi_table[PCI_NUM_PINS];
|
||||
|
||||
struct spapr_pci_msi {
|
||||
uint32_t config_addr;
|
||||
uint32_t irq;
|
||||
uint32_t nvec;
|
||||
} msi_table[SPAPR_MSIX_MAX_DEVS];
|
||||
GHashTable *msi;
|
||||
/* Temporary cache for migration purposes */
|
||||
int32_t msi_devs_num;
|
||||
spapr_pci_msi_mig *msi_devs;
|
||||
|
||||
QLIST_ENTRY(sPAPRPHBState) list;
|
||||
};
|
||||
|
||||
struct sPAPRPHBVFIOState {
|
||||
sPAPRPHBState phb;
|
||||
|
||||
int32_t iommugroupid;
|
||||
};
|
||||
|
||||
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
|
||||
|
||||
#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL
|
||||
|
@ -27,7 +27,6 @@ typedef struct sPAPREnvironment {
|
||||
long rtas_size;
|
||||
void *fdt_skel;
|
||||
target_ulong entry_point;
|
||||
uint32_t next_irq;
|
||||
uint64_t rtc_offset;
|
||||
struct PPCTimebase tb;
|
||||
bool has_graphics;
|
||||
@ -339,16 +338,6 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
|
||||
int spapr_allocate_irq(int hint, bool lsi);
|
||||
int spapr_allocate_irq_block(int num, bool lsi, bool msi);
|
||||
|
||||
static inline int spapr_allocate_msi(int hint)
|
||||
{
|
||||
return spapr_allocate_irq(hint, false);
|
||||
}
|
||||
|
||||
static inline int spapr_allocate_lsi(int hint)
|
||||
{
|
||||
return spapr_allocate_irq(hint, true);
|
||||
}
|
||||
|
||||
/* RTAS return codes */
|
||||
#define RTAS_OUT_SUCCESS 0
|
||||
#define RTAS_OUT_NO_ERRORS_FOUND 1
|
||||
@ -358,6 +347,58 @@ static inline int spapr_allocate_lsi(int hint)
|
||||
#define RTAS_OUT_NOT_SUPPORTED -3
|
||||
#define RTAS_OUT_NOT_AUTHORIZED -9002
|
||||
|
||||
/* RTAS tokens */
|
||||
#define RTAS_TOKEN_BASE 0x2000
|
||||
|
||||
#define RTAS_DISPLAY_CHARACTER (RTAS_TOKEN_BASE + 0x00)
|
||||
#define RTAS_GET_TIME_OF_DAY (RTAS_TOKEN_BASE + 0x01)
|
||||
#define RTAS_SET_TIME_OF_DAY (RTAS_TOKEN_BASE + 0x02)
|
||||
#define RTAS_POWER_OFF (RTAS_TOKEN_BASE + 0x03)
|
||||
#define RTAS_SYSTEM_REBOOT (RTAS_TOKEN_BASE + 0x04)
|
||||
#define RTAS_QUERY_CPU_STOPPED_STATE (RTAS_TOKEN_BASE + 0x05)
|
||||
#define RTAS_START_CPU (RTAS_TOKEN_BASE + 0x06)
|
||||
#define RTAS_STOP_SELF (RTAS_TOKEN_BASE + 0x07)
|
||||
#define RTAS_IBM_GET_SYSTEM_PARAMETER (RTAS_TOKEN_BASE + 0x08)
|
||||
#define RTAS_IBM_SET_SYSTEM_PARAMETER (RTAS_TOKEN_BASE + 0x09)
|
||||
#define RTAS_IBM_SET_XIVE (RTAS_TOKEN_BASE + 0x0A)
|
||||
#define RTAS_IBM_GET_XIVE (RTAS_TOKEN_BASE + 0x0B)
|
||||
#define RTAS_IBM_INT_OFF (RTAS_TOKEN_BASE + 0x0C)
|
||||
#define RTAS_IBM_INT_ON (RTAS_TOKEN_BASE + 0x0D)
|
||||
#define RTAS_CHECK_EXCEPTION (RTAS_TOKEN_BASE + 0x0E)
|
||||
#define RTAS_EVENT_SCAN (RTAS_TOKEN_BASE + 0x0F)
|
||||
#define RTAS_IBM_SET_TCE_BYPASS (RTAS_TOKEN_BASE + 0x10)
|
||||
#define RTAS_QUIESCE (RTAS_TOKEN_BASE + 0x11)
|
||||
#define RTAS_NVRAM_FETCH (RTAS_TOKEN_BASE + 0x12)
|
||||
#define RTAS_NVRAM_STORE (RTAS_TOKEN_BASE + 0x13)
|
||||
#define RTAS_READ_PCI_CONFIG (RTAS_TOKEN_BASE + 0x14)
|
||||
#define RTAS_WRITE_PCI_CONFIG (RTAS_TOKEN_BASE + 0x15)
|
||||
#define RTAS_IBM_READ_PCI_CONFIG (RTAS_TOKEN_BASE + 0x16)
|
||||
#define RTAS_IBM_WRITE_PCI_CONFIG (RTAS_TOKEN_BASE + 0x17)
|
||||
#define RTAS_IBM_QUERY_INTERRUPT_SOURCE_NUMBER (RTAS_TOKEN_BASE + 0x18)
|
||||
#define RTAS_IBM_CHANGE_MSI (RTAS_TOKEN_BASE + 0x19)
|
||||
#define RTAS_SET_INDICATOR (RTAS_TOKEN_BASE + 0x1A)
|
||||
#define RTAS_SET_POWER_LEVEL (RTAS_TOKEN_BASE + 0x1B)
|
||||
#define RTAS_GET_POWER_LEVEL (RTAS_TOKEN_BASE + 0x1C)
|
||||
#define RTAS_GET_SENSOR_STATE (RTAS_TOKEN_BASE + 0x1D)
|
||||
#define RTAS_IBM_CONFIGURE_CONNECTOR (RTAS_TOKEN_BASE + 0x1E)
|
||||
#define RTAS_IBM_OS_TERM (RTAS_TOKEN_BASE + 0x1F)
|
||||
#define RTAS_IBM_EXTENDED_OS_TERM (RTAS_TOKEN_BASE + 0x20)
|
||||
|
||||
#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x21)
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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;
|
||||
@ -373,11 +414,24 @@ static inline void rtas_st(target_ulong phys, int n, uint32_t val)
|
||||
stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val);
|
||||
}
|
||||
|
||||
|
||||
static inline void rtas_st_buffer(target_ulong phys, target_ulong phys_len,
|
||||
uint8_t *buffer, uint16_t buffer_len)
|
||||
{
|
||||
if (phys_len < 2) {
|
||||
return;
|
||||
}
|
||||
stw_be_phys(&address_space_memory,
|
||||
ppc64_phys_to_real(phys), buffer_len);
|
||||
cpu_physical_memory_write(ppc64_phys_to_real(phys + 2),
|
||||
buffer, MIN(buffer_len, phys_len - 2));
|
||||
}
|
||||
|
||||
typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
uint32_t token,
|
||||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets);
|
||||
int spapr_rtas_register(const char *name, spapr_rtas_fn fn);
|
||||
void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn);
|
||||
target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets);
|
||||
@ -407,6 +461,7 @@ struct sPAPRTCETable {
|
||||
uint32_t page_shift;
|
||||
uint64_t *table;
|
||||
bool bypass;
|
||||
bool vfio_accel;
|
||||
int fd;
|
||||
MemoryRegion iommu;
|
||||
QLIST_ENTRY(sPAPRTCETable) list;
|
||||
@ -418,7 +473,8 @@ int spapr_h_cas_compose_response(target_ulong addr, target_ulong size);
|
||||
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
|
||||
uint64_t bus_offset,
|
||||
uint32_t page_shift,
|
||||
uint32_t nb_table);
|
||||
uint32_t nb_table,
|
||||
bool vfio_accel);
|
||||
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet);
|
||||
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass);
|
||||
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
|
@ -136,7 +136,6 @@ struct ICSState {
|
||||
uint32_t nr_irqs;
|
||||
uint32_t offset;
|
||||
qemu_irq *qirqs;
|
||||
bool *islsi;
|
||||
ICSIRQState *irqs;
|
||||
XICSState *icp;
|
||||
};
|
||||
@ -150,12 +149,20 @@ struct ICSIRQState {
|
||||
#define XICS_STATUS_REJECTED 0x4
|
||||
#define XICS_STATUS_MASKED_PENDING 0x8
|
||||
uint8_t status;
|
||||
/* (flags & XICS_FLAGS_IRQ_MASK) == 0 means the interrupt is not allocated */
|
||||
#define XICS_FLAGS_IRQ_LSI 0x1
|
||||
#define XICS_FLAGS_IRQ_MSI 0x2
|
||||
#define XICS_FLAGS_IRQ_MASK 0x3
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define XICS_IRQS 1024
|
||||
|
||||
qemu_irq xics_get_qirq(XICSState *icp, int irq);
|
||||
void xics_set_irq_type(XICSState *icp, int irq, bool lsi);
|
||||
int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi);
|
||||
int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align);
|
||||
void xics_free(XICSState *icp, int irq, int num);
|
||||
|
||||
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu);
|
||||
|
||||
|
@ -101,6 +101,7 @@ enum VMStateFlags {
|
||||
VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/
|
||||
VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/
|
||||
VMS_MUST_EXIST = 0x1000, /* Field must exist in input */
|
||||
VMS_ALLOC = 0x2000, /* Alloc a buffer on the destination */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -429,6 +430,16 @@ extern const VMStateInfo vmstate_info_bitmap;
|
||||
.offset = offsetof(_state, _field), \
|
||||
}
|
||||
|
||||
#define VMSTATE_STRUCT_VARRAY_ALLOC(_field, _state, _field_num, _version, _vmsd, _type) {\
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.vmsd = &(_vmsd), \
|
||||
.num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
|
||||
.size = sizeof(_type), \
|
||||
.flags = VMS_STRUCT|VMS_VARRAY_INT32|VMS_ALLOC|VMS_POINTER, \
|
||||
.offset = vmstate_offset_pointer(_state, _field, _type), \
|
||||
}
|
||||
|
||||
#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
|
@ -736,6 +736,14 @@ enum {
|
||||
|
||||
QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
|
||||
QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
|
||||
|
||||
/* Feature definitions in AT_HWCAP2. */
|
||||
QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
|
||||
QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
|
||||
QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
|
||||
QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
|
||||
QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
|
||||
QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
|
||||
};
|
||||
|
||||
#define ELF_HWCAP get_elf_hwcap()
|
||||
@ -749,6 +757,8 @@ static uint32_t get_elf_hwcap(void)
|
||||
Altivec/FP/SPE support. Anything else is just a bonus. */
|
||||
#define GET_FEATURE(flag, feature) \
|
||||
do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
|
||||
#define GET_FEATURE2(flag, feature) \
|
||||
do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
|
||||
GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
|
||||
GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
|
||||
GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
|
||||
@ -757,7 +767,36 @@ static uint32_t get_elf_hwcap(void)
|
||||
GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
|
||||
GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
|
||||
GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
|
||||
GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
|
||||
GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
|
||||
GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
|
||||
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
|
||||
QEMU_PPC_FEATURE_ARCH_2_06);
|
||||
#undef GET_FEATURE
|
||||
#undef GET_FEATURE2
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
#define ELF_HWCAP2 get_elf_hwcap2()
|
||||
|
||||
static uint32_t get_elf_hwcap2(void)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
|
||||
uint32_t features = 0;
|
||||
|
||||
#define GET_FEATURE(flag, feature) \
|
||||
do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
|
||||
#define GET_FEATURE2(flag, feature) \
|
||||
do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
|
||||
|
||||
GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
|
||||
GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
|
||||
GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
|
||||
PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07);
|
||||
|
||||
#undef GET_FEATURE
|
||||
#undef GET_FEATURE2
|
||||
|
||||
return features;
|
||||
}
|
||||
@ -774,8 +813,9 @@ static uint32_t get_elf_hwcap(void)
|
||||
#define DLINFO_ARCH_ITEMS 5
|
||||
#define ARCH_DLINFO \
|
||||
do { \
|
||||
NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \
|
||||
NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \
|
||||
PowerPCCPU *cpu = POWERPC_CPU(thread_cpu); \
|
||||
NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
|
||||
NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
|
||||
NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
|
||||
/* \
|
||||
* Now handle glibc compatibility. \
|
||||
|
@ -1138,6 +1138,8 @@
|
||||
"POWER7 v2.3")
|
||||
POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7P,
|
||||
"POWER7+ v2.1")
|
||||
POWERPC_DEF("POWER8E_v1.0", CPU_POWERPC_POWER8E_v10, POWER8E,
|
||||
"POWER8E v1.0")
|
||||
POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8,
|
||||
"POWER8 v1.0")
|
||||
POWERPC_DEF("970", CPU_POWERPC_970, 970,
|
||||
@ -1386,6 +1388,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
|
||||
{ "POWER5gs", "POWER5+" },
|
||||
{ "POWER7", "POWER7_v2.3" },
|
||||
{ "POWER7+", "POWER7+_v2.1" },
|
||||
{ "POWER8E", "POWER8E_v1.0" },
|
||||
{ "POWER8", "POWER8_v1.0" },
|
||||
{ "970fx", "970fx_v3.1" },
|
||||
{ "970mp", "970mp_v1.1" },
|
||||
|
@ -559,9 +559,12 @@ enum {
|
||||
CPU_POWERPC_POWER7P_BASE = 0x004A0000,
|
||||
CPU_POWERPC_POWER7P_MASK = 0xFFFF0000,
|
||||
CPU_POWERPC_POWER7P_v21 = 0x004A0201,
|
||||
CPU_POWERPC_POWER8_BASE = 0x004B0000,
|
||||
CPU_POWERPC_POWER8E_BASE = 0x004B0000,
|
||||
CPU_POWERPC_POWER8E_MASK = 0xFFFF0000,
|
||||
CPU_POWERPC_POWER8E_v10 = 0x004B0100,
|
||||
CPU_POWERPC_POWER8_BASE = 0x004D0000,
|
||||
CPU_POWERPC_POWER8_MASK = 0xFFFF0000,
|
||||
CPU_POWERPC_POWER8_v10 = 0x004B0100,
|
||||
CPU_POWERPC_POWER8_v10 = 0x004D0100,
|
||||
CPU_POWERPC_970 = 0x00390202,
|
||||
CPU_POWERPC_970FX_v10 = 0x00391100,
|
||||
CPU_POWERPC_970FX_v20 = 0x003C0200,
|
||||
|
@ -119,7 +119,9 @@ void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
|
||||
fprintf_function cpu_fprintf, int flags);
|
||||
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int ppc64_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque);
|
||||
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
|
@ -2012,7 +2012,7 @@ enum {
|
||||
PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
|
||||
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
|
||||
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
|
||||
PPC2_ALTIVEC_207 | PPC2_ISA207S)
|
||||
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP)
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -21,6 +21,31 @@
|
||||
#include "qemu-common.h"
|
||||
#include "exec/gdbstub.h"
|
||||
|
||||
static int ppc_gdb_register_len_apple(int n)
|
||||
{
|
||||
switch (n) {
|
||||
case 0 ... 31:
|
||||
/* gprs */
|
||||
return 8;
|
||||
case 32 ... 63:
|
||||
/* fprs */
|
||||
return 8;
|
||||
case 64 ... 95:
|
||||
return 16;
|
||||
case 64+32: /* nip */
|
||||
case 65+32: /* msr */
|
||||
case 67+32: /* lr */
|
||||
case 68+32: /* ctr */
|
||||
case 69+32: /* xer */
|
||||
case 70+32: /* fpscr */
|
||||
return 8;
|
||||
case 66+32: /* cr */
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ppc_gdb_register_len(int n)
|
||||
{
|
||||
switch (n) {
|
||||
@ -132,6 +157,65 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
return r;
|
||||
}
|
||||
|
||||
int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int r = ppc_gdb_register_len_apple(n);
|
||||
|
||||
if (!r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (n < 32) {
|
||||
/* gprs */
|
||||
gdb_get_reg64(mem_buf, env->gpr[n]);
|
||||
} else if (n < 64) {
|
||||
/* fprs */
|
||||
stfq_p(mem_buf, env->fpr[n-32]);
|
||||
} else if (n < 96) {
|
||||
/* Altivec */
|
||||
stq_p(mem_buf, n - 64);
|
||||
stq_p(mem_buf + 8, 0);
|
||||
} else {
|
||||
switch (n) {
|
||||
case 64 + 32:
|
||||
gdb_get_reg64(mem_buf, env->nip);
|
||||
break;
|
||||
case 65 + 32:
|
||||
gdb_get_reg64(mem_buf, env->msr);
|
||||
break;
|
||||
case 66 + 32:
|
||||
{
|
||||
uint32_t cr = 0;
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||
}
|
||||
gdb_get_reg32(mem_buf, cr);
|
||||
break;
|
||||
}
|
||||
case 67 + 32:
|
||||
gdb_get_reg64(mem_buf, env->lr);
|
||||
break;
|
||||
case 68 + 32:
|
||||
gdb_get_reg64(mem_buf, env->ctr);
|
||||
break;
|
||||
case 69 + 32:
|
||||
gdb_get_reg64(mem_buf, env->xer);
|
||||
break;
|
||||
case 70 + 32:
|
||||
gdb_get_reg64(mem_buf, env->fpscr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (msr_le) {
|
||||
/* If cpu is in LE mode, convert memory contents to LE. */
|
||||
ppc_gdb_swap_register(mem_buf, n, r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
@ -185,3 +269,56 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
}
|
||||
return r;
|
||||
}
|
||||
int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int r = ppc_gdb_register_len_apple(n);
|
||||
|
||||
if (!r) {
|
||||
return r;
|
||||
}
|
||||
if (msr_le) {
|
||||
/* If cpu is in LE mode, convert memory contents to LE. */
|
||||
ppc_gdb_swap_register(mem_buf, n, r);
|
||||
}
|
||||
if (n < 32) {
|
||||
/* gprs */
|
||||
env->gpr[n] = ldq_p(mem_buf);
|
||||
} else if (n < 64) {
|
||||
/* fprs */
|
||||
env->fpr[n-32] = ldfq_p(mem_buf);
|
||||
} else {
|
||||
switch (n) {
|
||||
case 64 + 32:
|
||||
env->nip = ldq_p(mem_buf);
|
||||
break;
|
||||
case 65 + 32:
|
||||
ppc_store_msr(env, ldq_p(mem_buf));
|
||||
break;
|
||||
case 66 + 32:
|
||||
{
|
||||
uint32_t cr = ldl_p(mem_buf);
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 67 + 32:
|
||||
env->lr = ldq_p(mem_buf);
|
||||
break;
|
||||
case 68 + 32:
|
||||
env->ctr = ldq_p(mem_buf);
|
||||
break;
|
||||
case 69 + 32:
|
||||
env->xer = ldq_p(mem_buf);
|
||||
break;
|
||||
case 70 + 32:
|
||||
/* fpscr */
|
||||
store_fpscr(env, ldq_p(mem_buf), 0xffffffff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ static int cap_ppc_smt;
|
||||
static int cap_ppc_rma;
|
||||
static int cap_spapr_tce;
|
||||
static int cap_spapr_multitce;
|
||||
static int cap_spapr_vfio;
|
||||
static int cap_hior;
|
||||
static int cap_one_reg;
|
||||
static int cap_epr;
|
||||
@ -101,6 +102,7 @@ int kvm_arch_init(KVMState *s)
|
||||
cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
|
||||
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
|
||||
cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE);
|
||||
cap_spapr_vfio = false;
|
||||
cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG);
|
||||
cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
|
||||
cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR);
|
||||
@ -1660,7 +1662,8 @@ bool kvmppc_spapr_use_multitce(void)
|
||||
return cap_spapr_multitce;
|
||||
}
|
||||
|
||||
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
|
||||
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd,
|
||||
bool vfio_accel)
|
||||
{
|
||||
struct kvm_create_spapr_tce args = {
|
||||
.liobn = liobn,
|
||||
@ -1674,7 +1677,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
|
||||
* destroying the table, which the upper layers -will- do
|
||||
*/
|
||||
*pfd = -1;
|
||||
if (!cap_spapr_tce) {
|
||||
if (!cap_spapr_tce || (vfio_accel && !cap_spapr_vfio)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,8 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
|
||||
bool kvmppc_spapr_use_multitce(void);
|
||||
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
|
||||
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd,
|
||||
bool vfio_accel);
|
||||
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
|
||||
int kvmppc_reset_htab(int shift_hint);
|
||||
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
|
||||
@ -144,7 +145,8 @@ static inline bool kvmppc_spapr_use_multitce(void)
|
||||
}
|
||||
|
||||
static inline void *kvmppc_create_spapr_tce(uint32_t liobn,
|
||||
uint32_t window_size, int *fd)
|
||||
uint32_t window_size, int *fd,
|
||||
bool vfio_accel)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -426,7 +426,6 @@ static inline uint32_t SPR(uint32_t opcode)
|
||||
return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
|
||||
}
|
||||
/*** Get constants ***/
|
||||
EXTRACT_HELPER(IMM, 12, 8);
|
||||
/* 16 bits signed immediate value */
|
||||
EXTRACT_SHELPER(SIMM, 0, 16);
|
||||
/* 16 bits unsigned immediate value */
|
||||
@ -459,8 +458,6 @@ EXTRACT_HELPER(FPFLM, 17, 8);
|
||||
EXTRACT_HELPER(FPW, 16, 1);
|
||||
|
||||
/*** Jump target decoding ***/
|
||||
/* Displacement */
|
||||
EXTRACT_SHELPER(d, 0, 16);
|
||||
/* Immediate address */
|
||||
static inline target_ulong LI(uint32_t opcode)
|
||||
{
|
||||
@ -2665,11 +2662,6 @@ static inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2)
|
||||
tcg_gen_qemu_ld8u(arg1, arg2, ctx->mem_idx);
|
||||
}
|
||||
|
||||
static inline void gen_qemu_ld8s(DisasContext *ctx, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
tcg_gen_qemu_ld8s(arg1, arg2, ctx->mem_idx);
|
||||
}
|
||||
|
||||
static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2)
|
||||
{
|
||||
TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask;
|
||||
@ -4123,8 +4115,9 @@ static void gen_mcrxr(DisasContext *ctx)
|
||||
tcg_gen_trunc_tl_i32(t0, cpu_so);
|
||||
tcg_gen_trunc_tl_i32(t1, cpu_ov);
|
||||
tcg_gen_trunc_tl_i32(dst, cpu_ca);
|
||||
tcg_gen_shri_i32(t0, t0, 2);
|
||||
tcg_gen_shri_i32(t1, t1, 1);
|
||||
tcg_gen_shli_i32(t0, t0, 3);
|
||||
tcg_gen_shli_i32(t1, t1, 2);
|
||||
tcg_gen_shli_i32(dst, dst, 1);
|
||||
tcg_gen_or_i32(dst, dst, t0);
|
||||
tcg_gen_or_i32(dst, dst, t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
|
@ -34,6 +34,7 @@
|
||||
//#define PPC_DUMP_CPU
|
||||
//#define PPC_DEBUG_SPR
|
||||
//#define PPC_DUMP_SPR_ACCESSES
|
||||
/* #define USE_APPLE_GDB */
|
||||
|
||||
/* For user-mode emulation, we don't emulate any IRQ controller */
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
@ -8188,16 +8189,16 @@ static void init_proc_POWER8(CPUPPCState *env)
|
||||
init_proc_book3s_64(env, BOOK3S_CPU_POWER8);
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||
POWERPC_FAMILY(POWER8E)(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->fw_name = "PowerPC,POWER8";
|
||||
dc->desc = "POWER8";
|
||||
dc->desc = "POWER8E";
|
||||
dc->props = powerpc_servercpu_properties;
|
||||
pcc->pvr = CPU_POWERPC_POWER8_BASE;
|
||||
pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
|
||||
pcc->pvr = CPU_POWERPC_POWER8E_BASE;
|
||||
pcc->pvr_mask = CPU_POWERPC_POWER8E_MASK;
|
||||
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;
|
||||
pcc->init_proc = init_proc_POWER8;
|
||||
pcc->check_pow = check_pow_nocheck;
|
||||
@ -8251,6 +8252,18 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||
pcc->l1_icache_size = 0x8000;
|
||||
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
ppc_POWER8E_cpu_family_class_init(oc, data);
|
||||
|
||||
dc->desc = "POWER8";
|
||||
pcc->pvr = CPU_POWERPC_POWER8_BASE;
|
||||
pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
|
||||
}
|
||||
#endif /* defined (TARGET_PPC64) */
|
||||
|
||||
|
||||
@ -9667,6 +9680,13 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
|
||||
cc->gdb_num_core_regs = 71;
|
||||
|
||||
#ifdef USE_APPLE_GDB
|
||||
cc->gdb_read_register = ppc_cpu_gdb_read_register_apple;
|
||||
cc->gdb_write_register = ppc_cpu_gdb_write_register_apple;
|
||||
cc->gdb_num_core_regs = 71 + 32;
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
cc->gdb_core_xml_file = "power64-core.xml";
|
||||
#else
|
||||
|
11
trace-events
11
trace-events
@ -1169,12 +1169,13 @@ qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride,
|
||||
qxl_render_update_area_done(void *cookie) "%p"
|
||||
|
||||
# hw/ppc/spapr_pci.c
|
||||
spapr_pci_msi(const char *msg, uint32_t n, uint32_t ca) "%s (device#%d, cfg=%x)"
|
||||
spapr_pci_msi(const char *msg, uint32_t ca) "%s (cfg=%x)"
|
||||
spapr_pci_msi_setup(const char *name, unsigned vector, uint64_t addr) "dev\"%s\" vector %u, addr=%"PRIx64
|
||||
spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %u"
|
||||
spapr_pci_rtas_ibm_change_msi(unsigned cfg, unsigned func, unsigned req, unsigned first) "cfgaddr %x func %u, requested %u, first irq %u"
|
||||
spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
|
||||
spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
|
||||
spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
|
||||
spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) "Guest device at %x asked %u, have only %u"
|
||||
|
||||
# hw/intc/xics.c
|
||||
xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=%#x"
|
||||
@ -1188,6 +1189,12 @@ xics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]"
|
||||
xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x"
|
||||
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
|
||||
xics_ics_eoi(int nr) "ics_eoi: irq %#x"
|
||||
xics_alloc(int src, int irq) "source#%d, irq %d"
|
||||
xics_alloc_failed_hint(int src, int irq) "source#%d, irq %d is already in use"
|
||||
xics_alloc_failed_no_left(int src) "source#%d, no irq left"
|
||||
xics_alloc_block(int src, int first, int num, bool lsi, int align) "source#%d, first irq %d, %d irqs, lsi=%d, alignnum %d"
|
||||
xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
|
||||
xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free"
|
||||
|
||||
# hw/ppc/spapr.c
|
||||
spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes"
|
||||
|
13
vmstate.c
13
vmstate.c
@ -43,11 +43,18 @@ static int vmstate_size(void *opaque, VMStateField *field)
|
||||
return size;
|
||||
}
|
||||
|
||||
static void *vmstate_base_addr(void *opaque, VMStateField *field)
|
||||
static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
|
||||
{
|
||||
void *base_addr = opaque + field->offset;
|
||||
|
||||
if (field->flags & VMS_POINTER) {
|
||||
if (alloc && (field->flags & VMS_ALLOC)) {
|
||||
int n_elems = vmstate_n_elems(opaque, field);
|
||||
if (n_elems) {
|
||||
gsize size = n_elems * field->size;
|
||||
*((void **)base_addr + field->start) = g_malloc(size);
|
||||
}
|
||||
}
|
||||
base_addr = *(void **)base_addr + field->start;
|
||||
}
|
||||
|
||||
@ -81,7 +88,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
|
||||
field->field_exists(opaque, version_id)) ||
|
||||
(!field->field_exists &&
|
||||
field->version_id <= version_id)) {
|
||||
void *base_addr = vmstate_base_addr(opaque, field);
|
||||
void *base_addr = vmstate_base_addr(opaque, field, true);
|
||||
int i, n_elems = vmstate_n_elems(opaque, field);
|
||||
int size = vmstate_size(opaque, field);
|
||||
|
||||
@ -135,7 +142,7 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
||||
while (field->name) {
|
||||
if (!field->field_exists ||
|
||||
field->field_exists(opaque, vmsd->version_id)) {
|
||||
void *base_addr = vmstate_base_addr(opaque, field);
|
||||
void *base_addr = vmstate_base_addr(opaque, field, false);
|
||||
int i, n_elems = vmstate_n_elems(opaque, field);
|
||||
int size = vmstate_size(opaque, field);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user