mirror of https://github.com/xqemu/xqemu.git
ppc patch queue 2016-10-17
Highlights: * Significant rework of how PCI IO windows are placed for the pseries machine type * A number of extra tests added for ppc * Other tests clean up / fixed * Some cleanups to the XICS interrupt controller in preparation for the 'powernv' machine type A number of the test changes aren't strictly in ppc related code, but are included via my tree because they're primarily focused on improving test coverage for ppc. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJYBDqhAAoJEGw4ysog2bOSVPAP/RlWYnOCTDiKuSCXz7+joHl9 lY3K+x2r8DbFFmqxk82h+uObBG/dVQ7kcF+o3SD49dMUqoi/iD8rS5UFrDtArFKP vPh4h7KpVbQHyMWoHTjo1Zw94Sr2xEqRelQOrZjRA+a794kg6MKs3EIekHo9QdZl 33qU0aE02LNOmguDwsTqTavrs/19qjcUM+fAyfOMEMiaQHNxdwrQjvldlIeELPka Dz/iOS5Lxibq2txmZWMxiMAuBe6lmJQWlcUUy+xXylQ5OE7CQctCfm2hsWWoMpGo PnhY+UC+9Ctqvb4TyTzqjllEmEfwK219091+hW7epWIUXGuaWde1RCvwRUr7pFGD DN4/75M82aNrpG0ydjzLpqbOwj/h+YvQARdKTTS2/4iJCrDPd5O2rR4Yjkrt1lcq jrSSnqsCeYET+4JY4G4h3ZZsPRcLnnpcNrUcF9AwkRCe1ybr4npK8FGSd4AGWAOR J7/mZqs7Gne4DjbjIzwfntP8ak5AASPqJKEmwjAO7M8zD0/xm6Ovqbmo8Xte9Vxx ge4nBcAhoJJ8y1hiZNLOyy1d87WUiD84MiN/BuSK7UbeBVsfHvYWAcEsVGXFzaP0 hXwLHxddmflU7gy6hTbQ/f9SQiaobphCaP3uM4fLIOzAn64EIELCDvRwlr6NakRW CbJWqMsNz/WblA/ZSlA3 =tnCe -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.8-20161017' into staging ppc patch queue 2016-10-17 Highlights: * Significant rework of how PCI IO windows are placed for the pseries machine type * A number of extra tests added for ppc * Other tests clean up / fixed * Some cleanups to the XICS interrupt controller in preparation for the 'powernv' machine type A number of the test changes aren't strictly in ppc related code, but are included via my tree because they're primarily focused on improving test coverage for ppc. # gpg: Signature made Mon 17 Oct 2016 03:42:41 BST # gpg: using RSA key 0x6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-2.8-20161017: spapr: Improved placement of PCI host bridges in guest memory map spapr_pci: Add a 64-bit MMIO window spapr: Adjust placement of PCI host bridge to allow > 1TiB RAM spapr_pci: Delegate placement of PCI host bridges to machine type libqos: Limit spapr-pci to 32-bit MMIO for now libqos: Correct error in PCI hole sizing for spapr libqos: Isolate knowledge of spapr memory map to qpci_init_spapr() ppc/xics: Split ICS into ics-base and ics class ppc/xics: Make the ICSState a list spapr: fix inheritance chain for default machine options target-ppc: implement vexts[bh]2w and vexts[bhw]2d tests/boot-sector: Increase time-out to 90 seconds tests/boot-sector: Use mkstemp() to create a unique file name tests/boot-sector: Use minimum length for the Forth boot script qtest: ask endianness of the target in qtest_init() tests: minor cleanups in usb-hcd-uhci-test Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7bf59dfec4
|
@ -50,16 +50,17 @@ xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR %#"PRIx3
|
|||
xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR %#"PRIx32" new XIRR %#"PRIx32
|
||||
xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq %#"PRIx32" priority %#x"
|
||||
xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=%#x new pending priority=%#x"
|
||||
xics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq %#x]"
|
||||
xics_ics_simple_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq %#x]"
|
||||
xics_masked_pending(void) "set_irq_msi: masked pending"
|
||||
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_block(int src, int first, int num, bool lsi, int align) "source#%d, first irq %d, %d irqs, lsi=%d, alignnum %d"
|
||||
xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]"
|
||||
xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x"
|
||||
xics_ics_simple_reject(int nr, int srcno) "reject irq %#x [src %d]"
|
||||
xics_ics_simple_eoi(int nr) "ics_eoi: irq %#x"
|
||||
xics_alloc(int irq) "irq %d"
|
||||
xics_alloc_block(int first, int num, bool lsi, int align) "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"
|
||||
xics_icp_post_load(uint32_t server_no, uint32_t xirr, uint64_t addr, uint8_t pend) "server_no %d, xirr %#x, xirr_owner 0x%" PRIx64 ", pending %d"
|
||||
|
||||
# hw/intc/s390_flic_kvm.c
|
||||
flic_create_device(int err) "flic: create device failed %d"
|
||||
|
|
235
hw/intc/xics.c
235
hw/intc/xics.c
|
@ -96,13 +96,16 @@ void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
|
|||
static void xics_common_reset(DeviceState *d)
|
||||
{
|
||||
XICSState *xics = XICS_COMMON(d);
|
||||
ICSState *ics;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < xics->nr_servers; i++) {
|
||||
device_reset(DEVICE(&xics->ss[i]));
|
||||
}
|
||||
|
||||
device_reset(DEVICE(xics->ics));
|
||||
QLIST_FOREACH(ics, &xics->ics, list) {
|
||||
device_reset(DEVICE(ics));
|
||||
}
|
||||
}
|
||||
|
||||
static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name,
|
||||
|
@ -134,7 +137,6 @@ static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name,
|
|||
}
|
||||
|
||||
assert(info->set_nr_irqs);
|
||||
assert(xics->ics);
|
||||
info->set_nr_irqs(xics, value, errp);
|
||||
}
|
||||
|
||||
|
@ -174,6 +176,9 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v,
|
|||
|
||||
static void xics_common_initfn(Object *obj)
|
||||
{
|
||||
XICSState *xics = XICS_COMMON(obj);
|
||||
|
||||
QLIST_INIT(&xics->ics);
|
||||
object_property_add(obj, "nr_irqs", "int",
|
||||
xics_prop_get_nr_irqs, xics_prop_set_nr_irqs,
|
||||
NULL, NULL, NULL);
|
||||
|
@ -208,37 +213,62 @@ static const TypeInfo xics_common_info = {
|
|||
#define XISR(ss) (((ss)->xirr) & XISR_MASK)
|
||||
#define CPPR(ss) (((ss)->xirr) >> 24)
|
||||
|
||||
static void ics_reject(ICSState *ics, int nr);
|
||||
static void ics_resend(ICSState *ics);
|
||||
static void ics_eoi(ICSState *ics, int nr);
|
||||
|
||||
static void icp_check_ipi(XICSState *xics, int server)
|
||||
static void ics_reject(ICSState *ics, uint32_t nr)
|
||||
{
|
||||
ICPState *ss = xics->ss + server;
|
||||
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
|
||||
|
||||
if (k->reject) {
|
||||
k->reject(ics, nr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ics_resend(ICSState *ics)
|
||||
{
|
||||
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
|
||||
|
||||
if (k->resend) {
|
||||
k->resend(ics);
|
||||
}
|
||||
}
|
||||
|
||||
static void ics_eoi(ICSState *ics, int nr)
|
||||
{
|
||||
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
|
||||
|
||||
if (k->eoi) {
|
||||
k->eoi(ics, nr);
|
||||
}
|
||||
}
|
||||
|
||||
static void icp_check_ipi(ICPState *ss)
|
||||
{
|
||||
if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
trace_xics_icp_check_ipi(server, ss->mfrr);
|
||||
trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr);
|
||||
|
||||
if (XISR(ss)) {
|
||||
ics_reject(xics->ics, XISR(ss));
|
||||
if (XISR(ss) && ss->xirr_owner) {
|
||||
ics_reject(ss->xirr_owner, XISR(ss));
|
||||
}
|
||||
|
||||
ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
|
||||
ss->pending_priority = ss->mfrr;
|
||||
ss->xirr_owner = NULL;
|
||||
qemu_irq_raise(ss->output);
|
||||
}
|
||||
|
||||
static void icp_resend(XICSState *xics, int server)
|
||||
{
|
||||
ICPState *ss = xics->ss + server;
|
||||
ICSState *ics;
|
||||
|
||||
if (ss->mfrr < CPPR(ss)) {
|
||||
icp_check_ipi(xics, server);
|
||||
icp_check_ipi(ss);
|
||||
}
|
||||
QLIST_FOREACH(ics, &xics->ics, list) {
|
||||
ics_resend(ics);
|
||||
}
|
||||
ics_resend(xics->ics);
|
||||
}
|
||||
|
||||
void icp_set_cppr(XICSState *xics, int server, uint8_t cppr)
|
||||
|
@ -256,7 +286,10 @@ void icp_set_cppr(XICSState *xics, int server, uint8_t cppr)
|
|||
ss->xirr &= ~XISR_MASK; /* Clear XISR */
|
||||
ss->pending_priority = 0xff;
|
||||
qemu_irq_lower(ss->output);
|
||||
ics_reject(xics->ics, old_xisr);
|
||||
if (ss->xirr_owner) {
|
||||
ics_reject(ss->xirr_owner, old_xisr);
|
||||
ss->xirr_owner = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!XISR(ss)) {
|
||||
|
@ -271,7 +304,7 @@ void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr)
|
|||
|
||||
ss->mfrr = mfrr;
|
||||
if (mfrr < CPPR(ss)) {
|
||||
icp_check_ipi(xics, server);
|
||||
icp_check_ipi(ss);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,6 +315,7 @@ uint32_t icp_accept(ICPState *ss)
|
|||
qemu_irq_lower(ss->output);
|
||||
ss->xirr = ss->pending_priority << 24;
|
||||
ss->pending_priority = 0xff;
|
||||
ss->xirr_owner = NULL;
|
||||
|
||||
trace_xics_icp_accept(xirr, ss->xirr);
|
||||
|
||||
|
@ -299,30 +333,40 @@ uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)
|
|||
void icp_eoi(XICSState *xics, int server, uint32_t xirr)
|
||||
{
|
||||
ICPState *ss = xics->ss + server;
|
||||
ICSState *ics;
|
||||
uint32_t irq;
|
||||
|
||||
/* Send EOI -> ICS */
|
||||
ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
|
||||
trace_xics_icp_eoi(server, xirr, ss->xirr);
|
||||
ics_eoi(xics->ics, xirr & XISR_MASK);
|
||||
irq = xirr & XISR_MASK;
|
||||
QLIST_FOREACH(ics, &xics->ics, list) {
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
ics_eoi(ics, irq);
|
||||
}
|
||||
}
|
||||
if (!XISR(ss)) {
|
||||
icp_resend(xics, server);
|
||||
}
|
||||
}
|
||||
|
||||
static void icp_irq(XICSState *xics, int server, int nr, uint8_t priority)
|
||||
static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority)
|
||||
{
|
||||
XICSState *xics = ics->xics;
|
||||
ICPState *ss = xics->ss + server;
|
||||
|
||||
trace_xics_icp_irq(server, nr, priority);
|
||||
|
||||
if ((priority >= CPPR(ss))
|
||||
|| (XISR(ss) && (ss->pending_priority <= priority))) {
|
||||
ics_reject(xics->ics, nr);
|
||||
ics_reject(ics, nr);
|
||||
} else {
|
||||
if (XISR(ss)) {
|
||||
ics_reject(xics->ics, XISR(ss));
|
||||
if (XISR(ss) && ss->xirr_owner) {
|
||||
ics_reject(ss->xirr_owner, XISR(ss));
|
||||
ss->xirr_owner = NULL;
|
||||
}
|
||||
ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
|
||||
ss->xirr_owner = ics;
|
||||
ss->pending_priority = priority;
|
||||
trace_xics_icp_raise(ss->xirr, ss->pending_priority);
|
||||
qemu_irq_raise(ss->output);
|
||||
|
@ -397,7 +441,7 @@ static const TypeInfo icp_info = {
|
|||
/*
|
||||
* ICS: Source layer
|
||||
*/
|
||||
static void resend_msi(ICSState *ics, int srcno)
|
||||
static void ics_simple_resend_msi(ICSState *ics, int srcno)
|
||||
{
|
||||
ICSIRQState *irq = ics->irqs + srcno;
|
||||
|
||||
|
@ -405,13 +449,12 @@ static void resend_msi(ICSState *ics, int srcno)
|
|||
if (irq->status & XICS_STATUS_REJECTED) {
|
||||
irq->status &= ~XICS_STATUS_REJECTED;
|
||||
if (irq->priority != 0xff) {
|
||||
icp_irq(ics->xics, irq->server, srcno + ics->offset,
|
||||
irq->priority);
|
||||
icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resend_lsi(ICSState *ics, int srcno)
|
||||
static void ics_simple_resend_lsi(ICSState *ics, int srcno)
|
||||
{
|
||||
ICSIRQState *irq = ics->irqs + srcno;
|
||||
|
||||
|
@ -419,51 +462,51 @@ static void resend_lsi(ICSState *ics, int srcno)
|
|||
&& (irq->status & XICS_STATUS_ASSERTED)
|
||||
&& !(irq->status & XICS_STATUS_SENT)) {
|
||||
irq->status |= XICS_STATUS_SENT;
|
||||
icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority);
|
||||
icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_irq_msi(ICSState *ics, int srcno, int val)
|
||||
static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val)
|
||||
{
|
||||
ICSIRQState *irq = ics->irqs + srcno;
|
||||
|
||||
trace_xics_set_irq_msi(srcno, srcno + ics->offset);
|
||||
trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset);
|
||||
|
||||
if (val) {
|
||||
if (irq->priority == 0xff) {
|
||||
irq->status |= XICS_STATUS_MASKED_PENDING;
|
||||
trace_xics_masked_pending();
|
||||
} else {
|
||||
icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority);
|
||||
icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void set_irq_lsi(ICSState *ics, int srcno, int val)
|
||||
static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val)
|
||||
{
|
||||
ICSIRQState *irq = ics->irqs + srcno;
|
||||
|
||||
trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
|
||||
trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset);
|
||||
if (val) {
|
||||
irq->status |= XICS_STATUS_ASSERTED;
|
||||
} else {
|
||||
irq->status &= ~XICS_STATUS_ASSERTED;
|
||||
}
|
||||
resend_lsi(ics, srcno);
|
||||
ics_simple_resend_lsi(ics, srcno);
|
||||
}
|
||||
|
||||
static void ics_set_irq(void *opaque, int srcno, int val)
|
||||
static void ics_simple_set_irq(void *opaque, int srcno, int val)
|
||||
{
|
||||
ICSState *ics = (ICSState *)opaque;
|
||||
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
set_irq_lsi(ics, srcno, val);
|
||||
ics_simple_set_irq_lsi(ics, srcno, val);
|
||||
} else {
|
||||
set_irq_msi(ics, srcno, val);
|
||||
ics_simple_set_irq_msi(ics, srcno, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_xive_msi(ICSState *ics, int srcno)
|
||||
static void ics_simple_write_xive_msi(ICSState *ics, int srcno)
|
||||
{
|
||||
ICSIRQState *irq = ics->irqs + srcno;
|
||||
|
||||
|
@ -473,38 +516,38 @@ static void write_xive_msi(ICSState *ics, int srcno)
|
|||
}
|
||||
|
||||
irq->status &= ~XICS_STATUS_MASKED_PENDING;
|
||||
icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority);
|
||||
icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
|
||||
}
|
||||
|
||||
static void write_xive_lsi(ICSState *ics, int srcno)
|
||||
static void ics_simple_write_xive_lsi(ICSState *ics, int srcno)
|
||||
{
|
||||
resend_lsi(ics, srcno);
|
||||
ics_simple_resend_lsi(ics, srcno);
|
||||
}
|
||||
|
||||
void ics_write_xive(ICSState *ics, int nr, int server,
|
||||
uint8_t priority, uint8_t saved_priority)
|
||||
void ics_simple_write_xive(ICSState *ics, int srcno, int server,
|
||||
uint8_t priority, uint8_t saved_priority)
|
||||
{
|
||||
int srcno = nr - ics->offset;
|
||||
ICSIRQState *irq = ics->irqs + srcno;
|
||||
|
||||
irq->server = server;
|
||||
irq->priority = priority;
|
||||
irq->saved_priority = saved_priority;
|
||||
|
||||
trace_xics_ics_write_xive(nr, srcno, server, priority);
|
||||
trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server,
|
||||
priority);
|
||||
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
write_xive_lsi(ics, srcno);
|
||||
ics_simple_write_xive_lsi(ics, srcno);
|
||||
} else {
|
||||
write_xive_msi(ics, srcno);
|
||||
ics_simple_write_xive_msi(ics, srcno);
|
||||
}
|
||||
}
|
||||
|
||||
static void ics_reject(ICSState *ics, int nr)
|
||||
static void ics_simple_reject(ICSState *ics, uint32_t nr)
|
||||
{
|
||||
ICSIRQState *irq = ics->irqs + nr - ics->offset;
|
||||
|
||||
trace_xics_ics_reject(nr, nr - ics->offset);
|
||||
trace_xics_ics_simple_reject(nr, nr - ics->offset);
|
||||
if (irq->flags & XICS_FLAGS_IRQ_MSI) {
|
||||
irq->status |= XICS_STATUS_REJECTED;
|
||||
} else if (irq->flags & XICS_FLAGS_IRQ_LSI) {
|
||||
|
@ -512,35 +555,35 @@ static void ics_reject(ICSState *ics, int nr)
|
|||
}
|
||||
}
|
||||
|
||||
static void ics_resend(ICSState *ics)
|
||||
static void ics_simple_resend(ICSState *ics)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
/* FIXME: filter by server#? */
|
||||
if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
resend_lsi(ics, i);
|
||||
ics_simple_resend_lsi(ics, i);
|
||||
} else {
|
||||
resend_msi(ics, i);
|
||||
ics_simple_resend_msi(ics, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ics_eoi(ICSState *ics, int nr)
|
||||
static void ics_simple_eoi(ICSState *ics, uint32_t nr)
|
||||
{
|
||||
int srcno = nr - ics->offset;
|
||||
ICSIRQState *irq = ics->irqs + srcno;
|
||||
|
||||
trace_xics_ics_eoi(nr);
|
||||
trace_xics_ics_simple_eoi(nr);
|
||||
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
|
||||
irq->status &= ~XICS_STATUS_SENT;
|
||||
}
|
||||
}
|
||||
|
||||
static void ics_reset(DeviceState *dev)
|
||||
static void ics_simple_reset(DeviceState *dev)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
ICSState *ics = ICS_SIMPLE(dev);
|
||||
int i;
|
||||
uint8_t flags[ics->nr_irqs];
|
||||
|
||||
|
@ -557,7 +600,7 @@ static void ics_reset(DeviceState *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static int ics_post_load(ICSState *ics, int version_id)
|
||||
static int ics_simple_post_load(ICSState *ics, int version_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -568,20 +611,20 @@ static int ics_post_load(ICSState *ics, int version_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ics_dispatch_pre_save(void *opaque)
|
||||
static void ics_simple_dispatch_pre_save(void *opaque)
|
||||
{
|
||||
ICSState *ics = opaque;
|
||||
ICSStateClass *info = ICS_GET_CLASS(ics);
|
||||
ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
|
||||
|
||||
if (info->pre_save) {
|
||||
info->pre_save(ics);
|
||||
}
|
||||
}
|
||||
|
||||
static int ics_dispatch_post_load(void *opaque, int version_id)
|
||||
static int ics_simple_dispatch_post_load(void *opaque, int version_id)
|
||||
{
|
||||
ICSState *ics = opaque;
|
||||
ICSStateClass *info = ICS_GET_CLASS(ics);
|
||||
ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
|
||||
|
||||
if (info->post_load) {
|
||||
return info->post_load(ics, version_id);
|
||||
|
@ -590,7 +633,7 @@ static int ics_dispatch_post_load(void *opaque, int version_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ics_irq = {
|
||||
static const VMStateDescription vmstate_ics_simple_irq = {
|
||||
.name = "ics/irq",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
|
@ -604,86 +647,93 @@ static const VMStateDescription vmstate_ics_irq = {
|
|||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_ics = {
|
||||
static const VMStateDescription vmstate_ics_simple = {
|
||||
.name = "ics",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = ics_dispatch_pre_save,
|
||||
.post_load = ics_dispatch_post_load,
|
||||
.pre_save = ics_simple_dispatch_pre_save,
|
||||
.post_load = ics_simple_dispatch_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
/* Sanity check */
|
||||
VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
|
||||
|
||||
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
|
||||
vmstate_ics_irq, ICSIRQState),
|
||||
vmstate_ics_simple_irq,
|
||||
ICSIRQState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static void ics_initfn(Object *obj)
|
||||
static void ics_simple_initfn(Object *obj)
|
||||
{
|
||||
ICSState *ics = ICS(obj);
|
||||
ICSState *ics = ICS_SIMPLE(obj);
|
||||
|
||||
ics->offset = XICS_IRQ_BASE;
|
||||
}
|
||||
|
||||
static void ics_realize(DeviceState *dev, Error **errp)
|
||||
static void ics_simple_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
ICSState *ics = ICS_SIMPLE(dev);
|
||||
|
||||
if (!ics->nr_irqs) {
|
||||
error_setg(errp, "Number of interrupts needs to be greater 0");
|
||||
return;
|
||||
}
|
||||
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
|
||||
ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
|
||||
ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
|
||||
}
|
||||
|
||||
static void ics_class_init(ObjectClass *klass, void *data)
|
||||
static void ics_simple_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ICSStateClass *isc = ICS_CLASS(klass);
|
||||
ICSStateClass *isc = ICS_BASE_CLASS(klass);
|
||||
|
||||
dc->realize = ics_realize;
|
||||
dc->vmsd = &vmstate_ics;
|
||||
dc->reset = ics_reset;
|
||||
isc->post_load = ics_post_load;
|
||||
dc->realize = ics_simple_realize;
|
||||
dc->vmsd = &vmstate_ics_simple;
|
||||
dc->reset = ics_simple_reset;
|
||||
isc->post_load = ics_simple_post_load;
|
||||
isc->reject = ics_simple_reject;
|
||||
isc->resend = ics_simple_resend;
|
||||
isc->eoi = ics_simple_eoi;
|
||||
}
|
||||
|
||||
static const TypeInfo ics_info = {
|
||||
.name = TYPE_ICS,
|
||||
.parent = TYPE_DEVICE,
|
||||
static const TypeInfo ics_simple_info = {
|
||||
.name = TYPE_ICS_SIMPLE,
|
||||
.parent = TYPE_ICS_BASE,
|
||||
.instance_size = sizeof(ICSState),
|
||||
.class_init = ics_simple_class_init,
|
||||
.class_size = sizeof(ICSStateClass),
|
||||
.instance_init = ics_simple_initfn,
|
||||
};
|
||||
|
||||
static const TypeInfo ics_base_info = {
|
||||
.name = TYPE_ICS_BASE,
|
||||
.parent = TYPE_DEVICE,
|
||||
.abstract = true,
|
||||
.instance_size = sizeof(ICSState),
|
||||
.class_init = ics_class_init,
|
||||
.class_size = sizeof(ICSStateClass),
|
||||
.instance_init = ics_initfn,
|
||||
};
|
||||
|
||||
/*
|
||||
* Exported functions
|
||||
*/
|
||||
int xics_find_source(XICSState *xics, int irq)
|
||||
ICSState *xics_find_source(XICSState *xics, int irq)
|
||||
{
|
||||
int sources = 1;
|
||||
int src;
|
||||
ICSState *ics;
|
||||
|
||||
/* FIXME: implement multiple sources */
|
||||
for (src = 0; src < sources; ++src) {
|
||||
ICSState *ics = &xics->ics[src];
|
||||
QLIST_FOREACH(ics, &xics->ics, list) {
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
return src;
|
||||
return ics;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qemu_irq xics_get_qirq(XICSState *xics, int irq)
|
||||
{
|
||||
int src = xics_find_source(xics, irq);
|
||||
ICSState *ics = xics_find_source(xics, irq);
|
||||
|
||||
if (src >= 0) {
|
||||
ICSState *ics = &xics->ics[src];
|
||||
if (ics) {
|
||||
return ics->qirqs[irq - ics->offset];
|
||||
}
|
||||
|
||||
|
@ -701,7 +751,8 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
|
|||
static void xics_register_types(void)
|
||||
{
|
||||
type_register_static(&xics_common_info);
|
||||
type_register_static(&ics_info);
|
||||
type_register_static(&ics_simple_info);
|
||||
type_register_static(&ics_base_info);
|
||||
type_register_static(&icp_info);
|
||||
}
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@ static void ics_kvm_set_irq(void *opaque, int srcno, int val)
|
|||
|
||||
static void ics_kvm_reset(DeviceState *dev)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
ICSState *ics = ICS_SIMPLE(dev);
|
||||
int i;
|
||||
uint8_t flags[ics->nr_irqs];
|
||||
|
||||
|
@ -293,7 +293,7 @@ static void ics_kvm_reset(DeviceState *dev)
|
|||
|
||||
static void ics_kvm_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
ICSState *ics = ICS_SIMPLE(dev);
|
||||
|
||||
if (!ics->nr_irqs) {
|
||||
error_setg(errp, "Number of interrupts needs to be greater 0");
|
||||
|
@ -306,7 +306,7 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp)
|
|||
static void ics_kvm_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ICSStateClass *icsc = ICS_CLASS(klass);
|
||||
ICSStateClass *icsc = ICS_BASE_CLASS(klass);
|
||||
|
||||
dc->realize = ics_kvm_realize;
|
||||
dc->reset = ics_kvm_reset;
|
||||
|
@ -315,8 +315,8 @@ static void ics_kvm_class_init(ObjectClass *klass, void *data)
|
|||
}
|
||||
|
||||
static const TypeInfo ics_kvm_info = {
|
||||
.name = TYPE_KVM_ICS,
|
||||
.parent = TYPE_ICS,
|
||||
.name = TYPE_ICS_KVM,
|
||||
.parent = TYPE_ICS_SIMPLE,
|
||||
.instance_size = sizeof(ICSState),
|
||||
.class_init = ics_kvm_class_init,
|
||||
};
|
||||
|
@ -361,7 +361,13 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
|
|||
static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
|
||||
Error **errp)
|
||||
{
|
||||
xics->nr_irqs = xics->ics->nr_irqs = nr_irqs;
|
||||
ICSState *ics = QLIST_FIRST(&xics->ics);
|
||||
|
||||
/* This needs to be deprecated ... */
|
||||
xics->nr_irqs = nr_irqs;
|
||||
if (ics) {
|
||||
ics->nr_irqs = nr_irqs;
|
||||
}
|
||||
}
|
||||
|
||||
static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers,
|
||||
|
@ -394,6 +400,7 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp)
|
|||
{
|
||||
KVMXICSState *xicskvm = XICS_SPAPR_KVM(dev);
|
||||
XICSState *xics = XICS_COMMON(dev);
|
||||
ICSState *ics;
|
||||
int i, rc;
|
||||
Error *error = NULL;
|
||||
struct kvm_create_device xics_create_device = {
|
||||
|
@ -445,10 +452,12 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
xicskvm->kernel_xics_fd = xics_create_device.fd;
|
||||
|
||||
object_property_set_bool(OBJECT(xics->ics), true, "realized", &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto fail;
|
||||
QLIST_FOREACH(ics, &xics->ics, list) {
|
||||
object_property_set_bool(OBJECT(ics), true, "realized", &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
assert(xics->nr_servers);
|
||||
|
@ -477,10 +486,12 @@ fail:
|
|||
static void xics_kvm_initfn(Object *obj)
|
||||
{
|
||||
XICSState *xics = XICS_COMMON(obj);
|
||||
ICSState *ics;
|
||||
|
||||
xics->ics = ICS(object_new(TYPE_KVM_ICS));
|
||||
object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
|
||||
xics->ics->xics = xics;
|
||||
ics = ICS_SIMPLE(object_new(TYPE_ICS_KVM));
|
||||
object_property_add_child(obj, "ics", OBJECT(ics), NULL);
|
||||
ics->xics = xics;
|
||||
QLIST_INSERT_HEAD(&xics->ics, ics, list);
|
||||
}
|
||||
|
||||
static void xics_kvm_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -113,13 +113,17 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr, server, priority;
|
||||
ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
|
||||
uint32_t nr, srcno, server, priority;
|
||||
|
||||
if ((nargs != 3) || (nret != 1)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
if (!ics) {
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1));
|
||||
|
@ -131,7 +135,8 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
return;
|
||||
}
|
||||
|
||||
ics_write_xive(ics, nr, server, priority, priority);
|
||||
srcno = nr - ics->offset;
|
||||
ics_simple_write_xive(ics, srcno, server, priority, priority);
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
}
|
||||
|
@ -141,13 +146,17 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr;
|
||||
ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
|
||||
uint32_t nr, srcno;
|
||||
|
||||
if ((nargs != 1) || (nret != 3)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
if (!ics) {
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
|
||||
|
@ -157,8 +166,9 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
}
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
|
||||
rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
|
||||
srcno = nr - ics->offset;
|
||||
rtas_st(rets, 1, ics->irqs[srcno].server);
|
||||
rtas_st(rets, 2, ics->irqs[srcno].priority);
|
||||
}
|
||||
|
||||
static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
|
@ -166,13 +176,17 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr;
|
||||
ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
|
||||
uint32_t nr, srcno;
|
||||
|
||||
if ((nargs != 1) || (nret != 1)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
if (!ics) {
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
|
||||
|
@ -181,8 +195,9 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
return;
|
||||
}
|
||||
|
||||
ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
|
||||
ics->irqs[nr - ics->offset].priority);
|
||||
srcno = nr - ics->offset;
|
||||
ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff,
|
||||
ics->irqs[srcno].priority);
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
}
|
||||
|
@ -192,13 +207,17 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr;
|
||||
ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
|
||||
uint32_t nr, srcno;
|
||||
|
||||
if ((nargs != 1) || (nret != 1)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
if (!ics) {
|
||||
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
|
||||
|
@ -207,9 +226,10 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
return;
|
||||
}
|
||||
|
||||
ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
|
||||
ics->irqs[nr - ics->offset].saved_priority,
|
||||
ics->irqs[nr - ics->offset].saved_priority);
|
||||
srcno = nr - ics->offset;
|
||||
ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server,
|
||||
ics->irqs[srcno].saved_priority,
|
||||
ics->irqs[srcno].saved_priority);
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
}
|
||||
|
@ -217,7 +237,13 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
|
||||
Error **errp)
|
||||
{
|
||||
xics->nr_irqs = xics->ics->nr_irqs = nr_irqs;
|
||||
ICSState *ics = QLIST_FIRST(&xics->ics);
|
||||
|
||||
/* This needs to be deprecated ... */
|
||||
xics->nr_irqs = nr_irqs;
|
||||
if (ics) {
|
||||
ics->nr_irqs = nr_irqs;
|
||||
}
|
||||
}
|
||||
|
||||
static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers,
|
||||
|
@ -240,6 +266,7 @@ static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers,
|
|||
static void xics_spapr_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
XICSState *xics = XICS_SPAPR(dev);
|
||||
ICSState *ics;
|
||||
Error *error = NULL;
|
||||
int i;
|
||||
|
||||
|
@ -261,10 +288,12 @@ static void xics_spapr_realize(DeviceState *dev, Error **errp)
|
|||
spapr_register_hypercall(H_EOI, h_eoi);
|
||||
spapr_register_hypercall(H_IPOLL, h_ipoll);
|
||||
|
||||
object_property_set_bool(OBJECT(xics->ics), true, "realized", &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
QLIST_FOREACH(ics, &xics->ics, list) {
|
||||
object_property_set_bool(OBJECT(ics), true, "realized", &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < xics->nr_servers; i++) {
|
||||
|
@ -280,10 +309,12 @@ static void xics_spapr_realize(DeviceState *dev, Error **errp)
|
|||
static void xics_spapr_initfn(Object *obj)
|
||||
{
|
||||
XICSState *xics = XICS_SPAPR(obj);
|
||||
ICSState *ics;
|
||||
|
||||
xics->ics = ICS(object_new(TYPE_ICS));
|
||||
object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
|
||||
xics->ics->xics = xics;
|
||||
ics = ICS_SIMPLE(object_new(TYPE_ICS_SIMPLE));
|
||||
object_property_add_child(obj, "ics", OBJECT(ics), NULL);
|
||||
ics->xics = xics;
|
||||
QLIST_INSERT_HEAD(&xics->ics, ics, list);
|
||||
}
|
||||
|
||||
static void xics_spapr_class_init(ObjectClass *oc, void *data)
|
||||
|
@ -329,14 +360,15 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi,
|
||||
Error **errp)
|
||||
int xics_spapr_alloc(XICSState *xics, int irq_hint, bool lsi, Error **errp)
|
||||
{
|
||||
ICSState *ics = &xics->ics[src];
|
||||
ICSState *ics = QLIST_FIRST(&xics->ics);
|
||||
int irq;
|
||||
|
||||
if (!ics) {
|
||||
return -1;
|
||||
}
|
||||
if (irq_hint) {
|
||||
assert(src == xics_find_source(xics, irq_hint));
|
||||
if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
|
||||
error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
|
||||
return -1;
|
||||
|
@ -352,7 +384,7 @@ int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi,
|
|||
}
|
||||
|
||||
ics_set_irq_type(ics, irq - ics->offset, lsi);
|
||||
trace_xics_alloc(src, irq);
|
||||
trace_xics_alloc(irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
@ -361,13 +393,16 @@ int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi,
|
|||
* Allocate block of consecutive IRQs, and return the number of the first IRQ in
|
||||
* the block. If align==true, aligns the first IRQ number to num.
|
||||
*/
|
||||
int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi,
|
||||
bool align, Error **errp)
|
||||
int xics_spapr_alloc_block(XICSState *xics, int num, bool lsi, bool align,
|
||||
Error **errp)
|
||||
{
|
||||
ICSState *ics = QLIST_FIRST(&xics->ics);
|
||||
int i, first = -1;
|
||||
ICSState *ics = &xics->ics[src];
|
||||
|
||||
assert(src == 0);
|
||||
if (!ics) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* MSIMesage::data is used for storing VIRQ so
|
||||
* it has to be aligned to num to support multiple
|
||||
|
@ -394,7 +429,7 @@ int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi,
|
|||
}
|
||||
first += ics->offset;
|
||||
|
||||
trace_xics_alloc_block(src, first, num, lsi, align);
|
||||
trace_xics_alloc_block(first, num, lsi, align);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
@ -405,7 +440,7 @@ static void ics_free(ICSState *ics, int srcno, int num)
|
|||
|
||||
for (i = srcno; i < srcno + num; ++i) {
|
||||
if (ICS_IRQ_FREE(ics, i)) {
|
||||
trace_xics_ics_free_warn(ics - ics->xics->ics, i + ics->offset);
|
||||
trace_xics_ics_free_warn(0, i + ics->offset);
|
||||
}
|
||||
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
|
||||
}
|
||||
|
@ -413,15 +448,10 @@ static void ics_free(ICSState *ics, int srcno, int num)
|
|||
|
||||
void xics_spapr_free(XICSState *xics, int irq, int num)
|
||||
{
|
||||
int src = xics_find_source(xics, irq);
|
||||
ICSState *ics = xics_find_source(xics, irq);
|
||||
|
||||
if (src >= 0) {
|
||||
ICSState *ics = &xics->ics[src];
|
||||
|
||||
/* FIXME: implement multiple sources */
|
||||
assert(src == 0);
|
||||
|
||||
trace_xics_ics_free(ics - xics->ics, irq, num);
|
||||
if (ics) {
|
||||
trace_xics_ics_free(0, irq, num);
|
||||
ics_free(ics, irq - ics->offset, num);
|
||||
}
|
||||
}
|
||||
|
|
118
hw/ppc/spapr.c
118
hw/ppc/spapr.c
|
@ -2370,6 +2370,56 @@ static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine)
|
|||
return head;
|
||||
}
|
||||
|
||||
static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
|
||||
uint64_t *buid, hwaddr *pio,
|
||||
hwaddr *mmio32, hwaddr *mmio64,
|
||||
unsigned n_dma, uint32_t *liobns, Error **errp)
|
||||
{
|
||||
/*
|
||||
* New-style PHB window placement.
|
||||
*
|
||||
* Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
|
||||
* for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
|
||||
* windows.
|
||||
*
|
||||
* Some guest kernels can't work with MMIO windows above 1<<46
|
||||
* (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
|
||||
*
|
||||
* 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
|
||||
* PHB stacked together. (32TiB+2GiB)..(32TiB+64GiB) contains the
|
||||
* 2GiB 32-bit MMIO windows for each PHB. Then 33..64TiB has the
|
||||
* 1TiB 64-bit MMIO windows for each PHB.
|
||||
*/
|
||||
const uint64_t base_buid = 0x800000020000000ULL;
|
||||
const int max_phbs =
|
||||
(SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / SPAPR_PCI_MEM64_WIN_SIZE - 1;
|
||||
int i;
|
||||
|
||||
/* Sanity check natural alignments */
|
||||
QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
|
||||
QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
|
||||
QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
|
||||
QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
|
||||
/* Sanity check bounds */
|
||||
QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_IO_WIN_SIZE) > SPAPR_PCI_MEM32_WIN_SIZE);
|
||||
QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_MEM32_WIN_SIZE) > SPAPR_PCI_MEM64_WIN_SIZE);
|
||||
|
||||
if (index >= max_phbs) {
|
||||
error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
|
||||
max_phbs - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
*buid = base_buid + index;
|
||||
for (i = 0; i < n_dma; ++i) {
|
||||
liobns[i] = SPAPR_PCI_LIOBN(index, i);
|
||||
}
|
||||
|
||||
*pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
|
||||
*mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
|
||||
*mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
|
||||
}
|
||||
|
||||
static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
@ -2406,6 +2456,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
|||
mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus;
|
||||
fwc->get_dev_path = spapr_get_fw_dev_path;
|
||||
nc->nmi_monitor_handler = spapr_nmi;
|
||||
smc->phb_placement = spapr_phb_placement;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_machine_info = {
|
||||
|
@ -2470,11 +2521,71 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", true);
|
|||
/*
|
||||
* pseries-2.7
|
||||
*/
|
||||
#define SPAPR_COMPAT_2_7 \
|
||||
HW_COMPAT_2_7 \
|
||||
#define SPAPR_COMPAT_2_7 \
|
||||
HW_COMPAT_2_7 \
|
||||
{ \
|
||||
.driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
|
||||
.property = "mem_win_size", \
|
||||
.value = stringify(SPAPR_PCI_2_7_MMIO_WIN_SIZE),\
|
||||
}, \
|
||||
{ \
|
||||
.driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
|
||||
.property = "mem64_win_size", \
|
||||
.value = "0", \
|
||||
},
|
||||
|
||||
static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
|
||||
uint64_t *buid, hwaddr *pio,
|
||||
hwaddr *mmio32, hwaddr *mmio64,
|
||||
unsigned n_dma, uint32_t *liobns, Error **errp)
|
||||
{
|
||||
/* Legacy PHB placement for pseries-2.7 and earlier machine types */
|
||||
const uint64_t base_buid = 0x800000020000000ULL;
|
||||
const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
|
||||
const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
|
||||
const hwaddr pio_offset = 0x80000000; /* 2 GiB */
|
||||
const uint32_t max_index = 255;
|
||||
const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
|
||||
|
||||
uint64_t ram_top = MACHINE(spapr)->ram_size;
|
||||
hwaddr phb0_base, phb_base;
|
||||
int i;
|
||||
|
||||
/* Do we have hotpluggable memory? */
|
||||
if (MACHINE(spapr)->maxram_size > ram_top) {
|
||||
/* Can't just use maxram_size, because there may be an
|
||||
* alignment gap between normal and hotpluggable memory
|
||||
* regions */
|
||||
ram_top = spapr->hotplug_memory.base +
|
||||
memory_region_size(&spapr->hotplug_memory.mr);
|
||||
}
|
||||
|
||||
phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
|
||||
|
||||
if (index > max_index) {
|
||||
error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
|
||||
max_index);
|
||||
return;
|
||||
}
|
||||
|
||||
*buid = base_buid + index;
|
||||
for (i = 0; i < n_dma; ++i) {
|
||||
liobns[i] = SPAPR_PCI_LIOBN(index, i);
|
||||
}
|
||||
|
||||
phb_base = phb0_base + index * phb_spacing;
|
||||
*pio = phb_base + pio_offset;
|
||||
*mmio32 = phb_base + mmio_offset;
|
||||
/*
|
||||
* We don't set the 64-bit MMIO window, relying on the PHB's
|
||||
* fallback behaviour of automatically splitting a large "32-bit"
|
||||
* window into contiguous 32-bit and 64-bit windows
|
||||
*/
|
||||
}
|
||||
|
||||
static void spapr_machine_2_7_instance_options(MachineState *machine)
|
||||
{
|
||||
spapr_machine_2_8_instance_options(machine);
|
||||
}
|
||||
|
||||
static void spapr_machine_2_7_class_options(MachineClass *mc)
|
||||
|
@ -2484,6 +2595,7 @@ static void spapr_machine_2_7_class_options(MachineClass *mc)
|
|||
spapr_machine_2_8_class_options(mc);
|
||||
smc->tcg_default_cpu = "POWER7";
|
||||
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7);
|
||||
smc->phb_placement = phb_placement_2_7;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
|
||||
|
@ -2501,6 +2613,7 @@ DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
|
|||
|
||||
static void spapr_machine_2_6_instance_options(MachineState *machine)
|
||||
{
|
||||
spapr_machine_2_7_instance_options(machine);
|
||||
}
|
||||
|
||||
static void spapr_machine_2_6_class_options(MachineClass *mc)
|
||||
|
@ -2525,6 +2638,7 @@ DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
|
|||
|
||||
static void spapr_machine_2_5_instance_options(MachineState *machine)
|
||||
{
|
||||
spapr_machine_2_6_instance_options(machine);
|
||||
}
|
||||
|
||||
static void spapr_machine_2_5_class_options(MachineClass *mc)
|
||||
|
|
|
@ -594,7 +594,7 @@ out_no_events:
|
|||
void spapr_events_init(sPAPRMachineState *spapr)
|
||||
{
|
||||
QTAILQ_INIT(&spapr->pending_events);
|
||||
spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, 0, false,
|
||||
spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, false,
|
||||
&error_fatal);
|
||||
spapr->epow_notifier.notify = spapr_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&spapr->epow_notifier);
|
||||
|
|
|
@ -363,7 +363,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
}
|
||||
|
||||
/* Allocate MSIs */
|
||||
irq = xics_spapr_alloc_block(spapr->xics, 0, req_num, false,
|
||||
irq = xics_spapr_alloc_block(spapr->xics, req_num, false,
|
||||
ret_intr_type == RTAS_TYPE_MSI, &err);
|
||||
if (err) {
|
||||
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
|
||||
|
@ -1311,32 +1311,27 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||
sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1;
|
||||
|
||||
if (sphb->index != (uint32_t)-1) {
|
||||
hwaddr windows_base;
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn[0] != (uint32_t)-1)
|
||||
|| (sphb->dma_liobn[1] != (uint32_t)-1 && windows_supported == 2)
|
||||
|| (sphb->mem_win_addr != (hwaddr)-1)
|
||||
|| (sphb->mem64_win_addr != (hwaddr)-1)
|
||||
|| (sphb->io_win_addr != (hwaddr)-1)) {
|
||||
error_setg(errp, "Either \"index\" or other parameters must"
|
||||
" be specified for PAPR PHB, not both");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->index > SPAPR_PCI_MAX_INDEX) {
|
||||
error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
|
||||
SPAPR_PCI_MAX_INDEX);
|
||||
smc->phb_placement(spapr, sphb->index,
|
||||
&sphb->buid, &sphb->io_win_addr,
|
||||
&sphb->mem_win_addr, &sphb->mem64_win_addr,
|
||||
windows_supported, sphb->dma_liobn, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index;
|
||||
for (i = 0; i < windows_supported; ++i) {
|
||||
sphb->dma_liobn[i] = SPAPR_PCI_LIOBN(sphb->index, i);
|
||||
}
|
||||
|
||||
windows_base = SPAPR_PCI_WINDOW_BASE
|
||||
+ sphb->index * SPAPR_PCI_WINDOW_SPACING;
|
||||
sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF;
|
||||
sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF;
|
||||
}
|
||||
|
||||
if (sphb->buid == (uint64_t)-1) {
|
||||
|
@ -1360,6 +1355,38 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
if (sphb->mem64_win_size != 0) {
|
||||
if (sphb->mem64_win_addr == (hwaddr)-1) {
|
||||
error_setg(errp,
|
||||
"64-bit memory window address not specified for PHB");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) {
|
||||
error_setg(errp, "32-bit memory window of size 0x%"HWADDR_PRIx
|
||||
" (max 2 GiB)", sphb->mem_win_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->mem64_win_pciaddr == (hwaddr)-1) {
|
||||
/* 64-bit window defaults to identity mapping */
|
||||
sphb->mem64_win_pciaddr = sphb->mem64_win_addr;
|
||||
}
|
||||
} else if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) {
|
||||
/*
|
||||
* For compatibility with old configuration, if no 64-bit MMIO
|
||||
* window is specified, but the ordinary (32-bit) memory
|
||||
* window is specified as > 2GiB, we treat it as a 2GiB 32-bit
|
||||
* window, with a 64-bit MMIO window following on immediately
|
||||
* afterwards
|
||||
*/
|
||||
sphb->mem64_win_size = sphb->mem_win_size - SPAPR_PCI_MEM32_WIN_SIZE;
|
||||
sphb->mem64_win_addr = sphb->mem_win_addr + SPAPR_PCI_MEM32_WIN_SIZE;
|
||||
sphb->mem64_win_pciaddr =
|
||||
SPAPR_PCI_MEM_WIN_BUS_OFFSET + SPAPR_PCI_MEM32_WIN_SIZE;
|
||||
sphb->mem_win_size = SPAPR_PCI_MEM32_WIN_SIZE;
|
||||
}
|
||||
|
||||
if (spapr_pci_find_phb(spapr, sphb->buid)) {
|
||||
error_setg(errp, "PCI host bridges must have unique BUIDs");
|
||||
return;
|
||||
|
@ -1373,12 +1400,19 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||
sprintf(namebuf, "%s.mmio", sphb->dtbusname);
|
||||
memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, UINT64_MAX);
|
||||
|
||||
sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
|
||||
memory_region_init_alias(&sphb->memwindow, OBJECT(sphb),
|
||||
sprintf(namebuf, "%s.mmio32-alias", sphb->dtbusname);
|
||||
memory_region_init_alias(&sphb->mem32window, OBJECT(sphb),
|
||||
namebuf, &sphb->memspace,
|
||||
SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size);
|
||||
memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
|
||||
&sphb->memwindow);
|
||||
&sphb->mem32window);
|
||||
|
||||
sprintf(namebuf, "%s.mmio64-alias", sphb->dtbusname);
|
||||
memory_region_init_alias(&sphb->mem64window, OBJECT(sphb),
|
||||
namebuf, &sphb->memspace,
|
||||
sphb->mem64_win_pciaddr, sphb->mem64_win_size);
|
||||
memory_region_add_subregion(get_system_memory(), sphb->mem64_win_addr,
|
||||
&sphb->mem64window);
|
||||
|
||||
/* Initialize IO regions */
|
||||
sprintf(namebuf, "%s.io", sphb->dtbusname);
|
||||
|
@ -1445,8 +1479,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||
uint32_t irq;
|
||||
Error *local_err = NULL;
|
||||
|
||||
irq = xics_spapr_alloc_block(spapr->xics, 0, 1, true, false,
|
||||
&local_err);
|
||||
irq = xics_spapr_alloc_block(spapr->xics, 1, true, false, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
error_prepend(errp, "can't allocate LSIs: ");
|
||||
|
@ -1531,7 +1564,12 @@ static Property spapr_phb_properties[] = {
|
|||
DEFINE_PROP_UINT32("liobn64", sPAPRPHBState, dma_liobn[1], -1),
|
||||
DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
|
||||
DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size,
|
||||
SPAPR_PCI_MMIO_WIN_SIZE),
|
||||
SPAPR_PCI_MEM32_WIN_SIZE),
|
||||
DEFINE_PROP_UINT64("mem64_win_addr", sPAPRPHBState, mem64_win_addr, -1),
|
||||
DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size,
|
||||
SPAPR_PCI_MEM64_WIN_SIZE),
|
||||
DEFINE_PROP_UINT64("mem64_win_pciaddr", sPAPRPHBState, mem64_win_pciaddr,
|
||||
-1),
|
||||
DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
|
||||
DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_win_size,
|
||||
SPAPR_PCI_IO_WIN_SIZE),
|
||||
|
@ -1767,10 +1805,6 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
|||
int bus_off, i, j, ret;
|
||||
char nodename[FDT_NAME_MAX];
|
||||
uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
|
||||
const uint64_t mmiosize = memory_region_size(&phb->memwindow);
|
||||
const uint64_t w32max = (1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET;
|
||||
const uint64_t w32size = MIN(w32max, mmiosize);
|
||||
const uint64_t w64size = (mmiosize > w32size) ? (mmiosize - w32size) : 0;
|
||||
struct {
|
||||
uint32_t hi;
|
||||
uint64_t child;
|
||||
|
@ -1785,15 +1819,16 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
|||
{
|
||||
cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET),
|
||||
cpu_to_be64(phb->mem_win_addr),
|
||||
cpu_to_be64(w32size),
|
||||
cpu_to_be64(phb->mem_win_size),
|
||||
},
|
||||
{
|
||||
cpu_to_be32(b_ss(3)), cpu_to_be64(1ULL << 32),
|
||||
cpu_to_be64(phb->mem_win_addr + w32size),
|
||||
cpu_to_be64(w64size)
|
||||
cpu_to_be32(b_ss(3)), cpu_to_be64(phb->mem64_win_pciaddr),
|
||||
cpu_to_be64(phb->mem64_win_addr),
|
||||
cpu_to_be64(phb->mem64_win_size),
|
||||
},
|
||||
};
|
||||
const unsigned sizeof_ranges = (w64size ? 3 : 2) * sizeof(ranges[0]);
|
||||
const unsigned sizeof_ranges =
|
||||
(phb->mem64_win_size ? 3 : 2) * sizeof(ranges[0]);
|
||||
uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
|
||||
uint32_t interrupt_map_mask[] = {
|
||||
cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)};
|
||||
|
|
|
@ -453,7 +453,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
|
|||
dev->qdev.id = id;
|
||||
}
|
||||
|
||||
dev->irq = xics_spapr_alloc(spapr->xics, 0, dev->irq, false, &local_err);
|
||||
dev->irq = xics_spapr_alloc(spapr->xics, dev->irq, false, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
|
|
|
@ -53,8 +53,10 @@ struct sPAPRPHBState {
|
|||
bool dr_enabled;
|
||||
|
||||
MemoryRegion memspace, iospace;
|
||||
hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
|
||||
MemoryRegion memwindow, iowindow, msiwindow;
|
||||
hwaddr mem_win_addr, mem_win_size, mem64_win_addr, mem64_win_size;
|
||||
uint64_t mem64_win_pciaddr;
|
||||
hwaddr io_win_addr, io_win_size;
|
||||
MemoryRegion mem32window, mem64window, iowindow, msiwindow;
|
||||
|
||||
uint32_t dma_liobn[SPAPR_PCI_DMA_MAX_WINDOWS];
|
||||
hwaddr dma_win_addr, dma_win_size;
|
||||
|
@ -79,18 +81,17 @@ struct sPAPRPHBState {
|
|||
uint32_t numa_node;
|
||||
};
|
||||
|
||||
#define SPAPR_PCI_MAX_INDEX 255
|
||||
|
||||
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
|
||||
|
||||
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
|
||||
#define SPAPR_PCI_MEM32_WIN_SIZE \
|
||||
((1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET)
|
||||
#define SPAPR_PCI_MEM64_WIN_SIZE 0x10000000000ULL /* 1 TiB */
|
||||
|
||||
#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL
|
||||
#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL
|
||||
#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000
|
||||
#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \
|
||||
SPAPR_PCI_MEM_WIN_BUS_OFFSET)
|
||||
#define SPAPR_PCI_IO_WIN_OFF 0x80000000
|
||||
/* Without manual configuration, all PCI outbound windows will be
|
||||
* within this range */
|
||||
#define SPAPR_PCI_BASE (1ULL << 45) /* 32 TiB */
|
||||
#define SPAPR_PCI_LIMIT (1ULL << 46) /* 64 TiB */
|
||||
|
||||
#define SPAPR_PCI_2_7_MMIO_WIN_SIZE 0xf80000000
|
||||
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
|
||||
|
||||
#define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL
|
||||
|
|
|
@ -40,6 +40,10 @@ struct sPAPRMachineClass {
|
|||
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
|
||||
bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
|
||||
const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */
|
||||
void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index,
|
||||
uint64_t *buid, hwaddr *pio,
|
||||
hwaddr *mmio32, hwaddr *mmio64,
|
||||
unsigned n_dma, uint32_t *liobns, Error **errp);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -85,7 +85,7 @@ struct XICSState {
|
|||
uint32_t nr_servers;
|
||||
uint32_t nr_irqs;
|
||||
ICPState *ss;
|
||||
ICSState *ics;
|
||||
QLIST_HEAD(, ICSState) ics;
|
||||
};
|
||||
|
||||
#define TYPE_ICP "icp"
|
||||
|
@ -111,6 +111,7 @@ struct ICPState {
|
|||
DeviceState parent_obj;
|
||||
/*< public >*/
|
||||
CPUState *cs;
|
||||
ICSState *xirr_owner;
|
||||
uint32_t xirr;
|
||||
uint8_t pending_priority;
|
||||
uint8_t mfrr;
|
||||
|
@ -118,22 +119,29 @@ struct ICPState {
|
|||
bool cap_irq_xics_enabled;
|
||||
};
|
||||
|
||||
#define TYPE_ICS "ics"
|
||||
#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS)
|
||||
#define TYPE_ICS_BASE "ics-base"
|
||||
#define ICS_BASE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_BASE)
|
||||
|
||||
#define TYPE_KVM_ICS "icskvm"
|
||||
#define KVM_ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_KVM_ICS)
|
||||
/* Retain ics for sPAPR for migration from existing sPAPR guests */
|
||||
#define TYPE_ICS_SIMPLE "ics"
|
||||
#define ICS_SIMPLE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SIMPLE)
|
||||
|
||||
#define ICS_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS)
|
||||
#define ICS_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS)
|
||||
#define TYPE_ICS_KVM "icskvm"
|
||||
#define ICS_KVM(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_KVM)
|
||||
|
||||
#define ICS_BASE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS_BASE)
|
||||
#define ICS_BASE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS_BASE)
|
||||
|
||||
struct ICSStateClass {
|
||||
DeviceClass parent_class;
|
||||
|
||||
void (*pre_save)(ICSState *s);
|
||||
int (*post_load)(ICSState *s, int version_id);
|
||||
void (*reject)(ICSState *s, uint32_t irq);
|
||||
void (*resend)(ICSState *s);
|
||||
void (*eoi)(ICSState *s, uint32_t irq);
|
||||
};
|
||||
|
||||
struct ICSState {
|
||||
|
@ -145,6 +153,7 @@ struct ICSState {
|
|||
qemu_irq *qirqs;
|
||||
ICSIRQState *irqs;
|
||||
XICSState *xics;
|
||||
QLIST_ENTRY(ICSState) list;
|
||||
};
|
||||
|
||||
static inline bool ics_valid_irq(ICSState *ics, uint32_t nr)
|
||||
|
@ -172,10 +181,9 @@ struct ICSIRQState {
|
|||
#define XICS_IRQS_SPAPR 1024
|
||||
|
||||
qemu_irq xics_get_qirq(XICSState *icp, int irq);
|
||||
int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi,
|
||||
Error **errp);
|
||||
int xics_spapr_alloc_block(XICSState *icp, int src, int num, bool lsi,
|
||||
bool align, Error **errp);
|
||||
int xics_spapr_alloc(XICSState *icp, int irq_hint, bool lsi, Error **errp);
|
||||
int xics_spapr_alloc_block(XICSState *icp, int num, bool lsi, bool align,
|
||||
Error **errp);
|
||||
void xics_spapr_free(XICSState *icp, int irq, int num);
|
||||
|
||||
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu);
|
||||
|
@ -190,11 +198,11 @@ uint32_t icp_accept(ICPState *ss);
|
|||
uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr);
|
||||
void icp_eoi(XICSState *icp, int server, uint32_t xirr);
|
||||
|
||||
void ics_write_xive(ICSState *ics, int nr, int server,
|
||||
uint8_t priority, uint8_t saved_priority);
|
||||
void ics_simple_write_xive(ICSState *ics, int nr, int server,
|
||||
uint8_t priority, uint8_t saved_priority);
|
||||
|
||||
void ics_set_irq_type(ICSState *ics, int srcno, bool lsi);
|
||||
|
||||
int xics_find_source(XICSState *icp, int irq);
|
||||
ICSState *xics_find_source(XICSState *icp, int irq);
|
||||
|
||||
#endif /* XICS_H */
|
||||
|
|
7
qtest.c
7
qtest.c
|
@ -537,6 +537,13 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
|
|||
|
||||
qtest_send_prefix(chr);
|
||||
qtest_send(chr, "OK\n");
|
||||
} else if (strcmp(words[0], "endianness") == 0) {
|
||||
qtest_send_prefix(chr);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
qtest_sendf(chr, "OK big\n");
|
||||
#else
|
||||
qtest_sendf(chr, "OK little\n");
|
||||
#endif
|
||||
#ifdef TARGET_PPC64
|
||||
} else if (strcmp(words[0], "rtas") == 0) {
|
||||
uint64_t res, args, ret;
|
||||
|
|
|
@ -267,6 +267,11 @@ DEF_HELPER_3(vinsertb, void, avr, avr, i32)
|
|||
DEF_HELPER_3(vinserth, void, avr, avr, i32)
|
||||
DEF_HELPER_3(vinsertw, void, avr, avr, i32)
|
||||
DEF_HELPER_3(vinsertd, void, avr, avr, i32)
|
||||
DEF_HELPER_2(vextsb2w, void, avr, avr)
|
||||
DEF_HELPER_2(vextsh2w, void, avr, avr)
|
||||
DEF_HELPER_2(vextsb2d, void, avr, avr)
|
||||
DEF_HELPER_2(vextsh2d, void, avr, avr)
|
||||
DEF_HELPER_2(vextsw2d, void, avr, avr)
|
||||
DEF_HELPER_2(vupkhpx, void, avr, avr)
|
||||
DEF_HELPER_2(vupklpx, void, avr, avr)
|
||||
DEF_HELPER_2(vupkhsb, void, avr, avr)
|
||||
|
|
|
@ -1934,6 +1934,21 @@ VEXTRACT(uw, u32)
|
|||
VEXTRACT(d, u64)
|
||||
#undef VEXTRACT
|
||||
|
||||
#define VEXT_SIGNED(name, element, mask, cast, recast) \
|
||||
void helper_##name(ppc_avr_t *r, ppc_avr_t *b) \
|
||||
{ \
|
||||
int i; \
|
||||
VECTOR_FOR_INORDER_I(i, element) { \
|
||||
r->element[i] = (recast)((cast)(b->element[i] & mask)); \
|
||||
} \
|
||||
}
|
||||
VEXT_SIGNED(vextsb2w, s32, UINT8_MAX, int8_t, int32_t)
|
||||
VEXT_SIGNED(vextsb2d, s64, UINT8_MAX, int8_t, int64_t)
|
||||
VEXT_SIGNED(vextsh2w, s32, UINT16_MAX, int16_t, int32_t)
|
||||
VEXT_SIGNED(vextsh2d, s64, UINT16_MAX, int16_t, int64_t)
|
||||
VEXT_SIGNED(vextsw2d, s64, UINT32_MAX, int32_t, int64_t)
|
||||
#undef VEXT_SIGNED
|
||||
|
||||
#define VSPLTI(suffix, element, splat_type) \
|
||||
void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
|
||||
{ \
|
||||
|
|
|
@ -815,6 +815,11 @@ GEN_VXFORM_NOA(vclzb, 1, 28)
|
|||
GEN_VXFORM_NOA(vclzh, 1, 29)
|
||||
GEN_VXFORM_NOA(vclzw, 1, 30)
|
||||
GEN_VXFORM_NOA(vclzd, 1, 31)
|
||||
GEN_VXFORM_NOA_2(vextsb2w, 1, 24, 16)
|
||||
GEN_VXFORM_NOA_2(vextsh2w, 1, 24, 17)
|
||||
GEN_VXFORM_NOA_2(vextsb2d, 1, 24, 24)
|
||||
GEN_VXFORM_NOA_2(vextsh2d, 1, 24, 25)
|
||||
GEN_VXFORM_NOA_2(vextsw2d, 1, 24, 26)
|
||||
GEN_VXFORM_NOA_2(vctzb, 1, 24, 28)
|
||||
GEN_VXFORM_NOA_2(vctzh, 1, 24, 29)
|
||||
GEN_VXFORM_NOA_2(vctzw, 1, 24, 30)
|
||||
|
|
|
@ -215,6 +215,11 @@ GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000,
|
|||
GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000,
|
||||
PPC_ALTIVEC),
|
||||
GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000),
|
||||
GEN_VXFORM_300_EO(vextsb2w, 0x01, 0x18, 0x10),
|
||||
GEN_VXFORM_300_EO(vextsh2w, 0x01, 0x18, 0x11),
|
||||
GEN_VXFORM_300_EO(vextsb2d, 0x01, 0x18, 0x18),
|
||||
GEN_VXFORM_300_EO(vextsh2d, 0x01, 0x18, 0x19),
|
||||
GEN_VXFORM_300_EO(vextsw2d, 0x01, 0x18, 0x1A),
|
||||
GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C),
|
||||
GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D),
|
||||
GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E),
|
||||
|
|
|
@ -112,7 +112,7 @@ typedef struct {
|
|||
g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
|
||||
} while (0)
|
||||
|
||||
static const char *disk = "tests/acpi-test-disk.raw";
|
||||
static char disk[] = "tests/acpi-test-disk-XXXXXX";
|
||||
static const char *data_dir = "tests/acpi-test-data";
|
||||
#ifdef CONFIG_IASL
|
||||
static const char *iasl = stringify(CONFIG_IASL);
|
||||
|
|
|
@ -69,25 +69,32 @@ static uint8_t boot_sector[0x7e000] = {
|
|||
};
|
||||
|
||||
/* Create boot disk file. */
|
||||
int boot_sector_init(const char *fname)
|
||||
int boot_sector_init(char *fname)
|
||||
{
|
||||
FILE *f = fopen(fname, "w");
|
||||
int fd, ret;
|
||||
size_t len = sizeof boot_sector;
|
||||
|
||||
if (!f) {
|
||||
fd = mkstemp(fname);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* For Open Firmware based system, we can use a Forth script instead */
|
||||
if (strcmp(qtest_get_arch(), "ppc64") == 0) {
|
||||
memset(boot_sector, ' ', sizeof boot_sector);
|
||||
sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n",
|
||||
len = sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n",
|
||||
LOW(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET,
|
||||
HIGH(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1);
|
||||
}
|
||||
|
||||
fwrite(boot_sector, 1, sizeof boot_sector, f);
|
||||
fclose(f);
|
||||
ret = write(fd, boot_sector, len);
|
||||
close(fd);
|
||||
|
||||
if (ret != len) {
|
||||
fprintf(stderr, "Could not write \"%s\"", fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -99,9 +106,9 @@ void boot_sector_test(void)
|
|||
uint16_t signature;
|
||||
int i;
|
||||
|
||||
/* Wait at most 1 minute */
|
||||
/* Wait at most 90 seconds */
|
||||
#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
|
||||
#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1)
|
||||
#define TEST_CYCLES MAX((90 * G_USEC_PER_SEC / TEST_DELAY), 1)
|
||||
|
||||
/* Poll until code has run and modified memory. Once it has we know BIOS
|
||||
* initialization is done. TODO: check that IP reached the halt
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#ifndef TEST_BOOT_SECTOR_H
|
||||
#define TEST_BOOT_SECTOR_H
|
||||
|
||||
/* Create boot disk file. */
|
||||
int boot_sector_init(const char *fname);
|
||||
/* Create boot disk file. fname must be a suitable string for mkstemp() */
|
||||
int boot_sector_init(char *fname);
|
||||
|
||||
/* Loop until signature in memory is OK. */
|
||||
void boot_sector_test(void);
|
||||
|
|
|
@ -38,7 +38,8 @@ static const TestCase test_cases[] = {
|
|||
{ "ppc", "prep", 0x80000000, .bswap = true },
|
||||
{ "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" },
|
||||
{ "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" },
|
||||
{ "ppc64", "pseries", 0x10080000000ULL,
|
||||
{ "ppc64", "pseries", (1ULL << 45), .bswap = true, .superio = "i82378" },
|
||||
{ "ppc64", "pseries-2.7", 0x10080000000ULL,
|
||||
.bswap = true, .superio = "i82378" },
|
||||
{ "sh4", "r2d", 0xfe240000, .superio = "i82378" },
|
||||
{ "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" },
|
||||
|
|
|
@ -18,30 +18,23 @@
|
|||
|
||||
/* From include/hw/pci-host/spapr.h */
|
||||
|
||||
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
|
||||
|
||||
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
|
||||
|
||||
#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL
|
||||
#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL
|
||||
#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000
|
||||
#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \
|
||||
SPAPR_PCI_MEM_WIN_BUS_OFFSET)
|
||||
#define SPAPR_PCI_IO_WIN_OFF 0x80000000
|
||||
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
|
||||
|
||||
/* index is the phb index */
|
||||
|
||||
#define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index))
|
||||
#define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \
|
||||
(index) * SPAPR_PCI_WINDOW_SPACING)
|
||||
#define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF)
|
||||
#define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF)
|
||||
typedef struct QPCIWindow {
|
||||
uint64_t pci_base; /* window address in PCI space */
|
||||
uint64_t size; /* window size */
|
||||
} QPCIWindow;
|
||||
|
||||
typedef struct QPCIBusSPAPR {
|
||||
QPCIBus bus;
|
||||
QGuestAllocator *alloc;
|
||||
|
||||
uint64_t buid;
|
||||
|
||||
uint64_t pio_cpu_base;
|
||||
QPCIWindow pio;
|
||||
|
||||
uint64_t mmio32_cpu_base;
|
||||
QPCIWindow mmio32;
|
||||
|
||||
uint64_t pci_hole_start;
|
||||
uint64_t pci_hole_size;
|
||||
uint64_t pci_hole_alloc;
|
||||
|
@ -59,69 +52,75 @@ typedef struct QPCIBusSPAPR {
|
|||
|
||||
static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint64_t port = (uintptr_t)addr;
|
||||
uint8_t v;
|
||||
if (port < SPAPR_PCI_IO_WIN_SIZE) {
|
||||
v = readb(IOBASE(0) + port);
|
||||
if (port < s->pio.size) {
|
||||
v = readb(s->pio_cpu_base + port);
|
||||
} else {
|
||||
v = readb(MMIOBASE(0) + port);
|
||||
v = readb(s->mmio32_cpu_base + port);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint64_t port = (uintptr_t)addr;
|
||||
uint16_t v;
|
||||
if (port < SPAPR_PCI_IO_WIN_SIZE) {
|
||||
v = readw(IOBASE(0) + port);
|
||||
if (port < s->pio.size) {
|
||||
v = readw(s->pio_cpu_base + port);
|
||||
} else {
|
||||
v = readw(MMIOBASE(0) + port);
|
||||
v = readw(s->mmio32_cpu_base + port);
|
||||
}
|
||||
return bswap16(v);
|
||||
}
|
||||
|
||||
static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint64_t port = (uintptr_t)addr;
|
||||
uint32_t v;
|
||||
if (port < SPAPR_PCI_IO_WIN_SIZE) {
|
||||
v = readl(IOBASE(0) + port);
|
||||
if (port < s->pio.size) {
|
||||
v = readl(s->pio_cpu_base + port);
|
||||
} else {
|
||||
v = readl(MMIOBASE(0) + port);
|
||||
v = readl(s->mmio32_cpu_base + port);
|
||||
}
|
||||
return bswap32(v);
|
||||
}
|
||||
|
||||
static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint64_t port = (uintptr_t)addr;
|
||||
if (port < SPAPR_PCI_IO_WIN_SIZE) {
|
||||
writeb(IOBASE(0) + port, value);
|
||||
if (port < s->pio.size) {
|
||||
writeb(s->pio_cpu_base + port, value);
|
||||
} else {
|
||||
writeb(MMIOBASE(0) + port, value);
|
||||
writeb(s->mmio32_cpu_base + port, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint64_t port = (uintptr_t)addr;
|
||||
value = bswap16(value);
|
||||
if (port < SPAPR_PCI_IO_WIN_SIZE) {
|
||||
writew(IOBASE(0) + port, value);
|
||||
if (port < s->pio.size) {
|
||||
writew(s->pio_cpu_base + port, value);
|
||||
} else {
|
||||
writew(MMIOBASE(0) + port, value);
|
||||
writew(s->mmio32_cpu_base + port, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint64_t port = (uintptr_t)addr;
|
||||
value = bswap32(value);
|
||||
if (port < SPAPR_PCI_IO_WIN_SIZE) {
|
||||
writel(IOBASE(0) + port, value);
|
||||
if (port < s->pio.size) {
|
||||
writel(s->pio_cpu_base + port, value);
|
||||
} else {
|
||||
writel(MMIOBASE(0) + port, value);
|
||||
writel(s->mmio32_cpu_base + port, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,24 +128,21 @@ static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
|
|||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint32_t config_addr = (devfn << 8) | offset;
|
||||
return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
|
||||
config_addr, 1);
|
||||
return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 1);
|
||||
}
|
||||
|
||||
static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint32_t config_addr = (devfn << 8) | offset;
|
||||
return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
|
||||
config_addr, 2);
|
||||
return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 2);
|
||||
}
|
||||
|
||||
static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
|
||||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint32_t config_addr = (devfn << 8) | offset;
|
||||
return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
|
||||
config_addr, 4);
|
||||
return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 4);
|
||||
}
|
||||
|
||||
static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset,
|
||||
|
@ -154,8 +150,7 @@ static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset,
|
|||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint32_t config_addr = (devfn << 8) | offset;
|
||||
qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
|
||||
config_addr, 1, value);
|
||||
qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 1, value);
|
||||
}
|
||||
|
||||
static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset,
|
||||
|
@ -163,8 +158,7 @@ static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset,
|
|||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint32_t config_addr = (devfn << 8) | offset;
|
||||
qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
|
||||
config_addr, 2, value);
|
||||
qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 2, value);
|
||||
}
|
||||
|
||||
static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
|
||||
|
@ -172,8 +166,7 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
|
|||
{
|
||||
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
|
||||
uint32_t config_addr = (devfn << 8) | offset;
|
||||
qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
|
||||
config_addr, 4, value);
|
||||
qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 4, value);
|
||||
}
|
||||
|
||||
static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno,
|
||||
|
@ -242,6 +235,11 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data)
|
|||
/* FIXME */
|
||||
}
|
||||
|
||||
#define SPAPR_PCI_BASE (1ULL << 45)
|
||||
|
||||
#define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */
|
||||
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
|
||||
|
||||
QPCIBus *qpci_init_spapr(QGuestAllocator *alloc)
|
||||
{
|
||||
QPCIBusSPAPR *ret;
|
||||
|
@ -269,12 +267,28 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc)
|
|||
ret->bus.iomap = qpci_spapr_iomap;
|
||||
ret->bus.iounmap = qpci_spapr_iounmap;
|
||||
|
||||
/* FIXME: We assume the default location of the PHB for now.
|
||||
* Ideally we'd parse the device tree deposited in the guest to
|
||||
* get the window locations */
|
||||
ret->buid = 0x800000020000000ULL;
|
||||
|
||||
ret->pio_cpu_base = SPAPR_PCI_BASE;
|
||||
ret->pio.pci_base = 0;
|
||||
ret->pio.size = SPAPR_PCI_IO_WIN_SIZE;
|
||||
|
||||
/* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */
|
||||
ret->mmio32_cpu_base = SPAPR_PCI_BASE + SPAPR_PCI_MMIO32_WIN_SIZE;
|
||||
ret->mmio32.pci_base = 0x80000000; /* 2 GiB */
|
||||
ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE;
|
||||
|
||||
ret->pci_hole_start = 0xC0000000;
|
||||
ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE;
|
||||
ret->pci_hole_size =
|
||||
ret->mmio32.pci_base + ret->mmio32.size - ret->pci_hole_start;
|
||||
ret->pci_hole_alloc = 0;
|
||||
|
||||
ret->pci_iohole_start = 0xc000;
|
||||
ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE;
|
||||
ret->pci_iohole_size =
|
||||
ret->pio.pci_base + ret->pio.size - ret->pci_iohole_start;
|
||||
ret->pci_iohole_alloc = 0;
|
||||
|
||||
return &ret->bus;
|
||||
|
|
|
@ -86,7 +86,7 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr)
|
|||
int i;
|
||||
uint64_t u64 = 0;
|
||||
|
||||
if (qtest_big_endian()) {
|
||||
if (target_big_endian()) {
|
||||
for (i = 0; i < 8; ++i) {
|
||||
u64 |= (uint64_t)qpci_io_readb(dev->pdev,
|
||||
(void *)(uintptr_t)addr + i) << (7 - i) * 8;
|
||||
|
|
|
@ -37,6 +37,7 @@ struct QTestState
|
|||
bool irq_level[MAX_IRQ];
|
||||
GString *rx;
|
||||
pid_t qemu_pid; /* our child QEMU process */
|
||||
bool big_endian;
|
||||
};
|
||||
|
||||
static GHookList abrt_hooks;
|
||||
|
@ -47,6 +48,8 @@ static struct sigaction sigact_old;
|
|||
g_assert_cmpint(ret, !=, -1); \
|
||||
} while (0)
|
||||
|
||||
static int qtest_query_target_endianness(QTestState *s);
|
||||
|
||||
static int init_socket(const char *socket_path)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
|
@ -209,6 +212,10 @@ QTestState *qtest_init(const char *extra_args)
|
|||
kill(s->qemu_pid, SIGSTOP);
|
||||
}
|
||||
|
||||
/* ask endianness of the target */
|
||||
|
||||
s->big_endian = qtest_query_target_endianness(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -342,6 +349,20 @@ redo:
|
|||
return words;
|
||||
}
|
||||
|
||||
static int qtest_query_target_endianness(QTestState *s)
|
||||
{
|
||||
gchar **args;
|
||||
int big_endian;
|
||||
|
||||
qtest_sendf(s, "endianness\n");
|
||||
args = qtest_rsp(s, 1);
|
||||
g_assert(strcmp(args[1], "big") == 0 || strcmp(args[1], "little") == 0);
|
||||
big_endian = strcmp(args[1], "big") == 0;
|
||||
g_strfreev(args);
|
||||
|
||||
return big_endian;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
JSONMessageParser parser;
|
||||
QDict *response;
|
||||
|
@ -886,50 +907,7 @@ char *hmp(const char *fmt, ...)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool qtest_big_endian(void)
|
||||
bool qtest_big_endian(QTestState *s)
|
||||
{
|
||||
const char *arch = qtest_get_arch();
|
||||
int i;
|
||||
|
||||
static const struct {
|
||||
const char *arch;
|
||||
bool big_endian;
|
||||
} endianness[] = {
|
||||
{ "aarch64", false },
|
||||
{ "alpha", false },
|
||||
{ "arm", false },
|
||||
{ "cris", false },
|
||||
{ "i386", false },
|
||||
{ "lm32", true },
|
||||
{ "m68k", true },
|
||||
{ "microblaze", true },
|
||||
{ "microblazeel", false },
|
||||
{ "mips", true },
|
||||
{ "mips64", true },
|
||||
{ "mips64el", false },
|
||||
{ "mipsel", false },
|
||||
{ "moxie", true },
|
||||
{ "or32", true },
|
||||
{ "ppc", true },
|
||||
{ "ppc64", true },
|
||||
{ "ppcemb", true },
|
||||
{ "s390x", true },
|
||||
{ "sh4", false },
|
||||
{ "sh4eb", true },
|
||||
{ "sparc", true },
|
||||
{ "sparc64", true },
|
||||
{ "unicore32", false },
|
||||
{ "x86_64", false },
|
||||
{ "xtensa", false },
|
||||
{ "xtensaeb", true },
|
||||
{},
|
||||
};
|
||||
|
||||
for (i = 0; endianness[i].arch; i++) {
|
||||
if (strcmp(endianness[i].arch, arch) == 0) {
|
||||
return endianness[i].big_endian;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return s->big_endian;
|
||||
}
|
||||
|
|
|
@ -409,6 +409,14 @@ int64_t qtest_clock_step(QTestState *s, int64_t step);
|
|||
*/
|
||||
int64_t qtest_clock_set(QTestState *s, int64_t val);
|
||||
|
||||
/**
|
||||
* qtest_big_endian:
|
||||
* @s: QTestState instance to operate on.
|
||||
*
|
||||
* Returns: True if the architecture under test has a big endian configuration.
|
||||
*/
|
||||
bool qtest_big_endian(QTestState *s);
|
||||
|
||||
/**
|
||||
* qtest_get_arch:
|
||||
*
|
||||
|
@ -874,12 +882,14 @@ static inline int64_t clock_set(int64_t val)
|
|||
}
|
||||
|
||||
/**
|
||||
* qtest_big_endian:
|
||||
* target_big_endian:
|
||||
*
|
||||
* Returns: True if the architecture under test has a big endian configuration.
|
||||
*/
|
||||
bool qtest_big_endian(void);
|
||||
|
||||
static inline bool target_big_endian(void)
|
||||
{
|
||||
return qtest_big_endian(global_qtest);
|
||||
}
|
||||
|
||||
QDict *qmp_fd_receive(int fd);
|
||||
void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#define NETNAME "net0"
|
||||
|
||||
static const char *disk = "tests/pxe-test-disk.raw";
|
||||
static char disk[] = "tests/pxe-test-disk-XXXXXX";
|
||||
|
||||
static void test_pxe_one(const char *params, bool ipv6)
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ int main(int argc, char **argv)
|
|||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/spapr-phb/device", test_phb_device);
|
||||
|
||||
qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=100");
|
||||
qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=30");
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
|
|
|
@ -77,6 +77,9 @@ static void test_usb_storage_hotplug(void)
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *arch = qtest_get_arch();
|
||||
const char *cmd = "-device piix3-usb-uhci,id=uhci,addr=1d.0"
|
||||
" -drive id=drive0,if=none,file=/dev/null,format=raw"
|
||||
" -device usb-tablet,bus=uhci.0,port=1";
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
@ -87,13 +90,13 @@ int main(int argc, char **argv)
|
|||
qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
|
||||
|
||||
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
|
||||
qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
|
||||
" -drive id=drive0,if=none,file=/dev/null,format=raw"
|
||||
" -device usb-tablet,bus=uhci.0,port=1");
|
||||
qs = qtest_pc_boot(cmd);
|
||||
} else if (strcmp(arch, "ppc64") == 0) {
|
||||
qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
|
||||
" -drive id=drive0,if=none,file=/dev/null,format=raw"
|
||||
" -device usb-tablet,bus=uhci.0,port=1");
|
||||
qs = qtest_spapr_boot(cmd);
|
||||
} else {
|
||||
g_printerr("usb-hcd-uhci-test tests are only "
|
||||
"available on x86 or ppc64\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ret = g_test_run();
|
||||
qtest_shutdown(qs);
|
||||
|
|
|
@ -125,7 +125,7 @@ static inline void virtio_blk_fix_request(QVirtioBlkReq *req)
|
|||
bool host_endian = false;
|
||||
#endif
|
||||
|
||||
if (qtest_big_endian() != host_endian) {
|
||||
if (target_big_endian() != host_endian) {
|
||||
req->type = bswap32(req->type);
|
||||
req->ioprio = bswap32(req->ioprio);
|
||||
req->sector = bswap64(req->sector);
|
||||
|
|
Loading…
Reference in New Issue