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:
Peter Maydell 2014-06-29 11:59:00 +01:00
commit 2d80e0ab4b
32 changed files with 976 additions and 315 deletions

View File

@ -437,7 +437,7 @@ static void ics_set_irq(void *opaque, int srcno, int val)
{ {
ICSState *ics = (ICSState *)opaque; ICSState *ics = (ICSState *)opaque;
if (ics->islsi[srcno]) { if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
set_irq_lsi(ics, srcno, val); set_irq_lsi(ics, srcno, val);
} else { } else {
set_irq_msi(ics, srcno, val); 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); 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); write_xive_lsi(ics, srcno);
} else { } else {
write_xive_msi(ics, srcno); write_xive_msi(ics, srcno);
@ -496,7 +496,7 @@ static void ics_resend(ICSState *ics)
for (i = 0; i < ics->nr_irqs; i++) { for (i = 0; i < ics->nr_irqs; i++) {
/* FIXME: filter by server#? */ /* FIXME: filter by server#? */
if (ics->islsi[i]) { if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
resend_lsi(ics, i); resend_lsi(ics, i);
} else { } else {
resend_msi(ics, i); resend_msi(ics, i);
@ -511,7 +511,7 @@ static void ics_eoi(ICSState *ics, int nr)
trace_xics_ics_eoi(nr); trace_xics_ics_eoi(nr);
if (ics->islsi[srcno]) { if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
irq->status &= ~XICS_STATUS_SENT; irq->status &= ~XICS_STATUS_SENT;
} }
} }
@ -520,11 +520,18 @@ static void ics_reset(DeviceState *dev)
{ {
ICSState *ics = ICS(dev); ICSState *ics = ICS(dev);
int i; 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); memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
for (i = 0; i < ics->nr_irqs; i++) { for (i = 0; i < ics->nr_irqs; i++) {
ics->irqs[i].priority = 0xff; ics->irqs[i].priority = 0xff;
ics->irqs[i].saved_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 = { static const VMStateDescription vmstate_ics_irq = {
.name = "ics/irq", .name = "ics/irq",
.version_id = 1, .version_id = 2,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(server, ICSIRQState), VMSTATE_UINT32(server, ICSIRQState),
VMSTATE_UINT8(priority, ICSIRQState), VMSTATE_UINT8(priority, ICSIRQState),
VMSTATE_UINT8(saved_priority, ICSIRQState), VMSTATE_UINT8(saved_priority, ICSIRQState),
VMSTATE_UINT8(status, ICSIRQState), VMSTATE_UINT8(status, ICSIRQState),
VMSTATE_UINT8(flags, ICSIRQState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
}; };
@ -606,7 +614,6 @@ static void ics_realize(DeviceState *dev, Error **errp)
return; return;
} }
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); 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); ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
} }
@ -633,21 +640,166 @@ static const TypeInfo ics_info = {
/* /*
* Exported functions * 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) qemu_irq xics_get_qirq(XICSState *icp, int irq)
{ {
if (!ics_valid_irq(icp->ics, irq)) { int src = xics_find_source(icp, irq);
return NULL;
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) 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 */ /* Registration of global state belongs into realize */
spapr_rtas_register("ibm,set-xive", rtas_set_xive); spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
spapr_rtas_register("ibm,get-xive", rtas_get_xive); spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
spapr_rtas_register("ibm,int-off", rtas_int_off); spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
spapr_rtas_register("ibm,int-on", rtas_int_on); spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
spapr_register_hypercall(H_CPPR, h_cppr); spapr_register_hypercall(H_CPPR, h_cppr);
spapr_register_hypercall(H_IPI, h_ipi); spapr_register_hypercall(H_IPI, h_ipi);

View File

@ -38,10 +38,6 @@
typedef struct KVMXICSState { typedef struct KVMXICSState {
XICSState parent_obj; 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; int kernel_xics_fd;
} KVMXICSState; } KVMXICSState;
@ -224,7 +220,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
state |= KVM_XICS_MASKED; state |= KVM_XICS_MASKED;
} }
if (ics->islsi[i]) { if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
state |= KVM_XICS_LEVEL_SENSITIVE; state |= KVM_XICS_LEVEL_SENSITIVE;
if (irq->status & XICS_STATUS_ASSERTED) { if (irq->status & XICS_STATUS_ASSERTED) {
state |= KVM_XICS_PENDING; state |= KVM_XICS_PENDING;
@ -253,7 +249,7 @@ static void ics_kvm_set_irq(void *opaque, int srcno, int val)
int rc; int rc;
args.irq = srcno + ics->offset; args.irq = srcno + ics->offset;
if (!ics->islsi[srcno]) { if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) {
if (!val) { if (!val) {
return; return;
} }
@ -271,11 +267,18 @@ static void ics_kvm_reset(DeviceState *dev)
{ {
ICSState *ics = ICS(dev); ICSState *ics = ICS(dev);
int i; 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); memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
for (i = 0; i < ics->nr_irqs; i++) { for (i = 0; i < ics->nr_irqs; i++) {
ics->irqs[i].priority = 0xff; ics->irqs[i].priority = 0xff;
ics->irqs[i].saved_priority = 0xff; ics->irqs[i].saved_priority = 0xff;
ics->irqs[i].flags = flags[i];
} }
ics_set_kvm_state(ics, 1); ics_set_kvm_state(ics, 1);
@ -290,7 +293,6 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp)
return; return;
} }
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); 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); 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; goto fail;
} }
icpkvm->set_xive_token = spapr_rtas_register("ibm,set-xive", rtas_dummy); spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy);
icpkvm->get_xive_token = spapr_rtas_register("ibm,get-xive", rtas_dummy); spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy);
icpkvm->int_off_token = spapr_rtas_register("ibm,int-off", rtas_dummy); spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy);
icpkvm->int_on_token = spapr_rtas_register("ibm,int-on", rtas_dummy); spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy);
rc = kvmppc_define_rtas_kernel_token(icpkvm->set_xive_token, rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive");
"ibm,set-xive");
if (rc < 0) { if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive"); error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive");
goto fail; goto fail;
} }
rc = kvmppc_define_rtas_kernel_token(icpkvm->get_xive_token, rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive");
"ibm,get-xive");
if (rc < 0) { if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive"); error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive");
goto fail; 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) { if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on"); error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on");
goto fail; 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) { if (rc < 0) {
error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off"); error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off");
goto fail; goto fail;

View File

@ -39,6 +39,7 @@
#include "qemu/range.h" #include "qemu/range.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/misc/vfio.h"
/* #define DEBUG_VFIO */ /* #define DEBUG_VFIO */
#ifdef DEBUG_VFIO #ifdef DEBUG_VFIO
@ -3649,6 +3650,39 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
container->iommu_data.type1.initialized = true; 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 { } else {
error_report("vfio: No available IOMMU models"); error_report("vfio: No available IOMMU models");
ret = -EINVAL; ret = -EINVAL;
@ -4318,3 +4352,47 @@ static void register_vfio_pci_dev_type(void)
} }
type_init(register_vfio_pci_dev_type) 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);
}

