diff options
Diffstat (limited to 'firmware/thread.c')
-rw-r--r-- | firmware/thread.c | 170 |
1 files changed, 152 insertions, 18 deletions
diff --git a/firmware/thread.c b/firmware/thread.c index 126cc41c0f..37157be245 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -245,6 +245,20 @@ static int * const idle_stacks[NUM_CORES] NOCACHEDATA_ATTR = | |||
245 | [CPU] = cpu_idlestackbegin, | 245 | [CPU] = cpu_idlestackbegin, |
246 | [COP] = cop_idlestackbegin | 246 | [COP] = cop_idlestackbegin |
247 | }; | 247 | }; |
248 | |||
249 | #if CONFIG_CPU == PP5002 | ||
250 | /* Bytes to emulate the PP502x mailbox bits */ | ||
251 | struct core_semaphores | ||
252 | { | ||
253 | volatile uint8_t intend_wake; /* 00h */ | ||
254 | volatile uint8_t stay_awake; /* 01h */ | ||
255 | volatile uint8_t intend_sleep; /* 02h */ | ||
256 | volatile uint8_t unused; /* 03h */ | ||
257 | }; | ||
258 | |||
259 | static struct core_semaphores core_semaphores[NUM_CORES] NOCACHEBSS_ATTR; | ||
260 | #endif | ||
261 | |||
248 | #endif /* NUM_CORES */ | 262 | #endif /* NUM_CORES */ |
249 | 263 | ||
250 | #if CONFIG_CORELOCK == SW_CORELOCK | 264 | #if CONFIG_CORELOCK == SW_CORELOCK |
@@ -391,10 +405,22 @@ void corelock_unlock(struct corelock *cl) | |||
391 | * no other core requested a wakeup for it to perform a task. | 405 | * no other core requested a wakeup for it to perform a task. |
392 | *--------------------------------------------------------------------------- | 406 | *--------------------------------------------------------------------------- |
393 | */ | 407 | */ |
394 | static inline void core_sleep(IF_COP(unsigned int core,) struct thread_entry **waking) | 408 | #if NUM_CORES == 1 |
409 | /* Shared single-core build debugging version */ | ||
410 | static inline void core_sleep(struct thread_entry **waking) | ||
411 | { | ||
412 | set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); | ||
413 | if (*waking == NULL) | ||
414 | { | ||
415 | PROC_CTL(CURRENT_CORE) = PROC_SLEEP; | ||
416 | nop; nop; nop; | ||
417 | } | ||
418 | set_interrupt_status(IRQ_FIQ_ENABLED, IRQ_FIQ_STATUS); | ||
419 | } | ||
420 | #elif defined (CPU_PP502x) | ||
421 | static inline void core_sleep(unsigned int core, | ||
422 | struct thread_entry **waking) | ||
395 | { | 423 | { |
396 | #if NUM_CORES > 1 | ||
397 | #ifdef CPU_PP502x | ||
398 | #if 1 | 424 | #if 1 |
399 | /* Disabling IRQ and FIQ is important to making the fixed-time sequence | 425 | /* Disabling IRQ and FIQ is important to making the fixed-time sequence |
400 | * non-interruptable */ | 426 | * non-interruptable */ |
@@ -448,29 +474,83 @@ static inline void core_sleep(IF_COP(unsigned int core,) struct thread_entry **w | |||
448 | /* Enable IRQ, FIQ */ | 474 | /* Enable IRQ, FIQ */ |
449 | set_interrupt_status(IRQ_FIQ_ENABLED, IRQ_FIQ_STATUS); | 475 | set_interrupt_status(IRQ_FIQ_ENABLED, IRQ_FIQ_STATUS); |
450 | #endif /* ASM/C selection */ | 476 | #endif /* ASM/C selection */ |
451 | #else | 477 | } |
452 | /* TODO: PP5002 */ | 478 | #elif CONFIG_CPU == PP5002 |
453 | #endif /* CONFIG_CPU == */ | 479 | /* PP5002 has no mailboxes - emulate using bytes */ |
454 | #else | 480 | static inline void core_sleep(unsigned int core, |
481 | struct thread_entry **waking) | ||
482 | { | ||
483 | #if 1 | ||
484 | asm volatile ( | ||
485 | "mrs r1, cpsr \n" /* Disable IRQ, FIQ */ | ||
486 | "orr r1, r1, #0xc0 \n" | ||
487 | "msr cpsr_c, r1 \n" | ||
488 | "mov r0, #1 \n" /* Signal intent to sleep */ | ||
489 | "strb r0, [%[sem], #2] \n" | ||
490 | "ldr r0, [%[waking]] \n" /* *waking == NULL? */ | ||
491 | "cmp r0, #0 \n" | ||
492 | "ldreqb r0, [%[sem], #1] \n" /* && stay_awake == 0? */ | ||
493 | "cmpeq r0, #0 \n" | ||
494 | "moveq r0, #0xca \n" /* Then sleep */ | ||
495 | "streqb r0, [%[ctl], %[c], lsl #2] \n" | ||
496 | "nop \n" /* nop's needed because of pipeline */ | ||
497 | "nop \n" | ||
498 | "nop \n" | ||
499 | "mov r0, #0 \n" /* Clear stay_awake and sleep intent */ | ||
500 | "strb r0, [%[sem], #1] \n" | ||
501 | "strb r0, [%[sem], #2] \n" | ||
502 | "1: \n" /* Wait for wake procedure to finish */ | ||
503 | "ldrb r0, [%[sem], #0] \n" | ||
504 | "cmp r0, #0 \n" | ||
505 | "bne 1b \n" | ||
506 | "bic r1, r1, #0xc0 \n" /* Enable interrupts */ | ||
507 | "msr cpsr_c, r1 \n" | ||
508 | : | ||
509 | : [sem]"r"(&core_semaphores[core]), [c]"r"(core), | ||
510 | [waking]"r"(waking), [ctl]"r"(&PROC_CTL(CPU)) | ||
511 | : "r0", "r1" | ||
512 | ); | ||
513 | #else /* C version for reference */ | ||
514 | /* Disable IRQ, FIQ */ | ||
455 | set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); | 515 | set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); |
456 | if (*waking == NULL) | 516 | |
517 | /* Signal intent to sleep */ | ||
518 | core_semaphores[core].intend_sleep = 1; | ||
519 | |||
520 | /* Something waking or other processor intends to wake us? */ | ||
521 | if (*waking == NULL && core_semaphores[core].stay_awake == 0) | ||
457 | { | 522 | { |
458 | PROC_CTL(IF_COP_CORE(core)) = PROC_SLEEP; | 523 | PROC_CTL(core) = PROC_SLEEP; /* Snooze */ |
524 | nop; nop; nop; | ||
459 | } | 525 | } |
526 | |||
527 | /* Signal wake - clear wake flag */ | ||
528 | core_semaphores[core].stay_awake = 0; | ||
529 | core_semaphores[core].intend_sleep = 0; | ||
530 | |||
531 | /* Wait for other processor to finish wake procedure */ | ||
532 | while (core_semaphores[core].intend_wake != 0); | ||
533 | |||
534 | /* Enable IRQ, FIQ */ | ||
460 | set_interrupt_status(IRQ_FIQ_ENABLED, IRQ_FIQ_STATUS); | 535 | set_interrupt_status(IRQ_FIQ_ENABLED, IRQ_FIQ_STATUS); |
461 | #endif /* NUM_CORES */ | 536 | #endif /* ASM/C selection */ |
462 | } | 537 | } |
538 | #endif /* CPU type */ | ||
463 | 539 | ||
464 | /*--------------------------------------------------------------------------- | 540 | /*--------------------------------------------------------------------------- |
465 | * Wake another processor core that is sleeping or prevent it from doing so | 541 | * Wake another processor core that is sleeping or prevent it from doing so |
466 | * if it was already destined. FIQ, IRQ should be disabled before calling. | 542 | * if it was already destined. FIQ, IRQ should be disabled before calling. |
467 | *--------------------------------------------------------------------------- | 543 | *--------------------------------------------------------------------------- |
468 | */ | 544 | */ |
469 | void core_wake(IF_COP_VOID(unsigned int othercore)) | ||
470 | { | ||
471 | #if NUM_CORES == 1 | 545 | #if NUM_CORES == 1 |
546 | /* Shared single-core build debugging version */ | ||
547 | void core_wake(void) | ||
548 | { | ||
472 | /* No wakey - core already wakey */ | 549 | /* No wakey - core already wakey */ |
550 | } | ||
473 | #elif defined (CPU_PP502x) | 551 | #elif defined (CPU_PP502x) |
552 | void core_wake(unsigned int othercore) | ||
553 | { | ||
474 | #if 1 | 554 | #if 1 |
475 | /* avoid r0 since that contains othercore */ | 555 | /* avoid r0 since that contains othercore */ |
476 | asm volatile ( | 556 | asm volatile ( |
@@ -494,7 +574,8 @@ void core_wake(IF_COP_VOID(unsigned int othercore)) | |||
494 | "str r1, [%[mbx], #8] \n" /* Done with wake procedure */ | 574 | "str r1, [%[mbx], #8] \n" /* Done with wake procedure */ |
495 | "msr cpsr_c, r3 \n" /* Restore int status */ | 575 | "msr cpsr_c, r3 \n" /* Restore int status */ |
496 | : | 576 | : |
497 | : [ctl]"r"(&PROC_CTL(CPU)), [mbx]"r"(MBX_BASE), [oc]"r" (othercore) | 577 | : [ctl]"r"(&PROC_CTL(CPU)), [mbx]"r"(MBX_BASE), |
578 | [oc]"r"(othercore) | ||
498 | : "r1", "r2", "r3"); | 579 | : "r1", "r2", "r3"); |
499 | #else /* C version for reference */ | 580 | #else /* C version for reference */ |
500 | /* Disable interrupts - avoid reentrancy from the tick */ | 581 | /* Disable interrupts - avoid reentrancy from the tick */ |
@@ -509,18 +590,68 @@ void core_wake(IF_COP_VOID(unsigned int othercore)) | |||
509 | 590 | ||
510 | /* If sleeping, wake it up */ | 591 | /* If sleeping, wake it up */ |
511 | if (PROC_CTL(othercore) & PROC_SLEEP) | 592 | if (PROC_CTL(othercore) & PROC_SLEEP) |
512 | { | ||
513 | PROC_CTL(othercore) = 0; | 593 | PROC_CTL(othercore) = 0; |
514 | } | ||
515 | 594 | ||
516 | /* Done with wake procedure */ | 595 | /* Done with wake procedure */ |
517 | MBX_MSG_CLR = 0x1 << othercore; | 596 | MBX_MSG_CLR = 0x1 << othercore; |
518 | set_irq_level(oldlevel); | 597 | set_irq_level(oldlevel); |
519 | #endif /* ASM/C selection */ | 598 | #endif /* ASM/C selection */ |
520 | #else | ||
521 | PROC_CTL(othercore) = PROC_WAKE; | ||
522 | #endif | ||
523 | } | 599 | } |
600 | #elif CONFIG_CPU == PP5002 | ||
601 | /* PP5002 has no mailboxes - emulate using bytes */ | ||
602 | void core_wake(unsigned int othercore) | ||
603 | { | ||
604 | #if 1 | ||
605 | /* avoid r0 since that contains othercore */ | ||
606 | asm volatile ( | ||
607 | "mrs r3, cpsr \n" /* Disable IRQ */ | ||
608 | "orr r1, r3, #0x80 \n" | ||
609 | "msr cpsr_c, r1 \n" | ||
610 | "mov r1, #1 \n" /* Signal intent to wake other core */ | ||
611 | "orr r1, r1, r1, lsl #8 \n" /* and set stay_awake */ | ||
612 | "strh r1, [%[sem], #0] \n" | ||
613 | "mov r2, #0x8000 \n" | ||
614 | "1: \n" /* If it intends to sleep, let it first */ | ||
615 | "ldrb r1, [%[sem], #2] \n" /* intend_sleep != 0 ? */ | ||
616 | "cmp r1, #1 \n" | ||
617 | "ldr r1, [%[st]] \n" /* && not sleeping ? */ | ||
618 | "tsteq r1, r2, lsr %[oc] \n" | ||
619 | "beq 1b \n" /* Wait for sleep or wake */ | ||
620 | "tst r1, r2, lsr %[oc] \n" | ||
621 | "ldrne r2, =0xcf004054 \n" /* If sleeping, wake it */ | ||
622 | "movne r1, #0xce \n" | ||
623 | "strneb r1, [r2, %[oc], lsl #2] \n" | ||
624 | "mov r1, #0 \n" /* Done with wake procedure */ | ||
625 | "strb r1, [%[sem], #0] \n" | ||
626 | "msr cpsr_c, r3 \n" /* Restore int status */ | ||
627 | : | ||
628 | : [sem]"r"(&core_semaphores[othercore]), | ||
629 | [st]"r"(&PROC_STAT), | ||
630 | [oc]"r"(othercore) | ||
631 | : "r1", "r2", "r3" | ||
632 | ); | ||
633 | #else /* C version for reference */ | ||
634 | /* Disable interrupts - avoid reentrancy from the tick */ | ||
635 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
636 | |||
637 | /* Signal intent to wake other processor - set stay awake */ | ||
638 | core_semaphores[othercore].intend_wake = 1; | ||
639 | core_semaphores[othercore].stay_awake = 1; | ||
640 | |||
641 | /* If it intends to sleep, wait until it does or aborts */ | ||
642 | while (core_semaphores[othercore].intend_sleep != 0 && | ||
643 | (PROC_STAT & PROC_SLEEPING(othercore)) == 0); | ||
644 | |||
645 | /* If sleeping, wake it up */ | ||
646 | if (PROC_STAT & PROC_SLEEPING(othercore)) | ||
647 | PROC_CTL(othercore) = PROC_WAKE; | ||
648 | |||
649 | /* Done with wake procedure */ | ||
650 | core_semaphores[othercore].intend_wake = 0; | ||
651 | set_irq_level(oldlevel); | ||
652 | #endif /* ASM/C selection */ | ||
653 | } | ||
654 | #endif /* CPU type */ | ||
524 | 655 | ||
525 | #if NUM_CORES > 1 | 656 | #if NUM_CORES > 1 |
526 | /*--------------------------------------------------------------------------- | 657 | /*--------------------------------------------------------------------------- |
@@ -2539,10 +2670,13 @@ void init_threads(void) | |||
2539 | #if NUM_CORES > 1 /* This code path will not be run on single core targets */ | 2670 | #if NUM_CORES > 1 /* This code path will not be run on single core targets */ |
2540 | /* TODO: HAL interface for this */ | 2671 | /* TODO: HAL interface for this */ |
2541 | /* Wake up coprocessor and let it initialize kernel and threads */ | 2672 | /* Wake up coprocessor and let it initialize kernel and threads */ |
2673 | #ifdef CPU_PP502x | ||
2542 | MBX_MSG_CLR = 0x3f; | 2674 | MBX_MSG_CLR = 0x3f; |
2675 | #endif | ||
2543 | COP_CTL = PROC_WAKE; | 2676 | COP_CTL = PROC_WAKE; |
2544 | /* Sleep until finished */ | 2677 | /* Sleep until finished */ |
2545 | CPU_CTL = PROC_SLEEP; | 2678 | CPU_CTL = PROC_SLEEP; |
2679 | nop; nop; nop; nop; | ||
2546 | } | 2680 | } |
2547 | else | 2681 | else |
2548 | { | 2682 | { |