blob: 7e2c6e5d871510033cb92c971a9a53235023b601 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurst15ce78d2014-04-10 09:02:02 +01002 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
Jon Medhurstaaf37a32013-06-11 12:10:56 +01003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/slab.h>
11#include <linux/fs.h>
12#include <linux/mm.h>
13#include <linux/sched.h>
14#include <asm/uaccess.h>
15#include <asm/current.h>
16#include <linux/spinlock.h>
17
18static DEFINE_SPINLOCK(annotate_lock);
19static bool collect_annotations = false;
20
21static int annotate_copy(struct file *file, char const __user *buf, size_t count)
22{
23 int cpu = 0;
24 int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF];
25
26 if (file == NULL) {
27 // copy from kernel
28 memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count);
29 } else {
30 // copy from user space
31 if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0)
32 return -1;
33 }
34 per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF] = (write + count) & gator_buffer_mask[ANNOTATE_BUF];
35
36 return 0;
37}
38
39static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count_orig, loff_t *offset)
40{
41 int pid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff;
Jon Medhurstd3698592013-10-10 16:48:56 +010042 bool interrupt_context;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010043
44 if (*offset) {
45 return -EINVAL;
46 }
47
Jon Medhurstd3698592013-10-10 16:48:56 +010048 interrupt_context = in_interrupt();
49 // Annotations are not supported in interrupt context, but may work if you comment out the the next four lines of code.
50 // By doing so, annotations in interrupt context can result in deadlocks and lost data.
51 if (interrupt_context) {
52 printk(KERN_WARNING "gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n");
Jon Medhurstaaf37a32013-06-11 12:10:56 +010053 return -EINVAL;
54 }
55
56 retry:
57 // synchronize between cores and with collect_annotations
58 spin_lock(&annotate_lock);
59
60 if (!collect_annotations) {
61 // Not collecting annotations, tell the caller everything was written
62 size = count_orig;
63 goto annotate_write_out;
64 }
65
66 // Annotation only uses a single per-cpu buffer as the data must be in order to the engine
67 cpu = 0;
68
69 if (current == NULL) {
70 pid = 0;
71 } else {
72 pid = current->pid;
73 }
74
75 // determine total size of the payload
76 header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64;
77 available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size;
78 size = count < available ? count : available;
79
80 if (size <= 0) {
81 // Buffer is full, wait until space is available
82 spin_unlock(&annotate_lock);
Jon Medhurstd3698592013-10-10 16:48:56 +010083
84 // Drop the annotation as blocking is not allowed in interrupt context
85 if (interrupt_context) {
86 return -EINVAL;
87 }
88
Jon Medhurstaaf37a32013-06-11 12:10:56 +010089 wait_event_interruptible(gator_annotate_wait, buffer_bytes_available(cpu, ANNOTATE_BUF) > header_size || !collect_annotations);
Jon Medhurstd3698592013-10-10 16:48:56 +010090
91 // Check to see if a signal is pending
92 if (signal_pending(current)) {
93 return -EINTR;
94 }
95
Jon Medhurstaaf37a32013-06-11 12:10:56 +010096 goto retry;
97 }
98
99 // synchronize shared variables annotateBuf and annotatePos
100 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) {
101 u64 time = gator_get_time();
102 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
103 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
104 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, time);
105 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size);
106
107 // determine the sizes to capture, length1 + length2 will equal size
108 contiguous = contiguous_space_available(cpu, ANNOTATE_BUF);
109 if (size < contiguous) {
110 length1 = size;
111 length2 = 0;
112 } else {
113 length1 = contiguous;
114 length2 = size - contiguous;
115 }
116
117 if (annotate_copy(file, buf, length1) != 0) {
118 size = -EINVAL;
119 goto annotate_write_out;
120 }
121
122 if (length2 > 0 && annotate_copy(file, &buf[length1], length2) != 0) {
123 size = -EINVAL;
124 goto annotate_write_out;
125 }
126
127 // Check and commit; commit is set to occur once buffer is 3/4 full
128 buffer_check(cpu, ANNOTATE_BUF, time);
129 }
130
131annotate_write_out:
132 spin_unlock(&annotate_lock);
133
134 // return the number of bytes written
135 return size;
136}
137
138#include "gator_annotate_kernel.c"
139
140static int annotate_release(struct inode *inode, struct file *file)
141{
142 int cpu = 0;
143
144 // synchronize between cores
145 spin_lock(&annotate_lock);
146
147 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
148 uint32_t pid = current->pid;
149 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
150 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
151 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
152 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
153 }
154
155 // Check and commit; commit is set to occur once buffer is 3/4 full
156 buffer_check(cpu, ANNOTATE_BUF, gator_get_time());
157
158 spin_unlock(&annotate_lock);
159
160 return 0;
161}
162
163static const struct file_operations annotate_fops = {
164 .write = annotate_write,
165 .release = annotate_release
166};
167
168static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
169{
170 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
171}
172
173static int gator_annotate_start(void)
174{
175 collect_annotations = true;
176 return 0;
177}
178
179static void gator_annotate_stop(void)
180{
181 // the spinlock here will ensure that when this function exits, we are not in the middle of an annotation
182 spin_lock(&annotate_lock);
183 collect_annotations = false;
184 wake_up(&gator_annotate_wait);
185 spin_unlock(&annotate_lock);
186}