aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel/gdb-cache.S
blob: 1108badc3d32726104be191e7422d26b98405eba (plain) (blame)
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
###############################################################################
#
# MN10300 Low-level cache purging routines for gdbstub
#
# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
# Written by David Howells (dhowells@redhat.com)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public Licence
# as published by the Free Software Foundation; either version
# 2 of the Licence, or (at your option) any later version.
#
###############################################################################
#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/smp.h>
#include <asm/cache.h>
#include <asm/cpu-regs.h>
#include <asm/exceptions.h>
#include <asm/frame.inc>
#include <asm/serial-regs.h>

	.text

###############################################################################
#
# GDB stub cache purge
#
###############################################################################
	.type	gdbstub_purge_cache,@function
ENTRY(gdbstub_purge_cache)
	#######################################################################
	# read the addresses tagged in the cache's tag RAM and attempt to flush
	# those addresses specifically
	# - we rely on the hardware to filter out invalid tag entry addresses
	mov	DCACHE_TAG(0,0),a0		# dcache tag RAM access address
	mov	DCACHE_PURGE(0,0),a1		# dcache purge request address
	mov	L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1  # total number of entries

mn10300_dcache_flush_loop:
	mov	(a0),d0
	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
	or	L1_CACHE_TAG_VALID,d0		# retain valid entries in the
						# cache
	mov	d0,(a1)				# conditional purge

mn10300_dcache_flush_skip:
	add	L1_CACHE_BYTES,a0
	add	L1_CACHE_BYTES,a1
	add	-1,d1
	bne	mn10300_dcache_flush_loop

;; 	# unconditionally flush and invalidate the dcache
;; 	mov	DCACHE_PURGE(0,0),a1		# dcache purge request address
;; 	mov	L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1	# total number of
;;							# entries
;;
;; gdbstub_purge_cache__dcache_loop:
;; 	mov	(a1),d0				# unconditional purge
;;
;; 	add	L1_CACHE_BYTES,a1
;; 	add	-1,d1
;; 	bne	gdbstub_purge_cache__dcache_loop

	#######################################################################
	# now invalidate the icache
	mov	CHCTR,a0
	movhu	(a0),a1

	mov	epsw,d1
	and	~EPSW_IE,epsw
	nop
	nop

	# disable the icache
	and	~CHCTR_ICEN,d0
	movhu	d0,(a0)

	# and wait for it to calm down
	setlb
	movhu	(a0),d0
	btst	CHCTR_ICBUSY,d0
	lne

	# invalidate
	or	CHCTR_ICINV,d0
	movhu	d0,(a0)

	# wait for the cache to finish
	mov	CHCTR,a0
	setlb
	movhu	(a0),d0
	btst	CHCTR_ICBUSY,d0
	lne

	# and reenable it
	movhu	a1,(a0)
	movhu	(a0),d0			# read back to flush
					# (SIGILLs all over without this)

	mov	d1,epsw

	ret	[],0

	.size	gdbstub_purge_cache,.-gdbstub_purge_cache
CE)) return -EPERM; err = security_task_setioprio(task, ioprio); if (err) return err; task_lock(task); do { ioc = task->io_context; /* see wmb() in current_io_context() */ smp_read_barrier_depends(); if (ioc) break; ioc = alloc_io_context(GFP_ATOMIC, -1); if (!ioc) { err = -ENOMEM; break; } task->io_context = ioc; } while (1); if (!err) { ioc->ioprio = ioprio; ioc->ioprio_changed = 1; } task_unlock(task); return err; } asmlinkage long sys_ioprio_set(int which, int who, int ioprio) { int class = IOPRIO_PRIO_CLASS(ioprio); int data = IOPRIO_PRIO_DATA(ioprio); struct task_struct *p, *g; struct user_struct *user; struct pid *pgrp; int ret; switch (class) { case IOPRIO_CLASS_RT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; /* fall through, rt has prio field too */ case IOPRIO_CLASS_BE: if (data >= IOPRIO_BE_NR || data < 0) return -EINVAL; break; case IOPRIO_CLASS_IDLE: break; case IOPRIO_CLASS_NONE: if (data) return -EINVAL; break; default: return -EINVAL; } ret = -ESRCH; /* * We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic", * so we can't use rcu_read_lock(). See re-copy of ->ioprio * in copy_process(). */ read_lock(&tasklist_lock); switch (which) { case IOPRIO_WHO_PROCESS: if (!who) p = current; else p = find_task_by_vpid(who); if (p) ret = set_task_ioprio(p, ioprio); break; case IOPRIO_WHO_PGRP: if (!who) pgrp = task_pgrp(current); else pgrp = find_vpid(who); do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { ret = set_task_ioprio(p, ioprio); if (ret) break; } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); break; case IOPRIO_WHO_USER: if (!who) user = current->user; else user = find_user(who); if (!user) break; do_each_thread(g, p) { if (p->uid != who) continue; ret = set_task_ioprio(p, ioprio); if (ret) goto free_uid; } while_each_thread(g, p); free_uid: if (who) free_uid(user); break; default: ret = -EINVAL; } read_unlock(&tasklist_lock); return ret; } static int get_task_ioprio(struct task_struct *p) { int ret; ret = security_task_getioprio(p); if (ret) goto out; ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); if (p->io_context) ret = p->io_context->ioprio; out: return ret; } int ioprio_best(unsigned short aprio, unsigned short bprio) { unsigned short aclass = IOPRIO_PRIO_CLASS(aprio); unsigned short bclass = IOPRIO_PRIO_CLASS(bprio); if (aclass == IOPRIO_CLASS_NONE) aclass = IOPRIO_CLASS_BE; if (bclass == IOPRIO_CLASS_NONE) bclass = IOPRIO_CLASS_BE; if (aclass == bclass) return min(aprio, bprio); if (aclass > bclass) return bprio; else return aprio; } asmlinkage long sys_ioprio_get(int which, int who) { struct task_struct *g, *p; struct user_struct *user; struct pid *pgrp; int ret = -ESRCH; int tmpio; read_lock(&tasklist_lock); switch (which) { case IOPRIO_WHO_PROCESS: if (!who) p = current; else p = find_task_by_vpid(who); if (p) ret = get_task_ioprio(p); break; case IOPRIO_WHO_PGRP: if (!who) pgrp = task_pgrp(current); else pgrp = find_vpid(who); do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { tmpio = get_task_ioprio(p); if (tmpio < 0) continue; if (ret == -ESRCH) ret = tmpio; else ret = ioprio_best(ret, tmpio); } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); break; case IOPRIO_WHO_USER: if (!who) user = current->user; else user = find_user(who); if (!user) break; do_each_thread(g, p) { if (p->uid != user->uid) continue; tmpio = get_task_ioprio(p); if (tmpio < 0) continue; if (ret == -ESRCH) ret = tmpio; else ret = ioprio_best(ret, tmpio); } while_each_thread(g, p); if (who) free_uid(user); break; default: ret = -EINVAL; } read_unlock(&tasklist_lock); return ret; }