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