From patchwork Mon Nov 23 18:33:11 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathieu Poirier X-Patchwork-Id: 57187 Delivered-To: patch@linaro.org Received: by 10.112.155.196 with SMTP id vy4csp1603706lbb; Mon, 23 Nov 2015 10:37:09 -0800 (PST) X-Received: by 10.68.57.208 with SMTP id k16mr37665143pbq.70.1448303829397; Mon, 23 Nov 2015 10:37:09 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n1si7399997pap.152.2015.11.23.10.37.08; Mon, 23 Nov 2015 10:37:09 -0800 (PST) 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; 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; dkim=neutral (body hash did not verify) header.i=@linaro-org.20150623.gappssmtp.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755350AbbKWShG (ORCPT + 28 others); Mon, 23 Nov 2015 13:37:06 -0500 Received: from mail-pa0-f45.google.com ([209.85.220.45]:36073 "EHLO mail-pa0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755015AbbKWSe3 (ORCPT ); Mon, 23 Nov 2015 13:34:29 -0500 Received: by pacdm15 with SMTP id dm15so198929047pac.3 for ; Mon, 23 Nov 2015 10:34:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bvoblm0bT/FVhIr/dxJCMbHcJGHDadyoiZLzEcn/cnA=; b=xaRTTPO/uUbmt3KmMffdnv4x/9s1J++C6kYUNTPXXjIBJP0PvGPCFJQ1aLbY+CG0pX Elz5np/GykLX+9MqD1x7k2e9KkMW6oda6YcoVxo1aPa/dt7b4mbQqNWoaXDFFoe1nm+S UzpH1J4rjOte7wQDynAFacXygnqk023ftMk06ax2WwGe2MHz9LJ/j+Naajs5UejHQWo2 q7V5yWjWnV9iDRkZbaW1B2yagb17tqoQwuwqGXD5/62t2IeC323xXlxMUffdo9eyo301 vTQlcasdBpDUu8+NOfHCRfSf9SC+n7m+naisPathtCuZX6VeaDQCjdstu+TAjzKV7AYO riUg== 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=bvoblm0bT/FVhIr/dxJCMbHcJGHDadyoiZLzEcn/cnA=; b=Vnnh5CWMrxveMyvwJnCPeM0CuYiEir1oM9kIaTvf3QwIRD9qzk711icPbq6AhkCOTf o9K+OBPY9M0IXq7jqwGpwa0ZsFMFw9aCvOR9UV8x3cTuhg1lyLcHDEWDAflcPBELXGxz ZAR+klhA9NPH4Ka6ytY2Sto4v/4WmbQwnAX1ep7MBFUZBwt1iALOMaTW1vkdZrDECsKl Zmh+t9iVec+TkwRWhMr8K/+1TYNOO4/Fito3XqHenMw7RdVYkazDo4uxRlKu45Bp6jYV rrTDsXaXtpgazhBBE+vAo54h6t+De/UW24dQ5711EzB7JggZ8YmJ21/ldQuuLlH2Ir6q WVXQ== X-Gm-Message-State: ALoCoQngza3TZ29oxiNdnZV7I0co/Q3Swepy9YXWtPABeuVu2q3+5DyGztUle9AZxKp/mv3LH/yE X-Received: by 10.98.19.12 with SMTP id b12mr17421217pfj.78.1448303669226; Mon, 23 Nov 2015 10:34:29 -0800 (PST) Received: from t430.cg.shawcable.net ([184.64.168.246]) by smtp.gmail.com with ESMTPSA id r20sm10865186pfa.93.2015.11.23.10.34.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Nov 2015 10:34:28 -0800 (PST) From: Mathieu Poirier To: gregkh@linuxfoundation.org, a.p.zijlstra@chello.nl, alexander.shishkin@linux.intel.com, acme@kernel.org, mingo@redhat.com, corbet@lwn.net, nicolas.pitre@linaro.org Cc: zhang.chunyan@linaro.org, mike.leach@arm.com, tor@ti.com, al.grant@arm.com, pawel.moll@arm.com, fainelli@broadcom.com, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RESEND PATCH V4 19/26] coresight: etb10: implementing AUX space API Date: Mon, 23 Nov 2015 11:33:11 -0700 Message-Id: <1448303598-11249-20-git-send-email-mathieu.poirier@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1448303598-11249-1-git-send-email-mathieu.poirier@linaro.org> References: <1448303598-11249-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 Adding an ETB10 specific AUX area operations to be used by the perf framework when events are initialised. Part of this operation involves modeling the mmap'ed area based on the specific ways a sink buffer gathers information. Signed-off-by: Mathieu Poirier --- drivers/hwtracing/coresight/coresight-etb10.c | 228 ++++++++++++++++++++++++++ include/linux/coresight.h | 20 ++- 2 files changed, 246 insertions(+), 2 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index dc4d707b28aa..27ddf9ecc7cc 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -28,6 +28,11 @@ #include #include #include +#include +#include +#include + +#include #include "coresight-priv.h" @@ -65,6 +70,26 @@ #define ETB_FRAME_SIZE_WORDS 4 /** + * struct cs_buffer - keep track of a recording session' specifics + * @cur: index of the current buffer + * @nr_pages: max number of pages granted to us + * @offset: offset within the current buffer + * @data_size: how much we collected in this run + * @lost: other than zero if we had a HW buffer wrap around + * @snapshot: is this run in snapshot mode + * @data_pages: a handle the ring buffer + */ +struct cs_buffers { + unsigned int cur; + unsigned int nr_pages; + unsigned long offset; + local_t data_size; + local_t lost; + bool snapshot; + void **data_pages; +}; + +/** * struct etb_drvdata - specifics associated to an ETB component * @base: memory mapped base address for this component. * @dev: the device entity associated to this component. @@ -266,9 +291,212 @@ static void etb_disable(struct coresight_device *csdev) dev_info(drvdata->dev, "ETB disabled\n"); } +static void *etb_setup_aux(struct coresight_device *csdev, int cpu, + void **pages, int nr_pages, bool overwrite) +{ + int node; + struct cs_buffers *buf; + + if (cpu == -1) + cpu = smp_processor_id(); + node = cpu_to_node(cpu); + + buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node); + if (!buf) + return NULL; + + buf->snapshot = overwrite; + buf->nr_pages = nr_pages; + buf->data_pages = pages; + + return buf; +} + +static int etb_set_buffer(struct coresight_device *csdev, + struct perf_output_handle *handle, + void *sink_config) +{ + int ret = 0; + unsigned long head; + struct cs_buffers *buf = sink_config; + + /* wrap head around to the amount of space we have */ + head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1); + + /* find the page to write to */ + buf->cur = head / PAGE_SIZE; + + /* and offset within that page */ + buf->offset = head % PAGE_SIZE; + + local_set(&buf->data_size, 0); + + return ret; +} + +static unsigned long etb_reset_buffer(struct coresight_device *csdev, + struct perf_output_handle *handle, + void *sink_config, bool *lost) +{ + unsigned long size = 0; + struct cs_buffers *buf = sink_config; + + if (buf) { + /* + * In snapshot mode ->data_size holds the new address of the + * ring buffer's head. The size itself is the whole address + * range since we want the latest information. + */ + if (buf->snapshot) + handle->head = local_xchg(&buf->data_size, + buf->nr_pages << PAGE_SHIFT); + + /* + * Tell the tracer PMU how much we got in this run and if + * something went wrong along the way. Nobody else can use + * this cs_buffers instance until we are done. As such + * resetting parameters here and squaring off with the ring + * buffer API in the tracer PMU is fine. + */ + *lost = local_xchg(&buf->lost, 0); + size = local_xchg(&buf->data_size, 0); + } + + return size; +} + +static void etb_update_buffer(struct coresight_device *csdev, + struct perf_output_handle *handle, + void *sink_config) +{ + int i, cur; + u8 *buf_ptr; + u32 read_ptr, write_ptr, start; + u32 status, read_data, to_read; + unsigned long flags, offset; + struct cs_buffers *buf = sink_config; + struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + if (!buf) + return; + + spin_lock_irqsave(&drvdata->spinlock, flags); + + CS_UNLOCK(drvdata->base); + etb_disable_hw(drvdata); + + /* unit is in words, not bytes */ + read_ptr = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER); + write_ptr = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER); + + /* + * Entries should be aligned to the frame size. If they are not + * go back to the last alignement point to give decoding tools a + * chance to fix things. + */ + if (write_ptr % ETB_FRAME_SIZE_WORDS) { + dev_err(drvdata->dev, + "write_ptr: %lu not aligned to formatter frame size\n", + (unsigned long)write_ptr); + + write_ptr &= ~ETB_FRAME_SIZE_WORDS; + local_inc(&buf->lost); + } + + /* + * Get a hold of the status register and see if a wrap around + * has occurred. If so adjust things accordingly. Otherwise + * start at the beginning and go until the write pointer has + * been reached. + */ + status = readl_relaxed(drvdata->base + ETB_STATUS_REG); + if (status & ETB_STATUS_RAM_FULL) { + local_inc(&buf->lost); + to_read = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS; + start = write_ptr; + } else { + to_read = CIRC_CNT(write_ptr, read_ptr, + drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS); + start = read_ptr; + } + + /* + * Make sure we don't overwrite data that hasn't been consumed yet. + * It is entirely possible that the HW buffer has more data than the + * ring buffer can currently handle. If so adjust the start address + * to take only the last traces. + * + * In snapshot mode we are looking to get the latest traces only and as + * such, we don't care about not overwriting data that hasn't been + * processed by user space. + * + * Since metrics related to ETBs is in words, multiply by the + * amount of byte per word to have the right units. + */ + if (!buf->snapshot && to_read > handle->size) { + unsigned int capacity = drvdata->buffer_depth * + ETB_FRAME_SIZE_WORDS; + to_read = handle->size; + /* advance the start pointer to get the latest trace data */ + start += capacity - handle->size; + /* make sure we are still aligned */ + start &= ~ETB_FRAME_SIZE_WORDS; + /* wrap around if we've reach the end of the HW buffer */ + start &= capacity - 1; + /* let the decoder know we've skipped ahead */ + local_inc(&buf->lost); + } + + /* finally tell HW where we want to start reading from */ + writel_relaxed(start, drvdata->base + ETB_RAM_READ_POINTER); + + cur = buf->cur; + offset = buf->offset; + for (i = 0; i < to_read; i += 4) { + buf_ptr = buf->data_pages[cur] + offset; + read_data = readl_relaxed(drvdata->base + + ETB_RAM_READ_DATA_REG); + *buf_ptr++ = read_data >> 0; + *buf_ptr++ = read_data >> 8; + *buf_ptr++ = read_data >> 16; + *buf_ptr++ = read_data >> 24; + + offset += 4; + if (offset >= PAGE_SIZE) { + offset = 0; + cur++; + /* wrap around at the end of the buffer */ + cur &= buf->nr_pages - 1; + } + } + + /* reset ETB buffer for next run */ + writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER); + writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER); + + /* + * In snapshot mode all we have to do is communicate to + * perf_aux_output_end() the address of the current head. In full + * trace mode the same function expects a size to move rb->aux_head + * forward. + */ + if (buf->snapshot) + local_set(&buf->data_size, (cur * PAGE_SIZE) + offset); + else + local_add(to_read, &buf->data_size); + + etb_enable_hw(drvdata); + CS_LOCK(drvdata->base); + spin_unlock_irqrestore(&drvdata->spinlock, flags); +} + static const struct coresight_ops_sink etb_sink_ops = { .enable = etb_enable, .disable = etb_disable, + .setup_aux = etb_setup_aux, + .set_buffer = etb_set_buffer, + .reset_buffer = etb_reset_buffer, + .update_buffer = etb_update_buffer, }; static const struct coresight_ops etb_cs_ops = { diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 80b3465bd459..810a8b2511c4 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -14,6 +14,7 @@ #define _LINUX_CORESIGHT_H #include +#include #include /* Peripheral id registers (0xFD0-0xFEC) */ @@ -181,12 +182,27 @@ struct coresight_device { /** * struct coresight_ops_sink - basic operations for a sink * Operations available for sinks - * @enable: enables the sink. - * @disable: disables the sink. + * @enable: enables the sink. + * @disable: disables the sink. + * @setup_aux: initialises perf's ring buffer for trace collection. + * @set_buffer: initialises buffer mechanic before a trace session. + * @reset_buffer: finalises buffer mechanic after a trace session. + * @update_buffer: update buffer pointers after a trace session. */ struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, u32 mode); void (*disable)(struct coresight_device *csdev); + void *(*setup_aux)(struct coresight_device *csdev, int cpu, + void **pages, int nr_pages, bool overwrite); + int (*set_buffer)(struct coresight_device *csdev, + struct perf_output_handle *handle, + void *sink_config); + unsigned long (*reset_buffer)(struct coresight_device *csdev, + struct perf_output_handle *handle, + void *sink_config, bool *lost); + void (*update_buffer)(struct coresight_device *csdev, + struct perf_output_handle *handle, + void *sink_config); }; /**