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