1bd4c5b4e8f696ed4678674541a595f206bd24b2
[openwrt.git] / target / linux / lantiq / patches / 0019-MIPS-lantiq-adds-VPE-extensions.patch
1 From c6c810d83f0d95f54c3a6b338d219cec7ccef4c9 Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Thu, 29 Sep 2011 20:30:40 +0200
4 Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions
5
6 ---
7 arch/mips/Kconfig | 22 +++
8 arch/mips/include/asm/mipsmtregs.h | 54 +++++++
9 arch/mips/kernel/Makefile | 3 +-
10 arch/mips/kernel/mips-mt.c | 97 +++++++++++--
11 arch/mips/kernel/mtsched_proc.c | 279 ++++++++++++++++++++++++++++++++++++
12 arch/mips/kernel/perf_proc.c | 191 ++++++++++++++++++++++++
13 arch/mips/kernel/proc.c | 17 +++
14 arch/mips/kernel/smtc.c | 7 +
15 arch/mips/kernel/vpe.c | 250 ++++++++++++++++++++++++++++++++-
16 9 files changed, 905 insertions(+), 15 deletions(-)
17 create mode 100644 arch/mips/kernel/mtsched_proc.c
18 create mode 100644 arch/mips/kernel/perf_proc.c
19
20 --- a/arch/mips/Kconfig
21 +++ b/arch/mips/Kconfig
22 @@ -1915,6 +1915,28 @@ config MIPS_VPE_LOADER
23 Includes a loader for loading an elf relocatable object
24 onto another VPE and running it.
25
26 +config IFX_VPE_EXT
27 + bool "IFX APRP Extensions"
28 + depends on MIPS_VPE_LOADER
29 + default y
30 + help
31 + IFX included extensions in APRP
32 +
33 +config PERFCTRS
34 + bool "34K Performance counters"
35 + depends on MIPS_MT && PROC_FS
36 + default n
37 + help
38 + 34K Performance counter through /proc
39 +
40 +config MTSCHED
41 + bool "Support mtsched priority configuration for TCs"
42 + depends on MIPS_MT && PROC_FS
43 + default y
44 + help
45 + Support for mtsched priority configuration for TCs through
46 + /proc/mips/mtsched
47 +
48 config MIPS_MT_SMTC_IM_BACKSTOP
49 bool "Use per-TC register bits as backstop for inhibited IM bits"
50 depends on MIPS_MT_SMTC
51 --- a/arch/mips/include/asm/mipsmtregs.h
52 +++ b/arch/mips/include/asm/mipsmtregs.h
53 @@ -28,14 +28,34 @@
54 #define read_c0_vpeconf0() __read_32bit_c0_register($1, 2)
55 #define write_c0_vpeconf0(val) __write_32bit_c0_register($1, 2, val)
56
57 +#define read_c0_vpeconf1() __read_32bit_c0_register($1, 3)
58 +#define write_c0_vpeconf1(val) __write_32bit_c0_register($1, 3, val)
59 +
60 +#define read_c0_vpeschedule() __read_32bit_c0_register($1, 5)
61 +#define write_c0_vpeschedule(val) __write_32bit_c0_register($1, 5, val)
62 +
63 +#define read_c0_vpeschefback() __read_32bit_c0_register($1, 6)
64 +#define write_c0_vpeschefback(val) __write_32bit_c0_register($1, 6, val)
65 +
66 +#define read_c0_vpeopt() __read_32bit_c0_register($1, 7)
67 +#define write_c0_vpeopt(val) __write_32bit_c0_register($1, 7, val)
68 +
69 #define read_c0_tcstatus() __read_32bit_c0_register($2, 1)
70 #define write_c0_tcstatus(val) __write_32bit_c0_register($2, 1, val)
71
72 #define read_c0_tcbind() __read_32bit_c0_register($2, 2)
73 +#define write_c0_tcbind(val) __write_32bit_c0_register($2, 2, val)
74
75 #define read_c0_tccontext() __read_32bit_c0_register($2, 5)
76 #define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val)
77
78 +#define read_c0_tcschedule() __read_32bit_c0_register($2, 6)
79 +#define write_c0_tcschedule(val) __write_32bit_c0_register($2, 6, val)
80 +
81 +#define read_c0_tcschefback() __read_32bit_c0_register($2, 7)
82 +#define write_c0_tcschefback(val) __write_32bit_c0_register($2, 7, val)
83 +
84 +
85 #else /* Assembly */
86 /*
87 * Macros for use in assembly language code
88 @@ -74,6 +94,8 @@
89 #define MVPCONTROL_STLB_SHIFT 2
90 #define MVPCONTROL_STLB (_ULCAST_(1) << MVPCONTROL_STLB_SHIFT)
91
92 +#define MVPCONTROL_CPA_SHIFT 3
93 +#define MVPCONTROL_CPA (_ULCAST_(1) << MVPCONTROL_CPA_SHIFT)
94
95 /* MVPConf0 fields */
96 #define MVPCONF0_PTC_SHIFT 0
97 @@ -84,6 +106,8 @@
98 #define MVPCONF0_TCA ( _ULCAST_(1) << MVPCONF0_TCA_SHIFT)
99 #define MVPCONF0_PTLBE_SHIFT 16
100 #define MVPCONF0_PTLBE (_ULCAST_(0x3ff) << MVPCONF0_PTLBE_SHIFT)
101 +#define MVPCONF0_PCP_SHIFT 27
102 +#define MVPCONF0_PCP (_ULCAST_(1) << MVPCONF0_PCP_SHIFT)
103 #define MVPCONF0_TLBS_SHIFT 29
104 #define MVPCONF0_TLBS (_ULCAST_(1) << MVPCONF0_TLBS_SHIFT)
105 #define MVPCONF0_M_SHIFT 31
106 @@ -121,9 +145,25 @@
107 #define VPECONF0_VPA (_ULCAST_(1) << VPECONF0_VPA_SHIFT)
108 #define VPECONF0_MVP_SHIFT 1
109 #define VPECONF0_MVP (_ULCAST_(1) << VPECONF0_MVP_SHIFT)
110 +#define VPECONF0_ICS_SHIFT 16
111 +#define VPECONF0_ICS (_ULCAST_(1) << VPECONF0_ICS_SHIFT)
112 +#define VPECONF0_DCS_SHIFT 17
113 +#define VPECONF0_DCS (_ULCAST_(1) << VPECONF0_DCS_SHIFT)
114 #define VPECONF0_XTC_SHIFT 21
115 #define VPECONF0_XTC (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT)
116
117 +/* VPEOpt fields */
118 +#define VPEOPT_DWX_SHIFT 0
119 +#define VPEOPT_IWX_SHIFT 8
120 +#define VPEOPT_IWX0 ( _ULCAST_(0x1) << VPEOPT_IWX_SHIFT)
121 +#define VPEOPT_IWX1 ( _ULCAST_(0x2) << VPEOPT_IWX_SHIFT)
122 +#define VPEOPT_IWX2 ( _ULCAST_(0x4) << VPEOPT_IWX_SHIFT)
123 +#define VPEOPT_IWX3 ( _ULCAST_(0x8) << VPEOPT_IWX_SHIFT)
124 +#define VPEOPT_DWX0 ( _ULCAST_(0x1) << VPEOPT_DWX_SHIFT)
125 +#define VPEOPT_DWX1 ( _ULCAST_(0x2) << VPEOPT_DWX_SHIFT)
126 +#define VPEOPT_DWX2 ( _ULCAST_(0x4) << VPEOPT_DWX_SHIFT)
127 +#define VPEOPT_DWX3 ( _ULCAST_(0x8) << VPEOPT_DWX_SHIFT)
128 +
129 /* TCStatus fields (per TC) */
130 #define TCSTATUS_TASID (_ULCAST_(0xff))
131 #define TCSTATUS_IXMT_SHIFT 10
132 @@ -350,6 +390,14 @@ do { \
133 #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val)
134 #define read_vpe_c0_vpeconf0() mftc0(1, 2)
135 #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val)
136 +#define read_vpe_c0_vpeschedule() mftc0(1, 5)
137 +#define write_vpe_c0_vpeschedule(val) mttc0(1, 5, val)
138 +#define read_vpe_c0_vpeschefback() mftc0(1, 6)
139 +#define write_vpe_c0_vpeschefback(val) mttc0(1, 6, val)
140 +#define read_vpe_c0_vpeopt() mftc0(1, 7)
141 +#define write_vpe_c0_vpeopt(val) mttc0(1, 7, val)
142 +#define read_vpe_c0_wired() mftc0(6, 0)
143 +#define write_vpe_c0_wired(val) mttc0(6, 0, val)
144 #define read_vpe_c0_count() mftc0(9, 0)
145 #define write_vpe_c0_count(val) mttc0(9, 0, val)
146 #define read_vpe_c0_status() mftc0(12, 0)
147 @@ -381,6 +429,12 @@ do { \
148 #define write_tc_c0_tchalt(val) mttc0(2, 4, val)
149 #define read_tc_c0_tccontext() mftc0(2, 5)
150 #define write_tc_c0_tccontext(val) mttc0(2, 5, val)
151 +#define read_tc_c0_tcschedule() mftc0(2, 6)
152 +#define write_tc_c0_tcschedule(val) mttc0(2, 6, val)
153 +#define read_tc_c0_tcschefback() mftc0(2, 7)
154 +#define write_tc_c0_tcschefback(val) mttc0(2, 7, val)
155 +#define read_tc_c0_entryhi() mftc0(10, 0)
156 +#define write_tc_c0_entryhi(val) mttc0(10, 0, val)
157
158 /* GPR */
159 #define read_tc_gpr_sp() mftgpr(29)
160 --- a/arch/mips/kernel/Makefile
161 +++ b/arch/mips/kernel/Makefile
162 @@ -86,7 +86,8 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo3
163
164 obj-$(CONFIG_KGDB) += kgdb.o
165 obj-$(CONFIG_PROC_FS) += proc.o
166 -
167 +obj-$(CONFIG_MTSCHED) += mtsched_proc.o
168 +obj-$(CONFIG_PERFCTRS) += perf_proc.o
169 obj-$(CONFIG_64BIT) += cpu-bugs64.o
170
171 obj-$(CONFIG_I8253) += i8253.o
172 --- a/arch/mips/kernel/mips-mt.c
173 +++ b/arch/mips/kernel/mips-mt.c
174 @@ -21,26 +21,96 @@
175 #include <asm/cacheflush.h>
176
177 int vpelimit;
178 -
179 static int __init maxvpes(char *str)
180 {
181 get_option(&str, &vpelimit);
182 -
183 return 1;
184 }
185 -
186 __setup("maxvpes=", maxvpes);
187
188 int tclimit;
189 -
190 static int __init maxtcs(char *str)
191 {
192 get_option(&str, &tclimit);
193 + return 1;
194 +}
195 +__setup("maxtcs=", maxtcs);
196
197 +#ifdef CONFIG_IFX_VPE_EXT
198 +int stlb;
199 +static int __init istlbshared(char *str)
200 +{
201 + get_option(&str, &stlb);
202 return 1;
203 }
204 +__setup("vpe_tlb_shared=", istlbshared);
205
206 -__setup("maxtcs=", maxtcs);
207 +int vpe0_wired;
208 +static int __init vpe0wired(char *str)
209 +{
210 + get_option(&str, &vpe0_wired);
211 + return 1;
212 +}
213 +__setup("vpe0_wired_tlb_entries=", vpe0wired);
214 +
215 +int vpe1_wired;
216 +static int __init vpe1wired(char *str)
217 +{
218 + get_option(&str, &vpe1_wired);
219 + return 1;
220 +}
221 +__setup("vpe1_wired_tlb_entries=", vpe1wired);
222 +
223 +#ifdef CONFIG_MIPS_MT_SMTC
224 +extern int nostlb;
225 +#endif
226 +void configure_tlb(void)
227 +{
228 + int vpeflags, tcflags, tlbsiz;
229 + unsigned int config1val;
230 + vpeflags = dvpe();
231 + tcflags = dmt();
232 + write_c0_vpeconf0((read_c0_vpeconf0() | VPECONF0_MVP));
233 + write_c0_mvpcontrol((read_c0_mvpcontrol() | MVPCONTROL_VPC));
234 + mips_ihb();
235 + //printk("stlb = %d, vpe0_wired = %d vpe1_wired=%d\n", stlb,vpe0_wired, vpe1_wired);
236 + if (stlb) {
237 + if (!(read_c0_mvpconf0() & MVPCONF0_TLBS)) {
238 + emt(tcflags);
239 + evpe(vpeflags);
240 + return;
241 + }
242 +
243 + write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB);
244 + write_c0_wired(vpe0_wired + vpe1_wired);
245 + if (((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) {
246 + config1val = read_vpe_c0_config1();
247 + tlbsiz = (((config1val >> 25) & 0x3f) + 1);
248 + if (tlbsiz > 64)
249 + tlbsiz = 64;
250 + cpu_data[0].tlbsize = tlbsiz;
251 + current_cpu_data.tlbsize = tlbsiz;
252 + }
253 +
254 + }
255 + else {
256 + write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_STLB);
257 + write_c0_wired(vpe0_wired);
258 + }
259 +
260 + ehb();
261 + write_c0_mvpcontrol((read_c0_mvpcontrol() & ~MVPCONTROL_VPC));
262 + ehb();
263 + local_flush_tlb_all();
264 +
265 + printk("Wired TLB entries for Linux read_c0_wired() = %d\n", read_c0_wired());
266 +#ifdef CONFIG_MIPS_MT_SMTC
267 + nostlb = !stlb;
268 +#endif
269 + emt(tcflags);
270 + evpe(vpeflags);
271 +}
272 +#endif
273
274 /*
275 * Dump new MIPS MT state for the core. Does not leave TCs halted.
276 @@ -78,18 +148,18 @@ void mips_mt_regdump(unsigned long mvpct
277 if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) {
278 printk(" VPE %d\n", i);
279 printk(" VPEControl : %08lx\n",
280 - read_vpe_c0_vpecontrol());
281 + read_vpe_c0_vpecontrol());
282 printk(" VPEConf0 : %08lx\n",
283 - read_vpe_c0_vpeconf0());
284 + read_vpe_c0_vpeconf0());
285 printk(" VPE%d.Status : %08lx\n",
286 - i, read_vpe_c0_status());
287 + i, read_vpe_c0_status());
288 printk(" VPE%d.EPC : %08lx %pS\n",
289 - i, read_vpe_c0_epc(),
290 - (void *) read_vpe_c0_epc());
291 + i, read_vpe_c0_epc(),
292 + (void *) read_vpe_c0_epc());
293 printk(" VPE%d.Cause : %08lx\n",
294 - i, read_vpe_c0_cause());
295 + i, read_vpe_c0_cause());
296 printk(" VPE%d.Config7 : %08lx\n",
297 - i, read_vpe_c0_config7());
298 + i, read_vpe_c0_config7());
299 break; /* Next VPE */
300 }
301 }
302 @@ -287,6 +357,9 @@ void mips_mt_set_cpuoptions(void)
303 printk("Mapped %ld ITC cells starting at 0x%08x\n",
304 ((itcblkgrn & 0x7fe00000) >> 20), itc_base);
305 }
306 +#ifdef CONFIG_IFX_VPE_EXT
307 + configure_tlb();
308 +#endif
309 }
310
311 /*
312 --- /dev/null
313 +++ b/arch/mips/kernel/mtsched_proc.c
314 @@ -0,0 +1,279 @@
315 +/*
316 + * /proc hooks for MIPS MT scheduling policy management for 34K cores
317 + *
318 + * This program is free software; you can distribute it and/or modify it
319 + * under the terms of the GNU General Public License (Version 2) as
320 + * published by the Free Software Foundation.
321 + *
322 + * This program is distributed in the hope it will be useful, but WITHOUT
323 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
324 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325 + * for more details.
326 + *
327 + * You should have received a copy of the GNU General Public License along
328 + * with this program; if not, write to the Free Software Foundation, Inc.,
329 + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
330 + *
331 + * Copyright (C) 2006 Mips Technologies, Inc
332 + */
333 +
334 +#include <linux/kernel.h>
335 +
336 +#include <asm/cpu.h>
337 +#include <asm/processor.h>
338 +#include <asm/system.h>
339 +#include <asm/mipsregs.h>
340 +#include <asm/mipsmtregs.h>
341 +#include <asm/uaccess.h>
342 +#include <linux/proc_fs.h>
343 +
344 +static struct proc_dir_entry *mtsched_proc;
345 +
346 +#ifndef CONFIG_MIPS_MT_SMTC
347 +#define NTCS 2
348 +#else
349 +#define NTCS NR_CPUS
350 +#endif
351 +#define NVPES 2
352 +
353 +int lastvpe = 1;
354 +int lasttc = 8;
355 +
356 +static int proc_read_mtsched(char *page, char **start, off_t off,
357 + int count, int *eof, void *data)
358 +{
359 + int totalen = 0;
360 + int len;
361 +
362 + int i;
363 + int vpe;
364 + int mytc;
365 + unsigned long flags;
366 + unsigned int mtflags;
367 + unsigned int haltstate;
368 + unsigned int vpes_checked[NVPES];
369 + unsigned int vpeschedule[NVPES];
370 + unsigned int vpeschefback[NVPES];
371 + unsigned int tcschedule[NTCS];
372 + unsigned int tcschefback[NTCS];
373 +
374 + /* Dump the state of the MIPS MT scheduling policy manager */
375 + /* Inititalize control state */
376 + for(i = 0; i < NVPES; i++) {
377 + vpes_checked[i] = 0;
378 + vpeschedule[i] = 0;
379 + vpeschefback[i] = 0;
380 + }
381 + for(i = 0; i < NTCS; i++) {
382 + tcschedule[i] = 0;
383 + tcschefback[i] = 0;
384 + }
385 +
386 + /* Disable interrupts and multithreaded issue */
387 + local_irq_save(flags);
388 + mtflags = dvpe();
389 +
390 + /* Then go through the TCs, halt 'em, and extract the values */
391 + mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT;
392 + for(i = 0; i < NTCS; i++) {
393 + if(i == mytc) {
394 + /* No need to halt ourselves! */
395 + tcschedule[i] = read_c0_tcschedule();
396 + tcschefback[i] = read_c0_tcschefback();
397 + /* If VPE bound to TC hasn't been checked, do it */
398 + vpe = read_c0_tcbind() & TCBIND_CURVPE;
399 + if(!vpes_checked[vpe]) {
400 + vpeschedule[vpe] = read_c0_vpeschedule();
401 + vpeschefback[vpe] = read_c0_vpeschefback();
402 + vpes_checked[vpe] = 1;
403 + }
404 + } else {
405 + settc(i);
406 + haltstate = read_tc_c0_tchalt();
407 + write_tc_c0_tchalt(TCHALT_H);
408 + mips_ihb();
409 + tcschedule[i] = read_tc_c0_tcschedule();
410 + tcschefback[i] = read_tc_c0_tcschefback();
411 + /* If VPE bound to TC hasn't been checked, do it */
412 + vpe = read_tc_c0_tcbind() & TCBIND_CURVPE;
413 + if(!vpes_checked[vpe]) {
414 + vpeschedule[vpe] = read_vpe_c0_vpeschedule();
415 + vpeschefback[vpe] = read_vpe_c0_vpeschefback();
416 + vpes_checked[vpe] = 1;
417 + }
418 + if(!haltstate) write_tc_c0_tchalt(0);
419 + }
420 + }
421 + /* Re-enable MT and interrupts */
422 + evpe(mtflags);
423 + local_irq_restore(flags);
424 +
425 + for(vpe=0; vpe < NVPES; vpe++) {
426 + len = sprintf(page, "VPE[%d].VPEschedule = 0x%08x\n",
427 + vpe, vpeschedule[vpe]);
428 + totalen += len;
429 + page += len;
430 + len = sprintf(page, "VPE[%d].VPEschefback = 0x%08x\n",
431 + vpe, vpeschefback[vpe]);
432 + totalen += len;
433 + page += len;
434 + }
435 + for(i=0; i < NTCS; i++) {
436 + len = sprintf(page, "TC[%d].TCschedule = 0x%08x\n",
437 + i, tcschedule[i]);
438 + totalen += len;
439 + page += len;
440 + len = sprintf(page, "TC[%d].TCschefback = 0x%08x\n",
441 + i, tcschefback[i]);
442 + totalen += len;
443 + page += len;
444 + }
445 + return totalen;
446 +}
447 +
448 +/*
449 + * Write to perf counter registers based on text input
450 + */
451 +
452 +#define TXTBUFSZ 100
453 +
454 +static int proc_write_mtsched(struct file *file, const char *buffer,
455 + unsigned long count, void *data)
456 +{
457 + int len = 0;
458 + char mybuf[TXTBUFSZ];
459 + /* At most, we will set up 9 TCs and 2 VPEs, 11 entries in all */
460 + char entity[1]; //, entity1[1];
461 + int number[1];
462 + unsigned long value[1];
463 + int nparsed = 0 , index = 0;
464 + unsigned long flags;
465 + unsigned int mtflags;
466 + unsigned int haltstate;
467 + unsigned int tcbindval;
468 +
469 + if(count >= TXTBUFSZ) len = TXTBUFSZ-1;
470 + else len = count;
471 + memset(mybuf,0,TXTBUFSZ);
472 + if(copy_from_user(mybuf, buffer, len)) return -EFAULT;
473 +
474 + nparsed = sscanf(mybuf, "%c%d %lx",
475 + &entity[0] ,&number[0], &value[0]);
476 +
477 + /*
478 + * Having acquired the inputs, which might have
479 + * generated exceptions and preemptions,
480 + * program the registers.
481 + */
482 + /* Disable interrupts and multithreaded issue */
483 + local_irq_save(flags);
484 + mtflags = dvpe();
485 +
486 + if(entity[index] == 't' ) {
487 + /* Set TCSchedule or TCScheFBack of specified TC */
488 + if(number[index] > NTCS) goto skip;
489 + /* If it's our own TC, do it direct */
490 + if(number[index] ==
491 + ((read_c0_tcbind() & TCBIND_CURTC)
492 + >> TCBIND_CURTC_SHIFT)) {
493 + if(entity[index] == 't')
494 + write_c0_tcschedule(value[index]);
495 + else
496 + write_c0_tcschefback(value[index]);
497 + } else {
498 + /* Otherwise, we do it via MTTR */
499 + settc(number[index]);
500 + haltstate = read_tc_c0_tchalt();
501 + write_tc_c0_tchalt(TCHALT_H);
502 + mips_ihb();
503 + if(entity[index] == 't')
504 + write_tc_c0_tcschedule(value[index]);
505 + else
506 + write_tc_c0_tcschefback(value[index]);
507 + mips_ihb();
508 + if(!haltstate) write_tc_c0_tchalt(0);
509 + }
510 + } else if(entity[index] == 'v') {
511 + /* Set VPESchedule of specified VPE */
512 + if(number[index] > NVPES) goto skip;
513 + tcbindval = read_c0_tcbind();
514 + /* Are we doing this to our current VPE? */
515 + if((tcbindval & TCBIND_CURVPE) == number[index]) {
516 + /* Then life is simple */
517 + write_c0_vpeschedule(value[index]);
518 + } else {
519 + /*
520 + * Bind ourselves to the other VPE long enough
521 + * to program the bind value.
522 + */
523 + write_c0_tcbind((tcbindval & ~TCBIND_CURVPE)
524 + | number[index]);
525 + mips_ihb();
526 + write_c0_vpeschedule(value[index]);
527 + mips_ihb();
528 + /* Restore previous binding */
529 + write_c0_tcbind(tcbindval);
530 + mips_ihb();
531 + }
532 + }
533 +
534 + else if(entity[index] == 'r') {
535 + unsigned int vpes_checked[2], vpe ,i , mytc;
536 + vpes_checked[0] = vpes_checked[1] = 0;
537 +
538 + /* Then go through the TCs, halt 'em, and extract the values */
539 + mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT;
540 +
541 + for(i = 0; i < NTCS; i++) {
542 + if(i == mytc) {
543 + /* No need to halt ourselves! */
544 + write_c0_vpeschefback(0);
545 + write_c0_tcschefback(0);
546 + } else {
547 + settc(i);
548 + haltstate = read_tc_c0_tchalt();
549 + write_tc_c0_tchalt(TCHALT_H);
550 + mips_ihb();
551 + write_tc_c0_tcschefback(0);
552 + /* If VPE bound to TC hasn't been checked, do it */
553 + vpe = read_tc_c0_tcbind() & TCBIND_CURVPE;
554 + if(!vpes_checked[vpe]) {
555 + write_vpe_c0_vpeschefback(0);
556 + vpes_checked[vpe] = 1;
557 + }
558 + if(!haltstate) write_tc_c0_tchalt(0);
559 + }
560 + }
561 + }
562 + else {
563 + printk ("\n Usage : <t/v><0/1> <Hex Value>\n Example : t0 0x01\n");
564 + }
565 +
566 +skip:
567 + /* Re-enable MT and interrupts */
568 + evpe(mtflags);
569 + local_irq_restore(flags);
570 + return (len);
571 +}
572 +
573 +static int __init init_mtsched_proc(void)
574 +{
575 + extern struct proc_dir_entry *get_mips_proc_dir(void);
576 + struct proc_dir_entry *mips_proc_dir;
577 +
578 + if (!cpu_has_mipsmt) {
579 + printk("mtsched: not a MIPS MT capable processor\n");
580 + return -ENODEV;
581 + }
582 +
583 + mips_proc_dir = get_mips_proc_dir();
584 +
585 + mtsched_proc = create_proc_entry("mtsched", 0644, mips_proc_dir);
586 + mtsched_proc->read_proc = proc_read_mtsched;
587 + mtsched_proc->write_proc = proc_write_mtsched;
588 +
589 + return 0;
590 +}
591 +
592 +/* Automagically create the entry */
593 +module_init(init_mtsched_proc);
594 --- /dev/null
595 +++ b/arch/mips/kernel/perf_proc.c
596 @@ -0,0 +1,191 @@
597 +/*
598 + * /proc hooks for CPU performance counter support for SMTC kernel
599 + * (and ultimately others)
600 + * Copyright (C) 2006 Mips Technologies, Inc
601 + */
602 +
603 +#include <linux/kernel.h>
604 +
605 +#include <asm/cpu.h>
606 +#include <asm/processor.h>
607 +#include <asm/system.h>
608 +#include <asm/mipsregs.h>
609 +#include <asm/uaccess.h>
610 +#include <linux/proc_fs.h>
611 +
612 +/*
613 + * /proc diagnostic and statistics hooks
614 + */
615 +
616 +
617 +/* Internal software-extended event counters */
618 +
619 +static unsigned long long extencount[4] = {0,0,0,0};
620 +
621 +static struct proc_dir_entry *perf_proc;
622 +
623 +static int proc_read_perf(char *page, char **start, off_t off,
624 + int count, int *eof, void *data)
625 +{
626 + int totalen = 0;
627 + int len;
628 +
629 + len = sprintf(page, "PerfCnt[0].Ctl : 0x%08x\n", read_c0_perfctrl0());
630 + totalen += len;
631 + page += len;
632 + len = sprintf(page, "PerfCnt[0].Cnt : %Lu\n",
633 + extencount[0] + (unsigned long long)((unsigned)read_c0_perfcntr0()));
634 + totalen += len;
635 + page += len;
636 + len = sprintf(page, "PerfCnt[1].Ctl : 0x%08x\n", read_c0_perfctrl1());
637 + totalen += len;
638 + page += len;
639 + len = sprintf(page, "PerfCnt[1].Cnt : %Lu\n",
640 + extencount[1] + (unsigned long long)((unsigned)read_c0_perfcntr1()));
641 + totalen += len;
642 + page += len;
643 + len = sprintf(page, "PerfCnt[2].Ctl : 0x%08x\n", read_c0_perfctrl2());
644 + totalen += len;
645 + page += len;
646 + len = sprintf(page, "PerfCnt[2].Cnt : %Lu\n",
647 + extencount[2] + (unsigned long long)((unsigned)read_c0_perfcntr2()));
648 + totalen += len;
649 + page += len;
650 + len = sprintf(page, "PerfCnt[3].Ctl : 0x%08x\n", read_c0_perfctrl3());
651 + totalen += len;
652 + page += len;
653 + len = sprintf(page, "PerfCnt[3].Cnt : %Lu\n",
654 + extencount[3] + (unsigned long long)((unsigned)read_c0_perfcntr3()));
655 + totalen += len;
656 + page += len;
657 +
658 + return totalen;
659 +}
660 +
661 +/*
662 + * Write to perf counter registers based on text input
663 + */
664 +
665 +#define TXTBUFSZ 100
666 +
667 +static int proc_write_perf(struct file *file, const char *buffer,
668 + unsigned long count, void *data)
669 +{
670 + int len;
671 + int nparsed;
672 + int index;
673 + char mybuf[TXTBUFSZ];
674 +
675 + int which[4];
676 + unsigned long control[4];
677 + long long ctrdata[4];
678 +
679 + if(count >= TXTBUFSZ) len = TXTBUFSZ-1;
680 + else len = count;
681 + memset(mybuf,0,TXTBUFSZ);
682 + if(copy_from_user(mybuf, buffer, len)) return -EFAULT;
683 +
684 + nparsed = sscanf(mybuf,
685 + "%d %lx %Ld %d %lx %Ld %d %lx %Ld %d %lx %Ld",
686 + &which[0], &control[0], &ctrdata[0],
687 + &which[1], &control[1], &ctrdata[1],
688 + &which[2], &control[2], &ctrdata[2],
689 + &which[3], &control[3], &ctrdata[3]);
690 +
691 + for(index = 0; nparsed >= 3; index++) {
692 + switch (which[index]) {
693 + case 0:
694 + write_c0_perfctrl0(control[index]);
695 + if(ctrdata[index] != -1) {
696 + extencount[0] = (unsigned long long)ctrdata[index];
697 + write_c0_perfcntr0((unsigned long)0);
698 + }
699 + break;
700 + case 1:
701 + write_c0_perfctrl1(control[index]);
702 + if(ctrdata[index] != -1) {
703 + extencount[1] = (unsigned long long)ctrdata[index];
704 + write_c0_perfcntr1((unsigned long)0);
705 + }
706 + break;
707 + case 2:
708 + write_c0_perfctrl2(control[index]);
709 + if(ctrdata[index] != -1) {
710 + extencount[2] = (unsigned long long)ctrdata[index];
711 + write_c0_perfcntr2((unsigned long)0);
712 + }
713 + break;
714 + case 3:
715 + write_c0_perfctrl3(control[index]);
716 + if(ctrdata[index] != -1) {
717 + extencount[3] = (unsigned long long)ctrdata[index];
718 + write_c0_perfcntr3((unsigned long)0);
719 + }
720 + break;
721 + }
722 + nparsed -= 3;
723 + }
724 + return (len);
725 +}
726 +
727 +extern int (*perf_irq)(void);
728 +
729 +/*
730 + * Invoked when timer interrupt vector picks up a perf counter overflow
731 + */
732 +
733 +static int perf_proc_irq(void)
734 +{
735 + unsigned long snapshot;
736 +
737 + /*
738 + * It would be nice to do this as a loop, but we don't have
739 + * indirect access to CP0 registers.
740 + */
741 + snapshot = read_c0_perfcntr0();
742 + if ((long)snapshot < 0) {
743 + extencount[0] +=
744 + (unsigned long long)((unsigned)read_c0_perfcntr0());
745 + write_c0_perfcntr0(0);
746 + }
747 + snapshot = read_c0_perfcntr1();
748 + if ((long)snapshot < 0) {
749 + extencount[1] +=
750 + (unsigned long long)((unsigned)read_c0_perfcntr1());
751 + write_c0_perfcntr1(0);
752 + }
753 + snapshot = read_c0_perfcntr2();
754 + if ((long)snapshot < 0) {
755 + extencount[2] +=
756 + (unsigned long long)((unsigned)read_c0_perfcntr2());
757 + write_c0_perfcntr2(0);
758 + }
759 + snapshot = read_c0_perfcntr3();
760 + if ((long)snapshot < 0) {
761 + extencount[3] +=
762 + (unsigned long long)((unsigned)read_c0_perfcntr3());
763 + write_c0_perfcntr3(0);
764 + }
765 + return 0;
766 +}
767 +
768 +static int __init init_perf_proc(void)
769 +{
770 + extern struct proc_dir_entry *get_mips_proc_dir(void);
771 +
772 + struct proc_dir_entry *mips_proc_dir = get_mips_proc_dir();
773 +
774 + write_c0_perfcntr0(0);
775 + write_c0_perfcntr1(0);
776 + write_c0_perfcntr2(0);
777 + write_c0_perfcntr3(0);
778 + perf_proc = create_proc_entry("perf", 0644, mips_proc_dir);
779 + perf_proc->read_proc = proc_read_perf;
780 + perf_proc->write_proc = proc_write_perf;
781 + perf_irq = perf_proc_irq;
782 +
783 + return 0;
784 +}
785 +
786 +/* Automagically create the entry */
787 +module_init(init_perf_proc);
788 --- a/arch/mips/kernel/proc.c
789 +++ b/arch/mips/kernel/proc.c
790 @@ -7,6 +7,7 @@
791 #include <linux/kernel.h>
792 #include <linux/sched.h>
793 #include <linux/seq_file.h>
794 +#include <linux/proc_fs.h>
795 #include <asm/bootinfo.h>
796 #include <asm/cpu.h>
797 #include <asm/cpu-features.h>
798 @@ -110,3 +111,19 @@ const struct seq_operations cpuinfo_op =
799 .stop = c_stop,
800 .show = show_cpuinfo,
801 };
802 +
803 +/*
804 + * Support for MIPS/local /proc hooks in /proc/mips/
805 + */
806 +
807 +static struct proc_dir_entry *mips_proc = NULL;
808 +
809 +struct proc_dir_entry *get_mips_proc_dir(void)
810 +{
811 + /*
812 + * This ought not to be preemptable.
813 + */
814 + if(mips_proc == NULL)
815 + mips_proc = proc_mkdir("mips", NULL);
816 + return(mips_proc);
817 +}
818 --- a/arch/mips/kernel/smtc.c
819 +++ b/arch/mips/kernel/smtc.c
820 @@ -1334,6 +1334,13 @@ void smtc_get_new_mmu_context(struct mm_
821 asid = asid_cache(cpu);
822
823 do {
824 +#ifdef CONFIG_IFX_VPE_EXT
825 + /* If TLB is shared between AP and RP (AP is running SMTC),
826 + leave out max ASID i.e., ASID_MASK for RP
827 + */
828 + if (!nostlb && ((asid & ASID_MASK) == (ASID_MASK - 1)))
829 + asid++;
830 +#endif
831 if (!((asid += ASID_INC) & ASID_MASK) ) {
832 if (cpu_has_vtag_icache)
833 flush_icache_all();
834 --- a/arch/mips/kernel/vpe.c
835 +++ b/arch/mips/kernel/vpe.c
836 @@ -76,6 +76,58 @@ static struct kspd_notifications kspd_ev
837 static int kspd_events_reqd;
838 #endif
839
840 +#ifdef CONFIG_IFX_VPE_EXT
841 +static int is_sdepgm;
842 +extern int stlb;
843 +extern int vpe0_wired;
844 +extern int vpe1_wired;
845 +unsigned int vpe1_load_addr;
846 +
847 +static int __init load_address(char *str)
848 +{
849 + get_option(&str, &vpe1_load_addr);
850 + return 1;
851 +}
852 +__setup("vpe1_load_addr=", load_address);
853 +
854 +#include <asm/mipsmtregs.h>
855 +#define write_vpe_c0_wired(val) mttc0(6, 0, val)
856 +
857 +#ifndef COMMAND_LINE_SIZE
858 +# define COMMAND_LINE_SIZE 512
859 +#endif
860 +
861 +char command_line[COMMAND_LINE_SIZE * 2];
862 +
863 +static unsigned int vpe1_mem;
864 +static int __init vpe1mem(char *str)
865 +{
866 + vpe1_mem = memparse(str, &str);
867 + return 1;
868 +}
869 +__setup("vpe1_mem=", vpe1mem);
870 +
871 +uint32_t vpe1_wdog_ctr;
872 +static int __init wdog_ctr(char *str)
873 +{
874 + get_option(&str, &vpe1_wdog_ctr);
875 + return 1;
876 +}
877 +
878 +__setup("vpe1_wdog_ctr_addr=", wdog_ctr);
879 +EXPORT_SYMBOL(vpe1_wdog_ctr);
880 +
881 +uint32_t vpe1_wdog_timeout;
882 +static int __init wdog_timeout(char *str)
883 +{
884 + get_option(&str, &vpe1_wdog_timeout);
885 + return 1;
886 +}
887 +
888 +__setup("vpe1_wdog_timeout=", wdog_timeout);
889 +EXPORT_SYMBOL(vpe1_wdog_timeout);
890 +
891 +#endif
892 /* grab the likely amount of memory we will need. */
893 #ifdef CONFIG_MIPS_VPE_LOADER_TOM
894 #define P_SIZE (2 * 1024 * 1024)
895 @@ -268,6 +320,13 @@ static void *alloc_progmem(unsigned long
896 void *addr;
897
898 #ifdef CONFIG_MIPS_VPE_LOADER_TOM
899 +#ifdef CONFIG_IFX_VPE_EXT
900 + if (vpe1_load_addr) {
901 + memset((void *)vpe1_load_addr, 0, len);
902 + return (void *)vpe1_load_addr;
903 + }
904 +#endif
905 +
906 /*
907 * This means you must tell Linux to use less memory than you
908 * physically have, for example by passing a mem= boot argument.
909 @@ -746,6 +805,12 @@ static int vpe_run(struct vpe * v)
910 }
911
912 /* Write the address we want it to start running from in the TCPC register. */
913 +#if defined(CONFIG_IFX_VPE_EXT) && 0
914 + if (stlb)
915 + write_vpe_c0_wired(vpe0_wired + vpe1_wired);
916 + else
917 + write_vpe_c0_wired(vpe1_wired);
918 +#endif
919 write_tc_c0_tcrestart((unsigned long)v->__start);
920 write_tc_c0_tccontext((unsigned long)0);
921
922 @@ -759,6 +824,20 @@ static int vpe_run(struct vpe * v)
923
924 write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
925
926 +#if defined(CONFIG_IFX_VPE_EXT) && 0
927 + /*
928 + * $a2 & $a3 are used to pass command line parameters to VPE1. $a2
929 + * points to the start of the command line string and $a3 points to
930 + * the end of the string. This convention is identical to the Linux
931 + * kernel boot parameter passing mechanism. Please note that $a3 is
932 + * used to pass physical memory size or 0 in SDE tool kit. So, if you
933 + * are passing comand line parameters through $a2 & $a3 SDE programs
934 + * don't work as desired.
935 + */
936 + mttgpr(6, command_line);
937 + mttgpr(7, (command_line + strlen(command_line)));
938 + if (is_sdepgm)
939 +#endif
940 /*
941 * The sde-kit passes 'memsize' to __start in $a3, so set something
942 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and
943 @@ -833,6 +912,9 @@ static int find_vpe_symbols(struct vpe *
944 if ( (v->__start == 0) || (v->shared_ptr == NULL))
945 return -1;
946
947 +#ifdef CONFIG_IFX_VPE_EXT
948 + is_sdepgm = 1;
949 +#endif
950 return 0;
951 }
952
953 @@ -994,6 +1076,15 @@ static int vpe_elfload(struct vpe * v)
954 (unsigned long)v->load_addr + v->len);
955
956 if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
957 +#ifdef CONFIG_IFX_VPE_EXT
958 + if (vpe1_load_addr) {
959 + /* Conversion to KSEG1 is required ??? */
960 + v->__start = KSEG1ADDR(vpe1_load_addr);
961 + is_sdepgm = 0;
962 + return 0;
963 + }
964 +#endif
965 +
966 if (v->__start == 0) {
967 printk(KERN_WARNING "VPE loader: program does not contain "
968 "a __start symbol\n");
969 @@ -1064,6 +1155,9 @@ static int vpe_open(struct inode *inode,
970 struct vpe_notifications *not;
971 struct vpe *v;
972 int ret;
973 +#ifdef CONFIG_IFX_VPE_EXT
974 + int progsize;
975 +#endif
976
977 if (minor != iminor(inode)) {
978 /* assume only 1 device at the moment. */
979 @@ -1089,7 +1183,12 @@ static int vpe_open(struct inode *inode,
980 release_progmem(v->load_addr);
981 cleanup_tc(get_tc(tclimit));
982 }
983 -
984 +#ifdef CONFIG_IFX_VPE_EXT
985 + progsize = (vpe1_mem != 0) ? vpe1_mem : P_SIZE;
986 + //printk("progsize = %x\n", progsize);
987 + v->pbuffer = vmalloc(progsize);
988 + v->plen = progsize;
989 +#else
990 /* this of-course trashes what was there before... */
991 v->pbuffer = vmalloc(P_SIZE);
992 if (!v->pbuffer) {
993 @@ -1097,11 +1196,14 @@ static int vpe_open(struct inode *inode,
994 return -ENOMEM;
995 }
996 v->plen = P_SIZE;
997 +#endif
998 v->load_addr = NULL;
999 v->len = 0;
1000
1001 +#if 0
1002 v->uid = filp->f_cred->fsuid;
1003 v->gid = filp->f_cred->fsgid;
1004 +#endif
1005
1006 #ifdef CONFIG_MIPS_APSP_KSPD
1007 /* get kspd to tell us when a syscall_exit happens */
1008 @@ -1349,6 +1451,133 @@ static void kspd_sp_exit( int sp_id)
1009 cleanup_tc(get_tc(sp_id));
1010 }
1011 #endif
1012 +#ifdef CONFIG_IFX_VPE_EXT
1013 +int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags)
1014 +{
1015 + enum vpe_state state;
1016 + struct vpe *v = get_vpe(tclimit);
1017 + struct vpe_notifications *not;
1018 +
1019 + if (tcmask || flags) {
1020 + printk(KERN_WARNING "Currently tcmask and flags should be 0.\
1021 + other values not supported\n");
1022 + return -1;
1023 + }
1024 +
1025 + state = xchg(&v->state, VPE_STATE_INUSE);
1026 + if (state != VPE_STATE_UNUSED) {
1027 + vpe_stop(v);
1028 +
1029 + list_for_each_entry(not, &v->notify, list) {
1030 + not->stop(tclimit);
1031 + }
1032 + }
1033 +
1034 + v->__start = (unsigned long)sw_start_addr;
1035 + is_sdepgm = 0;
1036 +
1037 + if (!vpe_run(v)) {
1038 + printk(KERN_DEBUG "VPE loader: VPE1 running successfully\n");
1039 + return 0;
1040 + }
1041 + return -1;
1042 +}
1043 +
1044 +EXPORT_SYMBOL(vpe1_sw_start);
1045 +
1046 +int32_t vpe1_sw_stop(uint32_t flags)
1047 +{
1048 + struct vpe *v = get_vpe(tclimit);
1049 +
1050 + if (!vpe_free(v)) {
1051 + printk(KERN_DEBUG "RP Stopped\n");
1052 + return 0;
1053 + }
1054 + else
1055 + return -1;
1056 +}
1057 +
1058 +EXPORT_SYMBOL(vpe1_sw_stop);
1059 +
1060 +uint32_t vpe1_get_load_addr (uint32_t flags)
1061 +{
1062 + return vpe1_load_addr;
1063 +}
1064 +
1065 +EXPORT_SYMBOL(vpe1_get_load_addr);
1066 +
1067 +uint32_t vpe1_get_max_mem (uint32_t flags)
1068 +{
1069 + if (!vpe1_mem)
1070 + return P_SIZE;
1071 + else
1072 + return vpe1_mem;
1073 +}
1074 +
1075 +EXPORT_SYMBOL(vpe1_get_max_mem);
1076 +
1077 +void* vpe1_get_cmdline_argument(void)
1078 +{
1079 + return saved_command_line;
1080 +}
1081 +
1082 +EXPORT_SYMBOL(vpe1_get_cmdline_argument);
1083 +
1084 +int32_t vpe1_set_boot_param(char *field, char *value, char flags)
1085 +{
1086 + char *ptr, string[64];
1087 + int start_off, end_off;
1088 + if (!field)
1089 + return -1;
1090 + strcpy(string, field);
1091 + if (value) {
1092 + strcat(string, "=");
1093 + strcat(string, value);
1094 + strcat(command_line, " ");
1095 + strcat(command_line, string);
1096 + }
1097 + else {
1098 + ptr = strstr(command_line, string);
1099 + if (ptr) {
1100 + start_off = ptr - command_line;
1101 + ptr += strlen(string);
1102 + while ((*ptr != ' ') && (*ptr != '\0'))
1103 + ptr++;
1104 + end_off = ptr - command_line;
1105 + command_line[start_off] = '\0';
1106 + strcat (command_line, command_line+end_off);
1107 + }
1108 + }
1109 + return 0;
1110 +}
1111 +
1112 +EXPORT_SYMBOL(vpe1_set_boot_param);
1113 +
1114 +int32_t vpe1_get_boot_param(char *field, char **value, char flags)
1115 +{
1116 + char *ptr, string[64];
1117 + int i = 0;
1118 + if (!field)
1119 + return -1;
1120 + if ((ptr = strstr(command_line, field))) {
1121 + ptr += strlen(field) + 1; /* including = */
1122 + while ((*ptr != ' ') && (*ptr != '\0'))
1123 + string[i++] = *ptr++;
1124 + string[i] = '\0';
1125 + *value = kmalloc((strlen(string) + 1), GFP_KERNEL);
1126 + if (*value != NULL)
1127 + strcpy(*value, string);
1128 + }
1129 + else
1130 + *value = NULL;
1131 +
1132 + return 0;
1133 +}
1134 +
1135 +EXPORT_SYMBOL(vpe1_get_boot_param);
1136 +
1137 +extern void configure_tlb(void);
1138 +#endif
1139
1140 static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
1141 const char *buf, size_t len)
1142 @@ -1430,6 +1659,18 @@ static int __init vpe_module_init(void)
1143 printk("VPE loader: not a MIPS MT capable processor\n");
1144 return -ENODEV;
1145 }
1146 +#ifdef CONFIG_IFX_VPE_EXT
1147 +#ifndef CONFIG_MIPS_MT_SMTC
1148 + configure_tlb();
1149 +#endif
1150 +#endif
1151 +
1152 +#ifndef CONFIG_MIPS_MT_SMTC
1153 + if (!vpelimit)
1154 + vpelimit = 1;
1155 + if (!tclimit)
1156 + tclimit = 1;
1157 +#endif
1158
1159 if (vpelimit == 0) {
1160 printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
1161 @@ -1474,10 +1715,12 @@ static int __init vpe_module_init(void)
1162 mtflags = dmt();
1163 vpflags = dvpe();
1164
1165 + back_to_back_c0_hazard();
1166 +
1167 /* Put MVPE's into 'configuration state' */
1168 set_c0_mvpcontrol(MVPCONTROL_VPC);
1169
1170 - /* dump_mtregs(); */
1171 + dump_mtregs();
1172
1173 val = read_c0_mvpconf0();
1174 hw_tcs = (val & MVPCONF0_PTC) + 1;
1175 @@ -1489,6 +1732,7 @@ static int __init vpe_module_init(void)
1176 * reschedule send IPIs or similar we might hang.
1177 */
1178 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1179 + back_to_back_c0_hazard();
1180 evpe(vpflags);
1181 emt(mtflags);
1182 local_irq_restore(flags);
1183 @@ -1514,6 +1758,7 @@ static int __init vpe_module_init(void)
1184 }
1185
1186 v->ntcs = hw_tcs - tclimit;
1187 + write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
1188
1189 /* add the tc to the list of this vpe's tc's. */
1190 list_add(&t->tc, &v->tc);
1191 @@ -1582,6 +1827,7 @@ static int __init vpe_module_init(void)
1192 out_reenable:
1193 /* release config state */
1194 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1195 + back_to_back_c0_hazard();
1196
1197 evpe(vpflags);
1198 emt(mtflags);
This page took 0.100946 seconds and 3 git commands to generate.