diff options
author | Igor Nabirushkin <inabirushkin@nvidia.com> | 2014-10-20 00:22:32 +0400 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2015-01-29 22:02:49 -0800 |
commit | cd2cd13dc3161d4b3362c2a94dc2442d7e1631fa (patch) | |
tree | 16b28b80500b2d832df652b79cb18f79f2222722 | |
parent | d075eb663ba4bd87b64cfba88a79c01c92049619 (diff) |
misc: tegra-profiler: use mmap for samples
Tegra Profiler: send samples via memory mapping areas
to the user space.
Bug 1566270
Bug 1598009
Change-Id: I19aae4ca1f8d6a3ae7c36e99fb018d8fcd2152d3
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/559124
(cherry picked from commit 1a53b2fc3f15aeed1eee0f9aa6e259ae476acb82)
Reviewed-on: http://git-master/r/672026
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
-rw-r--r-- | drivers/misc/tegra-profiler/comm.c | 712 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/comm.h | 59 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/dwarf_unwind.c | 2 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/eh_unwind.c | 17 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/eh_unwind.h | 10 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/hrt.c | 46 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/hrt.h | 6 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/ma.c | 5 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/main.c | 5 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/power_clk.c | 5 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/quadd_proc.c | 4 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/version.h | 2 | ||||
-rw-r--r-- | include/linux/tegra_profiler.h | 53 |
13 files changed, 431 insertions, 495 deletions
diff --git a/drivers/misc/tegra-profiler/comm.c b/drivers/misc/tegra-profiler/comm.c index 793a19ce3602..8f42289d7bd7 100644 --- a/drivers/misc/tegra-profiler/comm.c +++ b/drivers/misc/tegra-profiler/comm.c @@ -33,400 +33,211 @@ #include "comm.h" #include "version.h" -#define QUADD_DATA_BUFF_SIZE (PAGE_SIZE * 8) +struct quadd_ring_buffer { + struct quadd_ring_buffer_hdr *rb_hdr; + char *buf; -struct quadd_comm_ctx comm_ctx; + size_t max_fill_count; + size_t nr_skipped_samples; -static inline void *rb_alloc(unsigned long size) -{ - return vmalloc(size); -} + struct quadd_mmap_area *mmap; -static inline void rb_free(void *addr) -{ - vfree(addr); -} + spinlock_t lock; +}; -static void rb_reset(struct quadd_ring_buffer *rb) -{ - rb->pos_read = 0; - rb->pos_write = 0; - rb->fill_count = 0; - rb->max_fill_count = 0; -} +struct quadd_comm_ctx { + struct quadd_comm_control_interface *control; -static int rb_init(struct quadd_ring_buffer *rb, size_t size) -{ - spin_lock_init(&rb->lock); + atomic_t active; - rb->size = size; - rb->buf = NULL; + struct mutex io_mutex; + int nr_users; - rb->buf = (char *) rb_alloc(rb->size); - if (!rb->buf) { - pr_err("Ring buffer alloc error\n"); - return -ENOMEM; - } - pr_info("rb: data buffer size: %u\n", (unsigned int)rb->size); + int params_ok; + pid_t process_pid; + uid_t debug_app_uid; - rb_reset(rb); + wait_queue_head_t read_wait; - return 0; -} + struct miscdevice *misc_dev; -static void rb_deinit(struct quadd_ring_buffer *rb) -{ - unsigned long flags; + struct list_head mmap_areas; + spinlock_t mmaps_lock; +}; - spin_lock_irqsave(&rb->lock, flags); - if (rb->buf) { - rb_reset(rb); +struct comm_cpu_context { + struct quadd_ring_buffer rb; +}; - rb_free(rb->buf); - rb->buf = NULL; - } - spin_unlock_irqrestore(&rb->lock, flags); -} +static struct quadd_comm_ctx comm_ctx; +static DEFINE_PER_CPU(struct comm_cpu_context, cpu_ctx); -static __attribute__((unused)) int rb_is_full(struct quadd_ring_buffer *rb) +static int __maybe_unused +rb_is_full(struct quadd_ring_buffer *rb) { - return rb->fill_count == rb->size; + struct quadd_ring_buffer_hdr *rb_hdr = rb->rb_hdr; + return (rb_hdr->pos_write + 1) % rb_hdr->size == rb_hdr->pos_read; } -static int rb_is_empty(struct quadd_ring_buffer *rb) +static int __maybe_unused +rb_is_empty(struct quadd_ring_buffer *rb) { - return rb->fill_count == 0; -} - -static int rb_is_empty_lock(struct quadd_ring_buffer *rb) -{ - int res; - unsigned long flags; - - spin_lock_irqsave(&rb->lock, flags); - res = rb->fill_count == 0; - spin_unlock_irqrestore(&rb->lock, flags); - - return res; + struct quadd_ring_buffer_hdr *rb_hdr = rb->rb_hdr; + return rb_hdr->pos_read == rb_hdr->pos_write; } static size_t -rb_get_free_space(struct quadd_ring_buffer *rb) +rb_get_filled_space(struct quadd_ring_buffer_hdr *rb_hdr) { - return rb->size - rb->fill_count; + return (rb_hdr->pos_write >= rb_hdr->pos_read) ? + rb_hdr->pos_write - rb_hdr->pos_read : + rb_hdr->pos_write + rb_hdr->size - rb_hdr->pos_read; } static size_t -rb_write(struct quadd_ring_buffer *rb, char *data, size_t length) +rb_get_free_space(struct quadd_ring_buffer_hdr *rb_hdr) { - size_t new_pos_write, chunk1; - - if (length > rb_get_free_space(rb)) - return 0; - - new_pos_write = (rb->pos_write + length) % rb->size; - - if (new_pos_write < rb->pos_write) { - chunk1 = rb->size - rb->pos_write; - memcpy(rb->buf + rb->pos_write, data, chunk1); - if (new_pos_write > 0) - memcpy(rb->buf, data + chunk1, new_pos_write); - } else { - memcpy(rb->buf + rb->pos_write, data, length); - } - - rb->pos_write = new_pos_write; - rb->fill_count += length; - - return length; + return rb_hdr->size - rb_get_filled_space(rb_hdr) - 1; } static ssize_t -rb_read_undo(struct quadd_ring_buffer *rb, size_t length) +rb_write(struct quadd_ring_buffer_hdr *rb_hdr, + char *mmap_buf, void *data, size_t length) { - if (rb_get_free_space(rb) < length) - return -EIO; - - if (rb->pos_read > length) - rb->pos_read -= length; - else - rb->pos_read += rb->size - length; - - rb->fill_count += length; - return length; -} - -static ssize_t -rb_read(struct quadd_ring_buffer *rb, char *data, size_t length) -{ - size_t new_pos_read, chunk1; - - if (length > rb->fill_count) - return 0; - - new_pos_read = (rb->pos_read + length) % rb->size; - - if (new_pos_read < rb->pos_read) { - chunk1 = rb->size - rb->pos_read; - memcpy(data, rb->buf + rb->pos_read, chunk1); - if (new_pos_read > 0) - memcpy(data + chunk1, rb->buf, new_pos_read); - } else { - memcpy(data, rb->buf + rb->pos_read, length); - } - - rb->pos_read = new_pos_read; - rb->fill_count -= length; - - return length; -} - -static ssize_t __maybe_unused -rb_read_user(struct quadd_ring_buffer *rb, char __user *data, size_t length) -{ - size_t new_pos_read, chunk1; + size_t new_pos_write, chunk1; - if (length > rb->fill_count) - return 0; + new_pos_write = (rb_hdr->pos_write + length) % rb_hdr->size; - new_pos_read = (rb->pos_read + length) % rb->size; + if (new_pos_write < rb_hdr->pos_write) { + chunk1 = rb_hdr->size - rb_hdr->pos_write; - if (new_pos_read < rb->pos_read) { - chunk1 = rb->size - rb->pos_read; - if (copy_to_user(data, rb->buf + rb->pos_read, chunk1)) - return -EFAULT; + memcpy(mmap_buf + rb_hdr->pos_write, data, chunk1); - if (new_pos_read > 0) { - if (copy_to_user(data + chunk1, rb->buf, - new_pos_read)) - return -EFAULT; - } + if (new_pos_write > 0) + memcpy(mmap_buf, data + chunk1, new_pos_write); } else { - if (copy_to_user(data, rb->buf + rb->pos_read, length)) - return -EFAULT; + memcpy(mmap_buf + rb_hdr->pos_write, data, length); } - rb->pos_read = new_pos_read; - rb->fill_count -= length; - + rb_hdr->pos_write = new_pos_write; return length; } -static void -write_sample(struct quadd_record_data *sample, +static ssize_t +write_sample(struct quadd_ring_buffer *rb, + struct quadd_record_data *sample, struct quadd_iovec *vec, int vec_count) { int i; - unsigned long flags; - struct quadd_ring_buffer *rb = &comm_ctx.rb; - size_t length_sample; + ssize_t err; + size_t length_sample, fill_count; + struct quadd_ring_buffer_hdr *rb_hdr = rb->rb_hdr, new_hdr; + + if (!rb_hdr) + return -EIO; - length_sample = sizeof(struct quadd_record_data); + length_sample = sizeof(*sample); for (i = 0; i < vec_count; i++) length_sample += vec[i].len; - spin_lock_irqsave(&rb->lock, flags); - - if (length_sample > rb_get_free_space(rb)) { - pr_err_once("Error: Buffer has been overflowed\n"); - spin_unlock_irqrestore(&rb->lock, flags); - return; + new_hdr.size = rb_hdr->size; + new_hdr.pos_write = rb_hdr->pos_write; + new_hdr.pos_read = rb_hdr->pos_read; + + pr_debug("[cpu: %d] type/len: %u/%#zx, read/write pos: %#x/%#x, free: %#zx\n", + smp_processor_id(), + sample->record_type, + length_sample, + new_hdr.pos_read, new_hdr.pos_write, + rb_get_free_space(&new_hdr)); + + if (length_sample > rb_get_free_space(&new_hdr)) { + pr_err_once("[cpu: %d] warning: buffer has been overflowed\n", + smp_processor_id()); + return -ENOSPC; } - if (!rb_write(rb, (char *)sample, sizeof(struct quadd_record_data))) { - spin_unlock_irqrestore(&rb->lock, flags); - return; - } + err = rb_write(&new_hdr, rb->buf, sample, sizeof(*sample)); + if (err < 0) + return err; for (i = 0; i < vec_count; i++) { - if (!rb_write(rb, vec[i].base, vec[i].len)) { - spin_unlock_irqrestore(&rb->lock, flags); - pr_err_once("%s: error: ring buffer\n", __func__); - return; - } + err = rb_write(&new_hdr, rb->buf, vec[i].base, vec[i].len); + if (err < 0) + return err; } - if (rb->fill_count > rb->max_fill_count) - rb->max_fill_count = rb->fill_count; + fill_count = rb_get_filled_space(&new_hdr); + if (fill_count > rb->max_fill_count) { + rb->max_fill_count = fill_count; + rb_hdr->max_fill_count = fill_count; + } - spin_unlock_irqrestore(&rb->lock, flags); + rb_hdr->pos_write = new_hdr.pos_write; + wake_up_all(&comm_ctx.read_wait); - wake_up_interruptible(&comm_ctx.read_wait); + return length_sample; } -static ssize_t read_sample(char *buffer, size_t max_length) +static size_t get_data_size(void) { - u32 sed; - unsigned int type; - int retval = -EIO, ip_size, bt_size; - int was_read = 0, write_offset = 0; - unsigned long flags; - struct quadd_ring_buffer *rb = &comm_ctx.rb; - struct quadd_record_data record; - size_t length_extra = 0, nr_events; - struct quadd_sample_data *sample; - - spin_lock_irqsave(&rb->lock, flags); - - if (rb_is_empty(rb)) { - retval = 0; - goto out; - } - - if (rb->fill_count < sizeof(record)) - goto out; + int cpu_id; + size_t size = 0; + struct comm_cpu_context *cc; + struct quadd_ring_buffer *rb; - retval = rb_read(rb, (char *)&record, sizeof(record)); - if (retval <= 0) - goto out; - - was_read += sizeof(record); - - type = record.record_type; - - switch (type) { - case QUADD_RECORD_TYPE_SAMPLE: - sample = &record.sample; - - if (rb->fill_count < sizeof(sed)) - goto out; - - retval = rb_read(rb, (char *)&sed, sizeof(sed)); - if (retval <= 0) - goto out; - - was_read += sizeof(sed); - - ip_size = (sed & QUADD_SED_IP64) ? - sizeof(u64) : sizeof(u32); + for_each_possible_cpu(cpu_id) { + cc = &per_cpu(cpu_ctx, cpu_id); - bt_size = sample->callchain_nr; + rb = &cc->rb; + if (!rb->rb_hdr) + continue; - length_extra = bt_size * ip_size; - - if (bt_size > 0) - length_extra += DIV_ROUND_UP(bt_size, 8) * sizeof(u32); - - nr_events = __sw_hweight32(sample->events_flags); - length_extra += nr_events * sizeof(u32); - - length_extra += sample->state ? sizeof(u32) : 0; - break; - - case QUADD_RECORD_TYPE_MMAP: - length_extra = sizeof(u64) * 2; - - if (record.mmap.filename_length > 0) { - length_extra += record.mmap.filename_length; - } else { - pr_err("Error: filename is empty\n"); - goto out; - } - break; - - case QUADD_RECORD_TYPE_HEADER: - length_extra = record.hdr.nr_events * sizeof(u32); - break; - - case QUADD_RECORD_TYPE_DEBUG: - length_extra = record.debug.extra_length; - break; - - case QUADD_RECORD_TYPE_MA: - length_extra = 0; - break; - - case QUADD_RECORD_TYPE_POWER_RATE: - length_extra = record.power_rate.nr_cpus * sizeof(u32); - break; - - case QUADD_RECORD_TYPE_ADDITIONAL_SAMPLE: - length_extra = record.additional_sample.extra_length; - break; - - case QUADD_RECORD_TYPE_SCHED: - length_extra = 0; - break; - - default: - goto out; + size += rb_get_filled_space(rb->rb_hdr); } - if (was_read + length_extra > max_length) { - retval = rb_read_undo(rb, was_read); - if (retval < 0) - goto out; + return size; +} - retval = 0; - goto out; - } +static ssize_t +put_sample(struct quadd_record_data *data, + struct quadd_iovec *vec, + int vec_count, int cpu_id) +{ + ssize_t err = 0; + unsigned long flags; + struct comm_cpu_context *cc; + struct quadd_ring_buffer *rb; + struct quadd_ring_buffer_hdr *rb_hdr; - if (length_extra > rb->fill_count) - goto out; + if (!atomic_read(&comm_ctx.active)) + return -EIO; - memcpy(buffer, &record, sizeof(record)); + cc = cpu_id < 0 ? &__get_cpu_var(cpu_ctx) : + &per_cpu(cpu_ctx, cpu_id); - write_offset += sizeof(record); + rb = &cc->rb; - if (type == QUADD_RECORD_TYPE_SAMPLE) { - memcpy(buffer + write_offset, &sed, sizeof(sed)); - write_offset += sizeof(sed); - } + spin_lock_irqsave(&rb->lock, flags); - if (length_extra > 0) { - retval = rb_read(rb, buffer + write_offset, - length_extra); - if (retval <= 0) - goto out; + err = write_sample(rb, data, vec, vec_count); + if (err < 0) { + pr_err_once("%s: error: write sample\n", __func__); + rb->nr_skipped_samples++; - write_offset += length_extra; + rb_hdr = rb->rb_hdr; + if (rb_hdr) + rb_hdr->skipped_samples++; } spin_unlock_irqrestore(&rb->lock, flags); - return write_offset; - -out: - spin_unlock_irqrestore(&rb->lock, flags); - return retval; -} - -static ssize_t -__read_sample(char __user *buffer, size_t max_length) -{ - ssize_t retval; - char *tmp_buf = comm_ctx.tmp_buf; - - max_length = min_t(size_t, max_length, QUADD_DATA_BUFF_SIZE); - - retval = read_sample(tmp_buf, max_length); - if (retval <= 0) - return retval; - - if (copy_to_user(buffer, tmp_buf, retval)) { - pr_err("%s: error: copy_to_user\n", __func__); - return -EFAULT; - } - - return retval; -} -static void put_sample(struct quadd_record_data *data, - struct quadd_iovec *vec, int vec_count) -{ - if (!atomic_read(&comm_ctx.active)) - return; - - write_sample(data, vec, vec_count); + return err; } static void comm_reset(void) { - unsigned long flags; - pr_debug("Comm reset\n"); - spin_lock_irqsave(&comm_ctx.rb.lock, flags); - rb_reset(&comm_ctx.rb); - spin_unlock_irqrestore(&comm_ctx.rb.lock, flags); } static int is_active(void) @@ -465,12 +276,12 @@ static int check_access_permission(void) return 0; } -static struct quadd_extabs_mmap * +static struct quadd_mmap_area * find_mmap(unsigned long vm_start) { - struct quadd_extabs_mmap *entry; + struct quadd_mmap_area *entry; - list_for_each_entry(entry, &comm_ctx.ext_mmaps, list) { + list_for_each_entry(entry, &comm_ctx.mmap_areas, list) { struct vm_area_struct *mmap_vma = entry->mmap_vma; if (vm_start == mmap_vma->vm_start) return entry; @@ -507,11 +318,10 @@ static unsigned int device_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - struct quadd_ring_buffer *rb = &comm_ctx.rb; poll_wait(file, &comm_ctx.read_wait, wait); - if (!rb_is_empty_lock(rb)) + if (get_data_size() > 0) mask |= POLLIN | POLLRDNORM; if (!atomic_read(&comm_ctx.active)) @@ -520,51 +330,108 @@ device_poll(struct file *file, poll_table *wait) return mask; } -static ssize_t -device_read(struct file *filp, - char __user *buffer, - size_t length, - loff_t *offset) +static int +init_mmap_hdr(struct quadd_mmap_rb_info *mmap_rb, + struct quadd_mmap_area *mmap) { - int err; - ssize_t res; - size_t samples_counter = 0; - size_t was_read = 0, min_size; + int cpu_id; + size_t size; + unsigned long flags; + struct vm_area_struct *vma; + struct quadd_ring_buffer *rb; + struct quadd_ring_buffer_hdr *rb_hdr; + struct quadd_mmap_header *mmap_hdr; + struct comm_cpu_context *cc; - err = check_access_permission(); - if (err) - return err; + if (mmap->type != QUADD_MMAP_TYPE_RB) + return -EIO; - mutex_lock(&comm_ctx.io_mutex); + cpu_id = mmap_rb->cpu_id; + cc = &per_cpu(cpu_ctx, cpu_id); - if (!atomic_read(&comm_ctx.active)) { - mutex_unlock(&comm_ctx.io_mutex); - return -EPIPE; - } + rb = &cc->rb; + + spin_lock_irqsave(&rb->lock, flags); - min_size = sizeof(struct quadd_record_data) + sizeof(u32); + mmap->rb = rb; - while (was_read + min_size < length) { - res = __read_sample(buffer + was_read, length - was_read); - if (res < 0) { - mutex_unlock(&comm_ctx.io_mutex); - pr_err("%s: error: data is corrupted (%zd)\n", - __func__, res); - return res; - } + rb->mmap = mmap; - if (res == 0) - break; + rb->max_fill_count = 0; + rb->nr_skipped_samples = 0; - was_read += res; - samples_counter++; + vma = mmap->mmap_vma; - if (!atomic_read(&comm_ctx.active)) - break; + size = vma->vm_end - vma->vm_start; + size -= sizeof(*mmap_hdr) + sizeof(*rb_hdr); + + mmap_hdr = mmap->data; + + mmap_hdr->magic = QUADD_MMAP_HEADER_MAGIC; + mmap_hdr->version = QUADD_MMAP_HEADER_VERSION; + mmap_hdr->cpu_id = cpu_id; + + rb_hdr = (struct quadd_ring_buffer_hdr *)(mmap_hdr + 1); + rb->rb_hdr = rb_hdr; + + rb_hdr->size = size; + rb_hdr->pos_read = 0; + rb_hdr->pos_write = 0; + + rb_hdr->max_fill_count = 0; + rb_hdr->skipped_samples = 0; + + rb->buf = (char *)(rb_hdr + 1); + + rb_hdr->state = QUADD_RB_STATE_ACTIVE; + + spin_unlock_irqrestore(&rb->lock, flags); + + pr_info("[cpu: %d] init_mmap_hdr: vma: %#lx - %#lx, data: %p - %p\n", + cpu_id, + vma->vm_start, vma->vm_end, + mmap->data, mmap->data + vma->vm_end - vma->vm_start); + + return 0; +} + +static void rb_stop(void) +{ + int cpu_id; + struct quadd_ring_buffer *rb; + struct quadd_ring_buffer_hdr *rb_hdr; + struct comm_cpu_context *cc; + + for_each_possible_cpu(cpu_id) { + cc = &per_cpu(cpu_ctx, cpu_id); + + rb = &cc->rb; + rb_hdr = rb->rb_hdr; + + if (!rb_hdr) + continue; + + pr_info("[%d] skipped samples/max filling: %zu/%zu\n", + cpu_id, rb->nr_skipped_samples, rb->max_fill_count); + + rb_hdr->state = QUADD_RB_STATE_STOPPED; } +} - mutex_unlock(&comm_ctx.io_mutex); - return was_read; +static void rb_reset(struct quadd_ring_buffer *rb) +{ + unsigned long flags; + + if (!rb) + return; + + spin_lock_irqsave(&rb->lock, flags); + + rb->mmap = NULL; + rb->buf = NULL; + rb->rb_hdr = NULL; + + spin_unlock_irqrestore(&rb->lock, flags); } static long @@ -573,15 +440,14 @@ device_ioctl(struct file *file, unsigned long ioctl_param) { int err = 0; - unsigned long flags; u64 *mmap_vm_start; - struct quadd_extabs_mmap *mmap; + struct quadd_mmap_area *mmap; struct quadd_parameters *user_params; struct quadd_comm_cap cap; struct quadd_module_state state; struct quadd_module_version versions; struct quadd_extables extabs; - struct quadd_ring_buffer *rb = &comm_ctx.rb; + struct quadd_mmap_rb_info mmap_rb; if (ioctl_num != IOCTL_SETUP && ioctl_num != IOCTL_GET_CAP && @@ -632,7 +498,6 @@ device_ioctl(struct file *file, err = -EINVAL; goto error_out; } - comm_ctx.rb_size = user_params->reserved[0]; pr_info("setup success: freq/mafreq: %u/%u, backtrace: %d, pid: %d\n", user_params->freq, @@ -671,14 +536,9 @@ device_ioctl(struct file *file, case IOCTL_GET_STATE: comm_ctx.control->get_state(&state); - state.buffer_size = comm_ctx.rb_size; - - spin_lock_irqsave(&rb->lock, flags); - state.buffer_fill_size = - comm_ctx.rb_size - rb_get_free_space(rb); - state.reserved[QUADD_MOD_STATE_IDX_RB_MAX_FILL_COUNT] = - rb->max_fill_count; - spin_unlock_irqrestore(&rb->lock, flags); + state.buffer_size = 0; + state.buffer_fill_size = get_data_size(); + state.reserved[QUADD_MOD_STATE_IDX_RB_MAX_FILL_COUNT] = 0; if (copy_to_user((void __user *)ioctl_param, &state, sizeof(struct quadd_module_state))) { @@ -697,22 +557,6 @@ device_ioctl(struct file *file, goto error_out; } - err = rb_init(rb, comm_ctx.rb_size); - if (err) { - pr_err("error: rb_init failed\n"); - atomic_set(&comm_ctx.active, 0); - goto error_out; - } - - comm_ctx.tmp_buf = kzalloc(QUADD_DATA_BUFF_SIZE, - GFP_KERNEL); - if (!comm_ctx.tmp_buf) { - pr_err("%s: error: alloc failed\n", __func__); - atomic_set(&comm_ctx.active, 0); - err = -ENOMEM; - goto error_out; - } - err = comm_ctx.control->start(); if (err) { pr_err("error: start failed\n"); @@ -726,12 +570,8 @@ device_ioctl(struct file *file, case IOCTL_STOP: if (atomic_cmpxchg(&comm_ctx.active, 1, 0)) { comm_ctx.control->stop(); - wake_up_interruptible(&comm_ctx.read_wait); - rb_deinit(&comm_ctx.rb); - - kfree(comm_ctx.tmp_buf); - comm_ctx.tmp_buf = NULL; - + wake_up_all(&comm_ctx.read_wait); + rb_stop(); pr_info("Stop profiling success\n"); } break; @@ -756,6 +596,9 @@ device_ioctl(struct file *file, goto error_out; } + mmap->type = QUADD_MMAP_TYPE_EXTABS; + mmap->rb = NULL; + err = comm_ctx.control->set_extab(&extabs, mmap); spin_unlock(&comm_ctx.mmaps_lock); if (err) { @@ -764,6 +607,32 @@ device_ioctl(struct file *file, } break; + case IOCTL_SET_MMAP_RB: + if (copy_from_user(&mmap_rb, (void __user *)ioctl_param, + sizeof(mmap_rb))) { + pr_err("%s: error: mmap_rb failed\n", __func__); + err = -EFAULT; + goto error_out; + } + + spin_lock(&comm_ctx.mmaps_lock); + mmap = find_mmap((unsigned long)mmap_rb.vm_start); + spin_unlock(&comm_ctx.mmaps_lock); + if (!mmap) { + pr_err("%s: error: mmap is not found\n", __func__); + err = -ENXIO; + goto error_out; + } + mmap->type = QUADD_MMAP_TYPE_RB; + + err = init_mmap_hdr(&mmap_rb, mmap); + if (err) { + pr_err("%s: error: init_mmap_hdr\n", __func__); + goto error_out; + } + + break; + default: pr_err("error: ioctl %u is unsupported in this version of module\n", ioctl_num); @@ -777,11 +646,11 @@ error_out: } static void -delete_mmap(struct quadd_extabs_mmap *mmap) +delete_mmap(struct quadd_mmap_area *mmap) { - struct quadd_extabs_mmap *entry, *next; + struct quadd_mmap_area *entry, *next; - list_for_each_entry_safe(entry, next, &comm_ctx.ext_mmaps, list) { + list_for_each_entry_safe(entry, next, &comm_ctx.mmap_areas, list) { if (entry == mmap) { list_del(&entry->list); vfree(entry->data); @@ -793,14 +662,16 @@ delete_mmap(struct quadd_extabs_mmap *mmap) static void mmap_open(struct vm_area_struct *vma) { + pr_debug("%s: mmap_open: vma: %#lx - %#lx\n", + __func__, vma->vm_start, vma->vm_end); } static void mmap_close(struct vm_area_struct *vma) { - struct quadd_extabs_mmap *mmap; + struct quadd_mmap_area *mmap; - pr_debug("mmap_close: vma: %#lx - %#lx\n", - vma->vm_start, vma->vm_end); + pr_debug("%s: mmap_close: vma: %#lx - %#lx\n", + __func__, vma->vm_start, vma->vm_end); spin_lock(&comm_ctx.mmaps_lock); @@ -810,7 +681,15 @@ static void mmap_close(struct vm_area_struct *vma) goto out; } - comm_ctx.control->delete_mmap(mmap); + pr_debug("mmap_close: type: %d\n", mmap->type); + + if (mmap->type == QUADD_MMAP_TYPE_EXTABS) + comm_ctx.control->delete_mmap(mmap); + else if (mmap->type == QUADD_MMAP_TYPE_RB) + rb_reset(mmap->rb); + else + pr_err("error: mmap area is uninitialized\n"); + delete_mmap(mmap); out: @@ -820,7 +699,7 @@ out: static int mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { void *data; - struct quadd_extabs_mmap *mmap; + struct quadd_mmap_area *mmap; unsigned long offset = vmf->pgoff << PAGE_SHIFT; pr_debug("mmap_fault: vma: %#lx - %#lx, pgoff: %#lx, vaddr: %p\n", @@ -853,7 +732,7 @@ static int device_mmap(struct file *filp, struct vm_area_struct *vma) { unsigned long vma_size, nr_pages; - struct quadd_extabs_mmap *entry; + struct quadd_mmap_area *entry; pr_debug("mmap: vma: %#lx - %#lx, pgoff: %#lx\n", vma->vm_start, vma->vm_end, vma->vm_pgoff); @@ -882,8 +761,14 @@ device_mmap(struct file *filp, struct vm_area_struct *vma) return -ENOMEM; } + entry->type = QUADD_MMAP_TYPE_NONE; + + pr_debug("%s: data: %p - %p (%#lx)\n", + __func__, entry->data, entry->data + nr_pages * PAGE_SIZE, + nr_pages * PAGE_SIZE); + spin_lock(&comm_ctx.mmaps_lock); - list_add_tail(&entry->list, &comm_ctx.ext_mmaps); + list_add_tail(&entry->list, &comm_ctx.mmap_areas); spin_unlock(&comm_ctx.mmaps_lock); vma->vm_ops = &mmap_vm_ops; @@ -900,16 +785,7 @@ static void unregister(void) kfree(comm_ctx.misc_dev); } -static void free_ctx(void) -{ - rb_deinit(&comm_ctx.rb); - - kfree(comm_ctx.tmp_buf); - comm_ctx.tmp_buf = NULL; -} - static const struct file_operations qm_fops = { - .read = device_read, .poll = device_poll, .open = device_open, .release = device_release, @@ -920,7 +796,7 @@ static const struct file_operations qm_fops = { static int comm_init(void) { - int res; + int res, cpu_id; struct miscdevice *misc_dev; misc_dev = kzalloc(sizeof(*misc_dev), GFP_KERNEL); @@ -947,13 +823,26 @@ static int comm_init(void) comm_ctx.params_ok = 0; comm_ctx.process_pid = 0; comm_ctx.nr_users = 0; - comm_ctx.tmp_buf = NULL; init_waitqueue_head(&comm_ctx.read_wait); - INIT_LIST_HEAD(&comm_ctx.ext_mmaps); + INIT_LIST_HEAD(&comm_ctx.mmap_areas); spin_lock_init(&comm_ctx.mmaps_lock); + for_each_possible_cpu(cpu_id) { + struct comm_cpu_context *cc = &per_cpu(cpu_ctx, cpu_id); + struct quadd_ring_buffer *rb = &cc->rb; + + rb->mmap = NULL; + rb->buf = NULL; + rb->rb_hdr = NULL; + + rb->max_fill_count = 0; + rb->nr_skipped_samples = 0; + + spin_lock_init(&rb->lock); + } + return 0; } @@ -974,6 +863,5 @@ void quadd_comm_events_exit(void) { mutex_lock(&comm_ctx.io_mutex); unregister(); - free_ctx(); mutex_unlock(&comm_ctx.io_mutex); } diff --git a/drivers/misc/tegra-profiler/comm.h b/drivers/misc/tegra-profiler/comm.h index 0bf56e16b465..66945ab766e0 100644 --- a/drivers/misc/tegra-profiler/comm.h +++ b/drivers/misc/tegra-profiler/comm.h @@ -26,29 +26,29 @@ struct miscdevice; struct quadd_parameters; struct quadd_extables; struct quadd_unwind_ctx; - -struct quadd_ring_buffer { - char *buf; - spinlock_t lock; - - size_t size; - size_t pos_read; - size_t pos_write; - size_t fill_count; - size_t max_fill_count; -}; +struct quadd_ring_buffer; struct quadd_iovec { void *base; size_t len; }; -struct quadd_extabs_mmap { +enum { + QUADD_MMAP_TYPE_NONE = 1, + QUADD_MMAP_TYPE_EXTABS, + QUADD_MMAP_TYPE_RB, +}; + +struct quadd_mmap_area { + int type; + struct vm_area_struct *mmap_vma; void *data; struct list_head list; struct list_head ex_entries; + + struct quadd_ring_buffer *rb; }; struct quadd_comm_control_interface { @@ -58,43 +58,20 @@ struct quadd_comm_control_interface { uid_t *debug_app_uid); void (*get_capabilities)(struct quadd_comm_cap *cap); void (*get_state)(struct quadd_module_state *state); + int (*set_extab)(struct quadd_extables *extabs, - struct quadd_extabs_mmap *mmap); - void (*delete_mmap)(struct quadd_extabs_mmap *mmap); + struct quadd_mmap_area *mmap); + void (*delete_mmap)(struct quadd_mmap_area *mmap); }; struct quadd_comm_data_interface { - void (*put_sample)(struct quadd_record_data *data, - struct quadd_iovec *vec, int vec_count); + ssize_t (*put_sample)(struct quadd_record_data *data, + struct quadd_iovec *vec, + int vec_count, int cpu_id); void (*reset)(void); int (*is_active)(void); }; -struct quadd_comm_ctx { - struct quadd_comm_control_interface *control; - - struct quadd_ring_buffer rb; - size_t rb_size; - - atomic_t active; - - struct mutex io_mutex; - int nr_users; - - int params_ok; - pid_t process_pid; - uid_t debug_app_uid; - - wait_queue_head_t read_wait; - - struct miscdevice *misc_dev; - - struct list_head ext_mmaps; - spinlock_t mmaps_lock; - - char *tmp_buf; -}; - struct quadd_comm_data_interface * quadd_comm_events_init(struct quadd_comm_control_interface *control); void quadd_comm_events_exit(void); diff --git a/drivers/misc/tegra-profiler/dwarf_unwind.c b/drivers/misc/tegra-profiler/dwarf_unwind.c index c4c620e6df7e..c71e26671577 100644 --- a/drivers/misc/tegra-profiler/dwarf_unwind.c +++ b/drivers/misc/tegra-profiler/dwarf_unwind.c @@ -193,7 +193,7 @@ validate_addr(struct ex_region_info *ri, int st) { struct extab_info *ei; - struct quadd_extabs_mmap *mmap; + struct quadd_mmap_area *mmap; unsigned long start, end; mmap = ri->mmap; diff --git a/drivers/misc/tegra-profiler/eh_unwind.c b/drivers/misc/tegra-profiler/eh_unwind.c index a8f13eecb628..728ca6394f99 100644 --- a/drivers/misc/tegra-profiler/eh_unwind.c +++ b/drivers/misc/tegra-profiler/eh_unwind.c @@ -93,7 +93,7 @@ struct pin_pages_work { static struct quadd_unwind_ctx ctx; static inline int -validate_mmap_addr(struct quadd_extabs_mmap *mmap, +validate_mmap_addr(struct quadd_mmap_area *mmap, unsigned long addr, unsigned long nbytes) { struct vm_area_struct *vma = mmap->mmap_vma; @@ -135,7 +135,7 @@ validate_mmap_addr(struct quadd_extabs_mmap *mmap, }) static inline long -read_mmap_data(struct quadd_extabs_mmap *mmap, const u32 *addr, u32 *retval) +read_mmap_data(struct quadd_mmap_area *mmap, const u32 *addr, u32 *retval) { if (!validate_mmap_addr(mmap, (unsigned long)addr, sizeof(u32))) { *retval = 0; @@ -395,7 +395,7 @@ static void rd_free_rcu(struct rcu_head *rh) } int quadd_unwind_set_extab(struct quadd_extables *extabs, - struct quadd_extabs_mmap *mmap) + struct quadd_mmap_area *mmap) { int err = 0; unsigned long nr_entries, nr_added, new_size; @@ -404,6 +404,9 @@ int quadd_unwind_set_extab(struct quadd_extables *extabs, struct regions_data *rd, *rd_new; struct ex_region_info *ex_entry; + if (mmap->type != QUADD_MMAP_TYPE_EXTABS) + return -EIO; + spin_lock(&ctx.lock); rd = rcu_dereference(ctx.rd); @@ -536,7 +539,7 @@ error_out: } static int -clean_mmap(struct regions_data *rd, struct quadd_extabs_mmap *mmap, int rm_ext) +clean_mmap(struct regions_data *rd, struct quadd_mmap_area *mmap, int rm_ext) { int nr_removed = 0; struct ex_region_info *entry, *next; @@ -555,7 +558,7 @@ clean_mmap(struct regions_data *rd, struct quadd_extabs_mmap *mmap, int rm_ext) return nr_removed; } -void quadd_unwind_delete_mmap(struct quadd_extabs_mmap *mmap) +void quadd_unwind_delete_mmap(struct quadd_mmap_area *mmap) { unsigned long nr_entries, nr_removed, new_size; struct regions_data *rd, *rd_new; @@ -634,7 +637,7 @@ unwind_find_idx(struct ex_region_info *ri, u32 addr) } static unsigned long -unwind_get_byte(struct quadd_extabs_mmap *mmap, +unwind_get_byte(struct quadd_mmap_area *mmap, struct unwind_ctrl_block *ctrl, long *err) { unsigned long ret; @@ -668,7 +671,7 @@ unwind_get_byte(struct quadd_extabs_mmap *mmap, * Execute the current unwind instruction. */ static long -unwind_exec_insn(struct quadd_extabs_mmap *mmap, +unwind_exec_insn(struct quadd_mmap_area *mmap, struct unwind_ctrl_block *ctrl) { long err; diff --git a/drivers/misc/tegra-profiler/eh_unwind.h b/drivers/misc/tegra-profiler/eh_unwind.h index f386f6a71769..77fdfc92aba9 100644 --- a/drivers/misc/tegra-profiler/eh_unwind.h +++ b/drivers/misc/tegra-profiler/eh_unwind.h @@ -22,7 +22,7 @@ struct quadd_callchain; struct quadd_ctx; struct quadd_extables; struct task_struct; -struct quadd_extabs_mmap; +struct quadd_mmap_area; unsigned int quadd_aarch32_get_user_callchain_ut(struct pt_regs *regs, @@ -36,8 +36,8 @@ int quadd_unwind_start(struct task_struct *task); void quadd_unwind_stop(void); int quadd_unwind_set_extab(struct quadd_extables *extabs, - struct quadd_extabs_mmap *mmap); -void quadd_unwind_delete_mmap(struct quadd_extabs_mmap *mmap); + struct quadd_mmap_area *mmap); +void quadd_unwind_delete_mmap(struct quadd_mmap_area *mmap); int quadd_aarch32_is_ex_entry_exist(struct pt_regs *regs, @@ -49,8 +49,6 @@ quadd_unwind_set_tail_info(unsigned long vm_start, unsigned long tf_start, unsigned long tf_end); -struct quadd_extabs_mmap; - struct extab_info { unsigned long addr; unsigned long length; @@ -68,7 +66,7 @@ struct ex_region_info { unsigned long vm_end; struct extables tabs; - struct quadd_extabs_mmap *mmap; + struct quadd_mmap_area *mmap; struct list_head list; diff --git a/drivers/misc/tegra-profiler/hrt.c b/drivers/misc/tegra-profiler/hrt.c index fc12c444cbd7..e781147367c9 100644 --- a/drivers/misc/tegra-profiler/hrt.c +++ b/drivers/misc/tegra-profiler/hrt.c @@ -1,7 +1,7 @@ /* * drivers/misc/tegra-profiler/hrt.c * - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -119,8 +119,31 @@ u64 quadd_get_time(void) get_posix_clock_monotonic_time(); } +static void +put_sample_cpu(struct quadd_record_data *data, + struct quadd_iovec *vec, + int vec_count, int cpu_id) +{ + ssize_t err; + struct quadd_comm_data_interface *comm = hrt.quadd_ctx->comm; + + err = comm->put_sample(data, vec, vec_count, cpu_id); + if (err < 0) + atomic64_inc(&hrt.skipped_samples); + + atomic64_inc(&hrt.counter_samples); +} + +void +quadd_put_sample(struct quadd_record_data *data, + struct quadd_iovec *vec, int vec_count) +{ + put_sample_cpu(data, vec, vec_count, -1); +} + static void put_header(void) { + int cpu_id; int nr_events = 0, max_events = QUADD_MAX_COUNTERS; int events[QUADD_MAX_COUNTERS]; struct quadd_record_data record; @@ -175,16 +198,8 @@ static void put_header(void) vec.base = events; vec.len = nr_events * sizeof(events[0]); - quadd_put_sample(&record, &vec, 1); -} - -void quadd_put_sample(struct quadd_record_data *data, - struct quadd_iovec *vec, int vec_count) -{ - struct quadd_comm_data_interface *comm = hrt.quadd_ctx->comm; - - comm->put_sample(data, vec, vec_count); - atomic64_inc(&hrt.counter_samples); + for_each_possible_cpu(cpu_id) + put_sample_cpu(&record, &vec, 1, cpu_id); } static void @@ -590,6 +605,7 @@ int quadd_hrt_start(void) hrt.ma_period = 0; atomic64_set(&hrt.counter_samples, 0); + atomic64_set(&hrt.skipped_samples, 0); reset_cpu_ctx(); @@ -636,8 +652,9 @@ void quadd_hrt_stop(void) { struct quadd_ctx *ctx = hrt.quadd_ctx; - pr_info("Stop hrt, number of samples: %llu\n", - atomic64_read(&hrt.counter_samples)); + pr_info("Stop hrt, samples all/skipped: %llu/%llu\n", + atomic64_read(&hrt.counter_samples), + atomic64_read(&hrt.skipped_samples)); if (ctx->pl310) ctx->pl310->stop(); @@ -647,6 +664,7 @@ void quadd_hrt_stop(void) hrt.active = 0; atomic64_set(&hrt.counter_samples, 0); + atomic64_set(&hrt.skipped_samples, 0); /* reset_cpu_ctx(); */ } @@ -662,7 +680,7 @@ void quadd_hrt_deinit(void) void quadd_hrt_get_state(struct quadd_module_state *state) { state->nr_all_samples = atomic64_read(&hrt.counter_samples); - state->nr_skipped_samples = 0; + state->nr_skipped_samples = atomic64_read(&hrt.skipped_samples); } static void init_arch_timer(void) diff --git a/drivers/misc/tegra-profiler/hrt.h b/drivers/misc/tegra-profiler/hrt.h index c4393aa8562b..baff679550e1 100644 --- a/drivers/misc/tegra-profiler/hrt.h +++ b/drivers/misc/tegra-profiler/hrt.h @@ -1,7 +1,7 @@ /* * drivers/misc/tegra-profiler/hrt.h * - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -48,9 +48,11 @@ struct quadd_hrt_ctx { struct quadd_ctx *quadd_ctx; int active; - atomic64_t counter_samples; atomic_t nr_active_all_core; + atomic64_t counter_samples; + atomic64_t skipped_samples; + struct timer_list ma_timer; unsigned int ma_period; diff --git a/drivers/misc/tegra-profiler/ma.c b/drivers/misc/tegra-profiler/ma.c index 26e6af2073c7..c7ccd82ac1b0 100644 --- a/drivers/misc/tegra-profiler/ma.c +++ b/drivers/misc/tegra-profiler/ma.c @@ -1,7 +1,7 @@ /* * drivers/misc/tegra-profiler/ma.c * - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -34,7 +34,6 @@ static void make_sample(struct quadd_hrt_ctx *hrt_ctx, { struct quadd_record_data record; struct quadd_ma_data *ma = &record.ma; - struct quadd_comm_data_interface *comm = hrt_ctx->quadd_ctx->comm; record.record_type = QUADD_RECORD_TYPE_MA; @@ -44,7 +43,7 @@ static void make_sample(struct quadd_hrt_ctx *hrt_ctx, ma->vm_size = vm_size << (PAGE_SHIFT-10); ma->rss_size = rss_size << (PAGE_SHIFT-10); - comm->put_sample(&record, NULL, 0); + quadd_put_sample(&record, NULL, 0); } static void check_ma(struct quadd_hrt_ctx *hrt_ctx) diff --git a/drivers/misc/tegra-profiler/main.c b/drivers/misc/tegra-profiler/main.c index e843ccb9f5f6..ff4bdd18375f 100644 --- a/drivers/misc/tegra-profiler/main.c +++ b/drivers/misc/tegra-profiler/main.c @@ -432,6 +432,7 @@ static void get_capabilities(struct quadd_comm_cap *cap) extra |= QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP; extra |= QUADD_COMM_CAP_EXTRA_UNWIND_MIXED; extra |= QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE; + extra |= QUADD_COMM_CAP_EXTRA_RB_MMAP_OP; if (ctx.hrt->tc) extra |= QUADD_COMM_CAP_EXTRA_ARCH_TIMER; @@ -456,13 +457,13 @@ void quadd_get_state(struct quadd_module_state *state) static int set_extab(struct quadd_extables *extabs, - struct quadd_extabs_mmap *mmap) + struct quadd_mmap_area *mmap) { return quadd_unwind_set_extab(extabs, mmap); } static void -delete_mmap(struct quadd_extabs_mmap *mmap) +delete_mmap(struct quadd_mmap_area *mmap) { quadd_unwind_delete_mmap(mmap); } diff --git a/drivers/misc/tegra-profiler/power_clk.c b/drivers/misc/tegra-profiler/power_clk.c index d928acaa4ae7..aaa5e5de7779 100644 --- a/drivers/misc/tegra-profiler/power_clk.c +++ b/drivers/misc/tegra-profiler/power_clk.c @@ -1,7 +1,7 @@ /* * drivers/misc/tegra-profiler/power_clk.c * - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -160,7 +160,6 @@ static void make_sample(void) struct quadd_record_data record; struct quadd_power_rate_data *power_rate = &record.power_rate; - struct quadd_comm_data_interface *comm = power_ctx.quadd_ctx->comm; record.record_type = QUADD_RECORD_TYPE_POWER_RATE; @@ -202,7 +201,7 @@ static void make_sample(void) vec.base = extra_cpus; vec.len = power_rate->nr_cpus * sizeof(extra_cpus[0]); - comm->put_sample(&record, &vec, 1); + quadd_put_sample(&record, &vec, 1); } static inline int is_data_changed(struct power_clk_source *s) diff --git a/drivers/misc/tegra-profiler/quadd_proc.c b/drivers/misc/tegra-profiler/quadd_proc.c index 779c79a9fb31..0d5ae5b9c717 100644 --- a/drivers/misc/tegra-profiler/quadd_proc.c +++ b/drivers/misc/tegra-profiler/quadd_proc.c @@ -1,7 +1,7 @@ /* * drivers/misc/tegra-profiler/quadd_proc.c * - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -98,6 +98,8 @@ static int show_capabilities(struct seq_file *f, void *offset) YES_NO(extra & QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE)); seq_printf(f, "arch timer is available: %s\n", YES_NO(extra & QUADD_COMM_CAP_EXTRA_ARCH_TIMER)); + seq_printf(f, "ring buffer mmap operation: %s\n", + YES_NO(extra & QUADD_COMM_CAP_EXTRA_RB_MMAP_OP)); seq_puts(f, "\n"); diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h index 5da67cea3ab9..e6238bb56a7a 100644 --- a/drivers/misc/tegra-profiler/version.h +++ b/drivers/misc/tegra-profiler/version.h @@ -18,7 +18,7 @@ #ifndef __QUADD_VERSION_H #define __QUADD_VERSION_H -#define QUADD_MODULE_VERSION "1.81" +#define QUADD_MODULE_VERSION "1.82" #define QUADD_MODULE_BRANCH "Dev" #endif /* __QUADD_VERSION_H */ diff --git a/include/linux/tegra_profiler.h b/include/linux/tegra_profiler.h index 5434d58ceae4..affbec553a69 100644 --- a/include/linux/tegra_profiler.h +++ b/include/linux/tegra_profiler.h @@ -1,7 +1,7 @@ /* * include/linux/tegra_profiler.h * - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -20,7 +20,7 @@ #include <linux/ioctl.h> #define QUADD_SAMPLES_VERSION 30 -#define QUADD_IO_VERSION 13 +#define QUADD_IO_VERSION 14 #define QUADD_IO_VERSION_DYNAMIC_RB 5 #define QUADD_IO_VERSION_RB_MAX_FILL_COUNT 6 @@ -31,6 +31,7 @@ #define QUADD_IO_VERSION_UNWIND_MIXED 11 #define QUADD_IO_VERSION_EXTABLES_MMAP 12 #define QUADD_IO_VERSION_ARCH_TIMER_OPT 13 +#define QUADD_IO_VERSION_DATA_MMAP 14 #define QUADD_SAMPLE_VERSION_THUMB_MODE_FLAG 17 #define QUADD_SAMPLE_VERSION_GROUP_SAMPLES 18 @@ -45,6 +46,8 @@ #define QUADD_SAMPLE_VERSION_HDR_UNW_METHOD 29 #define QUADD_SAMPLE_VERSION_HDR_ARCH_TIMER 30 +#define QUADD_MMAP_HEADER_VERSION 1 + #define QUADD_MAX_COUNTERS 32 #define QUADD_MAX_PROCESS 64 @@ -91,6 +94,11 @@ */ #define IOCTL_SET_EXTAB _IOW(QUADD_IOCTL, 6, struct quadd_extables) +/* + * Send ring buffer mmap info + */ +#define IOCTL_SET_MMAP_RB _IOW(QUADD_IOCTL, 7, struct quadd_mmap_rb_info) + #define QUADD_CPUMODE_TEGRA_POWER_CLUSTER_LP (1 << 29) /* LP CPU */ #define QUADD_CPUMODE_THUMB (1 << 30) /* thumb mode */ @@ -395,6 +403,7 @@ enum { #define QUADD_COMM_CAP_EXTRA_UNWIND_MIXED (1 << 6) #define QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE (1 << 7) #define QUADD_COMM_CAP_EXTRA_ARCH_TIMER (1 << 8) +#define QUADD_COMM_CAP_EXTRA_RB_MMAP_OP (1 << 9) struct quadd_comm_cap { u32 pmu:1, @@ -458,6 +467,46 @@ struct quadd_extables { u32 reserved[4]; /* reserved fields for future extensions */ }; +struct quadd_mmap_rb_info { + u32 cpu_id; + + u64 vm_start; + u64 vm_end; + + u32 reserved[4]; /* reserved fields for future extensions */ +}; + +#define QUADD_MMAP_HEADER_MAGIC 0x33445566 + +struct quadd_mmap_header { + u32 magic; + u32 version; + + u32 cpu_id; + u32 samples_version; + + u32 reserved[4]; /* reserved fields for future extensions */ +} __aligned(8); + +enum { + QUADD_RB_STATE_NONE = 0, + QUADD_RB_STATE_ACTIVE, + QUADD_RB_STATE_STOPPED, +}; + +struct quadd_ring_buffer_hdr { + u32 state; + u32 size; + + u32 pos_read; + u32 pos_write; + + u32 max_fill_count; + u32 skipped_samples; + + u32 reserved[4]; /* reserved fields for future extensions */ +} __aligned(8); + #pragma pack(pop) #ifdef __KERNEL__ |