View File

@ -153,8 +153,8 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev)
return -1; return -1;
} }
spapr_rtas_register("nvram-fetch", rtas_nvram_fetch); spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
spapr_rtas_register("nvram-store", rtas_nvram_store); spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
return 0; return 0;
} }

View File

@ -230,7 +230,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
d = UNI_NORTH_PCI_HOST_BRIDGE(dev); d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL); 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, 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, memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole); &d->pci_hole);

View File

@ -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.o spapr_vio.o spapr_events.o
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
obj-$(CONFIG_PSERIES) += spapr_pci.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 # PowerPC 4xx boards
obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
obj-y += ppc4xx_pci.o obj-y += ppc4xx_pci.o

View File

@ -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 * device it finds in the dt as serial output device. And we generate
* devices in reverse order to the dt. * devices in reverse order to the dt.
*/ */
dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, if (serial_hds[1]) {
soc, mpic, "serial1", 1, false); dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, soc, mpic, "serial1", 1, false);
soc, mpic, "serial0", 0, true); }
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, snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
MPC8544_UTIL_OFFSET); MPC8544_UTIL_OFFSET);

View File

@ -373,18 +373,11 @@ static void ppc_core99_init(MachineState *machine)
machine_arch = ARCH_MAC99; machine_arch = ARCH_MAC99;
} }
/* init basic PC hardware */ /* init basic PC hardware */
pci_vga_init(pci_bus);
escc_mem = escc_init(0, pic[0x25], pic[0x24], escc_mem = escc_init(0, pic[0x25], pic[0x24],
serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
memory_region_init_alias(escc_bar, NULL, "escc-bar", memory_region_init_alias(escc_bar, NULL, "escc-bar",
escc_mem, 0, memory_region_size(escc_mem)); 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); macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO);
dev = DEVICE(macio); dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */ 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); macio_init(macio, pic_mem, escc_bar);
/* We only emulate 2 out of 3 IDE controllers for now */ /* 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), macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[0]")); "ide[0]"));
macio_ide_init_drives(macio_ide, hd); 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; 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 */ /* The NewWorld NVRAM is not located in the MacIO device */
dev = qdev_create(NULL, TYPE_MACIO_NVRAM); dev = qdev_create(NULL, TYPE_MACIO_NVRAM);

View File

