linux/arch/mips/netlogic/xlp/cop2-ex.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2013 Broadcom Corporation.
   7 *
   8 * based on arch/mips/cavium-octeon/cpu.c
   9 * Copyright (C) 2009 Wind River Systems,
  10 *   written by Ralf Baechle <ralf@linux-mips.org>
  11 */
  12#include <linux/capability.h>
  13#include <linux/init.h>
  14#include <linux/irqflags.h>
  15#include <linux/notifier.h>
  16#include <linux/prefetch.h>
  17#include <linux/ptrace.h>
  18#include <linux/sched.h>
  19#include <linux/sched/task_stack.h>
  20
  21#include <asm/cop2.h>
  22#include <asm/current.h>
  23#include <asm/mipsregs.h>
  24#include <asm/page.h>
  25
  26#include <asm/netlogic/mips-extns.h>
  27
  28/*
  29 * 64 bit ops are done in inline assembly to support 32 bit
  30 * compilation
  31 */
  32void nlm_cop2_save(struct nlm_cop2_state *r)
  33{
  34        asm volatile(
  35                ".set   push\n"
  36                ".set   noat\n"
  37                "dmfc2  $1, $0, 0\n"
  38                "sd     $1, 0(%1)\n"
  39                "dmfc2  $1, $0, 1\n"
  40                "sd     $1, 8(%1)\n"
  41                "dmfc2  $1, $0, 2\n"
  42                "sd     $1, 16(%1)\n"
  43                "dmfc2  $1, $0, 3\n"
  44                "sd     $1, 24(%1)\n"
  45                "dmfc2  $1, $1, 0\n"
  46                "sd     $1, 0(%2)\n"
  47                "dmfc2  $1, $1, 1\n"
  48                "sd     $1, 8(%2)\n"
  49                "dmfc2  $1, $1, 2\n"
  50                "sd     $1, 16(%2)\n"
  51                "dmfc2  $1, $1, 3\n"
  52                "sd     $1, 24(%2)\n"
  53                ".set   pop\n"
  54                : "=m"(*r)
  55                : "r"(r->tx), "r"(r->rx));
  56
  57        r->tx_msg_status = __read_32bit_c2_register($2, 0);
  58        r->rx_msg_status = __read_32bit_c2_register($3, 0) & 0x0fffffff;
  59}
  60
  61void nlm_cop2_restore(struct nlm_cop2_state *r)
  62{
  63        u32 rstat;
  64
  65        asm volatile(
  66                ".set   push\n"
  67                ".set   noat\n"
  68                "ld     $1, 0(%1)\n"
  69                "dmtc2  $1, $0, 0\n"
  70                "ld     $1, 8(%1)\n"
  71                "dmtc2  $1, $0, 1\n"
  72                "ld     $1, 16(%1)\n"
  73                "dmtc2  $1, $0, 2\n"
  74                "ld     $1, 24(%1)\n"
  75                "dmtc2  $1, $0, 3\n"
  76                "ld     $1, 0(%2)\n"
  77                "dmtc2  $1, $1, 0\n"
  78                "ld     $1, 8(%2)\n"
  79                "dmtc2  $1, $1, 1\n"
  80                "ld     $1, 16(%2)\n"
  81                "dmtc2  $1, $1, 2\n"
  82                "ld     $1, 24(%2)\n"
  83                "dmtc2  $1, $1, 3\n"
  84                ".set   pop\n"
  85                : : "m"(*r), "r"(r->tx), "r"(r->rx));
  86
  87        __write_32bit_c2_register($2, 0, r->tx_msg_status);
  88        rstat = __read_32bit_c2_register($3, 0) & 0xf0000000u;
  89        __write_32bit_c2_register($3, 0, r->rx_msg_status | rstat);
  90}
  91
  92static int nlm_cu2_call(struct notifier_block *nfb, unsigned long action,
  93        void *data)
  94{
  95        unsigned long flags;
  96        unsigned int status;
  97
  98        switch (action) {
  99        case CU2_EXCEPTION:
 100                if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 101                        break;
 102                local_irq_save(flags);
 103                KSTK_STATUS(current) |= ST0_CU2;
 104                status = read_c0_status();
 105                write_c0_status(status | ST0_CU2);
 106                nlm_cop2_restore(&(current->thread.cp2));
 107                write_c0_status(status & ~ST0_CU2);
 108                local_irq_restore(flags);
 109                pr_info("COP2 access enabled for pid %d (%s)\n",
 110                                        current->pid, current->comm);
 111                return NOTIFY_BAD;      /* Don't call default notifier */
 112        }
 113
 114        return NOTIFY_OK;               /* Let default notifier send signals */
 115}
 116
 117static int __init nlm_cu2_setup(void)
 118{
 119        return cu2_notifier(nlm_cu2_call, 0);
 120}
 121early_initcall(nlm_cu2_setup);
 122