Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/815484/?format=api
{ "id": 815484, "url": "http://patchwork.ozlabs.org/api/patches/815484/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20170919115814.14724-3-marcandre.lureau@redhat.com/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170919115814.14724-3-marcandre.lureau@redhat.com>", "list_archive_url": null, "date": "2017-09-19T11:58:12", "name": "[v2,2/4] fw_cfg: do DMA read operation", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "95de2f88507a8bf0768025e2b57ada08028dd86a", "submitter": { "id": 66774, "url": "http://patchwork.ozlabs.org/api/people/66774/?format=api", "name": "Marc-André Lureau", "email": "marcandre.lureau@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20170919115814.14724-3-marcandre.lureau@redhat.com/mbox/", "series": [ { "id": 3856, "url": "http://patchwork.ozlabs.org/api/series/3856/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=3856", "date": "2017-09-19T11:58:10", "name": "fw_cfg: add DMA operations & etc/vmcoreinfo support", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/3856/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/815484/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/815484/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)", "ext-mx03.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com", "ext-mx03.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=marcandre.lureau@redhat.com" ], "Received": [ "from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xxLzv1LbLz9s7m\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 19 Sep 2017 22:00:43 +1000 (AEST)", "from localhost ([::1]:42018 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1duHCj-000082-9O\n\tfor incoming@patchwork.ozlabs.org; Tue, 19 Sep 2017 08:00:41 -0400", "from eggs.gnu.org ([2001:4830:134:3::10]:40646)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <marcandre.lureau@redhat.com>) id 1duHAe-0007Ne-LX\n\tfor qemu-devel@nongnu.org; Tue, 19 Sep 2017 07:58:35 -0400", "from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <marcandre.lureau@redhat.com>) id 1duHAd-00020n-At\n\tfor qemu-devel@nongnu.org; Tue, 19 Sep 2017 07:58:32 -0400", "from mx1.redhat.com ([209.132.183.28]:38118)\n\tby eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <marcandre.lureau@redhat.com>)\n\tid 1duHAd-00020D-31\n\tfor qemu-devel@nongnu.org; Tue, 19 Sep 2017 07:58:31 -0400", "from smtp.corp.redhat.com\n\t(int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby mx1.redhat.com (Postfix) with ESMTPS id 1628D7F772;\n\tTue, 19 Sep 2017 11:58:30 +0000 (UTC)", "from localhost (ovpn-112-56.ams2.redhat.com [10.36.112.56])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id 0E8B95C541;\n\tTue, 19 Sep 2017 11:58:24 +0000 (UTC)" ], "DMARC-Filter": "OpenDMARC Filter v1.3.2 mx1.redhat.com 1628D7F772", "From": "marcandre.lureau@redhat.com", "To": "linux-kernel@vger.kernel.org", "Date": "Tue, 19 Sep 2017 13:58:12 +0200", "Message-Id": "<20170919115814.14724-3-marcandre.lureau@redhat.com>", "In-Reply-To": "<20170919115814.14724-1-marcandre.lureau@redhat.com>", "References": "<20170919115814.14724-1-marcandre.lureau@redhat.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.16", "X-Greylist": "Sender IP whitelisted, not delayed by milter-greylist-4.5.16\n\t(mx1.redhat.com [10.5.110.27]);\n\tTue, 19 Sep 2017 11:58:30 +0000 (UTC)", "Content-Transfer-Encoding": "quoted-printable", "X-detected-operating-system": "by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic]\n\t[fuzzy]", "X-Received-From": "209.132.183.28", "Subject": "[Qemu-devel] [PATCH v2 2/4] fw_cfg: do DMA read operation", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.21", "Precedence": "list", "List-Id": "<qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<http://lists.nongnu.org/archive/html/qemu-devel/>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Cc": "=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@redhat.com>,\n\tsomlo@cmu.edu, qemu-devel@nongnu.org, mst@redhat.com", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>" }, "content": "From: Marc-André Lureau <marcandre.lureau@redhat.com>\n\nModify fw_cfg_read_blob() to use DMA if the device supports it.\nReturn errors, because the operation may fail.\n\nThis is a proof-of-concept patch with some FIXME. It uses yield() to\nwait for the memory to be cleared. Help on how to improve this is\nwelcome.\n\nWe may also want to switch all the *buf addresses to use only\nkmalloc'ed buffer (instead of using stack/image addresses with\ndma=false).\n\nSigned-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>\n---\n drivers/firmware/qemu_fw_cfg.c | 132 +++++++++++++++++++++++++++++++++++------\n 1 file changed, 115 insertions(+), 17 deletions(-)", "diff": "diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c\nindex 614037703530..a0e24fdf3ae5 100644\n--- a/drivers/firmware/qemu_fw_cfg.c\n+++ b/drivers/firmware/qemu_fw_cfg.c\n@@ -33,6 +33,7 @@\n #include <linux/slab.h>\n #include <linux/io.h>\n #include <linux/ioport.h>\n+#include <linux/dma-mapping.h>\n \n MODULE_AUTHOR(\"Gabriel L. Somlo <somlo@cmu.edu>\");\n MODULE_DESCRIPTION(\"QEMU fw_cfg sysfs support\");\n@@ -43,12 +44,25 @@ MODULE_LICENSE(\"GPL\");\n #define FW_CFG_ID 0x01\n #define FW_CFG_FILE_DIR 0x19\n \n+#define FW_CFG_VERSION_DMA 0x02\n+#define FW_CFG_DMA_CTL_ERROR 0x01\n+#define FW_CFG_DMA_CTL_READ 0x02\n+#define FW_CFG_DMA_CTL_SKIP 0x04\n+#define FW_CFG_DMA_CTL_SELECT 0x08\n+#define FW_CFG_DMA_CTL_WRITE 0x10\n+\n /* size in bytes of fw_cfg signature */\n #define FW_CFG_SIG_SIZE 4\n \n /* fw_cfg \"file name\" is up to 56 characters (including terminating nul) */\n #define FW_CFG_MAX_FILE_PATH 56\n \n+/* platform device for dma mapping */\n+static struct device *dev;\n+\n+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */\n+static u32 fw_cfg_rev;\n+\n /* fw_cfg file directory entry type */\n struct fw_cfg_file {\n \tu32 size;\n@@ -57,6 +71,12 @@ struct fw_cfg_file {\n \tchar name[FW_CFG_MAX_FILE_PATH];\n };\n \n+struct fw_cfg_dma {\n+\tu32 control;\n+\tu32 length;\n+\tu64 address;\n+} __packed;\n+\n /* fw_cfg device i/o register addresses */\n static bool fw_cfg_is_mmio;\n static phys_addr_t fw_cfg_p_base;\n@@ -75,12 +95,73 @@ static inline u16 fw_cfg_sel_endianness(u16 key)\n \treturn fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);\n }\n \n+static inline bool fw_cfg_dma_enabled(void)\n+{\n+\treturn fw_cfg_rev & FW_CFG_VERSION_DMA && fw_cfg_reg_dma;\n+}\n+\n+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)\n+{\n+\tdma_addr_t dma_addr = 0;\n+\tstruct fw_cfg_dma *d;\n+\tdma_addr_t dma;\n+\tssize_t ret = length;\n+\tenum dma_data_direction dir =\n+\t\t(control & FW_CFG_DMA_CTL_READ ? DMA_FROM_DEVICE : 0);\n+\n+\tif (address && length) {\n+\t\tdma_addr = dma_map_single(dev, address, length, dir);\n+\t\tif (dma_mapping_error(NULL, dma_addr)) {\n+\t\t\tWARN(1, \"%s: failed to map address\\n\", __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\t}\n+\n+\td = kmalloc(sizeof(*d), GFP_KERNEL | GFP_DMA);\n+\tif (!d) {\n+\t\tret = -ENOMEM;\n+\t\tgoto end;\n+\t}\n+\n+\tdma = dma_map_single(dev, d, sizeof(*d), DMA_BIDIRECTIONAL);\n+\tif (dma_mapping_error(NULL, dma)) {\n+\t\tWARN(1, \"%s: failed to map fw_cfg_dma\\n\", __func__);\n+\t\tret = -EFAULT;\n+\t\tgoto end;\n+\t}\n+\n+\t*d = (struct fw_cfg_dma) {\n+\t\t.address = cpu_to_be64(dma_addr),\n+\t\t.length = cpu_to_be32(length),\n+\t\t.control = cpu_to_be32(control)\n+\t};\n+\n+\tiowrite32be(dma >> 32, fw_cfg_reg_dma);\n+\tiowrite32be(dma, fw_cfg_reg_dma + 4);\n+\twhile (be32_to_cpu(d->control) & ~FW_CFG_DMA_CTL_ERROR)\n+\t\tyield(); /* FIXME: wait_event? */\n+\n+\tif (be32_to_cpu(d->control) & FW_CFG_DMA_CTL_ERROR)\n+\t\tret = -EIO;\n+\n+\tdma_unmap_single(dev, dma, sizeof(*d), DMA_BIDIRECTIONAL);\n+\n+end:\n+\tkfree(d);\n+\tif (dma_addr)\n+\t\tdma_unmap_single(dev, dma_addr, length, dir);\n+\n+\treturn ret;\n+}\n+\n /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */\n-static inline void fw_cfg_read_blob(u16 key,\n-\t\t\t\t void *buf, loff_t pos, size_t count)\n+static ssize_t fw_cfg_read_blob(u16 key,\n+\t\t\t\tvoid *buf, loff_t pos, size_t count,\n+\t\t\t\tbool dma)\n {\n \tu32 glk = -1U;\n \tacpi_status status;\n+\tssize_t ret = count;\n \n \t/* If we have ACPI, ensure mutual exclusion against any potential\n \t * device access by the firmware, e.g. via AML methods:\n@@ -90,17 +171,36 @@ static inline void fw_cfg_read_blob(u16 key,\n \t\t/* Should never get here */\n \t\tWARN(1, \"fw_cfg_read_blob: Failed to lock ACPI!\\n\");\n \t\tmemset(buf, 0, count);\n-\t\treturn;\n+\t\treturn -EBUSY;\n \t}\n \n \tmutex_lock(&fw_cfg_dev_lock);\n-\tiowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);\n-\twhile (pos-- > 0)\n-\t\tioread8(fw_cfg_reg_data);\n-\tioread8_rep(fw_cfg_reg_data, buf, count);\n+\tif (dma && fw_cfg_dma_enabled()) {\n+\t\tif (pos == 0) {\n+\t\t\tret = fw_cfg_dma_transfer(buf, count, key << 16\n+\t\t\t\t\t\t | FW_CFG_DMA_CTL_SELECT\n+\t\t\t\t\t\t | FW_CFG_DMA_CTL_READ);\n+\t\t} else {\n+\t\t\tiowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);\n+\t\t\tret = fw_cfg_dma_transfer(0, pos, FW_CFG_DMA_CTL_SKIP);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto end;\n+\t\t\tret = fw_cfg_dma_transfer(buf, count,\n+\t\t\t\t\t\t FW_CFG_DMA_CTL_READ);\n+\t\t}\n+\t} else {\n+\t\tiowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);\n+\t\twhile (pos-- > 0)\n+\t\t\tioread8(fw_cfg_reg_data);\n+\t\tioread8_rep(fw_cfg_reg_data, buf, count);\n+\t}\n+\n+end:\n \tmutex_unlock(&fw_cfg_dev_lock);\n \n \tacpi_release_global_lock(glk);\n+\n+\treturn ret;\n }\n \n /* clean up fw_cfg device i/o */\n@@ -192,7 +292,7 @@ static int fw_cfg_do_platform_probe(struct platform_device *pdev)\n #endif\n \n \t/* verify fw_cfg device signature */\n-\tfw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);\n+\tfw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE, false);\n \tif (memcmp(sig, \"QEMU\", FW_CFG_SIG_SIZE) != 0) {\n \t\tfw_cfg_io_cleanup();\n \t\treturn -ENODEV;\n@@ -201,9 +301,6 @@ static int fw_cfg_do_platform_probe(struct platform_device *pdev)\n \treturn 0;\n }\n \n-/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */\n-static u32 fw_cfg_rev;\n-\n static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)\n {\n \treturn sprintf(buf, \"%u\\n\", fw_cfg_rev);\n@@ -351,8 +448,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, struct kobject *kobj,\n \tif (count > entry->f.size - pos)\n \t\tcount = entry->f.size - pos;\n \n-\tfw_cfg_read_blob(entry->f.select, buf, pos, count);\n-\treturn count;\n+\treturn fw_cfg_read_blob(entry->f.select, buf, pos, count, true);\n }\n \n static struct bin_attribute fw_cfg_sysfs_attr_raw = {\n@@ -505,7 +601,7 @@ static int fw_cfg_register_dir_entries(void)\n \tstruct fw_cfg_file *dir;\n \tsize_t dir_size;\n \n-\tfw_cfg_read_blob(FW_CFG_FILE_DIR, &count, 0, sizeof(count));\n+\tfw_cfg_read_blob(FW_CFG_FILE_DIR, &count, 0, sizeof(count), false);\n \tcount = be32_to_cpu(count);\n \tdir_size = count * sizeof(struct fw_cfg_file);\n \n@@ -513,7 +609,7 @@ static int fw_cfg_register_dir_entries(void)\n \tif (!dir)\n \t\treturn -ENOMEM;\n \n-\tfw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);\n+\tfw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size, true);\n \n \tfor (i = 0; i < count; i++) {\n \t\tdir[i].size = be32_to_cpu(dir[i].size);\n@@ -544,9 +640,10 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)\n \t * one fw_cfg device exist system-wide, so if one was already found\n \t * earlier, we might as well stop here.\n \t */\n-\tif (fw_cfg_sel_ko)\n+\tif (dev)\n \t\treturn -EBUSY;\n \n+\tdev = &pdev->dev;\n \t/* create by_key and by_name subdirs of /sys/firmware/qemu_fw_cfg/ */\n \terr = -ENOMEM;\n \tfw_cfg_sel_ko = kobject_create_and_add(\"by_key\", fw_cfg_top_ko);\n@@ -562,7 +659,7 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)\n \t\tgoto err_probe;\n \n \t/* get revision number, add matching top-level attribute */\n-\tfw_cfg_read_blob(FW_CFG_ID, &fw_cfg_rev, 0, sizeof(fw_cfg_rev));\n+\tfw_cfg_read_blob(FW_CFG_ID, &fw_cfg_rev, 0, sizeof(fw_cfg_rev), false);\n \tfw_cfg_rev = le32_to_cpu(fw_cfg_rev);\n \terr = sysfs_create_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr);\n \tif (err)\n@@ -587,6 +684,7 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)\n err_name:\n \tfw_cfg_kobj_cleanup(fw_cfg_sel_ko);\n err_sel:\n+\tdev = NULL;\n \treturn err;\n }\n \n", "prefixes": [ "v2", "2/4" ] }