From patchwork Fri Mar 30 03:15:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leo Yan X-Patchwork-Id: 132579 Delivered-To: patch@linaro.org Received: by 10.46.84.29 with SMTP id i29csp2530711ljb; Thu, 29 Mar 2018 20:16:10 -0700 (PDT) X-Google-Smtp-Source: AIpwx49OnRt8gPVVHHYioN4rCuOwncl1/nymDPLy47Oo7TxqUWH67IiOhi00AisExoBos5jTm0+D X-Received: by 2002:a17:902:a701:: with SMTP id w1-v6mr6541897plq.109.1522379770321; Thu, 29 Mar 2018 20:16:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522379770; cv=none; d=google.com; s=arc-20160816; b=ZR8E1Z2hWSoWUgt9fgeVmX4TLBFzcpYBHytgUklaZ2RJxuto6vXzolq12YQ6ygvebB iG407VCu2EdX2Mn0o+tQdXGyRWTBk7YI64cL2reqjVDxQzg42yFsIi4bLU1T7AyTb5/H C0bt+Dszahv1k/0kaYJJuZe2mB0SMHoSdrM/N5aFnDKMN5QQURO8hkmqKP5BosUpcb0b Y3dC6msDwf4Zu4vqIlGFYD9j0u425MycZaJowLWlvYjcBoofwrLi3WVSPAwqi5iYT56E r0wrkFk5aD9R6c4/qDtUzdf+CTznKKzwjvQUkK42hYc+9+43Jlk2oINnybK3IZUfKa6+ hxGg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=SC+Y9Dd4/hPslmxENYAISjheGeV9ItZkUbxFlXes27Q=; b=nJADB5h/BWRf7whpH6S+YIOUiYYuu+uBT7WC4kvWDLJxQYx1XwfzPPQnZT6QCJN5xx 4cq+Xu7lFOE08srkIuvNI7RNU0rQ/5ok5kPmukDiTW67gNUms1nIud6Kp2r///XsJW4+ jfo8EvcNmrOwyuAjgjGwNMDpgpQm0nPyLkevJmhgFpAJqhtVlk1O0TN3o1+aClfCPBxf mSzTtAiUobXXNYqwKNwqH4Ru0gdma8ODkF3YcxtZKUsBs4Xr7kfK7N1w8CFoM80GWvJV WkEoy+EkpGd/YBIPmuChwDzu1ttrCig1fWTvUOHWgZEwTP88gYgL9e8Os89Y6/g1m7em WP1Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Ez0z0TLi; 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 sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c15si4912599pgu.312.2018.03.29.20.16.10; Thu, 29 Mar 2018 20:16:10 -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 header.s=google header.b=Ez0z0TLi; 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 sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752799AbeC3DQI (ORCPT + 29 others); Thu, 29 Mar 2018 23:16:08 -0400 Received: from mail-wr0-f193.google.com ([209.85.128.193]:34285 "EHLO mail-wr0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752728AbeC3DQC (ORCPT ); Thu, 29 Mar 2018 23:16:02 -0400 Received: by mail-wr0-f193.google.com with SMTP id o8so6994449wra.1 for ; Thu, 29 Mar 2018 20:16:01 -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=SC+Y9Dd4/hPslmxENYAISjheGeV9ItZkUbxFlXes27Q=; b=Ez0z0TLimIW5/ySEPbsKJvIbpYuKaAjYJVSBS04vuM0HFFjc2OmbhT7YYE5XgSckXF P7Soi5whNISe77b45I7HidulQ8eUSlC1TvBdrvpysVoIkqvuw+H9qnEQtsuEthImEMcd NY7iFHyvNQgB1uLvYnCse0RDZbGNkUaRBAcWQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=SC+Y9Dd4/hPslmxENYAISjheGeV9ItZkUbxFlXes27Q=; b=Fsp20c1IUFI1/E9iKLnwSNwyFl61CWhq8eo16QY8dF6dtaDKXkil2Tr8Rbzl61dNi+ eXTpZXyr1pI4o6iIrK5QjSYEpVltGTwxehPL3a30JPy8iStTcO2lW+5kt3SajChPv4AT ntNRPrR/G8snW4Sbz6cM5tsYnjHrdnYCEB+DkalqnkzKGWxBwsJlt92xKpG0WKDpLFoD um4+V8EEawG5cEvst0fNUdvdshE7M1JLfy+MTiXun3psCA3FRJVQYfUgIvXEEwnKXlAd EStk30ggy1/CRD8eMArAbz9u4YMpRALAxG5/+2MqO+iUyx6H9/aMMDb7JjVz6reVyPWs 4pzw== X-Gm-Message-State: AElRT7HlnZDRfVMMVEGgMMapyBGFzB6I2NQI6j2KCqM16tXqemt5ifmQ DMkt1HW2aDHifNGqAEHWkYW6gg== X-Received: by 10.223.154.47 with SMTP id z44mr8040993wrb.239.1522379760693; Thu, 29 Mar 2018 20:16:00 -0700 (PDT) Received: from localhost.localdomain (li622-172.members.linode.com. [212.71.249.172]) by smtp.gmail.com with ESMTPSA id z9sm12798903wrz.4.2018.03.29.20.15.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 29 Mar 2018 20:15:59 -0700 (PDT) From: Leo Yan To: Jonathan Corbet , Mathieu Poirier , Greg Kroah-Hartman , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, coresight@lists.linaro.org, Kim Phillips , Mike Leach Cc: Leo Yan Subject: [PATCH v4 3/6] coresight: Support panic kdump functionality Date: Fri, 30 Mar 2018 11:15:21 +0800 Message-Id: <1522379724-30648-4-git-send-email-leo.yan@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1522379724-30648-1-git-send-email-leo.yan@linaro.org> References: <1522379724-30648-1-git-send-email-leo.yan@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org After kernel panic happens, Coresight tracing data has much useful info which can be used for analysis. For example, the trace info from ETB RAM can be used to check the CPU execution flows before the crash. So we can save the tracing data from sink devices, and rely on kdump to save DDR content and uses "crash" tool to extract Coresight dumping from the vmcore file. This patch is to add a simple framework to support panic dump functionality; it registers panic notifier, and provide the helper functions coresight_kdump_source()/coresight_kdump_sink() so Coresight source and sink devices can be recorded into Coresight kdump node for kernel panic kdump. When kernel panic happens, the notifier iterates dump array and invoke callback function to dump tracing data. Later the tracing data can be used to reverse execution flow before the kernel panic. Signed-off-by: Leo Yan --- drivers/hwtracing/coresight/Kconfig | 9 + drivers/hwtracing/coresight/Makefile | 1 + .../hwtracing/coresight/coresight-panic-kdump.c | 199 +++++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 12 ++ include/linux/coresight.h | 4 + 5 files changed, 225 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-panic-kdump.c -- 2.7.4 diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index ef9cb3c..3089abf 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -103,4 +103,13 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.txt for detailed description and the example for usage. +config CORESIGHT_PANIC_KDUMP + bool "CoreSight Panic Kdump driver" + depends on ARM || ARM64 + help + This driver provides panic kdump functionality for CoreSight devices. + When kernel panic happen Coresight device supplied callback function + is to dump trace data to memory. From then on, kdump can be used to + extract the trace data from kernel dump file. + endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 61db9dd..946fe19 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ obj-$(CONFIG_CORESIGHT_DYNAMIC_REPLICATOR) += coresight-dynamic-replicator.o obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o +obj-$(CONFIG_CORESIGHT_PANIC_KDUMP) += coresight-panic-kdump.o diff --git a/drivers/hwtracing/coresight/coresight-panic-kdump.c b/drivers/hwtracing/coresight/coresight-panic-kdump.c new file mode 100644 index 0000000..f4589e9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-panic-kdump.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017~2018 Linaro Limited. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coresight-priv.h" + +/** + * struct coresight_kdump_node - Node information for dump + * @source_csdev: Handler for source coresight device + * @sink_csdev: Handler for sink coresight device + */ +struct coresight_kdump_node { + struct coresight_device *source_csdev; + struct coresight_device *sink_csdev; +}; + +static DEFINE_SPINLOCK(coresight_kdump_lock); +static struct coresight_kdump_node *coresight_kdump_nodes; +static struct notifier_block coresight_kdump_nb; + +/** + * coresight_kdump_source - Set source dump info for specific CPU + * @cpu: CPU ID + * @csdev: Source device structure handler + * @data: Pointer for source device metadata buffer + * @data_sz: Size of source device metadata buffer + * + * This function is a helper function which is used to set/clear source device + * handler and metadata when the tracer is enabled; and it can be used to clear + * source device related info when the tracer is disabled. + * + * Returns: 0 on success, negative errno otherwise. + */ +int coresight_kdump_source(int cpu, struct coresight_device *csdev, + char *data, unsigned int data_sz) +{ + struct coresight_kdump_node *node; + unsigned long flags; + + if (!coresight_kdump_nodes) + return -EPROBE_DEFER; + + spin_lock_irqsave(&coresight_kdump_lock, flags); + + node = &coresight_kdump_nodes[cpu]; + node->source_csdev = csdev; + + csdev->kdump_buf = data; + csdev->kdump_buf_sz = data_sz; + + spin_unlock_irqrestore(&coresight_kdump_lock, flags); + return 0; +} + +/** + * coresight_kdump_sink - Set sink device handler for specific CPU + * @cpu: CPU ID + * @csdev: Sink device structure handler + * + * This function is a helper function which is used to set sink device handler + * when the Coresight path has been enabled for specific CPU; and it can be used + * to clear sink device handler when the path is disabled. + * + * Returns: 0 on success, negative errno otherwise. + */ +int coresight_kdump_sink(int cpu, struct coresight_device *csdev) +{ + struct coresight_kdump_node *node; + unsigned long flags; + + if (!coresight_kdump_nodes) + return -EPROBE_DEFER; + + spin_lock_irqsave(&coresight_kdump_lock, flags); + + node = &coresight_kdump_nodes[cpu]; + node->sink_csdev = csdev; + + spin_unlock_irqrestore(&coresight_kdump_lock, flags); + return 0; +} + +/** + * coresight_kdump_sink_cb - Invoke sink callback for specific CPU + * @cpu: CPU ID + * + * This function is to invoke sink device corresponding callback. It needs + * to check two cases: one case is the CPU has not been enabled for Coresight + * path so there totally has no trace data for the CPU, another case is the + * CPU shares the same sink device with other CPUs but the tracing data has + * been dumped by previous CPUs; it skips dump for these two cases. + */ +static void coresight_kdump_sink_cb(int cpu) +{ + struct coresight_kdump_node *node; + struct coresight_device *csdev; + unsigned long flags; + + spin_lock_irqsave(&coresight_kdump_lock, flags); + + node = &coresight_kdump_nodes[cpu]; + csdev = node->sink_csdev; + + /* Path has not been enabled */ + if (!csdev) + goto skip_dump; + + /* Have been dumped by previous CPU */ + if (csdev->kdump_buf) + goto skip_dump; + + /* Invoke panic callback */ + csdev = coresight_kdump_nodes[cpu].sink_csdev; + if (csdev && sink_ops(csdev)->panic_cb) + sink_ops(csdev)->panic_cb(csdev); + +skip_dump: + spin_unlock_irqrestore(&coresight_kdump_lock, flags); +} + +/** + * coresight_kdump_notify - Invoke panic dump callbacks + * @nb: Pointer to notifier block + * @event: Notification reason + * @_unused: Pointer to notification data object, unused + * + * This function is called when panic happens to invoke dump callbacks, it takes + * panic CPU tracing data with high priority to firstly invoke panic CPU sink + * callback function, then the notifier iterates callback functions one by one + * for other CPUs. If one sink device is shared among CPUs, the sink panic + * callback is invoked for the first traversed CPU node and other sequential + * CPUs are skipped. + * + * Returns: 0 on success. + */ +static int coresight_kdump_notify(struct notifier_block *nb, + unsigned long event, void *_unused) +{ + int cpu, first; + + /* Give panic CPU trace data with high priority */ + first = atomic_read(&panic_cpu); + coresight_kdump_sink_cb(first); + + /* Dump rest CPUs trace data */ + for (cpu = 0; cpu < num_possible_cpus(); cpu++) { + if (cpu == first) + continue; + + coresight_kdump_sink_cb(cpu); + } + + return 0; +} + +/** + * coresight_kdump_init - Coresight kdump module initialization + * + * This function allcoates dump array and register panic norifier. + * + * Returns: 0 on success, negative errno otherwise. + */ +static int __init coresight_kdump_init(void) +{ + int ret; + + coresight_kdump_nodes = kmalloc_array(num_possible_cpus(), + sizeof(*coresight_kdump_nodes), + GFP_KERNEL); + if (!coresight_kdump_nodes) { + pr_err("%s: kmalloc failed\n", __func__); + return -ENOMEM; + } + + memset(coresight_kdump_nodes, 0, + num_possible_cpus() * sizeof(*coresight_kdump_nodes)); + + coresight_kdump_nb.notifier_call = coresight_kdump_notify; + ret = atomic_notifier_chain_register(&panic_notifier_list, + &coresight_kdump_nb); + if (ret) { + pr_err("%s: unable to register notifier: %d\n", + __func__, ret); + kfree(coresight_kdump_nodes); + return ret; + } + + return 0; +} +postcore_initcall(coresight_kdump_init); diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index f1d0e21d..76d27d6 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -151,4 +151,16 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif +#ifdef CONFIG_CORESIGHT_PANIC_KDUMP +extern int coresight_kdump_source(int cpu, struct coresight_device *csdev, + char *data, unsigned int data_sz); +extern int coresight_kdump_sink(int cpu, struct coresight_device *csdev); +#else +static inline int coresight_kdump_source(int cpu, + struct coresight_device *csdev, + char *data, unsigned int data_sz) { return 0; } +static inline void coresight_kdump_sink(int cpu, + struct coresight_device *csdev) { return 0; } +#endif + #endif diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d950dad..89aad8d 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -171,6 +171,8 @@ struct coresight_device { bool orphan; bool enable; /* true only if configured as part of a path */ bool activated; /* true only if a sink is part of a path */ + char *kdump_buf; + unsigned int kdump_buf_sz; }; #define to_coresight_device(d) container_of(d, struct coresight_device, dev) @@ -189,6 +191,7 @@ struct coresight_device { * @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. + * @panic_cb: hook function for panic notifier. */ struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, u32 mode); @@ -205,6 +208,7 @@ struct coresight_ops_sink { void (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config); + void (*panic_cb)(void *data); }; /**