@ -85,16 +85,16 @@
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
typedef struct sPAPRMachineState sPAPRMachineState;
typedef struct SPAPRMachine SPAPRMachine;
#define TYPE_SPAPR_MACHINE "spapr-machine" #define TYPE_SPAPR_MACHINE "spapr-machine"
#define SPAPR_MACHINE(obj) \ #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 >*/ /*< private >*/
MachineState parent_obj; MachineState parent_obj;
@ -102,76 +102,8 @@ struct SPAPRMachine {
char *kvm_type; char *kvm_type;
}; };
sPAPREnvironment *spapr; 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, static XICSState *try_create_xics(const char *type, int nr_servers,
int nr_irqs) int nr_irqs)
{ {
@ -442,6 +374,9 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
if (boot_device) { if (boot_device) {
_FDT((fdt_property_string(fdt, "qemu,boot-device", 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-width", graphic_width)));
_FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height))); _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
_FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth))); _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
@ -956,7 +891,7 @@ static const VMStateDescription vmstate_spapr = {
.version_id = 2, .version_id = 2,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(next_irq, sPAPREnvironment), VMSTATE_UNUSED(4), /* used to be @next_irq */
/* RTC offset */ /* RTC offset */
VMSTATE_UINT64(rtc_offset, sPAPREnvironment), 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 */ /* Set up Interrupt Controller before we create the VCPUs */
spapr->icp = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads, spapr->icp = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads,
XICS_IRQS); XICS_IRQS);
spapr->next_irq = XICS_IRQ_BASE;
/* init CPUs */ /* init CPUs */
if (cpu_model == NULL) { 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) 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); return g_strdup(sm->kvm_type);
} }
static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp) 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); g_free(sm->kvm_type);
sm->kvm_type = g_strdup(value); 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 = { static const TypeInfo spapr_machine_info = {
.name = TYPE_SPAPR_MACHINE, .name = TYPE_SPAPR_MACHINE,
.parent = TYPE_MACHINE, .parent = TYPE_MACHINE,
.instance_size = sizeof(SPAPRMachine), .instance_size = sizeof(sPAPRMachineState),
.instance_init = spapr_machine_initfn, .instance_init = spapr_machine_initfn,
.class_init = spapr_machine_class_init, .class_init = spapr_machine_class_init,
.interfaces = (InterfaceInfo[]) { .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) static void spapr_machine_register_types(void)
{ {
type_register_static(&spapr_machine_info); type_register_static(&spapr_machine_info);
type_register_static(&spapr_machine_2_1_info);
} }
type_init(spapr_machine_register_types) type_init(spapr_machine_register_types)

View File

@ -314,8 +314,9 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
void spapr_events_init(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; spapr->epow_notifier.notify = spapr_powerdown_req;
qemu_register_powerdown_notifier(&spapr->epow_notifier); qemu_register_powerdown_notifier(&spapr->epow_notifier);
spapr_rtas_register("check-exception", check_exception); spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
check_exception);
} }

View File

