aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/way_tracker.c
blob: 9131c9658c2a09a6a809cbed00dd6db24e5964c5 (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
106
107
108
109
110
111
112
113
114
#include <litmus/way_tracker.h>
#include <asm/io.h>
#include <litmus/color.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/kgdb.h>

#include <litmus/litmus.h>
#include <litmus/color.h>

static raw_spinlock_t lock;

static unsigned long *ways;

static int peek_next_way(unsigned int color)
{
	int ret;

	BUG_ON(color > color_cache_info.nr_colors);

	ret = find_first_bit(&ways[color], sizeof(unsigned long)*8);
	if (ret == sizeof(unsigned long)*8) {
		return -1;
	} else {
		return ret;
	}
}

static int take_next_way(unsigned int color)
{
	int idx;

	raw_spin_lock(&lock);
	idx = peek_next_way(color);
	if (idx != -1) {
		clear_bit(idx, &ways[color]);
		TRACE("Took, now %lu free of color %d\n", hweight_long(ways[color]), color);
	} else {
		printk(KERN_WARNING "Vury bad\n");
		/* Seriously bad. */
#ifdef CONFIG_KGDB
		kgdb_breakpoint();
#endif
		BUG();
	}
	raw_spin_unlock(&lock);
	return idx;
}

static void release_way(unsigned int color, int way)
{
	BUG_ON(way < 0 || way > color_cache_info.ways);
	raw_spin_lock(&lock);
	__set_bit(way, &ways[color]);
	TRACE("Released, now %lu free of color %d\n", hweight_long(ways[color]), color);
	raw_spin_unlock(&lock);
}

void color_page_info_take_ways(struct task_struct *t)
{
	struct color_page_info *cur;

	list_for_each_entry(cur, &tsk_rt(t)->color_page_info_list, list) {
		cur->way = take_next_way(cur->color);
		TRACE_TASK(t, "assign color %d way %d for info %p\n",
				cur->color, cur->way, cur);
	}
}

void color_page_info_release_ways(struct task_struct *t)
{
	struct color_page_info *cur;

	list_for_each_entry(cur, &tsk_rt(t)->color_page_info_list, list) {
		release_way(cur->color, cur->way);
		TRACE_TASK(t, "release color %d way %d for info %p\n",
				cur->color, cur->way, cur);
	}
}

void reset_way_tracker(void)
{
	int color, unused;

	for (color = 0; color < color_cache_info.nr_colors; ++color) {
		unused = sizeof(unsigned long)*8 - color_cache_info.ways;
		ways[color] = ULONG_MAX >> unused;
	}

}

static int __init init_way_tracker(void)
{
	int size;

	BUG_ON(!color_cache_info.nr_colors);
	BUG_ON(color_cache_info.ways > sizeof(unsigned long)*8);

	printk(KERN_INFO "Starting way tracker\n");

	size = sizeof(unsigned long) * color_cache_info.nr_colors;
	ways = kmalloc(size, GFP_ATOMIC);

	reset_way_tracker();

	raw_spin_lock_init(&lock);

	return 0;
}

module_init(init_way_tracker);