Received: by 10.223.185.116 with SMTP id b49csp1117724wrg; Wed, 14 Feb 2018 11:56:24 -0800 (PST) X-Google-Smtp-Source: AH8x2262GRNVOonTl2qoPOJBaTNktlsvv97Y89YnhPZg+uaXpraClyLsv3/IDDm9FbCNUX8mWzAF X-Received: by 10.99.47.132 with SMTP id v126mr120544pgv.129.1518638184386; Wed, 14 Feb 2018 11:56:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518638184; cv=none; d=google.com; s=arc-20160816; b=GiFlASYHI7LTI7WJ8sCvnE5+qoz1KF9nw+a43OHsG5UEDd6qzz8ygzEwKkLl+gvkwl NTaMkZSDavrRE3LO+jF1UpuSOrvHwaE9xlxgxUSBph34pd/OYg5saPJg4RyxP46SifhE Yh1YT6Xo4IJ+9/v2fsvJfg5BsIhFcxEgYqhifPVumO0/ndSLluF5whriQ5sIPf4lnIzf 6sKt/YOkltGc7bXkFUUXU/kflAWDXL5UsqHBzC2sgvPhPJtUc/ktQYX2mACsOAshcRuz kbsJSYyJoZ3eqwv1Hq+Q7CCd8r6KiSnydIuJr8YysCxajPnHNikntAP0/H0+NpRQHAcM QhDQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=q1OvUxsh7w48SYrLUh0b9Kavpt1MjEcBnnsdR0pol4Q=; b=H/QuVk+yspuWYtbmb07LwKmQduK1IMaFYCQsR0MG+3l+RYI6+fEQ8ot9hZSpJ4Vb9R gPJk1+XQT8UiU1fThb6mD/0aTJfOlSJbmzXyLw68LSfjhZPbMQfcjgkUF+FjlFfHzv/c nuleqeKsk6kXNzw6fAMUD4CdxMa8mBU/57cyMKKxRjH0Ok7cs3Vauos456TuLzOD1Vmf hkIAJ28LhSaSWHKfXaK1R/pcRSh1TOt/RAr9P8aiVGn7JV9f9IbUkVXSn4UTS85uyCRT BI9RCMIQuCg7wkptDMXg0bcoTRn57HPt+1WCdyS7HDAKlLGjqo20o6ITpVtKffzOgVKV dJNA== ARC-Authentication-Results: i=1; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l4-v6si185272plk.510.2018.02.14.11.56.09; Wed, 14 Feb 2018 11:56:24 -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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030738AbeBNOTV (ORCPT + 99 others); Wed, 14 Feb 2018 09:19:21 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:36162 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1030694AbeBNOTP (ORCPT ); Wed, 14 Feb 2018 09:19:15 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B43E940201A0; Wed, 14 Feb 2018 14:19:14 +0000 (UTC) Received: from localhost (ovpn-112-21.ams2.redhat.com [10.36.112.21]) by smtp.corp.redhat.com (Postfix) with ESMTP id 46C6621411B6; Wed, 14 Feb 2018 14:19:14 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: linux-kernel@vger.kernel.org Cc: bhe@redhat.com, slp@redhat.com, mst@redhat.com, somlo@cmu.edu, xiaolong.ye@intel.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [PATCH v14 8/9] fw_cfg: write vmcoreinfo details Date: Wed, 14 Feb 2018 15:18:49 +0100 Message-Id: <20180214141850.4017-9-marcandre.lureau@redhat.com> In-Reply-To: <20180214141850.4017-1-marcandre.lureau@redhat.com> References: <20180214141850.4017-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Wed, 14 Feb 2018 14:19:14 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Wed, 14 Feb 2018 14:19:14 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org If the "etc/vmcoreinfo" fw_cfg file is present and we are not running the kdump kernel, write the addr/size of the vmcoreinfo ELF note. The DMA operation is expected to run synchronously with today qemu, but the specification states that it may become async, so we run "control" field check in a loop for eventual changes. Signed-off-by: Marc-André Lureau --- drivers/firmware/qemu_fw_cfg.c | 144 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 37638b95cb45..69939e2529f2 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -34,11 +34,17 @@ #include #include #include +#include +#include +#include MODULE_AUTHOR("Gabriel L. Somlo "); MODULE_DESCRIPTION("QEMU fw_cfg sysfs support"); MODULE_LICENSE("GPL"); +/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */ +static u32 fw_cfg_rev; + /* fw_cfg device i/o register addresses */ static bool fw_cfg_is_mmio; static phys_addr_t fw_cfg_p_base; @@ -59,6 +65,65 @@ static inline u16 fw_cfg_sel_endianness(u16 key) (u16 __force)cpu_to_le16(key); } +static inline bool fw_cfg_dma_enabled(void) +{ + return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma; +} + +/* qemu fw_cfg device is sync today, but spec says it may become async */ +static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d) +{ + do { + u32 ctrl = be32_to_cpu(READ_ONCE(d->control)); + + if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0) + return; + + usleep_range(50, 100); + } while (true); + + /* do not reorder the read to d->control */ + rmb(); +} + +static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control) +{ + phys_addr_t dma; + struct fw_cfg_dma_access *d = NULL; + ssize_t ret = length; + + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto end; + } + + /* fw_cfg device does not need IOMMU protection, so use physical addresses */ + *d = (struct fw_cfg_dma_access) { + .address = cpu_to_be64(address ? virt_to_phys(address) : 0), + .length = cpu_to_be32(length), + .control = cpu_to_be32(control) + }; + + dma = virt_to_phys(d); + + iowrite32be((u64)dma >> 32, fw_cfg_reg_dma); + /* force memory to sync before notifying device via MMIO */ + wmb(); + iowrite32be(dma, fw_cfg_reg_dma + 4); + + fw_cfg_wait_for_control(d); + + if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) { + ret = -EIO; + } + +end: + kfree(d); + + return ret; +} + /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */ static inline void fw_cfg_read_blob(u16 key, void *buf, loff_t pos, size_t count) @@ -87,6 +152,47 @@ static inline void fw_cfg_read_blob(u16 key, acpi_release_global_lock(glk); } +#ifdef CONFIG_CRASH_CORE +/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */ +static ssize_t fw_cfg_write_blob(u16 key, + void *buf, loff_t pos, size_t count) +{ + u32 glk = -1U; + acpi_status status; + ssize_t ret = count; + + /* If we have ACPI, ensure mutual exclusion against any potential + * device access by the firmware, e.g. via AML methods: + */ + status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk); + if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) { + /* Should never get here */ + WARN(1, "%s: Failed to lock ACPI!\n", __func__); + return -EINVAL; + } + + mutex_lock(&fw_cfg_dev_lock); + if (pos == 0) { + ret = fw_cfg_dma_transfer(buf, count, key << 16 + | FW_CFG_DMA_CTL_SELECT + | FW_CFG_DMA_CTL_WRITE); + } else { + iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl); + ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP); + if (ret < 0) + goto end; + ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE); + } + +end: + mutex_unlock(&fw_cfg_dev_lock); + + acpi_release_global_lock(glk); + + return ret; +} +#endif /* CONFIG_CRASH_CORE */ + /* clean up fw_cfg device i/o */ static void fw_cfg_io_cleanup(void) { @@ -185,9 +291,6 @@ static int fw_cfg_do_platform_probe(struct platform_device *pdev) return 0; } -/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */ -static u32 fw_cfg_rev; - static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf) { return sprintf(buf, "%u\n", fw_cfg_rev); @@ -210,6 +313,32 @@ struct fw_cfg_sysfs_entry { struct list_head list; }; +#ifdef CONFIG_CRASH_CORE +static ssize_t fw_cfg_write_vmcoreinfo(const struct fw_cfg_file *f) +{ + static struct fw_cfg_vmcoreinfo *data; + ssize_t ret; + + data = kmalloc(sizeof(struct fw_cfg_vmcoreinfo), GFP_KERNEL); + if (!data) + return -ENOMEM; + + *data = (struct fw_cfg_vmcoreinfo) { + .guest_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF), + .size = cpu_to_le32(VMCOREINFO_NOTE_SIZE), + .paddr = cpu_to_le64(paddr_vmcoreinfo_note()) + }; + /* spare ourself reading host format support for now since we + * don't know what else to format - host may ignore ours + */ + ret = fw_cfg_write_blob(be16_to_cpu(f->select), data, + 0, sizeof(struct fw_cfg_vmcoreinfo)); + + kfree(data); + return ret; +} +#endif /* CONFIG_CRASH_CORE */ + /* get fw_cfg_sysfs_entry from kobject member */ static inline struct fw_cfg_sysfs_entry *to_entry(struct kobject *kobj) { @@ -450,6 +579,15 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f) int err; struct fw_cfg_sysfs_entry *entry; +#ifdef CONFIG_CRASH_CORE + if (fw_cfg_dma_enabled() && + strcmp(f->name, FW_CFG_VMCOREINFO_FILENAME) == 0 && + !is_kdump_kernel()) { + if (fw_cfg_write_vmcoreinfo(f) < 0) + pr_warn("fw_cfg: failed to write vmcoreinfo"); + } +#endif + /* allocate new entry */ entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) -- 2.16.1.73.g5832b7e9f2