linux/arch/c6x/kernel/process.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Port on Texas Instruments TMS320C6x architecture
   4 *
   5 *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
   6 *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
   7 */
   8#include <linux/module.h>
   9#include <linux/unistd.h>
  10#include <linux/ptrace.h>
  11#include <linux/init_task.h>
  12#include <linux/tick.h>
  13#include <linux/mqueue.h>
  14#include <linux/syscalls.h>
  15#include <linux/reboot.h>
  16#include <linux/sched/task.h>
  17#include <linux/sched/task_stack.h>
  18
  19#include <asm/syscalls.h>
  20
  21/* hooks for board specific support */
  22void    (*c6x_restart)(void);
  23void    (*c6x_halt)(void);
  24
  25extern asmlinkage void ret_from_fork(void);
  26extern asmlinkage void ret_from_kernel_thread(void);
  27
  28/*
  29 * power off function, if any
  30 */
  31void (*pm_power_off)(void);
  32EXPORT_SYMBOL(pm_power_off);
  33
  34void arch_cpu_idle(void)
  35{
  36        unsigned long tmp;
  37
  38        /*
  39         * Put local_irq_enable and idle in same execute packet
  40         * to make them atomic and avoid race to idle with
  41         * interrupts enabled.
  42         */
  43        asm volatile ("   mvc .s2 CSR,%0\n"
  44                      "   or  .d2 1,%0,%0\n"
  45                      "   mvc .s2 %0,CSR\n"
  46                      "|| idle\n"
  47                      : "=b"(tmp));
  48}
  49
  50static void halt_loop(void)
  51{
  52        printk(KERN_EMERG "System Halted, OK to turn off power\n");
  53        local_irq_disable();
  54        while (1)
  55                asm volatile("idle\n");
  56}
  57
  58void machine_restart(char *__unused)
  59{
  60        if (c6x_restart)
  61                c6x_restart();
  62        halt_loop();
  63}
  64
  65void machine_halt(void)
  66{
  67        if (c6x_halt)
  68                c6x_halt();
  69        halt_loop();
  70}
  71
  72void machine_power_off(void)
  73{
  74        if (pm_power_off)
  75                pm_power_off();
  76        halt_loop();
  77}
  78
  79void flush_thread(void)
  80{
  81}
  82
  83/*
  84 * Do necessary setup to start up a newly executed thread.
  85 */
  86void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp)
  87{
  88        /*
  89         * The binfmt loader will setup a "full" stack, but the C6X
  90         * operates an "empty" stack. So we adjust the usp so that
  91         * argc doesn't get destroyed if an interrupt is taken before
  92         * it is read from the stack.
  93         *
  94         * NB: Library startup code needs to match this.
  95         */
  96        usp -= 8;
  97
  98        regs->pc  = pc;
  99        regs->sp  = usp;
 100        regs->tsr |= 0x40; /* set user mode */
 101        current->thread.usp = usp;
 102}
 103
 104/*
 105 * Copy a new thread context in its stack.
 106 */
 107int copy_thread(unsigned long clone_flags, unsigned long usp,
 108                unsigned long ustk_size,
 109                struct task_struct *p)
 110{
 111        struct pt_regs *childregs;
 112
 113        childregs = task_pt_regs(p);
 114
 115        if (unlikely(p->flags & PF_KTHREAD)) {
 116                /* case of  __kernel_thread: we return to supervisor space */
 117                memset(childregs, 0, sizeof(struct pt_regs));
 118                childregs->sp = (unsigned long)(childregs + 1);
 119                p->thread.pc = (unsigned long) ret_from_kernel_thread;
 120                childregs->a0 = usp;            /* function */
 121                childregs->a1 = ustk_size;      /* argument */
 122        } else {
 123                /* Otherwise use the given stack */
 124                *childregs = *current_pt_regs();
 125                if (usp)
 126                        childregs->sp = usp;
 127                p->thread.pc = (unsigned long) ret_from_fork;
 128        }
 129
 130        /* Set usp/ksp */
 131        p->thread.usp = childregs->sp;
 132        thread_saved_ksp(p) = (unsigned long)childregs - 8;
 133        p->thread.wchan = p->thread.pc;
 134#ifdef __DSBT__
 135        {
 136                unsigned long dp;
 137
 138                asm volatile ("mv .S2 b14,%0\n" : "=b"(dp));
 139
 140                thread_saved_dp(p) = dp;
 141                if (usp == -1)
 142                        childregs->dp = dp;
 143        }
 144#endif
 145        return 0;
 146}
 147
 148unsigned long get_wchan(struct task_struct *p)
 149{
 150        return p->thread.wchan;
 151}
 152