Blame view

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