summaryrefslogtreecommitdiff
path: root/firmware/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/thread.c')
-rw-r--r--firmware/thread.c170
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 */
251struct 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
259static 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 */
394static 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 */
410static 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)
421static 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 480static 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 */
469void 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 */
547void 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)
552void 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 */
602void 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 {