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
  36static void c6x_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
  52/*
  53 * The idle loop for C64x
  54 */
  55void cpu_idle(void)
  56{
  57        /* endless idle loop with no priority at all */
  58        while (1) {
  59                tick_nohz_idle_enter();
  60                rcu_idle_enter();
  61                while (1) {
  62                        local_irq_disable();
  63                        if (need_resched()) {
  64                                local_irq_enable();
  65                                break;
  66                        }
  67                        c6x_idle(); /* enables local irqs */
  68                }
  69                rcu_idle_exit();
  70                tick_nohz_idle_exit();
  71
  72                preempt_enable_no_resched();
  73                schedule();
  74                preempt_disable();
  75        }
  76}
  77
  78static void halt_loop(void)
  79{
  80        printk(KERN_EMERG "System Halted, OK to turn off power\n");
  81        local_irq_disable();
  82        while (1)
  83                asm volatile("idle\n");
  84}
  85
  86void machine_restart(char *__unused)
  87{
  88        if (c6x_restart)
  89                c6x_restart();
  90        halt_loop();
  91}
  92
  93void machine_halt(void)
  94{
  95        if (c6x_halt)
  96                c6x_halt();
  97        halt_loop();
  98}
  99
 100void machine_power_off(void)
 101{
 102        if (pm_power_off)
 103                pm_power_off();
 104        halt_loop();
 105}
 106
 107void flush_thread(void)
 108{
 109}
 110
 111void exit_thread(void)
 112{
 113}
 114
 115/*
 116 * Do necessary setup to start up a newly executed thread.
 117 */
 118void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp)
 119{
 120        /*
 121         * The binfmt loader will setup a "full" stack, but the C6X
 122         * operates an "empty" stack. So we adjust the usp so that
 123         * argc doesn't get destroyed if an interrupt is taken before
 124         * it is read from the stack.
 125         *
 126         * NB: Library startup code needs to match this.
 127         */
 128        usp -= 8;
 129
 130        set_fs(USER_DS);
 131        regs->pc  = pc;
 132        regs->sp  = usp;
 133        regs->tsr |= 0x40; /* set user mode */
 134        current->thread.usp = usp;
 135}
 136
 137/*
 138 * Copy a new thread context in its stack.
 139 */
 140int copy_thread(unsigned long clone_flags, unsigned long usp,
 141                unsigned long ustk_size,
 142                struct task_struct *p)
 143{
 144        struct pt_regs *childregs;
 145
 146        childregs = task_pt_regs(p);
 147
 148        if (unlikely(p->flags & PF_KTHREAD)) {
 149                /* case of  __kernel_thread: we return to supervisor space */
 150                memset(childregs, 0, sizeof(struct pt_regs));
 151                childregs->sp = (unsigned long)(childregs + 1);
 152                p->thread.pc = (unsigned long) ret_from_kernel_thread;
 153                childregs->a0 = usp;            /* function */
 154                childregs->a1 = ustk_size;      /* argument */
 155        } else {
 156                /* Otherwise use the given stack */
 157                *childregs = *current_pt_regs();
 158                if (usp)
 159                        childregs->sp = usp;
 160                p->thread.pc = (unsigned long) ret_from_fork;
 161        }
 162
 163        /* Set usp/ksp */
 164        p->thread.usp = childregs->sp;
 165        thread_saved_ksp(p) = (unsigned long)childregs - 8;
 166        p->thread.wchan = p->thread.pc;
 167#ifdef __DSBT__
 168        {
 169                unsigned long dp;
 170
 171                asm volatile ("mv .S2 b14,%0\n" : "=b"(dp));
 172
 173                thread_saved_dp(p) = dp;
 174                if (usp == -1)
 175                        childregs->dp = dp;
 176        }
 177#endif
 178        return 0;
 179}
 180
 181unsigned long get_wchan(struct task_struct *p)
 182{
 183        return p->thread.wchan;
 184}
 185