2 * drivers/misc/tegra-profiler/mmap.c
4 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 #include <linux/module.h>
21 #include <linux/crc32.h>
23 #include <linux/slab.h>
24 #include <linux/err.h>
26 #include <linux/tegra_profiler.h>
32 static struct quadd_mmap_ctx mmap_ctx;
34 static int binary_search_and_add(unsigned int *array,
35 unsigned int length, unsigned int key)
37 unsigned int i_min, i_max, mid;
42 } else if (length == 1 && array[0] == key) {
50 memmove((char *)((unsigned int *)array + 1), array,
51 length * sizeof(unsigned int));
54 } else if (array[length - 1] < key) {
59 while (i_min < i_max) {
60 mid = i_min + (i_max - i_min) / 2;
62 if (key <= array[mid])
68 if (array[i_max] == key) {
71 memmove((char *)((unsigned int *)array + i_max + 1),
72 (char *)((unsigned int *)array + i_max),
73 (length - i_max) * sizeof(unsigned int));
79 static int check_hash(u32 key)
84 spin_lock_irqsave(&mmap_ctx.lock, flags);
86 if (mmap_ctx.nr_hashes >= QUADD_MMAP_SIZE_ARRAY) {
87 spin_unlock_irqrestore(&mmap_ctx.lock, flags);
91 res = binary_search_and_add(mmap_ctx.hash_array,
92 mmap_ctx.nr_hashes, key);
95 spin_unlock_irqrestore(&mmap_ctx.lock, flags);
99 spin_unlock_irqrestore(&mmap_ctx.lock, flags);
103 char *quadd_get_mmap(struct quadd_cpu_context *cpu_ctx,
104 struct pt_regs *regs, struct quadd_mmap_data *sample,
105 unsigned int *extra_length)
109 int length, length_aligned;
110 struct mm_struct *mm = current->mm;
111 struct vm_area_struct *vma;
112 struct file *vm_file;
114 char *file_name = NULL;
115 struct quadd_mmap_cpu_ctx *mm_cpu_ctx = this_cpu_ptr(mmap_ctx.cpu_ctx);
116 char *tmp_buf = mm_cpu_ctx->tmp_buf;
123 ip = instruction_pointer(regs);
125 if (user_mode(regs)) {
126 for (vma = find_vma(mm, ip); vma; vma = vma->vm_next) {
127 if (ip < vma->vm_start || ip >= vma->vm_end)
130 vm_file = vma->vm_file;
134 path = &vm_file->f_path;
136 file_name = d_path(path, tmp_buf, PATH_MAX);
137 if (IS_ERR(file_name)) {
140 sample->addr = vma->vm_start;
141 sample->len = vma->vm_end - vma->vm_start;
143 (u64)vma->vm_pgoff << PAGE_SHIFT;
151 mod = __module_address(ip);
155 file_name = mod->name;
157 sample->addr = (u32) mod->module_core;
158 sample->len = mod->core_size;
165 length = strlen(file_name);
166 if (length >= PATH_MAX) {
171 crc = crc32_le(~0, file_name, length);
172 crc = crc32_le(crc, (unsigned char *)&sample->addr,
173 sizeof(sample->addr));
174 crc = crc32_le(crc, (unsigned char *)&sample->len,
175 sizeof(sample->len));
177 if (!check_hash(crc)) {
178 strcpy(cpu_ctx->mmap_filename, file_name);
179 length_aligned = (length + 1 + 7) & (~7);
180 *extra_length = length_aligned;
182 return cpu_ctx->mmap_filename;
190 struct quadd_mmap_ctx *quadd_mmap_init(struct quadd_ctx *quadd_ctx)
195 struct quadd_mmap_cpu_ctx *cpu_ctx;
197 mmap_ctx.quadd_ctx = quadd_ctx;
199 hash = kzalloc(QUADD_MMAP_SIZE_ARRAY * sizeof(unsigned int),
202 pr_err("Failed to allocate mmap buffer\n");
203 return ERR_PTR(-ENOMEM);
205 mmap_ctx.hash_array = hash;
207 mmap_ctx.nr_hashes = 0;
208 spin_lock_init(&mmap_ctx.lock);
210 mmap_ctx.cpu_ctx = alloc_percpu(struct quadd_mmap_cpu_ctx);
211 if (!mmap_ctx.cpu_ctx)
212 return ERR_PTR(-ENOMEM);
214 for (cpu_id = 0; cpu_id < nr_cpu_ids; cpu_id++) {
215 cpu_ctx = per_cpu_ptr(mmap_ctx.cpu_ctx, cpu_id);
217 tmp = kzalloc(PATH_MAX + sizeof(unsigned long long),
220 pr_err("Failed to allocate mmap buffer\n");
221 return ERR_PTR(-ENOMEM);
223 cpu_ctx->tmp_buf = tmp;
229 void quadd_mmap_reset(void)
233 spin_lock_irqsave(&mmap_ctx.lock, flags);
234 mmap_ctx.nr_hashes = 0;
235 spin_unlock_irqrestore(&mmap_ctx.lock, flags);
238 void quadd_mmap_deinit(void)
242 struct quadd_mmap_cpu_ctx *cpu_ctx;
244 spin_lock_irqsave(&mmap_ctx.lock, flags);
245 kfree(mmap_ctx.hash_array);
246 mmap_ctx.hash_array = NULL;
248 for (cpu_id = 0; cpu_id < nr_cpu_ids; cpu_id++) {
249 cpu_ctx = per_cpu_ptr(mmap_ctx.cpu_ctx, cpu_id);
250 kfree(cpu_ctx->tmp_buf);
252 free_percpu(mmap_ctx.cpu_ctx);
254 spin_unlock_irqrestore(&mmap_ctx.lock, flags);