summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>2015-06-07 22:40:26 +0200
committerBen Skeggs <bskeggs@redhat.com>2015-08-28 12:37:24 +1000
commit305d2e4af7691cab0be85150bd8cb2848305d738 (patch)
tree5cf894216746f7fb370bfc1721185bf8c586d64a /bin
parentc758c5691a32a56a20f560e892c6f5fd228cd899 (diff)
downloadnouveau-305d2e4af7691cab0be85150bd8cb2848305d738.tar.gz
pm: allow to configure domains instead of simple counters
Configuring counters from the userspace require the kernel to handle some logic related to performance counters. Basically, it has to find a free slot to assign a counter, to handle extra counting modes like B4/B6 and it must return and error when it can't configure a counter. In my opinion, the kernel should not handle all of that logic but it should only write the configuration sent by the userspace without checking anything. In other words, it should overwrite the configuration even if it's already counting and do not return any errors. This patch allows the userspace to configure a domain instead of separate counters. This has the advantage to move all of the logic to the userspace. Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'bin')
-rw-r--r--bin/nv_perfmon.c193
1 files changed, 147 insertions, 46 deletions
diff --git a/bin/nv_perfmon.c b/bin/nv_perfmon.c
index 50c777779..47b2fef34 100644
--- a/bin/nv_perfmon.c
+++ b/bin/nv_perfmon.c
@@ -248,7 +248,8 @@ ui_menu_win = {
struct ui_perfmon_dom {
struct list_head head;
- struct list_head list;
+ struct list_head signals;
+ struct list_head perfdoms;
u8 id;
};
@@ -260,22 +261,27 @@ struct ui_perfmon_sig {
struct ui_main {
struct list_head head;
- u32 handle;
- struct nvif_object object;
- const char *name;
+ struct ui_perfmon_sig *sig;
u32 clk;
u32 ctr;
u64 incr;
};
+struct ui_perfdom {
+ struct nvif_object object;
+ struct list_head head;
+ struct ui_main *ctr[4];
+ u32 handle;
+};
+
static struct list_head ui_main_list = LIST_HEAD_INIT(ui_main_list);
static struct list_head ui_doms_list = LIST_HEAD_INIT(ui_doms_list);
+static struct list_head ui_perfdom_list = LIST_HEAD_INIT(ui_perfdom_list);
static u32 ui_main_handle = 0xc0000000;
static void
ui_main_remove(struct ui_main *item)
{
- nvif_object_fini(&item->object);
list_del(&item->head);
free(item);
}
@@ -303,7 +309,7 @@ ui_perfmon_query_signals(struct nvif_object *perfmon,
sig->signal = args.signal;
sig->name = malloc(sizeof(args.name));
strncpy(sig->name, args.name, sizeof(args.name));
- list_add_tail(&sig->head, &dom->list);
+ list_add_tail(&sig->head, &dom->signals);
args.iter = prev_iter;
ret = nvif_mthd(perfmon, NVIF_PERFMON_V0_QUERY_SIGNAL,
@@ -331,7 +337,8 @@ ui_perfmon_query_domains(struct nvif_object *perfmon)
if (prev_iter) {
dom = calloc(1, sizeof(*dom));
dom->id = args.id;
- INIT_LIST_HEAD(&dom->list);
+ INIT_LIST_HEAD(&dom->signals);
+ INIT_LIST_HEAD(&dom->perfdoms);
list_add_tail(&dom->head, &ui_doms_list);
args.iter = prev_iter;
@@ -346,6 +353,49 @@ ui_perfmon_query_domains(struct nvif_object *perfmon)
}
static void
+ui_perfdom_init(struct ui_perfdom *dom)
+{
+ struct nvif_perfdom_init args = {};
+ int ret;
+
+ ret = nvif_mthd(&dom->object, NVIF_PERFDOM_V0_INIT,
+ &args, sizeof(args));
+ assert(ret == 0);
+}
+
+static void
+ui_perfdom_sample(struct ui_perfdom *dom)
+{
+ struct nvif_perfdom_sample args = {};
+ int ret;
+
+ ret = nvif_mthd(&dom->object, NVIF_PERFDOM_V0_SAMPLE,
+ &args, sizeof(args));
+ assert(ret == 0);
+}
+
+static void
+ui_perfdom_read(struct ui_perfdom *dom)
+{
+ struct nvif_perfdom_read_v0 args = {};
+ int ret, i;
+
+ ret = nvif_mthd(&dom->object, NVIF_PERFDOM_V0_READ,
+ &args, sizeof(args));
+ assert(ret == 0 || ret == -EAGAIN);
+
+ if (ret == 0) {
+ for (i = 0; i < 4; i++) {
+ if (!dom->ctr[i])
+ continue;
+ dom->ctr[i]->ctr = args.ctr[i];
+ dom->ctr[i]->incr += args.ctr[i];
+ dom->ctr[i]->clk = args.clk;
+ }
+ }
+}
+
+static void
ui_perfmon_init(void)
{
struct nvif_object perfmon;
@@ -362,17 +412,37 @@ ui_perfmon_init(void)
}
static void
+ui_perfmon_free_signals(struct ui_perfmon_dom *dom)
+{
+ struct ui_perfmon_sig *sig, *next;
+
+ list_for_each_entry_safe(sig, next, &dom->signals, head) {
+ list_del(&sig->head);
+ free(sig->name);
+ free(sig);
+ }
+}
+
+static void
+ui_perfmon_free_perfdoms(struct ui_perfmon_dom *dom)
+{
+ struct ui_perfdom *perfdom, *next;
+
+ list_for_each_entry_safe(perfdom, next, &dom->perfdoms, head) {
+ nvif_object_fini(&perfdom->object);
+ list_del(&perfdom->head);
+ free(perfdom);
+ }
+}
+
+static void
ui_perfmon_fini(void)
{
- struct ui_perfmon_dom *dom, *next_dom;
- struct ui_perfmon_sig *sig, *next_sig;
-
- list_for_each_entry_safe(dom, next_dom, &ui_doms_list, head) {
- list_for_each_entry_safe(sig, next_sig, &dom->list, head) {
- list_del(&sig->head);
- free(sig->name);
- free(sig);
- }
+ struct ui_perfmon_dom *dom, *next;
+
+ list_for_each_entry_safe(dom, next, &ui_doms_list, head) {
+ ui_perfmon_free_perfdoms(dom);
+ ui_perfmon_free_signals(dom);
list_del(&dom->head);
free(dom);
}
@@ -384,31 +454,62 @@ ui_main_select(void)
struct ui_main *item, *temp;
struct ui_perfmon_dom *dom;
struct ui_perfmon_sig *sig;
+ struct ui_perfdom *perfdom;
int ret;
+ int i;
list_for_each_entry_safe(item, temp, &ui_main_list, head) {
ui_main_remove(item);
}
list_for_each_entry(dom, &ui_doms_list, head) {
- list_for_each_entry(sig, &dom->list, head) {
- struct nvif_perfctr_v0 args = {
- .logic_op = 0xaaaa,
- .domain = dom->id,
- };
+ list_for_each_entry(sig, &dom->signals, head) {
+ bool found = false;
item = calloc(1, sizeof(*item));
- item->handle = ui_main_handle++;
- item->name = sig->name;
+ item->sig = sig;
+ list_add_tail(&item->head, &ui_main_list);
+
+ /* find a slot */
+ list_for_each_entry(perfdom, &dom->perfdoms, head) {
+ for (i = 0; i < 4; i++) {
+ if (!perfdom->ctr[i]) {
+ perfdom->ctr[i] = item;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ /* no free slots, create a new perfdom */
+ perfdom = calloc(1, sizeof(*perfdom));
+ perfdom->handle = ui_main_handle++;
+ perfdom->ctr[0] = item;
+ list_add_tail(&perfdom->head, &dom->perfdoms);
+ }
+ }
+
+ /* init perfdom objects */
+ list_for_each_entry(perfdom, &dom->perfdoms, head) {
+ struct nvif_perfdom_v0 args = {};
+ int i;
+
+ args.domain = dom->id;
+ for (i = 0; i < 4; i++) {
+ struct ui_main *ctr = perfdom->ctr[i];
+ if (!ctr)
+ continue;
+ args.ctr[i].signal[0] = ctr->sig->signal;
+ args.ctr[i].logic_op = 0xaaaa;
+ }
- args.signal[0] = sig->signal;
ret = nvif_object_init(nvif_object(device), NULL,
- item->handle,
- NVIF_IOCTL_NEW_V0_PERFCTR,
+ perfdom->handle,
+ NVIF_IOCTL_NEW_V0_PERFDOM,
&args, sizeof(args),
- &item->object);
+ &perfdom->object);
assert(ret == 0);
- list_add_tail(&item->head, &ui_main_list);
}
}
}
@@ -416,34 +517,34 @@ ui_main_select(void)
static void
ui_main_alarm_handler(int signal)
{
- struct ui_main *item;
+ struct ui_perfmon_dom *dom;
+ struct ui_perfdom *perfdom;
bool sampled = false;
if (list_empty(&ui_main_list))
ui_main_select();
- list_for_each_entry(item, &ui_main_list, head) {
- struct nvif_perfctr_read_v0 args = {};
- int ret;
+ list_for_each_entry(dom, &ui_doms_list, head) {
+ if (list_empty(&dom->perfdoms))
+ continue;
- if (!sampled) {
- struct nvif_perfctr_sample args = {};
+ perfdom = list_first_entry(&dom->perfdoms,
+ typeof(*perfdom), head);
- ret = nvif_mthd(&item->object, NVIF_PERFCTR_V0_SAMPLE,
- &args, sizeof(args));
- assert(ret == 0);
+ /* sample previous batch of counters */
+ if (!sampled) {
+ ui_perfdom_sample(perfdom);
sampled = true;
}
- ret = nvif_mthd(&item->object, NVIF_PERFCTR_V0_READ,
- &args, sizeof(args));
- assert(ret == 0 || ret == -EAGAIN);
+ /* read previous batch of counters */
+ ui_perfdom_read(perfdom);
- if (ret == 0) {
- item->clk = args.clk;
- item->ctr = args.ctr;
- }
- item->incr += item->ctr;
+ /* setup next batch of counters for sampling */
+ list_move_tail(&perfdom->head, &dom->perfdoms);
+ perfdom = list_first_entry(&dom->perfdoms,
+ typeof(*perfdom), head);
+ ui_perfdom_init(perfdom);
}
}
@@ -485,7 +586,7 @@ ui_main_redraw(struct ui_table *t)
y = 2;
list_for_each_entry_from(item, &ui_main_list, head) {
- set_field_buffer(f[0], 0, item->name);
+ set_field_buffer(f[0], 0, item->sig->name);
set_field_userptr(f[0], item);
field_opts_on(f[0], O_VISIBLE | O_ACTIVE);