From patchwork Thu Dec 3 21:04:54 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathieu Poirier X-Patchwork-Id: 57688 Delivered-To: patch@linaro.org Received: by 10.112.155.196 with SMTP id vy4csp168319lbb; Thu, 3 Dec 2015 13:10:06 -0800 (PST) X-Received: by 10.98.64.80 with SMTP id n77mr16403002pfa.96.1449177006587; Thu, 03 Dec 2015 13:10:06 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id qd3si11347205pab.208.2015.12.03.13.10.06; Thu, 03 Dec 2015 13:10:06 -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 S1754739AbbLCVJ5 (ORCPT + 28 others); Thu, 3 Dec 2015 16:09:57 -0500 Received: from mail-ig0-f171.google.com ([209.85.213.171]:37995 "EHLO mail-ig0-f171.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754412AbbLCVFx (ORCPT ); Thu, 3 Dec 2015 16:05:53 -0500 Received: by igbxm8 with SMTP id xm8so22116543igb.1 for ; Thu, 03 Dec 2015 13:05:52 -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=S6kUDT3A5fwOIXrNDcLpUdAeMwoaDWP4H8wbIMM5goY=; b=eGi3igPDU8oEfJI4/OeQZOWWqT5Tth+MLLGGdczKc76n0Ibvxv6n8kWNSb1ukjyqSN NkVoMTlK9SJUmw7Ja54w3ERHxRDcsCn/4P01kNVxhAS71R1+/J9wIbVCC0iYuYsf86eG RiVf07wNBoIYNmfPnRE0tSLMMdpQTajbp2WnMInpetrp0LgqY2umL8ZILdxiyr5w4IEW hw24bVyjpAYO3DQh4mrZiGUiJXXV134ljnLYq6EEsxUROab5hKDOfpDKV8NPCBlJHiP1 RneHJATO1SsCNEFwU3GFvHKMo+pdbQaO63Z3bhnHYm49/S0YUGhFdb2hSeYL4M6xH5Ve sapA== 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=S6kUDT3A5fwOIXrNDcLpUdAeMwoaDWP4H8wbIMM5goY=; b=Y+2J3FOnv1IXsJDnem5Gf5/dVzyEH9FgT57OEggqjoIqcEbOnw2AfJozelg4nW5Dcq G/hCGf2ys1zPRilPiaKCopTT+SwLI3GIrjhCTT3KMVRA66xsa2W0cDpJjHEJw4Ip+yoy mueR5Ao6GcIgi1yUdh5E2rWtmoHIQ79PIhia5l10/5GkupVlhiC2hFDRhhnhOJc3j45Q sqzfWIwMxVVar0LfBfF9woErfj1f6o9IM1MKADM2oeyFxtwyEq10i9LzMrujiuMmKkAa 9ADZS2mHpg8RjEZvPWl4BDaypiUFeQTG845UAG+cB9gQW9s3nnCR3aNJTFsSfZJ5xJtV 6QJw== X-Gm-Message-State: ALoCoQnPLugPxUlo+UQMNtDdUt2dyqygXoozBSpCOFJfPiuTKC3oQ3EEOtqChQigg+c8K3EDwzZL3LFGT2af9lLzUHg23j/9XA== X-Received: by 10.50.157.34 with SMTP id wj2mr799475igb.32.1449176752887; Thu, 03 Dec 2015 13:05:52 -0800 (PST) Received: from t430.cg.shawcable.net (S0106002369de4dac.cg.shawcable.net. [184.64.168.246]) by smtp.gmail.com with ESMTPSA id d81sm3615433ioj.12.2015.12.03.13.05.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 03 Dec 2015 13:05:52 -0800 (PST) From: Mathieu Poirier To: gregkh@linuxfoundation.org, alexander.shishkin@linux.intel.com Cc: zhang.chunyan@linaro.org, mike.leach@arm.com, tor@ti.com, al.grant@arm.com, fainelli@broadcom.com, linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Mathieu Poirier Subject: [PATCH V6 18/26] coresight: etb10: implementing AUX space API Date: Thu, 3 Dec 2015 14:04:54 -0700 Message-Id: <1449176702-13213-19-git-send-email-mathieu.poirier@linaro.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1449176702-13213-1-git-send-email-mathieu.poirier@linaro.org> References: <1449176702-13213-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 | 237 ++++++++++++++++++++++++++ include/linux/coresight.h | 22 ++- 2 files changed, 257 insertions(+), 2 deletions(-) -- 2.1.4 -- 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..79c87f42c550 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,221 @@ static void etb_disable(struct coresight_device *csdev) dev_info(drvdata->dev, "ETB disabled\n"); } +static void *etb_get_config(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 void etb_put_config(void *config) +{ + struct cs_buffers *buf = config; + + kfree(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, capacity; + 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; + + capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS; + + 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 - 1); + 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 = capacity; + read_ptr = write_ptr; + } else { + to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->buffer_depth); + to_read *= ETB_FRAME_SIZE_WORDS; + } + + /* + * 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. + */ + if (!buf->snapshot && to_read > handle->size) { + u32 mask = ~(ETB_FRAME_SIZE_WORDS - 1); + + /* The new read pointer must be frame size aligned */ + to_read -= handle->size & mask; + /* + * Move the RAM read pointer up, keeping in mind that + * everything is in frame size units. + */ + read_ptr = (write_ptr + drvdata->buffer_depth) - + to_read / ETB_FRAME_SIZE_WORDS; + /* Wrap around if need be*/ + read_ptr &= ~(drvdata->buffer_depth - 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(read_ptr, 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, + .get_config = etb_get_config, + .put_config = etb_put_config, + .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 2b94994d2c02..12af12f54173 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,29 @@ 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. + * @get_config: initialises perf's ring buffer for trace collection. + * @put_config: release memory allocated in @get_config. + * @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 *(*get_config)(struct coresight_device *csdev, int cpu, + void **pages, int nr_pages, bool overwrite); + void (*put_config)(void *config); + 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); }; /**