@ -118,7 +118,8 @@ static int spapr_tce_table_realize(DeviceState *dev)
tcet->table = kvmppc_create_spapr_tce(tcet->liobn, tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
tcet->nb_table << tcet->nb_table <<
tcet->page_shift, tcet->page_shift,
&tcet->fd); &tcet->fd,
tcet->vfio_accel);
} }
if (!tcet->table) { 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, sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
uint64_t bus_offset, uint64_t bus_offset,
uint32_t page_shift, uint32_t page_shift,
uint32_t nb_table) uint32_t nb_table,
bool vfio_accel)
{ {
sPAPRTCETable *tcet; sPAPRTCETable *tcet;
@ -161,6 +163,7 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
tcet->bus_offset = bus_offset; tcet->bus_offset = bus_offset;
tcet->page_shift = page_shift; tcet->page_shift = page_shift;
tcet->nb_table = nb_table; tcet->nb_table = nb_table;
tcet->vfio_accel = vfio_accel;
object_property_add_child(OBJECT(owner), "tce-table", OBJECT(tcet), NULL); object_property_add_child(OBJECT(owner), "tce-table", OBJECT(tcet), NULL);

View File

@ -219,37 +219,13 @@ static void rtas_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr,
finish_write_pci_config(spapr, 0, addr, size, val, rets); 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. * Set MSI/MSIX message data.
* This is required for msi_notify()/msix_notify() which * This is required for msi_notify()/msix_notify() which
* will write at the addresses via spapr_msi_write(). * 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, static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
unsigned first_irq, unsigned req_num) unsigned first_irq, unsigned req_num)
@ -263,9 +239,12 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
return; return;
} }
for (i = 0; i < req_num; ++i, ++msg.data) { for (i = 0; i < req_num; ++i) {
msix_set_message(pdev, i, msg); msix_set_message(pdev, i, msg);
trace_spapr_pci_msi_setup(pdev->name, i, msg.address); 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 req_num = rtas_ld(args, 4); /* 0 == remove all */
unsigned int seq_num = rtas_ld(args, 5); unsigned int seq_num = rtas_ld(args, 5);
unsigned int ret_intr_type; unsigned int ret_intr_type;
int ndev, irq, max_irqs = 0; unsigned int irq, max_irqs = 0, num = 0;
sPAPRPHBState *phb = NULL; sPAPRPHBState *phb = NULL;
PCIDevice *pdev = NULL; PCIDevice *pdev = NULL;
bool msix = false;
spapr_pci_msi *msi;
int *config_addr_key;
switch (func) { switch (func) {
case RTAS_CHANGE_MSI_FN: case RTAS_CHANGE_MSI_FN:
@ -310,13 +292,18 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* Releasing MSIs */ /* Releasing MSIs */
if (!req_num) { if (!req_num) {
ndev = spapr_msicfg_find(phb, config_addr, false); msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
if (ndev < 0) { if (!msi) {
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr); trace_spapr_pci_msi("Releasing wrong config", config_addr);
rtas_st(rets, 0, RTAS_OUT_HW_ERROR); rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return; 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, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, 0); rtas_st(rets, 1, 0);
return; return;
@ -324,15 +311,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* Enabling MSI */ /* 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 */ /* Check if the device supports as many IRQs as requested */
if (ret_intr_type == RTAS_TYPE_MSI) { if (ret_intr_type == RTAS_TYPE_MSI) {
max_irqs = msi_nr_vectors_allocated(pdev); 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; max_irqs = pdev->msix_entries_nr;
} }
if (!max_irqs) { if (!max_irqs) {
error_report("Requested interrupt type %d is not enabled for device#%d", error_report("Requested interrupt type %d is not enabled for device %x",
ret_intr_type, ndev); ret_intr_type, config_addr);
rtas_st(rets, 0, -1); /* Hardware error */ rtas_st(rets, 0, -1); /* Hardware error */
return; return;
} }
/* Correct the number if the guest asked for too many */ /* Correct the number if the guest asked for too many */
if (req_num > max_irqs) { if (req_num > max_irqs) {
trace_spapr_pci_msi_retry(config_addr, req_num, max_irqs);
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 */ /* Allocate MSIs */
if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) { irq = xics_alloc_block(spapr->icp, 0, req_num, false,
/* Unexpected behaviour */ ret_intr_type == RTAS_TYPE_MSI);
error_report("Cannot reuse MSI config for device#%d", ndev); if (!irq) {
error_report("Cannot allocate MSIs for device %x", config_addr);
rtas_st(rets, 0, RTAS_OUT_HW_ERROR); rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return; return;
} }
/* There is no cached config, allocate MSIs */
if (!phb->msi_table[ndev].nvec) {
irq = spapr_allocate_irq_block(req_num, false,
ret_intr_type == RTAS_TYPE_MSI);
if (irq < 0) {
error_report("Cannot allocate MSIs for device#%d", ndev);
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) */ /* 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, 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, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, req_num); rtas_st(rets, 1, req_num);
rtas_st(rets, 2, ++seq_num); rtas_st(rets, 2, ++seq_num);
rtas_st(rets, 3, ret_intr_type); 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, 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); uint32_t config_addr = rtas_ld(args, 0);
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); 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); unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
int ndev;
sPAPRPHBState *phb = NULL; sPAPRPHBState *phb = NULL;
PCIDevice *pdev = NULL;
spapr_pci_msi *msi;
/* Fins sPAPRPHBState */ /* Find sPAPRPHBState */
phb = find_phb(spapr, buid); 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); rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return; return;
} }
/* Find device descriptor and start IRQ */ /* Find device descriptor and start IRQ */
ndev = spapr_msicfg_find(phb, config_addr, false); msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
if (ndev < 0) { if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) {
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr); trace_spapr_pci_msi("Failed to return vector", config_addr);
rtas_st(rets, 0, RTAS_OUT_HW_ERROR); rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return; return;
} }
intr_src_num = msi->first_irq + ioa_intr_num;
intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num, trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
intr_src_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++) { for (i = 0; i < PCI_NUM_PINS; i++) {
uint32_t irq; uint32_t irq;
irq = spapr_allocate_lsi(0); irq = xics_alloc_block(spapr->icp, 0, 1, true, false);
if (!irq) { if (!irq) {
error_setg(errp, "spapr_allocate_lsi failed"); error_setg(errp, "spapr_allocate_lsi failed");
return; return;
@ -649,6 +629,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
} }
info->finish_realize(sphb, 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) 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, tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn,
0, 0,
SPAPR_TCE_PAGE_SHIFT, SPAPR_TCE_PAGE_SHIFT,
0x40000000 >> SPAPR_TCE_PAGE_SHIFT); 0x40000000 >> SPAPR_TCE_PAGE_SHIFT, false);
if (!tcet) { if (!tcet) {
error_setg(errp, "Unable to create TCE table for %s", error_setg(errp, "Unable to create TCE table for %s",
sphb->dtbusname); sphb->dtbusname);
@ -712,22 +694,69 @@ static const VMStateDescription vmstate_spapr_pci_lsi = {
}; };
static const VMStateDescription vmstate_spapr_pci_msi = { static const VMStateDescription vmstate_spapr_pci_msi = {
.name = "spapr_pci/lsi", .name = "spapr_pci/msi",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField[]) { .fields = (VMStateField []) {
VMSTATE_UINT32(config_addr, struct spapr_pci_msi), VMSTATE_UINT32(key, spapr_pci_msi_mig),
VMSTATE_UINT32(irq, struct spapr_pci_msi), VMSTATE_UINT32(value.first_irq, spapr_pci_msi_mig),
VMSTATE_UINT32(nvec, struct spapr_pci_msi), VMSTATE_UINT32(value.num, spapr_pci_msi_mig),
VMSTATE_END_OF_LIST() 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 = { static const VMStateDescription vmstate_spapr_pci = {
.name = "spapr_pci", .name = "spapr_pci",
.version_id = 1, .version_id = 2,
.minimum_version_id = 1, .minimum_version_id = 2,
.pre_save = spapr_pci_pre_save,
.post_load = spapr_pci_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState), VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState),
VMSTATE_UINT32_EQUAL(dma_liobn, 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_UINT64_EQUAL(io_win_size, sPAPRPHBState),
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0, VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
vmstate_spapr_pci_lsi, struct spapr_pci_lsi), vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0, VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
vmstate_spapr_pci_msi, struct spapr_pci_msi), VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, sPAPRPHBState, msi_devs_num, 0,
vmstate_spapr_pci_msi, spapr_pci_msi_mig),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
}; };
@ -909,14 +938,20 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
void spapr_pci_rtas_init(void) void spapr_pci_rtas_init(void)
{ {
spapr_rtas_register("read-pci-config", rtas_read_pci_config); spapr_rtas_register(RTAS_READ_PCI_CONFIG, "read-pci-config",
spapr_rtas_register("write-pci-config", rtas_write_pci_config); rtas_read_pci_config);
spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config); spapr_rtas_register(RTAS_WRITE_PCI_CONFIG, "write-pci-config",
spapr_rtas_register("ibm,write-pci-config", rtas_ibm_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) { 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); 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
View 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)

View File

@ -36,9 +36,6 @@
#include <libfdt.h> #include <libfdt.h>
#define TOKEN_BASE 0x2000
#define TOKEN_MAX 0x100
static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr, static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs, uint32_t token, uint32_t nargs,
target_ulong args, target_ulong args,
@ -225,8 +222,6 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr,
env->msr = 0; env->msr = 0;
} }
#define DIAGNOSTICS_RUN_MODE 42
static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
sPAPREnvironment *spapr, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs, 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 parameter = rtas_ld(args, 0);
target_ulong buffer = rtas_ld(args, 1); target_ulong buffer = rtas_ld(args, 1);
target_ulong length = rtas_ld(args, 2); target_ulong length = rtas_ld(args, 2);
target_ulong ret = RTAS_OUT_NOT_SUPPORTED; target_ulong ret = RTAS_OUT_SUCCESS;
switch (parameter) { switch (parameter) {
case DIAGNOSTICS_RUN_MODE: case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
if (length == 1) { char *param_val = g_strdup_printf("MaxEntCap=%d,MaxPlatProcs=%d",
rtas_st(buffer, 0, 0); max_cpus, smp_cpus);
ret = RTAS_OUT_SUCCESS; rtas_st_buffer(buffer, length, (uint8_t *)param_val, strlen(param_val));
} g_free(param_val);
break; break;
} }
case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: {
uint8_t param_val = DIAGNOSTICS_RUN_MODE_DISABLED;
rtas_st_buffer(buffer, length, &param_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); 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; target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
switch (parameter) { 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; ret = RTAS_OUT_NOT_AUTHORIZED;
break; break;
} }
@ -271,17 +280,14 @@ static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
static struct rtas_call { static struct rtas_call {
const char *name; const char *name;
spapr_rtas_fn fn; spapr_rtas_fn fn;
} rtas_table[TOKEN_MAX]; } rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE];
static struct rtas_call *rtas_next = rtas_table;
target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs, target_ulong args, uint32_t token, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets) uint32_t nret, target_ulong rets)
{ {
if ((token >= TOKEN_BASE) if ((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)) {
&& ((token - TOKEN_BASE) < TOKEN_MAX)) { struct rtas_call *call = rtas_table + (token - RTAS_TOKEN_BASE);
struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
if (call->fn) { if (call->fn) {
call->fn(cpu, spapr, token, nargs, args, nret, rets); 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; 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; if (!((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX))) {
fprintf(stderr, "RTAS invalid token 0x%x\n", token);
for (i = 0; i < (rtas_next - rtas_table); i++) { exit(1);
if (strcmp(name, rtas_table[i].name) == 0) {
fprintf(stderr, "RTAS call \"%s\" registered twice\n", name);
exit(1);
}
} }
assert(rtas_next < (rtas_table + TOKEN_MAX)); 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);
}
rtas_next->name = name; rtas_table[token].name = name;
rtas_next->fn = fn; rtas_table[token].fn = fn;
return (rtas_next++ - rtas_table) + TOKEN_BASE;
} }
int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, 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; 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]; struct rtas_call *call = &rtas_table[i];
if (!call->name) { 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, ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
i + TOKEN_BASE); i + RTAS_TOKEN_BASE);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't add rtas token for %s: %s\n", fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
call->name, fdt_strerror(ret)); 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) static void core_rtas_register_types(void)
{ {
spapr_rtas_register("display-character", rtas_display_character); spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",
spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); rtas_display_character);
spapr_rtas_register("set-time-of-day", rtas_set_time_of_day); spapr_rtas_register(RTAS_GET_TIME_OF_DAY, "get-time-of-day",
spapr_rtas_register("power-off", rtas_power_off); rtas_get_time_of_day);
spapr_rtas_register("system-reboot", rtas_system_reboot); spapr_rtas_register(RTAS_SET_TIME_OF_DAY, "set-time-of-day",
spapr_rtas_register("query-cpu-stopped-state", 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); rtas_query_cpu_stopped_state);
spapr_rtas_register("start-cpu", rtas_start_cpu); spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
spapr_rtas_register("stop-self", rtas_stop_self); spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
spapr_rtas_register("ibm,get-system-parameter", spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
"ibm,get-system-parameter",
rtas_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); rtas_ibm_set_system_parameter);
} }

