summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Nabirushkin <inabirushkin@nvidia.com>2014-10-20 00:22:32 +0400
committerWinnie Hsu <whsu@nvidia.com>2015-01-29 22:02:49 -0800
commitcd2cd13dc3161d4b3362c2a94dc2442d7e1631fa (patch)
tree16b28b80500b2d832df652b79cb18f79f2222722
parentd075eb663ba4bd87b64cfba88a79c01c92049619 (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.c712
-rw-r--r--drivers/misc/tegra-profiler/comm.h59
-rw-r--r--drivers/misc/tegra-profiler/dwarf_unwind.c2
-rw-r--r--drivers/misc/tegra-profiler/eh_unwind.c17
-rw-r--r--drivers/misc/tegra-profiler/eh_unwind.h10
-rw-r--r--drivers/misc/tegra-profiler/hrt.c46
-rw-r--r--drivers/misc/tegra-profiler/hrt.h6
-rw-r--r--drivers/misc/tegra-profiler/ma.c5
-rw-r--r--drivers/misc/tegra-profiler/main.c5
-rw-r--r--drivers/misc/tegra-profiler/power_clk.c5
-rw-r--r--drivers/misc/tegra-profiler/quadd_proc.c4
-rw-r--r--drivers/misc/tegra-profiler/version.h2
-rw-r--r--include/linux/tegra_profiler.h53
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__