Skip to content

Commit 634c89d

Browse files
refactor(a13): some more potential ipi bug and perf fixes
1 parent d9eab29 commit 634c89d

File tree

2 files changed

+102
-99
lines changed
  • hw/arm/apple-silicon
  • include/hw/arm/apple-silicon

2 files changed

+102
-99
lines changed

hw/arm/apple-silicon/a13.c

Lines changed: 98 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ static QTAILQ_HEAD(, AppleA13Cluster) clusters =
120120
static uint64_t ipi_cr = kDeferredIPITimerDefault;
121121
static QEMUTimer *ipicr_timer = NULL;
122122

123-
bool apple_a13_is_asleep(AppleA13State *acpu)
123+
bool apple_a13_is_asleep(const AppleA13State *acpu)
124124
{
125125
return CPU(acpu)->halted;
126126
}
127127

128-
bool apple_a13_is_off(AppleA13State *acpu)
128+
bool apple_a13_is_off(const AppleA13State *acpu)
129129
{
130130
return acpu->parent_obj.power_state == PSCI_OFF;
131131
}
@@ -213,15 +213,21 @@ static void apple_a13_cluster_cpreg_write(CPUARMState *env,
213213
}
214214

215215
/* Deliver IPI */
216-
static void apple_a13_cluster_deliver_ipi(AppleA13Cluster *c, uint64_t cpu_id,
217-
uint64_t src_cpu, uint64_t flag)
216+
static void apple_a13_deliver_ipi(AppleA13State *cpu, uint64_t src_cpu,
217+
uint64_t flag)
218218
{
219-
if (c->cpus[cpu_id]->ipi_sr) {
219+
if (cpu->ipi_sr) {
220220
return;
221221
}
222222

223-
c->cpus[cpu_id]->ipi_sr = 1LL | (src_cpu << IPI_SR_SRC_CPU_SHIFT) | flag;
224-
qemu_irq_raise(c->cpus[cpu_id]->fast_ipi);
223+
cpu->ipi_sr = 1LL | (src_cpu << IPI_SR_SRC_CPU_SHIFT) | flag;
224+
qemu_irq_raise(cpu->fast_ipi);
225+
}
226+
227+
static void apple_a13_cluster_deliver_ipi(AppleA13Cluster *c, uint64_t cpu_id,
228+
uint64_t src_cpu, uint64_t flag)
229+
{
230+
apple_a13_deliver_ipi(c->cpus[cpu_id], src_cpu, flag);
225231
}
226232

227233
static int apple_a13_cluster_pre_save(void *opaque)
@@ -248,17 +254,14 @@ static void apple_a13_cluster_reset(DeviceState *dev)
248254
static int add_cpu_to_cluster(Object *obj, void *opaque)
249255
{
250256
AppleA13Cluster *cluster = opaque;
251-
CPUState *cpu = (CPUState *)object_dynamic_cast(obj, TYPE_CPU);
252257
AppleA13State *acpu =
253258
(AppleA13State *)object_dynamic_cast(obj, TYPE_APPLE_A13);
254259

255-
if (!cpu) {
256-
return 0;
257-
}
258-
cpu->cluster_index = cluster->parent_obj.cluster_id;
259260
if (!acpu) {
260261
return 0;
261262
}
263+
264+
acpu->parent_obj.parent_obj.cluster_index = cluster->parent_obj.cluster_id;
262265
cluster->cpus[acpu->cpu_id] = acpu;
263266
return 0;
264267
}
@@ -271,28 +274,40 @@ static void apple_a13_cluster_realize(DeviceState *dev, Error **errp)
271274

272275
static void apple_a13_cluster_tick(AppleA13Cluster *c)
273276
{
274-
int i;
275-
int j;
277+
uint32_t on = 0, awake = 0;
276278

277-
for (i = 0; i < A13_MAX_CPU; i++) { /* source */
278-
for (j = 0; j < A13_MAX_CPU; j++) { /* target */
279-
if (c->cpus[j] && c->deferredIPI[i][j] &&
280-
!apple_a13_is_off(c->cpus[j])) {
281-
apple_a13_cluster_deliver_ipi(c, j, i, IPI_RR_TYPE_DEFERRED);
282-
break;
283-
}
279+
for (uint32_t i = 0; i < A13_MAX_CPU; ++i) {
280+
const AppleA13State *cpu = c->cpus[i];
281+
if (!cpu || apple_a13_is_off(cpu)) {
282+
continue;
283+
}
284+
on |= BIT32(i);
285+
if (!apple_a13_is_asleep(cpu)) {
286+
awake |= BIT32(i);
284287
}
285288
}
286289

287-
for (i = 0; i < A13_MAX_CPU; i++) { /* source */
288-
for (j = 0; j < A13_MAX_CPU; j++) { /* target */
289-
if (c->cpus[j] && c->noWakeIPI[i][j] &&
290-
!apple_a13_is_asleep(c->cpus[j]) &&
291-
!apple_a13_is_off(c->cpus[j])) {
292-
apple_a13_cluster_deliver_ipi(c, j, i, IPI_RR_TYPE_NOWAKE);
293-
break;
294-
}
290+
if (!on) {
291+
return;
292+
}
293+
294+
for (uint32_t src = 0; src < A13_MAX_CPU; ++src) {
295+
if (!c->cpus[src]) {
296+
continue;
295297
}
298+
299+
const uint32_t noWakeCandidates = c->noWakeIPI[src] & awake;
300+
const uint32_t candidates =
301+
noWakeCandidates | (c->deferredIPI[src] & on);
302+
if (!candidates) {
303+
continue;
304+
}
305+
306+
const uint32_t dest = ctz32(candidates);
307+
const uint32_t type = (noWakeCandidates & BIT32(dest)) ?
308+
IPI_RR_TYPE_NOWAKE :
309+
IPI_RR_TYPE_DEFERRED;
310+
apple_a13_cluster_deliver_ipi(c, dest, src, type);
296311
}
297312
}
298313

@@ -310,14 +325,14 @@ static void apple_a13_cluster_ipicr_tick(void *opaque)
310325

311326
static void apple_a13_cluster_reset_handler(void *opaque)
312327
{
328+
ipi_cr = kDeferredIPITimerDefault;
313329
if (ipicr_timer) {
314330
timer_del(ipicr_timer);
315-
ipicr_timer = NULL;
331+
} else {
332+
ipicr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
333+
apple_a13_cluster_ipicr_tick, NULL);
316334
}
317-
ipicr_timer =
318-
timer_new_ns(QEMU_CLOCK_VIRTUAL, apple_a13_cluster_ipicr_tick, NULL);
319-
timer_mod_ns(ipicr_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
320-
kDeferredIPITimerDefault);
335+
timer_mod_ns(ipicr_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ipi_cr);
321336
}
322337

323338
static void apple_a13_cluster_instance_init(Object *obj)
@@ -339,19 +354,18 @@ static void apple_a13_ipi_rr_local(CPUARMState *env, const ARMCPRegInfo *ri,
339354

340355
uint32_t phys_id = (value & 0xFF) | (acpu->cluster_id << 8);
341356
AppleA13Cluster *c = apple_a13_find_cluster(acpu->cluster_id);
342-
uint32_t cpu_id = -1U;
343-
int i;
344-
345-
for (i = 0; i < A13_MAX_CPU; i++) {
346-
if (c->cpus[i]) {
347-
if (c->cpus[i]->phys_id == phys_id) {
348-
cpu_id = i;
349-
break;
350-
}
357+
uint32_t dst_cpu_id = -1U;
358+
AppleA13State *dst_acpu;
359+
360+
for (uint32_t i = 0; i < A13_MAX_CPU; i++) {
361+
if (c->cpus[i] != NULL && c->cpus[i]->phys_id == phys_id) {
362+
dst_cpu_id = i;
363+
dst_acpu = c->cpus[dst_cpu_id];
364+
break;
351365
}
352366
}
353367

354-
if (cpu_id == -1U || c->cpus[cpu_id] == NULL) {
368+
if (dst_cpu_id == -1U) {
355369
qemu_log_mask(LOG_GUEST_ERROR,
356370
"CPU %x failed to send fast IPI to local CPU %x: value: "
357371
"0x" HWADDR_FMT_plx "\n",
@@ -361,27 +375,25 @@ static void apple_a13_ipi_rr_local(CPUARMState *env, const ARMCPRegInfo *ri,
361375

362376
switch (value & IPI_RR_TYPE_MASK) {
363377
case IPI_RR_TYPE_NOWAKE:
364-
if (apple_a13_is_asleep(c->cpus[cpu_id])) {
365-
c->noWakeIPI[acpu->cpu_id][cpu_id] = 1;
378+
if (apple_a13_is_asleep(dst_acpu)) {
379+
c->noWakeIPI[acpu->cpu_id] |= BIT32(dst_cpu_id);
366380
} else {
367-
apple_a13_cluster_deliver_ipi(c, cpu_id, acpu->cpu_id,
368-
IPI_RR_TYPE_IMMEDIATE);
381+
apple_a13_deliver_ipi(dst_acpu, acpu->cpu_id,
382+
IPI_RR_TYPE_IMMEDIATE);
369383
}
370384
break;
371385
case IPI_RR_TYPE_DEFERRED:
372-
c->deferredIPI[acpu->cpu_id][cpu_id] = 1;
386+
c->deferredIPI[acpu->cpu_id] |= BIT32(dst_cpu_id);
373387
break;
374388
case IPI_RR_TYPE_RETRACT:
375-
c->deferredIPI[acpu->cpu_id][cpu_id] = 0;
376-
c->noWakeIPI[acpu->cpu_id][cpu_id] = 0;
389+
c->deferredIPI[acpu->cpu_id] &= ~BIT32(dst_cpu_id);
390+
c->noWakeIPI[acpu->cpu_id] &= ~BIT32(dst_cpu_id);
377391
break;
378392
case IPI_RR_TYPE_IMMEDIATE:
379-
apple_a13_cluster_deliver_ipi(c, cpu_id, acpu->cpu_id,
380-
IPI_RR_TYPE_IMMEDIATE);
393+
apple_a13_deliver_ipi(dst_acpu, acpu->cpu_id, IPI_RR_TYPE_IMMEDIATE);
381394
break;
382395
default:
383396
g_assert_not_reached();
384-
break;
385397
}
386398
}
387399

@@ -392,27 +404,24 @@ static void apple_a13_ipi_rr_global(CPUARMState *env, const ARMCPRegInfo *ri,
392404
AppleA13State *acpu =
393405
container_of(env_archcpu(env), AppleA13State, parent_obj);
394406
uint32_t cluster_id = (value >> IPI_RR_TARGET_CLUSTER_SHIFT) & 0xFF;
395-
AppleA13Cluster *c = apple_a13_find_cluster(cluster_id);
396-
397-
if (!c) {
407+
AppleA13Cluster *cluster = apple_a13_find_cluster(cluster_id);
408+
if (!cluster) {
398409
return;
399410
}
400411

401412
uint32_t phys_id = (value & 0xFF) | (cluster_id << 8);
402-
uint32_t cpu_id = -1;
403-
int i;
413+
uint32_t dst_cpu_id = -1;
414+
AppleA13State *dst_acpu;
404415

405-
for (i = 0; i < A13_MAX_CPU; i++) {
406-
if (c->cpus[i] == NULL) {
407-
continue;
408-
}
409-
if (c->cpus[i]->phys_id == phys_id) {
410-
cpu_id = i;
416+
for (uint32_t i = 0; i < A13_MAX_CPU; i++) {
417+
if (cluster->cpus[i] != NULL && cluster->cpus[i]->phys_id == phys_id) {
418+
dst_cpu_id = i;
419+
dst_acpu = cluster->cpus[dst_cpu_id];
411420
break;
412421
}
413422
}
414423

415-
if (cpu_id == -1U || c->cpus[cpu_id] == NULL) {
424+
if (dst_cpu_id == -1U) {
416425
qemu_log_mask(LOG_GUEST_ERROR,
417426
"CPU %x failed to send fast IPI to global CPU %x: value: "
418427
"0x" HWADDR_FMT_plx "\n",
@@ -422,27 +431,25 @@ static void apple_a13_ipi_rr_global(CPUARMState *env, const ARMCPRegInfo *ri,
422431

423432
switch (value & IPI_RR_TYPE_MASK) {
424433
case IPI_RR_TYPE_NOWAKE:
425-
if (apple_a13_is_asleep(c->cpus[cpu_id])) {
426-
c->noWakeIPI[acpu->cpu_id][cpu_id] = 1;
434+
if (apple_a13_is_asleep(dst_acpu)) {
435+
cluster->noWakeIPI[acpu->cpu_id] |= BIT32(dst_cpu_id);
427436
} else {
428-
apple_a13_cluster_deliver_ipi(c, cpu_id, acpu->cpu_id,
429-
IPI_RR_TYPE_IMMEDIATE);
437+
apple_a13_deliver_ipi(dst_acpu, acpu->cpu_id,
438+
IPI_RR_TYPE_IMMEDIATE);
430439
}
431440
break;
432441
case IPI_RR_TYPE_DEFERRED:
433-
c->deferredIPI[acpu->cpu_id][cpu_id] = 1;
442+
cluster->deferredIPI[acpu->cpu_id] |= BIT32(dst_cpu_id);
434443
break;
435444
case IPI_RR_TYPE_RETRACT:
436-
c->deferredIPI[acpu->cpu_id][cpu_id] = 0;
437-
c->noWakeIPI[acpu->cpu_id][cpu_id] = 0;
445+
cluster->deferredIPI[acpu->cpu_id] &= ~BIT32(dst_cpu_id);
446+
cluster->noWakeIPI[acpu->cpu_id] &= ~BIT32(dst_cpu_id);
438447
break;
439448
case IPI_RR_TYPE_IMMEDIATE:
440-
apple_a13_cluster_deliver_ipi(c, cpu_id, acpu->cpu_id,
441-
IPI_RR_TYPE_IMMEDIATE);
449+
apple_a13_deliver_ipi(dst_acpu, acpu->cpu_id, IPI_RR_TYPE_IMMEDIATE);
442450
break;
443451
default:
444452
g_assert_not_reached();
445-
break;
446453
}
447454
}
448455

@@ -469,10 +476,10 @@ static void apple_a13_ipi_write_sr(CPUARMState *env, const ARMCPRegInfo *ri,
469476

470477
switch (value & IPI_RR_TYPE_MASK) {
471478
case IPI_RR_TYPE_NOWAKE:
472-
c->noWakeIPI[src_cpu][acpu->cpu_id] = 0;
479+
c->noWakeIPI[src_cpu] &= ~BIT32(acpu->cpu_id);
473480
break;
474481
case IPI_RR_TYPE_DEFERRED:
475-
c->deferredIPI[src_cpu][acpu->cpu_id] = 0;
482+
c->deferredIPI[src_cpu] &= ~BIT32(acpu->cpu_id);
476483
break;
477484
default:
478485
break;
@@ -482,7 +489,7 @@ static void apple_a13_ipi_write_sr(CPUARMState *env, const ARMCPRegInfo *ri,
482489
/* Read deferred interrupt timeout (global) */
483490
static uint64_t apple_a13_ipi_read_cr(CPUARMState *env, const ARMCPRegInfo *ri)
484491
{
485-
uint64_t abstime;
492+
uint64_t abstime = 0;
486493

487494
nanoseconds_to_absolutetime(ipi_cr, &abstime);
488495
return abstime;
@@ -492,18 +499,18 @@ static uint64_t apple_a13_ipi_read_cr(CPUARMState *env, const ARMCPRegInfo *ri)
492499
static void apple_a13_ipi_write_cr(CPUARMState *env, const ARMCPRegInfo *ri,
493500
uint64_t value)
494501
{
495-
uint64_t nanosec = kDeferredIPITimerDefault;
496-
uint64_t ct;
502+
uint64_t nanosec = 0;
503+
uint64_t ct = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
497504

498505
if (value != 0) {
499-
absolutetime_to_nanoseconds(value, &nanosec);
500-
if (nanosec == 0) {
501-
nanosec = kDeferredIPITimerDefault;
502-
}
506+
absolutetime_to_nanoseconds(value & 0xFFFF, &nanosec);
503507
}
504508

505-
ct = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
506-
timer_mod_ns(ipicr_timer, ((ct / ipi_cr) * ipi_cr) + nanosec);
509+
if (nanosec == 0) {
510+
timer_del(ipicr_timer);
511+
} else {
512+
timer_mod_ns(ipicr_timer, ct + nanosec);
513+
}
507514
ipi_cr = nanosec;
508515
}
509516

@@ -751,7 +758,7 @@ static const Property apple_a13_cluster_properties[] = {
751758
};
752759

753760
static const VMStateDescription vmstate_apple_a13 = {
754-
.name = "apple_a13",
761+
.name = "AppleA13State",
755762
.version_id = 1,
756763
.minimum_version_id = 1,
757764
.fields =
@@ -799,18 +806,15 @@ static const VMStateDescription vmstate_apple_a13 = {
799806
};
800807

801808
static const VMStateDescription vmstate_apple_a13_cluster = {
802-
.name = "apple_a13_cluster",
809+
.name = "AppleA13Cluster",
803810
.version_id = 1,
804811
.minimum_version_id = 1,
805812
.pre_save = apple_a13_cluster_pre_save,
806813
.post_load = apple_a13_cluster_post_load,
807814
.fields =
808815
(const VMStateField[]){
809-
VMSTATE_UINT32_2DARRAY(deferredIPI, AppleA13Cluster, A13_MAX_CPU,
810-
A13_MAX_CPU),
811-
VMSTATE_UINT32_2DARRAY(noWakeIPI, AppleA13Cluster, A13_MAX_CPU,
812-
A13_MAX_CPU),
813-
VMSTATE_UINT64(tick, AppleA13Cluster),
816+
VMSTATE_UINT32_ARRAY(deferredIPI, AppleA13Cluster, A13_MAX_CPU),
817+
VMSTATE_UINT32_ARRAY(noWakeIPI, AppleA13Cluster, A13_MAX_CPU),
814818
VMSTATE_UINT64(ipi_cr, AppleA13Cluster),
815819
VMSTATE_A13_CLUSTER_CPREG(CTRR_A_LWR_EL1),
816820
VMSTATE_A13_CLUSTER_CPREG(CTRR_A_UPR_EL1),

include/hw/arm/apple-silicon/a13.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,8 @@ typedef struct AppleA13Cluster {
111111
uint32_t cluster_type;
112112
MemoryRegion mr;
113113
AppleA13State *cpus[A13_MAX_CPU];
114-
uint32_t deferredIPI[A13_MAX_CPU][A13_MAX_CPU];
115-
uint32_t noWakeIPI[A13_MAX_CPU][A13_MAX_CPU];
116-
uint64_t tick;
114+
uint32_t deferredIPI[A13_MAX_CPU];
115+
uint32_t noWakeIPI[A13_MAX_CPU];
117116
uint64_t ipi_cr;
118117
QTAILQ_ENTRY(AppleA13Cluster) next;
119118
A13_CPREG_VAR_DEF(CTRR_A_LWR_EL1);
@@ -128,8 +127,8 @@ AppleA13State *apple_a13_create(const char *name, uint32_t cpu_id,
128127
uint32_t phys_id, uint32_t cluster_id,
129128
uint16_t cluster_type);
130129
AppleA13State *apple_a13_from_node(AppleDTNode *node);
131-
bool apple_a13_is_asleep(AppleA13State *acpu);
132-
bool apple_a13_is_off(AppleA13State *acpu);
130+
bool apple_a13_is_asleep(const AppleA13State *acpu);
131+
bool apple_a13_is_off(const AppleA13State *acpu);
133132
void apple_a13_set_on(AppleA13State *acpu);
134133
void apple_a13_reset(AppleA13State *acpu);
135134
void apple_a13_set_off(AppleA13State *acpu);

0 commit comments

Comments
 (0)