View File

@ -449,7 +449,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
dev->qdev.id = id; dev->qdev.id = id;
} }
dev->irq = spapr_allocate_msi(dev->irq); dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false);
if (!dev->irq) { if (!dev->irq) {
return -1; return -1;
} }
@ -460,7 +460,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
0, 0,
SPAPR_TCE_PAGE_SHIFT, SPAPR_TCE_PAGE_SHIFT,
pc->rtce_window_size >> 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); 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); spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
/* RTAS calls */ /* RTAS calls */
spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass); spapr_rtas_register(RTAS_IBM_SET_TCE_BYPASS, "ibm,set-tce-bypass",
spapr_rtas_register("quiesce", rtas_quiesce); rtas_set_tce_bypass);
spapr_rtas_register(RTAS_QUIESCE, "quiesce", rtas_quiesce);
return bus; return bus;
} }

9
include/hw/misc/vfio.h Normal file
View 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

View File

@ -27,13 +27,15 @@
#include "hw/pci/pci_host.h" #include "hw/pci/pci_host.h"
#include "hw/ppc/xics.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_HOST_BRIDGE "spapr-pci-host-bridge"
#define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge"
#define SPAPR_PCI_HOST_BRIDGE(obj) \ #define SPAPR_PCI_HOST_BRIDGE(obj) \
OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE) 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) \ #define SPAPR_PCI_HOST_BRIDGE_CLASS(klass) \
OBJECT_CLASS_CHECK(sPAPRPHBClass, (klass), TYPE_SPAPR_PCI_HOST_BRIDGE) OBJECT_CLASS_CHECK(sPAPRPHBClass, (klass), TYPE_SPAPR_PCI_HOST_BRIDGE)
#define SPAPR_PCI_HOST_BRIDGE_GET_CLASS(obj) \ #define SPAPR_PCI_HOST_BRIDGE_GET_CLASS(obj) \
@ -41,6 +43,7 @@
typedef struct sPAPRPHBClass sPAPRPHBClass; typedef struct sPAPRPHBClass sPAPRPHBClass;
typedef struct sPAPRPHBState sPAPRPHBState; typedef struct sPAPRPHBState sPAPRPHBState;
typedef struct sPAPRPHBVFIOState sPAPRPHBVFIOState;
struct sPAPRPHBClass { struct sPAPRPHBClass {
PCIHostBridgeClass parent_class; PCIHostBridgeClass parent_class;
@ -48,6 +51,16 @@ struct sPAPRPHBClass {
void (*finish_realize)(sPAPRPHBState *sphb, Error **errp); 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 { struct sPAPRPHBState {
PCIHostState parent_obj; PCIHostState parent_obj;
@ -67,15 +80,20 @@ struct sPAPRPHBState {
uint32_t irq; uint32_t irq;
} lsi_table[PCI_NUM_PINS]; } lsi_table[PCI_NUM_PINS];
struct spapr_pci_msi { GHashTable *msi;
uint32_t config_addr; /* Temporary cache for migration purposes */
uint32_t irq; int32_t msi_devs_num;
uint32_t nvec; spapr_pci_msi_mig *msi_devs;
} msi_table[SPAPR_MSIX_MAX_DEVS];
QLIST_ENTRY(sPAPRPHBState) list; QLIST_ENTRY(sPAPRPHBState) list;
}; };
struct sPAPRPHBVFIOState {
sPAPRPHBState phb;
int32_t iommugroupid;
};
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL #define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL #define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL

View File

@ -27,7 +27,6 @@ typedef struct sPAPREnvironment {
long rtas_size; long rtas_size;
void *fdt_skel; void *fdt_skel;
target_ulong entry_point; target_ulong entry_point;
uint32_t next_irq;
uint64_t rtc_offset; uint64_t rtc_offset;
struct PPCTimebase tb; struct PPCTimebase tb;
bool has_graphics; 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(int hint, bool lsi);
int spapr_allocate_irq_block(int num, bool lsi, bool msi); 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 */ /* RTAS return codes */
#define RTAS_OUT_SUCCESS 0 #define RTAS_OUT_SUCCESS 0
#define RTAS_OUT_NO_ERRORS_FOUND 1 #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_SUPPORTED -3
#define RTAS_OUT_NOT_AUTHORIZED -9002 #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) static inline uint64_t ppc64_phys_to_real(uint64_t addr)
{ {
return addr & ~0xF000000000000000ULL; 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); 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, typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t token,
uint32_t nargs, target_ulong args, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets); 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, target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs, target_ulong args, uint32_t token, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets); uint32_t nret, target_ulong rets);
@ -407,6 +461,7 @@ struct sPAPRTCETable {
uint32_t page_shift; uint32_t page_shift;
uint64_t *table; uint64_t *table;
bool bypass; bool bypass;
bool vfio_accel;
int fd; int fd;
MemoryRegion iommu; MemoryRegion iommu;
QLIST_ENTRY(sPAPRTCETable) list; 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, sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
uint64_t bus_offset, uint64_t bus_offset,
uint32_t page_shift, uint32_t page_shift,
uint32_t nb_table); uint32_t nb_table,
bool vfio_accel);
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet); MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet);
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass); void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass);
int spapr_dma_dt(void *fdt, int node_off, const char *propname, int spapr_dma_dt(void *fdt, int node_off, const char *propname,

View File

@ -136,7 +136,6 @@ struct ICSState {
uint32_t nr_irqs; uint32_t nr_irqs;
uint32_t offset; uint32_t offset;
qemu_irq *qirqs; qemu_irq *qirqs;
bool *islsi;
ICSIRQState *irqs; ICSIRQState *irqs;
XICSState *icp; XICSState *icp;
}; };
@ -150,12 +149,20 @@ struct ICSIRQState {
#define XICS_STATUS_REJECTED 0x4 #define XICS_STATUS_REJECTED 0x4
#define XICS_STATUS_MASKED_PENDING 0x8 #define XICS_STATUS_MASKED_PENDING 0x8
uint8_t status; 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 #define XICS_IRQS 1024
qemu_irq xics_get_qirq(XICSState *icp, int irq); qemu_irq xics_get_qirq(XICSState *icp, int irq);
void xics_set_irq_type(XICSState *icp, int irq, bool lsi); 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); void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu);

