1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
21bc15386SPeter Tyser
31bc15386SPeter Tyser #include <common.h>
41bc15386SPeter Tyser #include <exports.h>
51bc15386SPeter Tyser
61bc15386SPeter Tyser /*
71bc15386SPeter Tyser * Author: Arun Dharankar <ADharankar@ATTBI.Com>
81bc15386SPeter Tyser *
91bc15386SPeter Tyser * A very simple thread/schedular model:
101bc15386SPeter Tyser * - only one master thread, and no parent child relation maintained
111bc15386SPeter Tyser * - parent thread cannot be stopped or deleted
121bc15386SPeter Tyser * - no permissions or credentials
131bc15386SPeter Tyser * - no elaborate safety checks
141bc15386SPeter Tyser * - cooperative multi threading
151bc15386SPeter Tyser * - Simple round-robin scheduleing with no priorities
161bc15386SPeter Tyser * - no metering/statistics collection
171bc15386SPeter Tyser *
181bc15386SPeter Tyser * Basic idea of implementing this is to allow more than one tests to
191bc15386SPeter Tyser * execute "simultaneously".
201bc15386SPeter Tyser *
211bc15386SPeter Tyser * This may be modified such thread_yield may be called in syscalls, and
221bc15386SPeter Tyser * timer interrupts.
231bc15386SPeter Tyser */
241bc15386SPeter Tyser
251bc15386SPeter Tyser
261bc15386SPeter Tyser #define MAX_THREADS 8
271bc15386SPeter Tyser
281bc15386SPeter Tyser #define CTX_SIZE 512
291bc15386SPeter Tyser #define STK_SIZE 8*1024
301bc15386SPeter Tyser
311bc15386SPeter Tyser #define STATE_EMPTY 0
321bc15386SPeter Tyser #define STATE_RUNNABLE 1
331bc15386SPeter Tyser #define STATE_STOPPED 2
341bc15386SPeter Tyser #define STATE_TERMINATED 2
351bc15386SPeter Tyser
361bc15386SPeter Tyser #define MASTER_THREAD 0
371bc15386SPeter Tyser
381bc15386SPeter Tyser #define RC_FAILURE (-1)
391bc15386SPeter Tyser #define RC_SUCCESS (0)
401bc15386SPeter Tyser
411bc15386SPeter Tyser typedef vu_char *jmp_ctx;
421bc15386SPeter Tyser unsigned long setctxsp (vu_char *sp);
431bc15386SPeter Tyser int ppc_setjmp(jmp_ctx env);
441bc15386SPeter Tyser void ppc_longjmp(jmp_ctx env, int val);
451bc15386SPeter Tyser #define setjmp ppc_setjmp
461bc15386SPeter Tyser #define longjmp ppc_longjmp
471bc15386SPeter Tyser
481bc15386SPeter Tyser struct lthread {
491bc15386SPeter Tyser int state;
501bc15386SPeter Tyser int retval;
511bc15386SPeter Tyser char stack[STK_SIZE];
521bc15386SPeter Tyser uchar context[CTX_SIZE];
531bc15386SPeter Tyser int (*func) (void *);
541bc15386SPeter Tyser void *arg;
551bc15386SPeter Tyser };
561bc15386SPeter Tyser static volatile struct lthread lthreads[MAX_THREADS];
571bc15386SPeter Tyser static volatile int current_tid = MASTER_THREAD;
581bc15386SPeter Tyser
591bc15386SPeter Tyser
601bc15386SPeter Tyser static uchar dbg = 0;
611bc15386SPeter Tyser
621bc15386SPeter Tyser #define PDEBUG(fmt, args...) { \
631bc15386SPeter Tyser if(dbg != 0) { \
641bc15386SPeter Tyser printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);\
651bc15386SPeter Tyser printf(fmt, ##args); \
661bc15386SPeter Tyser printf("\n"); \
671bc15386SPeter Tyser } \
681bc15386SPeter Tyser }
691bc15386SPeter Tyser
701bc15386SPeter Tyser static int testthread (void *);
711bc15386SPeter Tyser static void sched_init (void);
721bc15386SPeter Tyser static int thread_create (int (*func) (void *), void *arg);
731bc15386SPeter Tyser static int thread_start (int id);
741bc15386SPeter Tyser static void thread_yield (void);
751bc15386SPeter Tyser static int thread_delete (int id);
761bc15386SPeter Tyser static int thread_join (int *ret);
771bc15386SPeter Tyser
781bc15386SPeter Tyser #if 0 /* not used yet */
791bc15386SPeter Tyser static int thread_stop (int id);
801bc15386SPeter Tyser #endif /* not used yet */
811bc15386SPeter Tyser
821bc15386SPeter Tyser /* An example of schedular test */
831bc15386SPeter Tyser
841bc15386SPeter Tyser #define NUMTHREADS 7
sched(int ac,char * av[])851bc15386SPeter Tyser int sched (int ac, char *av[])
861bc15386SPeter Tyser {
871bc15386SPeter Tyser int i, j;
881bc15386SPeter Tyser int tid[NUMTHREADS];
891bc15386SPeter Tyser int names[NUMTHREADS];
901bc15386SPeter Tyser
911bc15386SPeter Tyser app_startup(av);
921bc15386SPeter Tyser
931bc15386SPeter Tyser sched_init ();
941bc15386SPeter Tyser
951bc15386SPeter Tyser for (i = 0; i < NUMTHREADS; i++) {
961bc15386SPeter Tyser names[i] = i;
971bc15386SPeter Tyser j = thread_create (testthread, (void *) &names[i]);
981bc15386SPeter Tyser if (j == RC_FAILURE)
991bc15386SPeter Tyser printf ("schedtest: Failed to create thread %d\n", i);
1001bc15386SPeter Tyser if (j > 0) {
1011bc15386SPeter Tyser printf ("schedtest: Created thread with id %d, name %d\n",
1021bc15386SPeter Tyser j, i);
1031bc15386SPeter Tyser tid[i] = j;
1041bc15386SPeter Tyser }
1051bc15386SPeter Tyser }
1061bc15386SPeter Tyser printf ("schedtest: Threads created\n");
1071bc15386SPeter Tyser
1081bc15386SPeter Tyser printf ("sched_test: function=0x%08x\n", (unsigned)testthread);
1091bc15386SPeter Tyser for (i = 0; i < NUMTHREADS; i++) {
1101bc15386SPeter Tyser printf ("schedtest: Setting thread %d runnable\n", tid[i]);
1111bc15386SPeter Tyser thread_start (tid[i]);
1121bc15386SPeter Tyser thread_yield ();
1131bc15386SPeter Tyser }
1141bc15386SPeter Tyser printf ("schedtest: Started %d threads\n", NUMTHREADS);
1151bc15386SPeter Tyser
1161bc15386SPeter Tyser while (1) {
1171bc15386SPeter Tyser printf ("schedtest: Waiting for threads to complete\n");
1181bc15386SPeter Tyser if (tstc () && getc () == 0x3) {
1191bc15386SPeter Tyser printf ("schedtest: Aborting threads...\n");
1201bc15386SPeter Tyser for (i = 0; i < NUMTHREADS; i++) {
1211bc15386SPeter Tyser printf ("schedtest: Deleting thread %d\n", tid[i]);
1221bc15386SPeter Tyser thread_delete (tid[i]);
1231bc15386SPeter Tyser }
1241bc15386SPeter Tyser return RC_SUCCESS;
1251bc15386SPeter Tyser }
1261bc15386SPeter Tyser j = -1;
1271bc15386SPeter Tyser i = thread_join (&j);
1281bc15386SPeter Tyser if (i == RC_FAILURE) {
1291bc15386SPeter Tyser printf ("schedtest: No threads pending, "
1301bc15386SPeter Tyser "exiting schedular test\n");
1311bc15386SPeter Tyser return RC_SUCCESS;
1321bc15386SPeter Tyser }
1331bc15386SPeter Tyser printf ("schedtest: thread is %d returned %d\n", i, j);
1341bc15386SPeter Tyser thread_yield ();
1351bc15386SPeter Tyser }
1361bc15386SPeter Tyser
1371bc15386SPeter Tyser return RC_SUCCESS;
1381bc15386SPeter Tyser }
1391bc15386SPeter Tyser
testthread(void * name)1401bc15386SPeter Tyser static int testthread (void *name)
1411bc15386SPeter Tyser {
1421bc15386SPeter Tyser int i;
1431bc15386SPeter Tyser
1441bc15386SPeter Tyser printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n",
1451bc15386SPeter Tyser *(int *) name, (unsigned)&i);
1461bc15386SPeter Tyser
1471bc15386SPeter Tyser printf ("Thread %02d, i=%d\n", *(int *) name, i);
1481bc15386SPeter Tyser
1491bc15386SPeter Tyser for (i = 0; i < 0xffff * (*(int *) name + 1); i++) {
1501bc15386SPeter Tyser if (tstc () && getc () == 0x3) {
1511bc15386SPeter Tyser printf ("testthread: myname %d terminating.\n",
1521bc15386SPeter Tyser *(int *) name);
1531bc15386SPeter Tyser return *(int *) name + 1;
1541bc15386SPeter Tyser }
1551bc15386SPeter Tyser
1561bc15386SPeter Tyser if (i % 100 == 0)
1571bc15386SPeter Tyser thread_yield ();
1581bc15386SPeter Tyser }
1591bc15386SPeter Tyser
1601bc15386SPeter Tyser printf ("testthread: returning %d, i=0x%x\n",
1611bc15386SPeter Tyser *(int *) name + 1, i);
1621bc15386SPeter Tyser
1631bc15386SPeter Tyser return *(int *) name + 1;
1641bc15386SPeter Tyser }
1651bc15386SPeter Tyser
1661bc15386SPeter Tyser
sched_init(void)1671bc15386SPeter Tyser static void sched_init (void)
1681bc15386SPeter Tyser {
1691bc15386SPeter Tyser int i;
1701bc15386SPeter Tyser
1711bc15386SPeter Tyser for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++)
1721bc15386SPeter Tyser lthreads[i].state = STATE_EMPTY;
1731bc15386SPeter Tyser
1741bc15386SPeter Tyser current_tid = MASTER_THREAD;
1751bc15386SPeter Tyser lthreads[current_tid].state = STATE_RUNNABLE;
1761bc15386SPeter Tyser PDEBUG ("sched_init: master context = 0x%08x",
1771bc15386SPeter Tyser (unsigned)lthreads[current_tid].context);
1781bc15386SPeter Tyser return;
1791bc15386SPeter Tyser }
1801bc15386SPeter Tyser
thread_yield(void)1811bc15386SPeter Tyser static void thread_yield (void)
1821bc15386SPeter Tyser {
1831bc15386SPeter Tyser static int i;
1841bc15386SPeter Tyser
1851bc15386SPeter Tyser PDEBUG ("thread_yield: current tid=%d", current_tid);
1861bc15386SPeter Tyser
1871bc15386SPeter Tyser #define SWITCH(new) \
1881bc15386SPeter Tyser if(lthreads[new].state == STATE_RUNNABLE) { \
1891bc15386SPeter Tyser PDEBUG("thread_yield: %d match, ctx=0x%08x", \
1901bc15386SPeter Tyser new, \
1911bc15386SPeter Tyser (unsigned)lthreads[current_tid].context); \
1921bc15386SPeter Tyser if(setjmp(lthreads[current_tid].context) == 0) { \
1931bc15386SPeter Tyser current_tid = new; \
1941bc15386SPeter Tyser PDEBUG("thread_yield: tid %d returns 0", \
1951bc15386SPeter Tyser new); \
1961bc15386SPeter Tyser longjmp(lthreads[new].context, 1); \
1971bc15386SPeter Tyser } else { \
1981bc15386SPeter Tyser PDEBUG("thread_yield: tid %d returns 1", \
1991bc15386SPeter Tyser new); \
2001bc15386SPeter Tyser return; \
2011bc15386SPeter Tyser } \
2021bc15386SPeter Tyser }
2031bc15386SPeter Tyser
2041bc15386SPeter Tyser for (i = current_tid + 1; i < MAX_THREADS; i++) {
2051bc15386SPeter Tyser SWITCH (i);
2061bc15386SPeter Tyser }
2071bc15386SPeter Tyser
2081bc15386SPeter Tyser if (current_tid != 0) {
2091bc15386SPeter Tyser for (i = 0; i <= current_tid; i++) {
2101bc15386SPeter Tyser SWITCH (i);
2111bc15386SPeter Tyser }
2121bc15386SPeter Tyser }
2131bc15386SPeter Tyser
2141bc15386SPeter Tyser PDEBUG ("thread_yield: returning from thread_yield");
2151bc15386SPeter Tyser return;
2161bc15386SPeter Tyser }
2171bc15386SPeter Tyser
thread_create(int (* func)(void *),void * arg)2181bc15386SPeter Tyser static int thread_create (int (*func) (void *), void *arg)
2191bc15386SPeter Tyser {
2201bc15386SPeter Tyser int i;
2211bc15386SPeter Tyser
2221bc15386SPeter Tyser for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
2231bc15386SPeter Tyser if (lthreads[i].state == STATE_EMPTY) {
2241bc15386SPeter Tyser lthreads[i].state = STATE_STOPPED;
2251bc15386SPeter Tyser lthreads[i].func = func;
2261bc15386SPeter Tyser lthreads[i].arg = arg;
2271bc15386SPeter Tyser PDEBUG ("thread_create: returns new tid %d", i);
2281bc15386SPeter Tyser return i;
2291bc15386SPeter Tyser }
2301bc15386SPeter Tyser }
2311bc15386SPeter Tyser
2321bc15386SPeter Tyser PDEBUG ("thread_create: returns failure");
2331bc15386SPeter Tyser return RC_FAILURE;
2341bc15386SPeter Tyser }
2351bc15386SPeter Tyser
thread_delete(int id)2361bc15386SPeter Tyser static int thread_delete (int id)
2371bc15386SPeter Tyser {
2381bc15386SPeter Tyser if (id <= MASTER_THREAD || id > MAX_THREADS)
2391bc15386SPeter Tyser return RC_FAILURE;
2401bc15386SPeter Tyser
2411bc15386SPeter Tyser if (current_tid == id)
2421bc15386SPeter Tyser return RC_FAILURE;
2431bc15386SPeter Tyser
2441bc15386SPeter Tyser lthreads[id].state = STATE_EMPTY;
2451bc15386SPeter Tyser return RC_SUCCESS;
2461bc15386SPeter Tyser }
2471bc15386SPeter Tyser
thread_launcher(void)2481bc15386SPeter Tyser static void thread_launcher (void)
2491bc15386SPeter Tyser {
2501bc15386SPeter Tyser PDEBUG ("thread_launcher: invoking func=0x%08x",
2511bc15386SPeter Tyser (unsigned)lthreads[current_tid].func);
2521bc15386SPeter Tyser
2531bc15386SPeter Tyser lthreads[current_tid].retval =
2541bc15386SPeter Tyser lthreads[current_tid].func (lthreads[current_tid].arg);
2551bc15386SPeter Tyser
2561bc15386SPeter Tyser PDEBUG ("thread_launcher: tid %d terminated", current_tid);
2571bc15386SPeter Tyser
2581bc15386SPeter Tyser lthreads[current_tid].state = STATE_TERMINATED;
2591bc15386SPeter Tyser thread_yield ();
2601bc15386SPeter Tyser printf ("thread_launcher: should NEVER get here!\n");
2611bc15386SPeter Tyser
2621bc15386SPeter Tyser return;
2631bc15386SPeter Tyser }
2641bc15386SPeter Tyser
thread_start(int id)2651bc15386SPeter Tyser static int thread_start (int id)
2661bc15386SPeter Tyser {
2671bc15386SPeter Tyser PDEBUG ("thread_start: id=%d", id);
2681bc15386SPeter Tyser if (id <= MASTER_THREAD || id > MAX_THREADS) {
2691bc15386SPeter Tyser return RC_FAILURE;
2701bc15386SPeter Tyser }
2711bc15386SPeter Tyser
2721bc15386SPeter Tyser if (lthreads[id].state != STATE_STOPPED)
2731bc15386SPeter Tyser return RC_FAILURE;
2741bc15386SPeter Tyser
2751bc15386SPeter Tyser if (setjmp (lthreads[current_tid].context) == 0) {
2761bc15386SPeter Tyser lthreads[id].state = STATE_RUNNABLE;
2771bc15386SPeter Tyser current_tid = id;
2781bc15386SPeter Tyser PDEBUG ("thread_start: to be stack=0%08x",
2791bc15386SPeter Tyser (unsigned)lthreads[id].stack);
2801bc15386SPeter Tyser setctxsp ((vu_char *)<hreads[id].stack[STK_SIZE]);
2811bc15386SPeter Tyser thread_launcher ();
2821bc15386SPeter Tyser }
2831bc15386SPeter Tyser
2841bc15386SPeter Tyser PDEBUG ("thread_start: Thread id=%d started, parent returns", id);
2851bc15386SPeter Tyser
2861bc15386SPeter Tyser return RC_SUCCESS;
2871bc15386SPeter Tyser }
2881bc15386SPeter Tyser
2891bc15386SPeter Tyser #if 0 /* not used so far */
2901bc15386SPeter Tyser static int thread_stop (int id)
2911bc15386SPeter Tyser {
2921bc15386SPeter Tyser if (id <= MASTER_THREAD || id >= MAX_THREADS)
2931bc15386SPeter Tyser return RC_FAILURE;
2941bc15386SPeter Tyser
2951bc15386SPeter Tyser if (current_tid == id)
2961bc15386SPeter Tyser return RC_FAILURE;
2971bc15386SPeter Tyser
2981bc15386SPeter Tyser lthreads[id].state = STATE_STOPPED;
2991bc15386SPeter Tyser return RC_SUCCESS;
3001bc15386SPeter Tyser }
3011bc15386SPeter Tyser #endif /* not used so far */
3021bc15386SPeter Tyser
thread_join(int * ret)3031bc15386SPeter Tyser static int thread_join (int *ret)
3041bc15386SPeter Tyser {
3051bc15386SPeter Tyser int i, j = 0;
3061bc15386SPeter Tyser
3071bc15386SPeter Tyser PDEBUG ("thread_join: *ret = %d", *ret);
3081bc15386SPeter Tyser
3091bc15386SPeter Tyser if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) {
3101bc15386SPeter Tyser PDEBUG ("thread_join: invalid tid %d", *ret);
3111bc15386SPeter Tyser return RC_FAILURE;
3121bc15386SPeter Tyser }
3131bc15386SPeter Tyser
3141bc15386SPeter Tyser if (*ret == -1) {
3151bc15386SPeter Tyser PDEBUG ("Checking for tid = -1");
3161bc15386SPeter Tyser while (1) {
3171bc15386SPeter Tyser /* PDEBUG("thread_join: start while-loopn"); */
3181bc15386SPeter Tyser j = 0;
3191bc15386SPeter Tyser for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
3201bc15386SPeter Tyser if (lthreads[i].state == STATE_TERMINATED) {
3211bc15386SPeter Tyser *ret = lthreads[i].retval;
3221bc15386SPeter Tyser lthreads[i].state = STATE_EMPTY;
3231bc15386SPeter Tyser /* PDEBUG("thread_join: returning retval %d of tid %d",
3241bc15386SPeter Tyser ret, i); */
3251bc15386SPeter Tyser return RC_SUCCESS;
3261bc15386SPeter Tyser }
3271bc15386SPeter Tyser
3281bc15386SPeter Tyser if (lthreads[i].state != STATE_EMPTY) {
3291bc15386SPeter Tyser PDEBUG ("thread_join: %d used slots tid %d state=%d",
3301bc15386SPeter Tyser j, i, lthreads[i].state);
3311bc15386SPeter Tyser j++;
3321bc15386SPeter Tyser }
3331bc15386SPeter Tyser }
3341bc15386SPeter Tyser if (j == 0) {
3351bc15386SPeter Tyser PDEBUG ("thread_join: all slots empty!");
3361bc15386SPeter Tyser return RC_FAILURE;
3371bc15386SPeter Tyser }
3381bc15386SPeter Tyser /* PDEBUG("thread_join: yielding"); */
3391bc15386SPeter Tyser thread_yield ();
3401bc15386SPeter Tyser /* PDEBUG("thread_join: back from yield"); */
3411bc15386SPeter Tyser }
3421bc15386SPeter Tyser }
3431bc15386SPeter Tyser
3441bc15386SPeter Tyser if (lthreads[*ret].state == STATE_TERMINATED) {
3451bc15386SPeter Tyser i = *ret;
3461bc15386SPeter Tyser *ret = lthreads[*ret].retval;
3471bc15386SPeter Tyser lthreads[*ret].state = STATE_EMPTY;
3481bc15386SPeter Tyser PDEBUG ("thread_join: returing %d for tid %d", *ret, i);
3491bc15386SPeter Tyser return RC_SUCCESS;
3501bc15386SPeter Tyser }
3511bc15386SPeter Tyser
3521bc15386SPeter Tyser PDEBUG ("thread_join: thread %d is not terminated!", *ret);
3531bc15386SPeter Tyser return RC_FAILURE;
3541bc15386SPeter Tyser }
355