misc: tegra-profiler: use mmap for samples
Igor Nabirushkin [Sun, 19 Oct 2014 20:22:32 +0000 (00:22 +0400)]
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>

13 files changed:
drivers/misc/tegra-profiler/comm.c
drivers/misc/tegra-profiler/comm.h
drivers/misc/tegra-profiler/dwarf_unwind.c
drivers/misc/tegra-profiler/eh_unwind.c
drivers/misc/tegra-profiler/eh_unwind.h
drivers/misc/tegra-profiler/hrt.c
drivers/misc/tegra-profiler/hrt.h
drivers/misc/tegra-profiler/ma.c
drivers/misc/tegra-profiler/main.c
drivers/misc/tegra-profiler/power_clk.c
drivers/misc/tegra-profiler/quadd_proc.c
drivers/misc/tegra-profiler/version.h
include/linux/tegra_profiler.h

index 793a19c..8f42289 100644 (file)
 #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);
 }
index 0bf56e1..66945ab 100644 (file)
@@ -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);
index c4c620e..c71e266 100644 (file)
@@ -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;
index a8f13ee..728ca63 100644 (file)
@@ -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;
index f386f6a..77fdfc9 100644 (file)
@@ -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;
 
index fc12c44..e781147 100644 (file)
@@ -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)
index c4393aa..baff679 100644 (file)
@@ -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;
 
index 26e6af2..c7ccd82 100644 (file)
@@ -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)
index e843ccb..ff4bdd1 100644 (file)
@@ -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);
 }
index d928aca..aaa5e5d 100644 (file)
@@ -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)
index 779c79a..0d5ae5b 100644 (file)
@@ -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");
 
index 5da67ce..e6238bb 100644 (file)
@@ -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 */
index 5434d58..affbec5 100644 (file)
@@ -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
 
  */
 #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__