View File

@ -101,6 +101,7 @@ enum VMStateFlags {
VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/ VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/
VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/ VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/
VMS_MUST_EXIST = 0x1000, /* Field must exist in input */ VMS_MUST_EXIST = 0x1000, /* Field must exist in input */
VMS_ALLOC = 0x2000, /* Alloc a buffer on the destination */
}; };
typedef struct { typedef struct {
@ -429,6 +430,16 @@ extern const VMStateInfo vmstate_info_bitmap;
.offset = offsetof(_state, _field), \ .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) { \ #define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
.name = (stringify(_field)), \ .name = (stringify(_field)), \
.version_id = (_version), \ .version_id = (_version), \

View File

@ -736,6 +736,14 @@ enum {
QEMU_PPC_FEATURE_TRUE_LE = 0x00000002, QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
QEMU_PPC_FEATURE_PPC_LE = 0x00000001, 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() #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. */ Altivec/FP/SPE support. Anything else is just a bonus. */
#define GET_FEATURE(flag, feature) \ #define GET_FEATURE(flag, feature) \
do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0) 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_64B, QEMU_PPC_FEATURE_64);
GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU); GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC); 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_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE); GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC); 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_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; return features;
} }
@ -774,8 +813,9 @@ static uint32_t get_elf_hwcap(void)
#define DLINFO_ARCH_ITEMS 5 #define DLINFO_ARCH_ITEMS 5
#define ARCH_DLINFO \ #define ARCH_DLINFO \
do { \ do { \
NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ PowerPCCPU *cpu = POWERPC_CPU(thread_cpu); \
NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ 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); \ NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
/* \ /* \
* Now handle glibc compatibility. \ * Now handle glibc compatibility. \

View File

@ -1138,6 +1138,8 @@
"POWER7 v2.3") "POWER7 v2.3")
POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7P, POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7P,
"POWER7+ v2.1") "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, POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8,
"POWER8 v1.0") "POWER8 v1.0")
POWERPC_DEF("970", CPU_POWERPC_970, 970, POWERPC_DEF("970", CPU_POWERPC_970, 970,
@ -1386,6 +1388,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
{ "POWER5gs", "POWER5+" }, { "POWER5gs", "POWER5+" },
{ "POWER7", "POWER7_v2.3" }, { "POWER7", "POWER7_v2.3" },
{ "POWER7+", "POWER7+_v2.1" }, { "POWER7+", "POWER7+_v2.1" },
{ "POWER8E", "POWER8E_v1.0" },
{ "POWER8", "POWER8_v1.0" }, { "POWER8", "POWER8_v1.0" },
{ "970fx", "970fx_v3.1" }, { "970fx", "970fx_v3.1" },
{ "970mp", "970mp_v1.1" }, { "970mp", "970mp_v1.1" },

View File

@ -559,9 +559,12 @@ enum {
CPU_POWERPC_POWER7P_BASE = 0x004A0000, CPU_POWERPC_POWER7P_BASE = 0x004A0000,
CPU_POWERPC_POWER7P_MASK = 0xFFFF0000, CPU_POWERPC_POWER7P_MASK = 0xFFFF0000,
CPU_POWERPC_POWER7P_v21 = 0x004A0201, 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_MASK = 0xFFFF0000,
CPU_POWERPC_POWER8_v10 = 0x004B0100, CPU_POWERPC_POWER8_v10 = 0x004D0100,
CPU_POWERPC_970 = 0x00390202, CPU_POWERPC_970 = 0x00390202,
CPU_POWERPC_970FX_v10 = 0x00391100, CPU_POWERPC_970FX_v10 = 0x00391100,
CPU_POWERPC_970FX_v20 = 0x003C0200, CPU_POWERPC_970FX_v20 = 0x003C0200,

View File

@ -119,7 +119,9 @@ void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags); fprintf_function cpu_fprintf, int flags);
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); 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(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(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, int ppc64_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
CPUState *cpu, void *opaque); CPUState *cpu, void *opaque);
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,

View File

@ -2012,7 +2012,7 @@ enum {
PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \ PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
PPC2_ALTIVEC_207 | PPC2_ISA207S) PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP)
}; };
/*****************************************************************************/ /*****************************************************************************/

View File

@ -21,6 +21,31 @@
#include "qemu-common.h" #include "qemu-common.h"
#include "exec/gdbstub.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) static int ppc_gdb_register_len(int n)
{ {
switch (n) { switch (n) {
@ -132,6 +157,65 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
return r; 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) int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{ {
PowerPCCPU *cpu = POWERPC_CPU(cs); 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; 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;
}

View File

@ -63,6 +63,7 @@ static int cap_ppc_smt;
static int cap_ppc_rma; static int cap_ppc_rma;
static int cap_spapr_tce; static int cap_spapr_tce;
static int cap_spapr_multitce; static int cap_spapr_multitce;
static int cap_spapr_vfio;
static int cap_hior; static int cap_hior;
static int cap_one_reg; static int cap_one_reg;
static int cap_epr; 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_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE); 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_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG);
cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR); cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR);
@ -1660,7 +1662,8 @@ bool kvmppc_spapr_use_multitce(void)
return cap_spapr_multitce; 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 = { struct kvm_create_spapr_tce args = {
.liobn = liobn, .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 * destroying the table, which the upper layers -will- do
*/ */
*pfd = -1; *pfd = -1;
if (!cap_spapr_tce) { if (!cap_spapr_tce || (vfio_accel && !cap_spapr_vfio)) {
return NULL; return NULL;
} }

View File

@ -33,7 +33,8 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
bool kvmppc_spapr_use_multitce(void); 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_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
int kvmppc_reset_htab(int shift_hint); int kvmppc_reset_htab(int shift_hint);
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); 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, 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; return NULL;
} }

