From patchwork Mon Jul 18 19:51:24 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathieu Poirier X-Patchwork-Id: 72247 Delivered-To: patch@linaro.org Received: by 10.140.29.52 with SMTP id a49csp290771qga; Mon, 18 Jul 2016 12:51:55 -0700 (PDT) X-Received: by 10.98.81.1 with SMTP id f1mr48782715pfb.33.1468871512811; Mon, 18 Jul 2016 12:51:52 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v12si5016786pfi.276.2016.07.18.12.51.52; Mon, 18 Jul 2016 12:51:52 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752337AbcGRTvo (ORCPT + 29 others); Mon, 18 Jul 2016 15:51:44 -0400 Received: from mail-io0-f171.google.com ([209.85.223.171]:32773 "EHLO mail-io0-f171.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751659AbcGRTvi (ORCPT ); Mon, 18 Jul 2016 15:51:38 -0400 Received: by mail-io0-f171.google.com with SMTP id 38so461180iol.0 for ; Mon, 18 Jul 2016 12:51:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Nuwg4ragMQL6yNVZsgmD8RCeIDYehnGyjencq7tcFYY=; b=SHkXxkUVfilnbeDI2BkD210wsEZmFoFqw82xl5hzYCdRsjk26gCtfMpfQ0smTad98R vcU6wQf30Q1TvJJgFinUObu5vMVAAIN1Ujg6NBr1AliD74ucIOz6SDzLYdThH0nrhRfM vXx7yK9L4JJ9GgJhgZGYYWg1RWAnDNIQC64Wc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Nuwg4ragMQL6yNVZsgmD8RCeIDYehnGyjencq7tcFYY=; b=N7WrQEv8lYYfGBHG4ukS81MH+pQhkUQveJd8SMXLiyZjcEinffuOR27CpR4Jqd2TzZ kdaNh5tyrjKE53TwRMe5GeosQPLe65ce3Bh34wgeh0iKdV1A6bTHBjwTuigW9hZqaRnb slCKM15VZDyVMhHwyVZp3B4idjamK+hNW1gtx8Y/dPBX1ANMej+BGVu0fLKyfU2BZ8NC LK1573YK03Hx8CMkiiPWtPUP0FX2lAsC/eCEV/LKsMW8+E1bT5naUt1lwv5HLdxTY4kq RJOklkMgT/f1qI+IWDtWqDtkj0oYWtp6i2HmApveAVCooPr6N6VAbls7ScA3yqOG3lk8 xtOQ== X-Gm-Message-State: ALyK8tKjY55Oz934OxraKxS/qZdddKnVbYg7GWcSqCsXCFay7ejHqftRXyIHYBU+nkJghWs7 X-Received: by 10.107.150.83 with SMTP id y80mr37568954iod.113.1468871497358; Mon, 18 Jul 2016 12:51:37 -0700 (PDT) Received: from t430.cg.shawcable.net (S0106002369de4dac.cg.shawcable.net. [68.147.8.254]) by smtp.gmail.com with ESMTPSA id r128sm5270676ita.6.2016.07.18.12.51.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 18 Jul 2016 12:51:36 -0700 (PDT) From: Mathieu Poirier To: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org, alexander.shishkin@linux.intel.com, Mathieu Poirier Subject: [PATCH 03/10] coresight: etm-perf: configuring filters from perf core Date: Mon, 18 Jul 2016 13:51:24 -0600 Message-Id: <1468871491-10997-4-git-send-email-mathieu.poirier@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1468871491-10997-1-git-send-email-mathieu.poirier@linaro.org> References: <1468871491-10997-1-git-send-email-mathieu.poirier@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch implements the required API needed to access and retrieve range and start/stop filters from the perf core. Signed-off-by: Mathieu Poirier --- drivers/hwtracing/coresight/coresight-etm-perf.c | 146 ++++++++++++++++++++--- drivers/hwtracing/coresight/coresight-etm-perf.h | 32 +++++ 2 files changed, 162 insertions(+), 16 deletions(-) -- 2.7.4 diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 78a1bc0013a2..fde7f42149c5 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -29,6 +29,7 @@ #include #include "coresight-priv.h" +#include "coresight-etm-perf.h" static struct pmu etm_pmu; static bool etm_perf_up; @@ -83,12 +84,44 @@ static const struct attribute_group *etm_pmu_attr_groups[] = { static void etm_event_read(struct perf_event *event) {} +static int etm_addr_filters_alloc(struct perf_event *event) +{ + struct etm_filters *filters; + int node = event->cpu == -1 ? -1 : cpu_to_node(event->cpu); + + filters = kzalloc_node(sizeof(struct etm_filters), GFP_KERNEL, node); + if (!filters) + return -ENOMEM; + + if (event->parent) + memcpy(filters, event->parent->hw.addr_filters, + sizeof(*filters)); + + event->hw.addr_filters = filters; + + return 0; +} + +static void etm_event_destroy(struct perf_event *event) +{ + kfree(event->hw.addr_filters); + event->hw.addr_filters = NULL; +} + static int etm_event_init(struct perf_event *event) { + int ret; + if (event->attr.type != etm_pmu.type) return -ENOENT; - return 0; + ret = etm_addr_filters_alloc(event); + if (ret) + return ret; + + event->destroy = etm_event_destroy; + + return ret; } static void free_event_data(struct work_struct *work) @@ -456,6 +489,85 @@ static void etm_free_drv_configs(struct perf_event *event) } } +static int etm_addr_filters_validate(struct list_head *filters) +{ + bool range = false, address = false; + int index = 0; + struct perf_addr_filter *filter; + + list_for_each_entry(filter, filters, entry) { + /* + * No need to go further if there's no more + * room for filters. + */ + if (++index > ETM_ADDR_CMP_MAX) + return -EOPNOTSUPP; + + /* + * As taken from the struct perf_addr_filter documentation: + * @range: 1: range, 0: address + * + * At this time we don't allow range and start/stop filtering + * to cohabitate, they have to be mutually exclusive. + */ + if ((filter->range == 1) && address) + return -EOPNOTSUPP; + + if ((filter->range == 0) && range) + return -EOPNOTSUPP; + + /* + * For range filtering, the second address in the address + * range comparator needs to be higher than the first. + * Invalid otherwise. + */ + if (filter->range && filter->size == 0) + return -EINVAL; + + /* + * Everything checks out with this filter, record what we've + * received before moving on to the next one. + */ + if (filter->range) + range = true; + else + address = true; + } + + return 0; +} + +static void etm_addr_filters_sync(struct perf_event *event) +{ + struct perf_addr_filters_head *head = perf_event_addr_filters(event); + unsigned long start, stop, *offs = event->addr_filters_offs; + struct etm_filters *filters = event->hw.addr_filters; + struct perf_addr_filter *filter; + int i = 0; + + list_for_each_entry(filter, &head->list, entry) { + start = filter->offset + offs[i]; + stop = start + filter->size; + + if (filter->range == 1) { + filters->filter[i].start_addr = start; + filters->filter[i].stop_addr = stop; + filters->filter[i].type = ETM_ADDR_TYPE_RANGE; + } else { + if (filter->filter == 1) { + filters->filter[i].start_addr = start; + filters->filter[i].type = ETM_ADDR_TYPE_START; + } else { + filters->filter[i].stop_addr = stop; + filters->filter[i].type = ETM_ADDR_TYPE_STOP; + } + } + i++; + } + + filters->nr_filters = i; +} + int etm_perf_symlink(struct coresight_device *csdev, bool link) { char entry[sizeof("cpu9999999")]; @@ -485,21 +597,23 @@ static int __init etm_perf_init(void) { int ret; - etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE; - - etm_pmu.attr_groups = etm_pmu_attr_groups; - etm_pmu.task_ctx_nr = perf_sw_context; - etm_pmu.read = etm_event_read; - etm_pmu.event_init = etm_event_init; - etm_pmu.setup_aux = etm_setup_aux; - etm_pmu.free_aux = etm_free_aux; - etm_pmu.start = etm_event_start; - etm_pmu.stop = etm_event_stop; - etm_pmu.add = etm_event_add; - etm_pmu.del = etm_event_del; - etm_pmu.get_drv_configs = etm_get_drv_configs; - etm_pmu.free_drv_configs - = etm_free_drv_configs; + etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE; + + etm_pmu.attr_groups = etm_pmu_attr_groups; + etm_pmu.task_ctx_nr = perf_sw_context; + etm_pmu.read = etm_event_read; + etm_pmu.event_init = etm_event_init; + etm_pmu.setup_aux = etm_setup_aux; + etm_pmu.free_aux = etm_free_aux; + etm_pmu.start = etm_event_start; + etm_pmu.stop = etm_event_stop; + etm_pmu.add = etm_event_add; + etm_pmu.del = etm_event_del; + etm_pmu.get_drv_configs = etm_get_drv_configs; + etm_pmu.free_drv_configs = etm_free_drv_configs; + etm_pmu.addr_filters_sync = etm_addr_filters_sync; + etm_pmu.addr_filters_validate = etm_addr_filters_validate; + etm_pmu.nr_addr_filters = ETM_ADDR_CMP_MAX; ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1); if (ret == 0) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 87f5a134eb6f..28be38a9be60 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -20,6 +20,38 @@ struct coresight_device; +/* + * In both ETMv3 and v4 the maximum number of address comparator implentable + * is 8. The actual number is implementation specific and will be checked + * when filters are applied. + */ +#define ETM_ADDR_CMP_MAX 8 + +/** + * struct etm_filter - single instruction range or start/stop configuration. + * @start_addr: The address to start tracing on. + * @stop_addr: The address to stop tracing on. + * @type: Is this a range or start/stop filter. + */ +struct etm_filter { + unsigned long start_addr; + unsigned long stop_addr; + enum etm_addr_type type; +}; + +/** + * struct etm_filters - set of filters for a session + * @etm_filter: All the filters for this session. + * @nr_filters: Number of filters + * @ssstatus: Status of the start/stop logic. + */ +struct etm_filters { + struct etm_filter filter[ETM_ADDR_CMP_MAX]; + unsigned int nr_filters; + bool ssstatus; +}; + + #ifdef CONFIG_CORESIGHT int etm_perf_symlink(struct coresight_device *csdev, bool link);