View File

@ -426,7 +426,6 @@ static inline uint32_t SPR(uint32_t opcode)
return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5); return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
} }
/*** Get constants ***/ /*** Get constants ***/
EXTRACT_HELPER(IMM, 12, 8);
/* 16 bits signed immediate value */ /* 16 bits signed immediate value */
EXTRACT_SHELPER(SIMM, 0, 16); EXTRACT_SHELPER(SIMM, 0, 16);
/* 16 bits unsigned immediate value */ /* 16 bits unsigned immediate value */
@ -459,8 +458,6 @@ EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1); EXTRACT_HELPER(FPW, 16, 1);
/*** Jump target decoding ***/ /*** Jump target decoding ***/
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */ /* Immediate address */
static inline target_ulong LI(uint32_t opcode) 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); 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) static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2)
{ {
TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask; 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(t0, cpu_so);
tcg_gen_trunc_tl_i32(t1, cpu_ov); tcg_gen_trunc_tl_i32(t1, cpu_ov);
tcg_gen_trunc_tl_i32(dst, cpu_ca); tcg_gen_trunc_tl_i32(dst, cpu_ca);
tcg_gen_shri_i32(t0, t0, 2); tcg_gen_shli_i32(t0, t0, 3);
tcg_gen_shri_i32(t1, t1, 1); 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, t0);
tcg_gen_or_i32(dst, dst, t1); tcg_gen_or_i32(dst, dst, t1);
tcg_temp_free_i32(t0); tcg_temp_free_i32(t0);

View File

@ -34,6 +34,7 @@
//#define PPC_DUMP_CPU //#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR //#define PPC_DEBUG_SPR
//#define PPC_DUMP_SPR_ACCESSES //#define PPC_DUMP_SPR_ACCESSES
/* #define USE_APPLE_GDB */
/* For user-mode emulation, we don't emulate any IRQ controller */ /* For user-mode emulation, we don't emulate any IRQ controller */
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
@ -8188,16 +8189,16 @@ static void init_proc_POWER8(CPUPPCState *env)
init_proc_book3s_64(env, BOOK3S_CPU_POWER8); 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); DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
dc->fw_name = "PowerPC,POWER8"; dc->fw_name = "PowerPC,POWER8";
dc->desc = "POWER8"; dc->desc = "POWER8E";
dc->props = powerpc_servercpu_properties; dc->props = powerpc_servercpu_properties;
pcc->pvr = CPU_POWERPC_POWER8_BASE; pcc->pvr = CPU_POWERPC_POWER8E_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER8_MASK; pcc->pvr_mask = CPU_POWERPC_POWER8E_MASK;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06; pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;
pcc->init_proc = init_proc_POWER8; pcc->init_proc = init_proc_POWER8;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
@ -8251,6 +8252,18 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x8000; pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; 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) */ #endif /* defined (TARGET_PPC64) */
@ -9667,6 +9680,13 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
#endif #endif
cc->gdb_num_core_regs = 71; 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) #if defined(TARGET_PPC64)
cc->gdb_core_xml_file = "power64-core.xml"; cc->gdb_core_xml_file = "power64-core.xml";
#else #else

View File

@ -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" qxl_render_update_area_done(void *cookie) "%p"
# hw/ppc/spapr_pci.c # 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_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_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_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_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 # hw/intc/xics.c
xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=%#x" 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_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_reject(int nr, int srcno) "reject irq %#x [src %d]"
xics_ics_eoi(int nr) "ics_eoi: irq %#x" 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 # hw/ppc/spapr.c
spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes" spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes"

View File

@ -43,11 +43,18 @@ static int vmstate_size(void *opaque, VMStateField *field)
return size; 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; void *base_addr = opaque + field->offset;
if (field->flags & VMS_POINTER) { 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; 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(opaque, version_id)) ||
(!field->field_exists && (!field->field_exists &&
field->version_id <= version_id)) { 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 i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field); int size = vmstate_size(opaque, field);
@ -135,7 +142,7 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
while (field->name) { while (field->name) {
if (!field->field_exists || if (!field->field_exists ||
field->field_exists(opaque, vmsd->version_id)) { 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 i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field); int size = vmstate_size(opaque, field);