2018-09-14 17:52:07

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 01/21] platform: goldfish: pipe: Remove license boilerplate

From: Roman Kiryanov <[email protected]>

The boilerplate license is not necessary when the SPDX line is
present.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe_qemu.h | 14 --------------
1 file changed, 14 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe_qemu.h b/drivers/platform/goldfish/goldfish_pipe_qemu.h
index c272e11c5433..b4d78c108afd 100644
--- a/drivers/platform/goldfish/goldfish_pipe_qemu.h
+++ b/drivers/platform/goldfish/goldfish_pipe_qemu.h
@@ -1,18 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2018 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
/*
* IMPORTANT: The following constants must match the ones used and defined in
* external/qemu/include/hw/misc/goldfish_pipe.h
--
2.19.0.397.gdd90340f6a-goog



2018-09-14 17:52:18

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 02/21] platform: goldfish: pipe: Prevent memory corruption from several threads writing to the same variable

From: Roman Kiryanov <[email protected]>

Move the "pages" buffer into "struct goldfish_pipe". Since we are
locking the mutex on the pipe in transfer_max_buffers, other threads
willnot be able to write into it, but other pipe instances could be
served because they have its own buffer.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 24 +++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index b4a484bbcdaa..6ae2b00f4bff 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -163,6 +163,9 @@ struct goldfish_pipe {

/* Pointer to the parent goldfish_pipe_dev instance */
struct goldfish_pipe_dev *dev;
+
+ /* A buffer of pages, too large to fit into a stack frame */
+ struct page *pages[MAX_BUFFERS_PER_COMMAND];
};

/* The global driver data. Holds a reference to the i/o page used to
@@ -340,21 +343,23 @@ static int transfer_max_buffers(struct goldfish_pipe *pipe,
s32 *consumed_size,
int *status)
{
- static struct page *pages[MAX_BUFFERS_PER_COMMAND];
unsigned long first_page = address & PAGE_MASK;
unsigned int iter_last_page_size;
- int pages_count = pin_user_pages(first_page, last_page,
- last_page_size, is_write,
- pages, &iter_last_page_size);
-
- if (pages_count < 0)
- return pages_count;
+ int pages_count;

/* Serialize access to the pipe command buffers */
if (mutex_lock_interruptible(&pipe->lock))
return -ERESTARTSYS;

- populate_rw_params(pages, pages_count, address, address_end,
+ pages_count = pin_user_pages(first_page, last_page,
+ last_page_size, is_write,
+ pipe->pages, &iter_last_page_size);
+ if (pages_count < 0) {
+ mutex_unlock(&pipe->lock);
+ return pages_count;
+ }
+
+ populate_rw_params(pipe->pages, pages_count, address, address_end,
first_page, last_page, iter_last_page_size, is_write,
pipe->command_buffer);

@@ -364,10 +369,9 @@ static int transfer_max_buffers(struct goldfish_pipe *pipe,

*consumed_size = pipe->command_buffer->rw_params.consumed_size;

- release_user_pages(pages, pages_count, is_write, *consumed_size);
+ release_user_pages(pipe->pages, pages_count, is_write, *consumed_size);

mutex_unlock(&pipe->lock);
-
return 0;
}

--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:52:27

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 03/21] platform: goldfish: pipe: Remove a redundant blank line

From: Roman Kiryanov <[email protected]>

The blank line is not required there.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 6ae2b00f4bff..8747ec330b7b 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -47,7 +47,6 @@
* exchange is properly mapped during a transfer.
*/

-
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:52:37

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 04/21] platform: goldfish: pipe: Remove redundant struct declarations

From: Roman Kiryanov <[email protected]>

goldfish_pipe_command is defines just after declaration and
nothing refers to goldfish_pipe before it is defined.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 8747ec330b7b..6b21671c75ee 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -82,8 +82,6 @@ enum {
};

struct goldfish_pipe_dev;
-struct goldfish_pipe;
-struct goldfish_pipe_command;

/* A per-pipe command structure, shared with the host */
struct goldfish_pipe_command {
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:52:45

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 05/21] platform: goldfish: pipe: Remove redundant header include

From: Roman Kiryanov <[email protected]>

No symbols were used from this header.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 6b21671c75ee..fe01ef88ddfb 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -59,7 +59,6 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/goldfish.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/acpi.h>
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:52:55

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 06/21] platform: goldfish: pipe: Add DMA support to goldfish pipe

From: Roman Kiryanov <[email protected]>

Goldfish DMA is an extension to the pipe device and is designed
to facilitate high-speed RAM->RAM transfers from guest to host.

See uapi/linux/goldfish/goldfish_dma.h for more details.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 312 +++++++++++++++++-
.../platform/goldfish/goldfish_pipe_qemu.h | 2 +
include/uapi/linux/goldfish/goldfish_dma.h | 84 +++++
3 files changed, 396 insertions(+), 2 deletions(-)
create mode 100644 include/uapi/linux/goldfish/goldfish_dma.h

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index fe01ef88ddfb..064a50a7f187 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -63,21 +63,28 @@
#include <linux/mm.h>
#include <linux/acpi.h>
#include <linux/bug.h>
+#include <uapi/linux/goldfish/goldfish_dma.h>
#include "goldfish_pipe_qemu.h"

/*
* Update this when something changes in the driver's behavior so the host
* can benefit from knowing it
+ * Notes:
+ * version 2 was an intermediate release and isn't supported anymore.
+ * version 3 is goldfish_pipe_v2 without DMA support.
+ * version 4 (current) is goldfish_pipe_v2 with DMA support.
*/
enum {
- PIPE_DRIVER_VERSION = 2,
+ PIPE_DRIVER_VERSION = 4,
PIPE_CURRENT_DEVICE_VERSION = 2
};

enum {
MAX_BUFFERS_PER_COMMAND = 336,
MAX_SIGNALLED_PIPES = 64,
- INITIAL_PIPES_CAPACITY = 64
+ INITIAL_PIPES_CAPACITY = 64,
+ DMA_REGION_MIN_SIZE = PAGE_SIZE,
+ DMA_REGION_MAX_SIZE = 256 << 20
};

struct goldfish_pipe_dev;
@@ -100,6 +107,11 @@ struct goldfish_pipe_command {
/* buffer sizes, guest -> host */
u32 sizes[MAX_BUFFERS_PER_COMMAND];
} rw_params;
+ /* Parameters for PIPE_CMD_DMA_HOST_(UN)MAP */
+ struct {
+ u64 dma_paddr;
+ u64 sz;
+ } dma_maphost_params;
};
};

@@ -122,6 +134,24 @@ struct goldfish_pipe_dev_buffers {
signalled_pipe_buffers[MAX_SIGNALLED_PIPES];
};

+/*
+ * The main data structure tracking state is
+ * struct goldfish_dma_context, which is included
+ * as an extra pointer field in struct goldfish_pipe.
+ * Each such context is associated with possibly
+ * one physical address and size describing the
+ * allocated DMA region, and only one allocation
+ * is allowed for each pipe fd. Further allocations
+ * require more open()'s of pipe fd's.
+ */
+struct goldfish_dma_context {
+ struct device *pdev_dev; /* pointer to feed to dma_*_coherent */
+ void *dma_vaddr; /* kernel vaddr of dma region */
+ size_t dma_size; /* size of dma region */
+ dma_addr_t phys_begin; /* paddr of dma region */
+ dma_addr_t phys_end; /* paddr of dma region + dma_size */
+};
+
/* This data type models a given pipe instance */
struct goldfish_pipe {
/* pipe ID - index into goldfish_pipe_dev::pipes array */
@@ -162,6 +192,9 @@ struct goldfish_pipe {

/* A buffer of pages, too large to fit into a stack frame */
struct page *pages[MAX_BUFFERS_PER_COMMAND];
+
+ /* Holds information about reserved DMA region for this pipe */
+ struct goldfish_dma_context *dma;
};

/* The global driver data. Holds a reference to the i/o page used to
@@ -208,6 +241,9 @@ struct goldfish_pipe_dev {
int irq;
int version;
unsigned char __iomem *base;
+
+ /* DMA info */
+ size_t dma_alloc_total;
};

struct goldfish_pipe_dev goldfish_pipe_dev;
@@ -739,6 +775,8 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file)
spin_unlock_irqrestore(&dev->lock, flags);
if (status < 0)
goto err_cmd;
+ pipe->dma = NULL;
+
/* All is done, save the pipe into the file's private data field */
file->private_data = pipe;
return 0;
@@ -754,6 +792,40 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file)
return status;
}

+static void goldfish_pipe_dma_release_host(struct goldfish_pipe *pipe)
+{
+ struct goldfish_dma_context *dma = pipe->dma;
+ struct device *pdev_dev;
+
+ if (!dma)
+ return;
+
+ pdev_dev = pipe->dev->pdev_dev;
+
+ if (dma->dma_vaddr) {
+ pipe->command_buffer->dma_maphost_params.dma_paddr =
+ dma->phys_begin;
+ pipe->command_buffer->dma_maphost_params.sz = dma->dma_size;
+ goldfish_pipe_cmd(pipe, PIPE_CMD_DMA_HOST_UNMAP);
+ }
+}
+
+static void goldfish_pipe_dma_release_guest(struct goldfish_pipe *pipe)
+{
+ struct goldfish_dma_context *dma = pipe->dma;
+
+ if (!dma)
+ return;
+
+ if (dma->dma_vaddr) {
+ dma_free_coherent(dma->pdev_dev,
+ dma->dma_size,
+ dma->dma_vaddr,
+ dma->phys_begin);
+ pipe->dev->dma_alloc_total -= dma->dma_size;
+ }
+}
+
static int goldfish_pipe_release(struct inode *inode, struct file *filp)
{
unsigned long flags;
@@ -761,6 +833,7 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp)
struct goldfish_pipe_dev *dev = pipe->dev;

/* The guest is closing the channel, so tell the emulator right now */
+ goldfish_pipe_dma_release_host(pipe);
goldfish_pipe_cmd(pipe, PIPE_CMD_CLOSE);

spin_lock_irqsave(&dev->lock, flags);
@@ -769,11 +842,242 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp)
spin_unlock_irqrestore(&dev->lock, flags);

filp->private_data = NULL;
+
+ /* Even if a fd is duped or involved in a forked process,
+ * open/release methods are called only once, ever.
+ * This makes goldfish_pipe_release a safe point
+ * to delete the DMA region.
+ */
+ goldfish_pipe_dma_release_guest(pipe);
+
+ kfree(pipe->dma);
free_page((unsigned long)pipe->command_buffer);
kfree(pipe);
+
return 0;
}

+/* VMA open/close are for debugging purposes only.
+ * One might think that fork() (and thus pure calls to open())
+ * will require some sort of bookkeeping or refcounting
+ * for dma contexts (incl. when to call dma_free_coherent),
+ * but |vm_private_data| field and |vma_open/close| are only
+ * for situations where the driver needs to interact with vma's
+ * directly with its own per-VMA data structure (which does
+ * need to be refcounted).
+ *
+ * Here, we just use the kernel's existing
+ * VMA processing; we don't do anything on our own.
+ * The only reason we would want to do so is if we had to do
+ * special processing for the virtual (not physical) memory
+ * already associated with DMA memory; it is much less related
+ * to the task of knowing when to alloc/dealloc DMA memory.
+ */
+static void goldfish_dma_vma_open(struct vm_area_struct *vma)
+{
+ /* Not used */
+}
+
+static void goldfish_dma_vma_close(struct vm_area_struct *vma)
+{
+ /* Not used */
+}
+
+static const struct vm_operations_struct goldfish_dma_vm_ops = {
+ .open = goldfish_dma_vma_open,
+ .close = goldfish_dma_vma_close,
+};
+
+static bool is_page_size_multiple(unsigned long sz)
+{
+ return !(sz & (PAGE_SIZE - 1));
+}
+
+static bool check_region_size_valid(size_t size)
+{
+ if (size < DMA_REGION_MIN_SIZE)
+ return false;
+
+ if (size > DMA_REGION_MAX_SIZE)
+ return false;
+
+ return is_page_size_multiple(size);
+}
+
+static int goldfish_pipe_dma_alloc_locked(struct goldfish_pipe *pipe)
+{
+ struct goldfish_dma_context *dma = pipe->dma;
+
+ if (dma->dma_vaddr)
+ return 0;
+
+ dma->phys_begin = 0;
+ dma->dma_vaddr = dma_alloc_coherent(dma->pdev_dev,
+ dma->dma_size,
+ &dma->phys_begin,
+ GFP_KERNEL);
+ if (!dma->dma_vaddr)
+ return -ENOMEM;
+ dma->phys_end = dma->phys_begin + dma->dma_size;
+ pipe->dev->dma_alloc_total += dma->dma_size;
+ pipe->command_buffer->dma_maphost_params.dma_paddr = dma->phys_begin;
+ pipe->command_buffer->dma_maphost_params.sz = dma->dma_size;
+ return goldfish_pipe_cmd_locked(pipe, PIPE_CMD_DMA_HOST_MAP);
+}
+
+static int goldfish_dma_mmap_locked(struct goldfish_pipe *pipe,
+ struct vm_area_struct *vma)
+{
+ struct goldfish_dma_context *dma = pipe->dma;
+ struct device *pdev_dev = pipe->dev->pdev_dev;
+ size_t sz_requested = vma->vm_end - vma->vm_start;
+ int status;
+
+ if (!check_region_size_valid(sz_requested)) {
+ dev_err(pdev_dev, "%s: bad size (%zu) requested\n", __func__,
+ sz_requested);
+ return -EINVAL;
+ }
+
+ /* Alloc phys region if not allocated already. */
+ status = goldfish_pipe_dma_alloc_locked(pipe);
+ if (status)
+ return status;
+
+ status = remap_pfn_range(vma,
+ vma->vm_start,
+ dma->phys_begin >> PAGE_SHIFT,
+ sz_requested,
+ vma->vm_page_prot);
+ if (status < 0) {
+ dev_err(pdev_dev, "Cannot remap pfn range....\n");
+ return -EAGAIN;
+ }
+ vma->vm_ops = &goldfish_dma_vm_ops;
+ return 0;
+}
+
+/* When we call mmap() on a pipe fd, we obtain a pointer into
+ * the physically contiguous DMA region of the pipe device
+ * (Goldfish DMA).
+ */
+static int goldfish_dma_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct goldfish_pipe *pipe =
+ (struct goldfish_pipe *)(filp->private_data);
+ int status;
+
+ if (mutex_lock_interruptible(&pipe->lock))
+ return -ERESTARTSYS;
+
+ status = goldfish_dma_mmap_locked(pipe, vma);
+ mutex_unlock(&pipe->lock);
+ return status;
+}
+
+static int goldfish_pipe_dma_create_region(struct goldfish_pipe *pipe,
+ size_t size)
+{
+ struct goldfish_dma_context *dma =
+ kzalloc(sizeof(struct goldfish_dma_context), GFP_KERNEL);
+ struct device *pdev_dev = pipe->dev->pdev_dev;
+
+ if (dma) {
+ if (mutex_lock_interruptible(&pipe->lock)) {
+ kfree(dma);
+ return -ERESTARTSYS;
+ }
+
+ if (pipe->dma) {
+ mutex_unlock(&pipe->lock);
+ kfree(dma);
+ dev_err(pdev_dev, "The DMA region already allocated\n");
+ return -EBUSY;
+ }
+
+ dma->dma_size = size;
+ dma->pdev_dev = pipe->dev->pdev_dev;
+ pipe->dma = dma;
+ mutex_unlock(&pipe->lock);
+ return 0;
+ }
+
+ dev_err(pdev_dev, "Could not allocate DMA context info!\n");
+ return -ENOMEM;
+}
+
+static long goldfish_dma_ioctl_getoff(struct goldfish_pipe *pipe,
+ unsigned long arg)
+{
+ struct device *pdev_dev = pipe->dev->pdev_dev;
+ struct goldfish_dma_ioctl_info ioctl_data;
+ struct goldfish_dma_context *dma;
+
+ BUILD_BUG_ON(FIELD_SIZEOF(struct goldfish_dma_ioctl_info, phys_begin) <
+ FIELD_SIZEOF(struct goldfish_dma_context, phys_begin));
+
+ if (mutex_lock_interruptible(&pipe->lock)) {
+ dev_err(pdev_dev, "DMA_GETOFF: the pipe is not locked\n");
+ return -EACCES;
+ }
+
+ dma = pipe->dma;
+ if (dma) {
+ ioctl_data.phys_begin = dma->phys_begin;
+ ioctl_data.size = dma->dma_size;
+ } else {
+ ioctl_data.phys_begin = 0;
+ ioctl_data.size = 0;
+ }
+
+ if (copy_to_user((void __user *)arg, &ioctl_data,
+ sizeof(ioctl_data))) {
+ mutex_unlock(&pipe->lock);
+ return -EFAULT;
+ }
+
+ mutex_unlock(&pipe->lock);
+ return 0;
+}
+
+static long goldfish_dma_ioctl_create_region(struct goldfish_pipe *pipe,
+ unsigned long arg)
+{
+ struct goldfish_dma_ioctl_info ioctl_data;
+
+ if (copy_from_user(&ioctl_data, (void __user *)arg, sizeof(ioctl_data)))
+ return -EFAULT;
+
+ if (!check_region_size_valid(ioctl_data.size)) {
+ dev_err(pipe->dev->pdev_dev,
+ "DMA_CREATE_REGION: bad size (%lld) requested\n",
+ ioctl_data.size);
+ return -EINVAL;
+ }
+
+ return goldfish_pipe_dma_create_region(pipe, ioctl_data.size);
+}
+
+static long goldfish_dma_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct goldfish_pipe *pipe =
+ (struct goldfish_pipe *)(file->private_data);
+
+ switch (cmd) {
+ case GOLDFISH_DMA_IOC_LOCK:
+ return 0;
+ case GOLDFISH_DMA_IOC_UNLOCK:
+ wake_up_interruptible(&pipe->wake_queue);
+ return 0;
+ case GOLDFISH_DMA_IOC_GETOFF:
+ return goldfish_dma_ioctl_getoff(pipe, arg);
+ case GOLDFISH_DMA_IOC_CREATE_REGION:
+ return goldfish_dma_ioctl_create_region(pipe, arg);
+ }
+ return -ENOTTY;
+}
+
static const struct file_operations goldfish_pipe_fops = {
.owner = THIS_MODULE,
.read = goldfish_pipe_read,
@@ -781,6 +1085,10 @@ static const struct file_operations goldfish_pipe_fops = {
.poll = goldfish_pipe_poll,
.open = goldfish_pipe_open,
.release = goldfish_pipe_release,
+ /* DMA-related operations */
+ .mmap = goldfish_dma_mmap,
+ .unlocked_ioctl = goldfish_dma_ioctl,
+ .compat_ioctl = goldfish_dma_ioctl,
};

static struct miscdevice goldfish_pipe_miscdev = {
diff --git a/drivers/platform/goldfish/goldfish_pipe_qemu.h b/drivers/platform/goldfish/goldfish_pipe_qemu.h
index b4d78c108afd..0ffc51dba54c 100644
--- a/drivers/platform/goldfish/goldfish_pipe_qemu.h
+++ b/drivers/platform/goldfish/goldfish_pipe_qemu.h
@@ -93,6 +93,8 @@ enum PipeCmdCode {
* parallel processing of pipe operations on the host.
*/
PIPE_CMD_WAKE_ON_DONE_IO,
+ PIPE_CMD_DMA_HOST_MAP,
+ PIPE_CMD_DMA_HOST_UNMAP,
};

#endif /* GOLDFISH_PIPE_QEMU_H */
diff --git a/include/uapi/linux/goldfish/goldfish_dma.h b/include/uapi/linux/goldfish/goldfish_dma.h
new file mode 100644
index 000000000000..a9019023a5bf
--- /dev/null
+++ b/include/uapi/linux/goldfish/goldfish_dma.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef UAPI_GOLDFISH_DMA_H
+#define UAPI_GOLDFISH_DMA_H
+
+#include <linux/types.h>
+
+/* GOLDFISH DMA
+ *
+ * Goldfish DMA is an extension to the pipe device
+ * and is designed to facilitate high-speed RAM->RAM
+ * transfers from guest to host.
+ *
+ * Interface (guest side):
+ *
+ * The guest user calls goldfish_dma_alloc (ioctls)
+ * and then mmap() on a goldfish pipe fd,
+ * which means that it wants high-speed access to
+ * host-visible memory.
+ *
+ * The guest can then write into the pointer
+ * returned by mmap(), and these writes
+ * become immediately visible on the host without BQL
+ * or otherweise context switching.
+ *
+ * dma_alloc_coherent() is used to obtain contiguous
+ * physical memory regions, and we allocate and interact
+ * with this region on both guest and host through
+ * the following ioctls:
+ *
+ * - LOCK: lock the region for data access.
+ * - UNLOCK: unlock the region. This may also be done from the host
+ * through the WAKE_ON_UNLOCK_DMA procedure.
+ * - CREATE_REGION: initialize size info for a dma region.
+ * - GETOFF: send physical address to guest drivers.
+ * - (UN)MAPHOST: uses goldfish_pipe_cmd to tell the host to
+ * (un)map to the guest physical address associated
+ * with the current dma context. This makes the physically
+ * contiguous memory (in)visible to the host.
+ *
+ * Guest userspace obtains a pointer to the DMA memory
+ * through mmap(), which also lazily allocates the memory
+ * with dma_alloc_coherent. (On last pipe close(), the region is freed).
+ * The mmaped() region can handle very high bandwidth
+ * transfers, and pipe operations can be used at the same
+ * time to handle synchronization and command communication.
+ */
+
+#define GOLDFISH_DMA_BUFFER_SIZE (32 * 1024 * 1024)
+
+struct goldfish_dma_ioctl_info {
+ __u64 phys_begin;
+ __u64 size;
+};
+
+/* There is an ioctl associated with goldfish dma driver.
+ * Make it conflict with ioctls that are not likely to be used
+ * in the emulator.
+ * 'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict!
+ * 'G' 00-0F linux/gigaset_dev.h conflict!
+ */
+#define GOLDFISH_DMA_IOC_MAGIC 'G'
+#define GOLDFISH_DMA_IOC_OP(OP) _IOWR(GOLDFISH_DMA_IOC_MAGIC, OP, \
+ struct goldfish_dma_ioctl_info)
+
+#define GOLDFISH_DMA_IOC_LOCK GOLDFISH_DMA_IOC_OP(0)
+#define GOLDFISH_DMA_IOC_UNLOCK GOLDFISH_DMA_IOC_OP(1)
+#define GOLDFISH_DMA_IOC_GETOFF GOLDFISH_DMA_IOC_OP(2)
+#define GOLDFISH_DMA_IOC_CREATE_REGION GOLDFISH_DMA_IOC_OP(3)
+
+#endif /* UAPI_GOLDFISH_DMA_H */
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:53:04

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 07/21] platform: goldfish: pipe: Remove the goldfish_interrupt_tasklet global variable

From: Roman Kiryanov <[email protected]>

This is a series of patches to remove mutable global variables
to introduce another version of the pipe driver for the older
host interface. I don't want to have two driver states where only
one is used.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 24 +++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 064a50a7f187..8a5ce7c01f11 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -242,6 +242,9 @@ struct goldfish_pipe_dev {
int version;
unsigned char __iomem *base;

+ /* an irq tasklet to run goldfish_interrupt_task */
+ struct tasklet_struct irq_tasklet;
+
/* DMA info */
size_t dma_alloc_total;
};
@@ -618,14 +621,14 @@ static struct goldfish_pipe *signalled_pipes_pop_front(
return pipe;
}

-static void goldfish_interrupt_task(unsigned long unused)
+static void goldfish_interrupt_task(unsigned long dev_addr)
{
/* Iterate over the signalled pipes and wake them one by one */
+ struct goldfish_pipe_dev *dev = (struct goldfish_pipe_dev *)dev_addr;
struct goldfish_pipe *pipe;
int wakes;

- while ((pipe = signalled_pipes_pop_front(&goldfish_pipe_dev, &wakes)) !=
- NULL) {
+ while ((pipe = signalled_pipes_pop_front(dev, &wakes)) != NULL) {
if (wakes & PIPE_WAKE_CLOSED) {
pipe->flags = 1 << BIT_CLOSED_ON_HOST;
} else {
@@ -641,7 +644,6 @@ static void goldfish_interrupt_task(unsigned long unused)
wake_up_interruptible(&pipe->wake_queue);
}
}
-static DECLARE_TASKLET(goldfish_interrupt_tasklet, goldfish_interrupt_task, 0);

/*
* The general idea of the interrupt handling:
@@ -684,7 +686,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)

spin_unlock_irqrestore(&dev->lock, flags);

- tasklet_schedule(&goldfish_interrupt_tasklet);
+ tasklet_schedule(&dev->irq_tasklet);
return IRQ_HANDLED;
}

@@ -1108,9 +1110,14 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
static int goldfish_pipe_device_init(struct platform_device *pdev)
{
struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
- int err = devm_request_irq(&pdev->dev, dev->irq,
- goldfish_pipe_interrupt,
- IRQF_SHARED, "goldfish_pipe", dev);
+ int err;
+
+ tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task,
+ (unsigned long)dev);
+
+ err = devm_request_irq(&pdev->dev, dev->irq,
+ goldfish_pipe_interrupt,
+ IRQF_SHARED, "goldfish_pipe", dev);
if (err) {
dev_err(&pdev->dev, "unable to allocate IRQ for v2\n");
return err;
@@ -1162,6 +1169,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
static void goldfish_pipe_device_deinit(struct platform_device *pdev)
{
misc_deregister(&goldfish_pipe_miscdev);
+ tasklet_kill(&goldfish_pipe_dev.irq_tasklet);
kfree(goldfish_pipe_dev.pipes);
free_page((unsigned long)goldfish_pipe_dev.buffers);
}
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:53:12

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 08/21] platform: goldfish: pipe: Remove the goldfish_pipe_miscdev global variable

From: Roman Kiryanov <[email protected]>

This is a series of patches to remove mutable global variables
to introduce another version of the pipe driver for the older
host interface. I don't want to have two driver states where
only one is used.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 8a5ce7c01f11..53832e46ad1a 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -245,6 +245,8 @@ struct goldfish_pipe_dev {
/* an irq tasklet to run goldfish_interrupt_task */
struct tasklet_struct irq_tasklet;

+ struct miscdevice miscdev;
+
/* DMA info */
size_t dma_alloc_total;
};
@@ -1093,11 +1095,14 @@ static const struct file_operations goldfish_pipe_fops = {
.compat_ioctl = goldfish_dma_ioctl,
};

-static struct miscdevice goldfish_pipe_miscdev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "goldfish_pipe",
- .fops = &goldfish_pipe_fops,
-};
+static void init_miscdevice(struct miscdevice *miscdev)
+{
+ memset(miscdev, 0, sizeof(*miscdev));
+
+ miscdev->minor = MISC_DYNAMIC_MINOR;
+ miscdev->name = "goldfish_pipe";
+ miscdev->fops = &goldfish_pipe_fops;
+}

static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
{
@@ -1123,7 +1128,8 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
return err;
}

- err = misc_register(&goldfish_pipe_miscdev);
+ init_miscdevice(&dev->miscdev);
+ err = misc_register(&dev->miscdev);
if (err) {
dev_err(&pdev->dev, "unable to register v2 device\n");
return err;
@@ -1168,7 +1174,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)

static void goldfish_pipe_device_deinit(struct platform_device *pdev)
{
- misc_deregister(&goldfish_pipe_miscdev);
+ misc_deregister(&goldfish_pipe_dev.miscdev);
tasklet_kill(&goldfish_pipe_dev.irq_tasklet);
kfree(goldfish_pipe_dev.pipes);
free_page((unsigned long)goldfish_pipe_dev.buffers);
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:53:34

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 12/21] platform: goldfish: pipe: Return status from "deinit" since "remove" does not do much

From: Roman Kiryanov <[email protected]>

This way deinit will have a chance to report an error.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe_v2.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index ccde28abcb24..7187b2e603d4 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -1193,13 +1193,15 @@ static int goldfish_pipe_device_init(struct platform_device *pdev,
return 0;
}

-static void goldfish_pipe_device_deinit(struct platform_device *pdev,
- struct goldfish_pipe_dev *dev)
+static int goldfish_pipe_device_deinit(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev)
{
misc_deregister(&dev->miscdev);
tasklet_kill(&dev->irq_tasklet);
kfree(dev->pipes);
free_page((unsigned long)dev->buffers);
+
+ return 0;
}

static int goldfish_pipe_probe(struct platform_device *pdev)
@@ -1245,8 +1247,7 @@ static int goldfish_pipe_remove(struct platform_device *pdev)
{
struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev);

- goldfish_pipe_device_deinit(pdev, dev);
- return 0;
+ return goldfish_pipe_device_deinit(pdev, dev);
}

static const struct acpi_device_id goldfish_pipe_acpi_match[] = {
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:53:47

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 15/21] platform: goldfish: pipe: Rename the init function (add "v2")

From: Roman Kiryanov <[email protected]>

This is the v2 driver, in the next few patches v1 will be
introduced.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 2 +-
drivers/platform/goldfish/goldfish_pipe_v2.c | 6 +++---
drivers/platform/goldfish/goldfish_pipe_v2.h | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 802bbf0d6d23..8a65cdfd6555 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -108,7 +108,7 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
if (WARN_ON(version < PIPE_CURRENT_DEVICE_VERSION))
return -EINVAL;

- return goldfish_pipe_device_init(pdev, base, irq);
+ return goldfish_pipe_device_v2_init(pdev, base, irq);
}

static int goldfish_pipe_remove(struct platform_device *pdev)
diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index 6a8641c7c36e..9fa5136be909 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -1121,9 +1121,9 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
writel(lower_32_bits(paddr), portl);
}

-int goldfish_pipe_device_init(struct platform_device *pdev,
- char __iomem *base,
- int irq)
+int goldfish_pipe_device_v2_init(struct platform_device *pdev,
+ char __iomem *base,
+ int irq)
{
struct goldfish_pipe_dev *dev;
int err;
diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.h b/drivers/platform/goldfish/goldfish_pipe_v2.h
index 679d863774a8..8be09ae6d3ec 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.h
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.h
@@ -17,8 +17,8 @@
#define GOLDFISH_PIPE_V2_H

/* The entry point to the pipe v2 driver */
-int goldfish_pipe_device_init(struct platform_device *pdev,
- char __iomem *base,
- int irq);
+int goldfish_pipe_device_v2_init(struct platform_device *pdev,
+ char __iomem *base,
+ int irq);

#endif /* #define GOLDFISH_PIPE_V2_H */
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:53:53

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 17/21] platform: goldfish: pipe: Add a dedicated constant for the device name

From: Roman Kiryanov <[email protected]>

Create a constant to refer to the device name instead if several copies
of a string.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.h | 2 ++
drivers/platform/goldfish/goldfish_pipe_v2.c | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.h b/drivers/platform/goldfish/goldfish_pipe.h
index 41e831f59eff..178efcf52d22 100644
--- a/drivers/platform/goldfish/goldfish_pipe.h
+++ b/drivers/platform/goldfish/goldfish_pipe.h
@@ -16,6 +16,8 @@
#ifndef GOLDFISH_PIPE_H
#define GOLDFISH_PIPE_H

+#define DEVICE_NAME "goldfish_pipe"
+
struct goldfish_pipe_dev_base {
/* the destructor, the pointer is set in init */
int (*deinit)(void *pipe_dev, struct platform_device *pdev);
diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index e3358c682562..2332aa4bfcea 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -1109,7 +1109,7 @@ static void init_miscdevice(struct miscdevice *miscdev)
memset(miscdev, 0, sizeof(*miscdev));

miscdev->minor = MISC_DYNAMIC_MINOR;
- miscdev->name = "goldfish_pipe";
+ miscdev->name = DEVICE_NAME;
miscdev->fops = &goldfish_pipe_fops;
}

@@ -1140,7 +1140,7 @@ int goldfish_pipe_device_v2_init(struct platform_device *pdev,

err = devm_request_irq(&pdev->dev, irq,
goldfish_pipe_interrupt,
- IRQF_SHARED, "goldfish_pipe", dev);
+ IRQF_SHARED, DEVICE_NAME, dev);
if (err) {
dev_err(&pdev->dev, "unable to allocate IRQ for v2\n");
return err;
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:53:56

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 18/21] platform: goldfish: pipe: Rename PIPE_REG to PIPE_V2_REG

From: Roman Kiryanov <[email protected]>

PIPE_V1_REG will be introduced later for v1 support.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 4 ++--
drivers/platform/goldfish/goldfish_pipe_qemu.h | 18 +++++++++---------
drivers/platform/goldfish/goldfish_pipe_v2.c | 16 ++++++++--------
3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 8a65cdfd6555..d963b7485ce5 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -102,8 +102,8 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
* reading device version back: this allows the host implementation to
* detect the old driver (if there was no version write before read).
*/
- writel((u32)PIPE_DRIVER_VERSION, base + PIPE_REG_VERSION);
- version = readl(base + PIPE_REG_VERSION);
+ writel((u32)PIPE_DRIVER_VERSION, base + PIPE_V2_REG_VERSION);
+ version = readl(base + PIPE_V2_REG_VERSION);

if (WARN_ON(version < PIPE_CURRENT_DEVICE_VERSION))
return -EINVAL;
diff --git a/drivers/platform/goldfish/goldfish_pipe_qemu.h b/drivers/platform/goldfish/goldfish_pipe_qemu.h
index 0ffc51dba54c..599b69f0baa1 100644
--- a/drivers/platform/goldfish/goldfish_pipe_qemu.h
+++ b/drivers/platform/goldfish/goldfish_pipe_qemu.h
@@ -62,19 +62,19 @@ enum PipeFlagsBits {
BIT_WAKE_ON_READ = 2, /* want to be woken on reads */
};

-enum PipeRegs {
- PIPE_REG_CMD = 0,
+enum PipeV2Regs {
+ PIPE_V2_REG_CMD = 0,

- PIPE_REG_SIGNAL_BUFFER_HIGH = 4,
- PIPE_REG_SIGNAL_BUFFER = 8,
- PIPE_REG_SIGNAL_BUFFER_COUNT = 12,
+ PIPE_V2_REG_SIGNAL_BUFFER_HIGH = 4,
+ PIPE_V2_REG_SIGNAL_BUFFER = 8,
+ PIPE_V2_REG_SIGNAL_BUFFER_COUNT = 12,

- PIPE_REG_OPEN_BUFFER_HIGH = 20,
- PIPE_REG_OPEN_BUFFER = 24,
+ PIPE_V2_REG_OPEN_BUFFER_HIGH = 20,
+ PIPE_V2_REG_OPEN_BUFFER = 24,

- PIPE_REG_VERSION = 36,
+ PIPE_V2_REG_VERSION = 36,

- PIPE_REG_GET_SIGNALLED = 48,
+ PIPE_V2_REG_GET_SIGNALLED = 48,
};

enum PipeCmdCode {
diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index 2332aa4bfcea..862ef3a56388 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -259,7 +259,7 @@ static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe,
pipe->command_buffer->cmd = cmd;
/* failure by default */
pipe->command_buffer->status = PIPE_ERROR_INVAL;
- writel(pipe->id, pipe->dev->base + PIPE_REG_CMD);
+ writel(pipe->id, pipe->dev->base + PIPE_V2_REG_CMD);
return pipe->command_buffer->status;
}

@@ -276,7 +276,7 @@ static int goldfish_pipe_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)

/*
* This function converts an error code returned by the emulator through
- * the PIPE_REG_STATUS i/o register into a valid negative errno value.
+ * the PIPE_V2_REG_STATUS i/o register into a valid negative errno value.
*/
static int goldfish_pipe_error_convert(int status)
{
@@ -673,7 +673,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
/* Request the signalled pipes from the device */
spin_lock_irqsave(&dev->lock, flags);

- count = readl(dev->base + PIPE_REG_GET_SIGNALLED);
+ count = readl(dev->base + PIPE_V2_REG_GET_SIGNALLED);
if (count == 0) {
spin_unlock_irqrestore(&dev->lock, flags);
return IRQ_NONE;
@@ -1181,15 +1181,15 @@ int goldfish_pipe_device_v2_init(struct platform_device *pdev,

/* Send the buffer addresses to the host */
write_pa_addr(&dev->buffers->signalled_pipe_buffers,
- dev->base + PIPE_REG_SIGNAL_BUFFER,
- dev->base + PIPE_REG_SIGNAL_BUFFER_HIGH);
+ dev->base + PIPE_V2_REG_SIGNAL_BUFFER,
+ dev->base + PIPE_V2_REG_SIGNAL_BUFFER_HIGH);

writel(MAX_SIGNALLED_PIPES,
- dev->base + PIPE_REG_SIGNAL_BUFFER_COUNT);
+ dev->base + PIPE_V2_REG_SIGNAL_BUFFER_COUNT);

write_pa_addr(&dev->buffers->open_command_params,
- dev->base + PIPE_REG_OPEN_BUFFER,
- dev->base + PIPE_REG_OPEN_BUFFER_HIGH);
+ dev->base + PIPE_V2_REG_OPEN_BUFFER,
+ dev->base + PIPE_V2_REG_OPEN_BUFFER_HIGH);

platform_set_drvdata(pdev, dev);
return 0;
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:54:01

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 19/21] platform: goldfish: pipe: Add the goldfish_pipe_v1 driver

From: Roman Kiryanov <[email protected]>

This is the v1 goldfish pipe driver.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/Makefile | 3 +-
drivers/platform/goldfish/goldfish_pipe.c | 9 +-
.../platform/goldfish/goldfish_pipe_qemu.h | 27 +
drivers/platform/goldfish/goldfish_pipe_v1.c | 632 ++++++++++++++++++
drivers/platform/goldfish/goldfish_pipe_v1.h | 24 +
5 files changed, 690 insertions(+), 5 deletions(-)
create mode 100644 drivers/platform/goldfish/goldfish_pipe_v1.c
create mode 100644 drivers/platform/goldfish/goldfish_pipe_v1.h

diff --git a/drivers/platform/goldfish/Makefile b/drivers/platform/goldfish/Makefile
index 6a9f6e6de46d..acb105dbd9fd 100644
--- a/drivers/platform/goldfish/Makefile
+++ b/drivers/platform/goldfish/Makefile
@@ -1,4 +1,5 @@
#
# Makefile for Goldfish platform specific drivers
#
-obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o goldfish_pipe_v2.o
+obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o \
+ goldfish_pipe_v1.o goldfish_pipe_v2.o
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index d963b7485ce5..e45e262517a0 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -56,6 +56,7 @@
#include <linux/acpi.h>
#include "goldfish_pipe_qemu.h"
#include "goldfish_pipe.h"
+#include "goldfish_pipe_v1.h"
#include "goldfish_pipe_v2.h"

/*
@@ -105,10 +106,10 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
writel((u32)PIPE_DRIVER_VERSION, base + PIPE_V2_REG_VERSION);
version = readl(base + PIPE_V2_REG_VERSION);

- if (WARN_ON(version < PIPE_CURRENT_DEVICE_VERSION))
- return -EINVAL;
-
- return goldfish_pipe_device_v2_init(pdev, base, irq);
+ if (version < PIPE_CURRENT_DEVICE_VERSION)
+ return goldfish_pipe_device_v1_init(pdev, base, irq);
+ else
+ return goldfish_pipe_device_v2_init(pdev, base, irq);
}

static int goldfish_pipe_remove(struct platform_device *pdev)
diff --git a/drivers/platform/goldfish/goldfish_pipe_qemu.h b/drivers/platform/goldfish/goldfish_pipe_qemu.h
index 599b69f0baa1..ed2c7938fede 100644
--- a/drivers/platform/goldfish/goldfish_pipe_qemu.h
+++ b/drivers/platform/goldfish/goldfish_pipe_qemu.h
@@ -62,6 +62,33 @@ enum PipeFlagsBits {
BIT_WAKE_ON_READ = 2, /* want to be woken on reads */
};

+enum PipeV1Regs {
+ /* write: value = command */
+ PIPE_V1_REG_COMMAND = 0x00,
+ /* read */
+ PIPE_V1_REG_STATUS = 0x04,
+ /* read/write: channel id */
+ PIPE_V1_REG_CHANNEL = 0x08,
+ /* read/write: channel id */
+ PIPE_V1_REG_CHANNEL_HIGH = 0x30,
+ /* read/write: buffer size */
+ PIPE_V1_REG_SIZE = 0x0C,
+ /* write: physical address */
+ PIPE_V1_REG_ADDRESS = 0x10,
+ /* write: physical address */
+ PIPE_V1_REG_ADDRESS_HIGH = 0x34,
+ /* read: wake flags */
+ PIPE_V1_REG_WAKES = 0x14,
+ /* read/write: batch data address */
+ PIPE_V1_REG_PARAMS_ADDR_LOW = 0x18,
+ /* read/write: batch data address */
+ PIPE_V1_REG_PARAMS_ADDR_HIGH = 0x1C,
+ /* write: batch access */
+ PIPE_V1_REG_ACCESS_PARAMS = 0x20,
+ /* read: device version */
+ PIPE_V1_REG_VERSION = 0x24,
+};
+
enum PipeV2Regs {
PIPE_V2_REG_CMD = 0,

diff --git a/drivers/platform/goldfish/goldfish_pipe_v1.c b/drivers/platform/goldfish/goldfish_pipe_v1.c
new file mode 100644
index 000000000000..6e603204dd62
--- /dev/null
+++ b/drivers/platform/goldfish/goldfish_pipe_v1.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ * Copyright (C) 2014 Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* This source file contains the implementation of the legacy version of
+ * a goldfish pipe device driver. See goldfish_pipe_v2.c for the current
+ * version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/bug.h>
+#include <linux/goldfish.h>
+#include "goldfish_pipe_qemu.h"
+#include "goldfish_pipe.h"
+
+#define MAX_PAGES_TO_GRAB 32
+
+/* A value that will not be set by qemu emulator */
+#define INITIAL_BATCH_RESULT (0xdeadbeaf)
+
+struct goldfish_pipe_dev;
+
+/* This data type models a given pipe instance */
+struct goldfish_pipe {
+ struct goldfish_pipe_dev *dev;
+
+ /* The wake flags pipe is waiting for
+ * Note: not protected with any lock, uses atomic operations
+ * and barriers to make it thread-safe.
+ */
+ unsigned long flags;
+
+ wait_queue_head_t wake_queue;
+
+ /* protects access to the pipe */
+ struct mutex lock;
+};
+
+struct access_params {
+ unsigned long channel;
+ u32 size;
+ unsigned long address;
+ u32 cmd;
+ u32 result;
+ /* reserved for future extension */
+ u32 flags;
+};
+
+/* The driver state. Holds a reference to the i/o page used to
+ * communicate with the emulator, and a wake queue for blocked tasks
+ * waiting to be awoken.
+ */
+struct goldfish_pipe_dev {
+ /* Needed for the 'remove' call */
+ struct goldfish_pipe_dev_base super;
+
+ /* ptr to platform device's device struct */
+ struct device *pdev_dev;
+
+ /* the base address for MMIO */
+ char __iomem *base;
+
+ struct access_params *aps;
+
+ struct miscdevice miscdev;
+
+ /* Global device spinlock */
+ spinlock_t lock;
+};
+
+static int goldfish_pipe_device_deinit(void *raw_dev,
+ struct platform_device *pdev);
+
+static u32 goldfish_cmd_status(struct goldfish_pipe *pipe, u32 cmd)
+{
+ unsigned long flags;
+ u32 status;
+ struct goldfish_pipe_dev *dev = pipe->dev;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ gf_write_ptr(pipe, dev->base + PIPE_V1_REG_CHANNEL,
+ dev->base + PIPE_V1_REG_CHANNEL_HIGH);
+ writel(cmd, dev->base + PIPE_V1_REG_COMMAND);
+ status = readl(dev->base + PIPE_V1_REG_STATUS);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return status;
+}
+
+static void goldfish_cmd(struct goldfish_pipe *pipe, u32 cmd)
+{
+ unsigned long flags;
+ struct goldfish_pipe_dev *dev = pipe->dev;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ gf_write_ptr(pipe, dev->base + PIPE_V1_REG_CHANNEL,
+ dev->base + PIPE_V1_REG_CHANNEL_HIGH);
+ writel(cmd, dev->base + PIPE_V1_REG_COMMAND);
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/* This function converts an error code returned by the emulator through
+ * the PIPE_V1_REG_STATUS i/o register into a valid negative errno value.
+ */
+static int goldfish_pipe_error_convert(int status)
+{
+ switch (status) {
+ case PIPE_ERROR_AGAIN:
+ return -EAGAIN;
+ case PIPE_ERROR_NOMEM:
+ return -ENOMEM;
+ case PIPE_ERROR_IO:
+ return -EIO;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Notice: QEMU will return 0 for un-known register access, indicating
+ * access_params is supported or not
+ */
+static int valid_batchbuffer_addr(struct goldfish_pipe_dev *dev,
+ struct access_params *aps)
+{
+ u32 aph, apl;
+ u64 paddr;
+
+ aph = readl(dev->base + PIPE_V1_REG_PARAMS_ADDR_HIGH);
+ apl = readl(dev->base + PIPE_V1_REG_PARAMS_ADDR_LOW);
+
+ paddr = ((u64)aph << 32) | apl;
+ return paddr == (__pa(aps));
+}
+
+static int setup_access_params_addr(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev)
+{
+ u64 paddr;
+ struct access_params *aps;
+
+ aps = devm_kzalloc(&pdev->dev, sizeof(struct access_params),
+ GFP_KERNEL);
+ if (!aps)
+ return -ENOMEM;
+
+ paddr = __pa(aps);
+ writel((u32)(paddr >> 32), dev->base + PIPE_V1_REG_PARAMS_ADDR_HIGH);
+ writel((u32)paddr, dev->base + PIPE_V1_REG_PARAMS_ADDR_LOW);
+
+ if (valid_batchbuffer_addr(dev, aps)) {
+ dev->aps = aps;
+ return 0;
+ }
+
+ devm_kfree(&pdev->dev, aps);
+ return -EFAULT;
+}
+
+static int access_with_param(struct goldfish_pipe_dev *dev, const int cmd,
+ unsigned long address, unsigned long avail,
+ struct goldfish_pipe *pipe, int *status)
+{
+ struct access_params *aps = dev->aps;
+
+ if (!aps)
+ return -EINVAL;
+
+ aps->result = INITIAL_BATCH_RESULT;
+ aps->channel = (unsigned long)pipe;
+ aps->size = avail;
+ aps->address = address;
+ aps->cmd = cmd;
+ writel(cmd, dev->base + PIPE_V1_REG_ACCESS_PARAMS);
+
+ /*
+ * If the aps->result has not changed, that means
+ * that the batch command failed
+ */
+ if (aps->result == INITIAL_BATCH_RESULT)
+ return -EINVAL;
+
+ *status = aps->result;
+ return 0;
+}
+
+static int transfer_pages(struct goldfish_pipe_dev *dev,
+ struct goldfish_pipe *pipe,
+ int cmd,
+ unsigned long xaddr,
+ unsigned long size)
+{
+ unsigned long irq_flags;
+ int status = 0;
+
+ spin_lock_irqsave(&dev->lock, irq_flags);
+ if (access_with_param(dev, cmd, xaddr, size, pipe, &status)) {
+ gf_write_ptr(pipe, dev->base + PIPE_V1_REG_CHANNEL,
+ dev->base + PIPE_V1_REG_CHANNEL_HIGH);
+
+ writel(size, dev->base + PIPE_V1_REG_SIZE);
+
+ gf_write_ptr((void *)xaddr,
+ dev->base + PIPE_V1_REG_ADDRESS,
+ dev->base + PIPE_V1_REG_ADDRESS_HIGH);
+
+ writel(cmd, dev->base + PIPE_V1_REG_COMMAND);
+
+ status = readl(dev->base + PIPE_V1_REG_STATUS);
+ }
+ spin_unlock_irqrestore(&dev->lock, irq_flags);
+
+ return status;
+}
+
+static unsigned long translate_address(const struct page *page,
+ unsigned long addr)
+{
+ return page_to_phys(page) | (addr & ~PAGE_MASK);
+}
+
+static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
+ size_t bufflen, int is_write)
+{
+ struct goldfish_pipe *pipe = filp->private_data;
+ struct goldfish_pipe_dev *dev = pipe->dev;
+ unsigned long address;
+ unsigned long address_end;
+ const int wake_bit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ;
+ const int pipe_cmd = is_write ? PIPE_CMD_WRITE : PIPE_CMD_READ;
+ int count = 0;
+ int ret = -EINVAL;
+
+ /* If the emulator already closed the pipe, no need to go further */
+ if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
+ return -EIO;
+
+ /* Null reads or writes succeeds */
+ if (unlikely(bufflen == 0))
+ return 0;
+
+ /* Check the buffer range for access */
+ if (!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ,
+ buffer, bufflen))
+ return -EFAULT;
+
+ address = (unsigned long)buffer;
+ address_end = address + bufflen;
+
+ /* Serialize access to the pipe */
+ if (mutex_lock_interruptible(&pipe->lock))
+ return -ERESTARTSYS;
+
+ while (address < address_end) {
+ struct page *pages[MAX_PAGES_TO_GRAB];
+ unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE;
+ unsigned long avail;
+ unsigned long xaddr;
+ unsigned long xaddr_prev;
+ long first_page;
+ long last_page;
+ long requested_pages;
+ int status;
+ int n_pages;
+ int page_i;
+ int num_contiguous_pages;
+
+ /*
+ * Attempt to grab multiple physically contiguous pages.
+ */
+ first_page = address & PAGE_MASK;
+ last_page = (address_end - 1) & PAGE_MASK;
+ requested_pages =
+ min(((last_page - first_page) >> PAGE_SHIFT) + 1,
+ (long)MAX_PAGES_TO_GRAB);
+
+ ret = get_user_pages_fast(first_page, requested_pages,
+ !is_write, pages);
+ if (ret < 0) {
+ dev_err(dev->pdev_dev,
+ "%s: get_user_pages_fast failed: %d\n",
+ __func__, ret);
+ break;
+ } else if (!ret) {
+ dev_err(dev->pdev_dev,
+ "%s: error: no pages returned, requested %ld\n",
+ __func__, requested_pages);
+ break;
+ }
+
+ n_pages = ret;
+ xaddr = translate_address(pages[0], address);
+ xaddr_prev = xaddr;
+ num_contiguous_pages = 1;
+ for (page_i = 1; page_i < n_pages; page_i++) {
+ unsigned long xaddr_i;
+
+ xaddr_i = translate_address(pages[page_i], address);
+ if (xaddr_i == xaddr_prev + PAGE_SIZE) {
+ page_end += PAGE_SIZE;
+ xaddr_prev = xaddr_i;
+ num_contiguous_pages++;
+ } else {
+ dev_err(dev->pdev_dev,
+ "%s: discontinuous page boundary: %d "
+ "pages instead\n",
+ __func__, page_i);
+ break;
+ }
+ }
+ avail = min(page_end, address_end) - address;
+
+ status = transfer_pages(dev, pipe, pipe_cmd, xaddr, avail);
+
+ for (page_i = 0; page_i < n_pages; page_i++) {
+ if (status > 0 && !is_write &&
+ page_i < num_contiguous_pages)
+ set_page_dirty(pages[page_i]);
+
+ put_page(pages[page_i]);
+ }
+
+ if (status > 0) { /* Correct transfer */
+ count += status;
+ address += status;
+ continue;
+ } else if (status == 0) { /* EOF */
+ ret = 0;
+ break;
+ } else if (status < 0 && count > 0) {
+ /*
+ * An error occurred and we already transferred
+ * something on one of the previous pages.
+ * Just return what we already copied and log this
+ * err.
+ *
+ * Note: This seems like an incorrect approach but
+ * cannot change it until we check if any user space
+ * ABI relies on this behavior.
+ */
+ if (status != PIPE_ERROR_AGAIN)
+ dev_err_ratelimited(dev->pdev_dev,
+ "backend returned error %d on %s\n",
+ status, is_write ? "write" : "read");
+ ret = 0;
+ break;
+ }
+
+ /*
+ * If the error is not PIPE_ERROR_AGAIN, or if we are not in
+ * non-blocking mode, just return the error code.
+ */
+ if (status != PIPE_ERROR_AGAIN ||
+ (filp->f_flags & O_NONBLOCK) != 0) {
+ ret = goldfish_pipe_error_convert(status);
+ break;
+ }
+
+ /*
+ * The backend blocked the read/write, wait until the backend
+ * tells us it's ready to process more data.
+ */
+ set_bit(wake_bit, &pipe->flags);
+
+ /* Tell the emulator we're going to wait for a wake event */
+ goldfish_cmd(pipe, pipe_cmd);
+
+ /* Unlock the pipe, then wait for the wake signal */
+ mutex_unlock(&pipe->lock);
+
+ while (test_bit(wake_bit, &pipe->flags)) {
+ if (wait_event_interruptible(pipe->wake_queue,
+ !test_bit(wake_bit, &pipe->flags)))
+ return -ERESTARTSYS;
+
+ if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
+ return -EIO;
+ }
+
+ /* Try to re-acquire the lock */
+ if (mutex_lock_interruptible(&pipe->lock))
+ return -ERESTARTSYS;
+ }
+ mutex_unlock(&pipe->lock);
+
+ return (ret < 0) ? ret : count;
+}
+
+static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer,
+ size_t bufflen, loff_t *ppos)
+{
+ return goldfish_pipe_read_write(filp, buffer, bufflen,
+ /* is_write */ 0);
+}
+
+static ssize_t goldfish_pipe_write(struct file *filp,
+ const char __user *buffer, size_t bufflen,
+ loff_t *ppos)
+{
+ return goldfish_pipe_read_write(filp, (char __user *)buffer,
+ bufflen, /* is_write */ 1);
+}
+
+static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait)
+{
+ struct goldfish_pipe *pipe = filp->private_data;
+ __poll_t mask = 0;
+ int status;
+
+ if (mutex_lock_interruptible(&pipe->lock))
+ return -ERESTARTSYS;
+
+ poll_wait(filp, &pipe->wake_queue, wait);
+
+ status = goldfish_cmd_status(pipe, PIPE_CMD_POLL);
+
+ mutex_unlock(&pipe->lock);
+
+ if (status & PIPE_POLL_IN)
+ mask |= EPOLLIN | EPOLLRDNORM;
+
+ if (status & PIPE_POLL_OUT)
+ mask |= EPOLLOUT | EPOLLWRNORM;
+
+ if (status & PIPE_POLL_HUP)
+ mask |= EPOLLHUP;
+
+ if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
+ mask |= EPOLLERR;
+
+ return mask;
+}
+
+static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
+{
+ struct goldfish_pipe_dev *dev = dev_id;
+ unsigned long irq_flags;
+ int count = 0;
+
+ /*
+ * We're going to read from the emulator a list of (channel,flags)
+ * pairs corresponding to the wake events that occurred on each
+ * blocked pipe (i.e. channel).
+ */
+ spin_lock_irqsave(&dev->lock, irq_flags);
+ for (;;) {
+ /* First read the channel, 0 means the end of the list */
+ struct goldfish_pipe *pipe;
+ unsigned long wakes;
+ unsigned long channel = 0;
+
+#ifdef CONFIG_64BIT
+ channel =
+ (u64)readl(dev->base + PIPE_V1_REG_CHANNEL_HIGH) << 32;
+#endif
+ channel |= readl(dev->base + PIPE_V1_REG_CHANNEL);
+ if (!channel)
+ break;
+
+ /* Convert channel to struct pipe pointer + read wake flags */
+ wakes = readl(dev->base + PIPE_V1_REG_WAKES);
+ pipe = (struct goldfish_pipe *)(ptrdiff_t)channel;
+
+ /* Did the emulator just closed a pipe? */
+ if (wakes & PIPE_WAKE_CLOSED) {
+ set_bit(BIT_CLOSED_ON_HOST, &pipe->flags);
+ wakes |= PIPE_WAKE_READ | PIPE_WAKE_WRITE;
+ }
+ if (wakes & PIPE_WAKE_READ)
+ clear_bit(BIT_WAKE_ON_READ, &pipe->flags);
+ if (wakes & PIPE_WAKE_WRITE)
+ clear_bit(BIT_WAKE_ON_WRITE, &pipe->flags);
+
+ wake_up_interruptible(&pipe->wake_queue);
+ count++;
+ }
+ spin_unlock_irqrestore(&dev->lock, irq_flags);
+
+ return (count == 0) ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* A helper function to get the instance of goldfish_pipe_dev from file */
+static struct goldfish_pipe_dev *to_goldfish_pipe_dev(struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+
+ return container_of(miscdev, struct goldfish_pipe_dev, miscdev);
+}
+
+/**
+ * goldfish_pipe_open - open a channel to the AVD
+ * @inode: inode of device
+ * @file: file struct of opener
+ *
+ * Create a new pipe link between the emulator and the use application.
+ * Each new request produces a new pipe.
+ *
+ * Note: we use the pipe ID as a mux. All goldfish emulations are 32bit
+ * right now so this is fine. A move to 64bit will need this addressing
+ */
+static int goldfish_pipe_open(struct inode *inode, struct file *file)
+{
+ struct goldfish_pipe_dev *dev = to_goldfish_pipe_dev(file);
+ struct goldfish_pipe *pipe;
+ int status;
+
+ /* Allocate new pipe kernel object */
+ pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
+ if (!pipe)
+ return -ENOMEM;
+
+ pipe->dev = dev;
+ init_waitqueue_head(&pipe->wake_queue);
+ mutex_init(&pipe->lock);
+
+ /*
+ * Now, tell the emulator we're opening a new pipe. We use the
+ * pipe object's address as the channel identifier for simplicity.
+ */
+
+ status = goldfish_cmd_status(pipe, PIPE_CMD_OPEN);
+ if (status < 0) {
+ kfree(pipe);
+ return status;
+ }
+
+ /* All is done, save the pipe into the file's private data field */
+ file->private_data = pipe;
+ return 0;
+}
+
+static int goldfish_pipe_release(struct inode *inode, struct file *filp)
+{
+ struct goldfish_pipe *pipe = filp->private_data;
+
+ pr_debug("%s: call. pipe=%p file=%p\n", __func__, pipe, filp);
+ /* The guest is closing the channel, so tell the emulator right now */
+ goldfish_cmd(pipe, PIPE_CMD_CLOSE);
+ kfree(pipe);
+ filp->private_data = NULL;
+ return 0;
+}
+
+static const struct file_operations goldfish_pipe_fops = {
+ .owner = THIS_MODULE,
+ .read = goldfish_pipe_read,
+ .write = goldfish_pipe_write,
+ .poll = goldfish_pipe_poll,
+ .open = goldfish_pipe_open,
+ .release = goldfish_pipe_release,
+};
+
+static void init_miscdevice(struct miscdevice *miscdev)
+{
+ memset(miscdev, 0, sizeof(*miscdev));
+
+ miscdev->minor = MISC_DYNAMIC_MINOR;
+ miscdev->name = DEVICE_NAME;
+ miscdev->fops = &goldfish_pipe_fops;
+};
+
+static int goldfish_pipe_device_deinit(void *raw_dev,
+ struct platform_device *pdev);
+
+int goldfish_pipe_device_v1_init(struct platform_device *pdev,
+ void __iomem *base,
+ int irq)
+{
+ struct goldfish_pipe_dev *dev;
+ int err;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->super.deinit = &goldfish_pipe_device_deinit;
+ dev->pdev_dev = &pdev->dev;
+ spin_lock_init(&dev->lock);
+
+ err = devm_request_irq(&pdev->dev, irq,
+ &goldfish_pipe_interrupt, IRQF_SHARED,
+ DEVICE_NAME, dev);
+ if (err) {
+ dev_err(&pdev->dev, "unable to allocate IRQ for v1\n");
+ return err;
+ }
+
+ init_miscdevice(&dev->miscdev);
+ err = misc_register(&dev->miscdev);
+ if (err) {
+ dev_err(&pdev->dev, "unable to register v1 device\n");
+ return err;
+ }
+
+ setup_access_params_addr(pdev, dev);
+
+ platform_set_drvdata(pdev, dev);
+ return 0;
+}
+
+static int goldfish_pipe_device_deinit(void *raw_dev,
+ struct platform_device *pdev)
+{
+ struct goldfish_pipe_dev *dev = raw_dev;
+
+ misc_deregister(&dev->miscdev);
+ return 0;
+}
diff --git a/drivers/platform/goldfish/goldfish_pipe_v1.h b/drivers/platform/goldfish/goldfish_pipe_v1.h
new file mode 100644
index 000000000000..6d61441e2a7f
--- /dev/null
+++ b/drivers/platform/goldfish/goldfish_pipe_v1.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef GOLDFISH_PIPE_V1_H
+#define GOLDFISH_PIPE_V1_H
+
+/* The entry point to the pipe v1 driver */
+int goldfish_pipe_device_v1_init(struct platform_device *pdev,
+ void __iomem *base,
+ int irq);
+
+#endif /* #define GOLDFISH_PIPE_V1_H */
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:54:03

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 20/21] platform: goldfish: pipe: Remove redundant casting

From: Roman Kiryanov <[email protected]>

This casting is not required.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index e45e262517a0..f6c144e71c30 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -103,7 +103,7 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
* reading device version back: this allows the host implementation to
* detect the old driver (if there was no version write before read).
*/
- writel((u32)PIPE_DRIVER_VERSION, base + PIPE_V2_REG_VERSION);
+ writel(PIPE_DRIVER_VERSION, base + PIPE_V2_REG_VERSION);
version = readl(base + PIPE_V2_REG_VERSION);

if (version < PIPE_CURRENT_DEVICE_VERSION)
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:54:39

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 09/21] platform: goldfish: pipe: Remove the goldfish_pipe_dev global variable

From: Roman Kiryanov <[email protected]>

This is the last patch in the series of patches to remove mutable
global variables to introduce another version of the pipe driver
for the older host interface. I don't want to have two driver
states where only one is used.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe.c | 66 +++++++++++++----------
1 file changed, 37 insertions(+), 29 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 53832e46ad1a..c68035be4389 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -202,6 +202,9 @@ struct goldfish_pipe {
* waiting to be awoken.
*/
struct goldfish_pipe_dev {
+ /* A magic number to check if this is an instance of this struct */
+ void *magic;
+
/*
* Global device spinlock. Protects the following members:
* - pipes, pipes_capacity
@@ -251,8 +254,6 @@ struct goldfish_pipe_dev {
size_t dma_alloc_total;
};

-struct goldfish_pipe_dev goldfish_pipe_dev;
-
static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe,
enum PipeCmdCode cmd)
{
@@ -647,6 +648,9 @@ static void goldfish_interrupt_task(unsigned long dev_addr)
}
}

+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev);
+
/*
* The general idea of the interrupt handling:
*
@@ -667,7 +671,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
unsigned long flags;
struct goldfish_pipe_dev *dev = dev_id;

- if (dev != &goldfish_pipe_dev)
+ if (dev->magic != &goldfish_pipe_device_deinit)
return IRQ_NONE;

/* Request the signalled pipes from the device */
@@ -719,6 +723,14 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
return id;
}

+/* A helper function to get the instance of goldfish_pipe_dev from file */
+static struct goldfish_pipe_dev *to_goldfish_pipe_dev(struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+
+ return container_of(miscdev, struct goldfish_pipe_dev, miscdev);
+}
+
/**
* goldfish_pipe_open - open a channel to the AVD
* @inode: inode of device
@@ -732,7 +744,7 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
*/
static int goldfish_pipe_open(struct inode *inode, struct file *file)
{
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
+ struct goldfish_pipe_dev *dev = to_goldfish_pipe_dev(file);
unsigned long flags;
int id;
int status;
@@ -1112,9 +1124,9 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
writel(lower_32_bits(paddr), portl);
}

-static int goldfish_pipe_device_init(struct platform_device *pdev)
+static int goldfish_pipe_device_init(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev)
{
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
int err;

tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task,
@@ -1169,26 +1181,29 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
dev->base + PIPE_REG_OPEN_BUFFER,
dev->base + PIPE_REG_OPEN_BUFFER_HIGH);

+ platform_set_drvdata(pdev, dev);
return 0;
}

-static void goldfish_pipe_device_deinit(struct platform_device *pdev)
+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev)
{
- misc_deregister(&goldfish_pipe_dev.miscdev);
- tasklet_kill(&goldfish_pipe_dev.irq_tasklet);
- kfree(goldfish_pipe_dev.pipes);
- free_page((unsigned long)goldfish_pipe_dev.buffers);
+ misc_deregister(&dev->miscdev);
+ tasklet_kill(&dev->irq_tasklet);
+ kfree(dev->pipes);
+ free_page((unsigned long)dev->buffers);
}

static int goldfish_pipe_probe(struct platform_device *pdev)
{
- int err;
struct resource *r;
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
+ struct goldfish_pipe_dev *dev;

- /* not thread safe, but this should not happen */
- WARN_ON(dev->base);
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;

+ dev->magic = &goldfish_pipe_device_deinit;
spin_lock_init(&dev->lock);

r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1203,10 +1218,9 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
}

r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!r) {
- err = -EINVAL;
- goto error;
- }
+ if (!r)
+ return -EINVAL;
+
dev->irq = r->start;

/*
@@ -1221,20 +1235,14 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION))
return -EINVAL;

- err = goldfish_pipe_device_init(pdev);
- if (!err)
- return 0;
-
-error:
- dev->base = NULL;
- return err;
+ return goldfish_pipe_device_init(pdev, dev);
}

static int goldfish_pipe_remove(struct platform_device *pdev)
{
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
- goldfish_pipe_device_deinit(pdev);
- dev->base = NULL;
+ struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev);
+
+ goldfish_pipe_device_deinit(pdev, dev);
return 0;
}

--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:54:41

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 10/21] platform: goldfish: pipe: Move goldfish_pipe to goldfish_pipe_v2

From: Roman Kiryanov <[email protected]>

This is the v2 driver. The next few patches will add v1.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/Makefile | 2 +-
.../platform/goldfish/{goldfish_pipe.c => goldfish_pipe_v2.c} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename drivers/platform/goldfish/{goldfish_pipe.c => goldfish_pipe_v2.c} (100%)

diff --git a/drivers/platform/goldfish/Makefile b/drivers/platform/goldfish/Makefile
index e0c202df9674..81f899a987a2 100644
--- a/drivers/platform/goldfish/Makefile
+++ b/drivers/platform/goldfish/Makefile
@@ -1,4 +1,4 @@
#
# Makefile for Goldfish platform specific drivers
#
-obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o
+obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe_v2.o
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
similarity index 100%
rename from drivers/platform/goldfish/goldfish_pipe.c
rename to drivers/platform/goldfish/goldfish_pipe_v2.c
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:54:44

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 11/21] platform: goldfish: pipe: Move memory allocation from probe to init

From: Roman Kiryanov <[email protected]>

There will be two separate init functions for v1 and v2 and they
will allocate different state.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe_v2.c | 41 +++++++++++---------
1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index c68035be4389..ccde28abcb24 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -241,8 +241,6 @@ struct goldfish_pipe_dev {
struct device *pdev_dev;

/* Some device-specific data */
- int irq;
- int version;
unsigned char __iomem *base;

/* an irq tasklet to run goldfish_interrupt_task */
@@ -1125,14 +1123,23 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
}

static int goldfish_pipe_device_init(struct platform_device *pdev,
- struct goldfish_pipe_dev *dev)
+ char __iomem *base,
+ int irq)
{
+ struct goldfish_pipe_dev *dev;
int err;

+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->magic = &goldfish_pipe_device_deinit;
+ spin_lock_init(&dev->lock);
+
tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task,
(unsigned long)dev);

- err = devm_request_irq(&pdev->dev, dev->irq,
+ err = devm_request_irq(&pdev->dev, irq,
goldfish_pipe_interrupt,
IRQF_SHARED, "goldfish_pipe", dev);
if (err) {
@@ -1147,6 +1154,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev,
return err;
}

+ dev->base = base;
dev->pdev_dev = &pdev->dev;
dev->first_signalled_pipe = NULL;
dev->pipes_capacity = INITIAL_PIPES_CAPACITY;
@@ -1197,22 +1205,17 @@ static void goldfish_pipe_device_deinit(struct platform_device *pdev,
static int goldfish_pipe_probe(struct platform_device *pdev)
{
struct resource *r;
- struct goldfish_pipe_dev *dev;
-
- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- dev->magic = &goldfish_pipe_device_deinit;
- spin_lock_init(&dev->lock);
+ char __iomem *base;
+ int irq;
+ int version;

r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r || resource_size(r) < PAGE_SIZE) {
dev_err(&pdev->dev, "can't allocate i/o page\n");
return -EINVAL;
}
- dev->base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
- if (!dev->base) {
+ base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
+ if (!base) {
dev_err(&pdev->dev, "ioremap failed\n");
return -EINVAL;
}
@@ -1221,7 +1224,7 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
if (!r)
return -EINVAL;

- dev->irq = r->start;
+ irq = r->start;

/*
* Exchange the versions with the host device
@@ -1230,12 +1233,12 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
* reading device version back: this allows the host implementation to
* detect the old driver (if there was no version write before read).
*/
- writel((u32)PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION);
- dev->version = readl(dev->base + PIPE_REG_VERSION);
- if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION))
+ writel((u32)PIPE_DRIVER_VERSION, base + PIPE_REG_VERSION);
+ version = readl(base + PIPE_REG_VERSION);
+ if (WARN_ON(version < PIPE_CURRENT_DEVICE_VERSION))
return -EINVAL;

- return goldfish_pipe_device_init(pdev, dev);
+ return goldfish_pipe_device_init(pdev, base, irq);
}

static int goldfish_pipe_remove(struct platform_device *pdev)
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:54:53

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 13/21] platform: goldfish: pipe: Split the driver to v2 specific and the rest

From: Roman Kiryanov <[email protected]>

Move probe/remove and other driver stuff to a separate file
to plug v1 there later.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/Makefile | 2 +-
drivers/platform/goldfish/goldfish_pipe.c | 145 +++++++++++++++++++
drivers/platform/goldfish/goldfish_pipe.h | 24 +++
drivers/platform/goldfish/goldfish_pipe_v2.c | 102 ++-----------
drivers/platform/goldfish/goldfish_pipe_v2.h | 24 +++
5 files changed, 209 insertions(+), 88 deletions(-)
create mode 100644 drivers/platform/goldfish/goldfish_pipe.c
create mode 100644 drivers/platform/goldfish/goldfish_pipe.h
create mode 100644 drivers/platform/goldfish/goldfish_pipe_v2.h

diff --git a/drivers/platform/goldfish/Makefile b/drivers/platform/goldfish/Makefile
index 81f899a987a2..6a9f6e6de46d 100644
--- a/drivers/platform/goldfish/Makefile
+++ b/drivers/platform/goldfish/Makefile
@@ -1,4 +1,4 @@
#
# Makefile for Goldfish platform specific drivers
#
-obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe_v2.o
+obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o goldfish_pipe_v2.o
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
new file mode 100644
index 000000000000..802bbf0d6d23
--- /dev/null
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ * Copyright (C) 2014 Linaro Limited
+ * Copyright (C) 2011-2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* This source file contains the implementation of a special device driver
+ * that intends to provide a *very* fast communication channel between the
+ * guest system and the QEMU emulator.
+ *
+ * Usage from the guest is simply the following (error handling simplified):
+ *
+ * int fd = open("/dev/qemu_pipe",O_RDWR);
+ * .... write() or read() through the pipe.
+ *
+ * This driver doesn't deal with the exact protocol used during the session.
+ * It is intended to be as simple as something like:
+ *
+ * // do this _just_ after opening the fd to connect to a specific
+ * // emulator service.
+ * const char* msg = "<pipename>";
+ * if (write(fd, msg, strlen(msg)+1) < 0) {
+ * ... could not connect to <pipename> service
+ * close(fd);
+ * }
+ *
+ * // after this, simply read() and write() to communicate with the
+ * // service. Exact protocol details left as an exercise to the reader.
+ *
+ * This driver is very fast because it doesn't copy any data through
+ * intermediate buffers, since the emulator is capable of translating
+ * guest user addresses into host ones.
+ *
+ * Note that we must however ensure that each user page involved in the
+ * exchange is properly mapped during a transfer.
+ */
+
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include "goldfish_pipe_qemu.h"
+#include "goldfish_pipe.h"
+#include "goldfish_pipe_v2.h"
+
+/*
+ * Update this when something changes in the driver's behavior so the host
+ * can benefit from knowing it
+ * Notes:
+ * version 2 was an intermediate release and isn't supported anymore.
+ * version 3 is goldfish_pipe_v2 without DMA support.
+ * version 4 (current) is goldfish_pipe_v2 with DMA support.
+ */
+enum {
+ PIPE_DRIVER_VERSION = 4,
+ PIPE_CURRENT_DEVICE_VERSION = 2
+};
+
+static int goldfish_pipe_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ char __iomem *base;
+ int irq;
+ int version;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r || resource_size(r) < PAGE_SIZE) {
+ dev_err(&pdev->dev, "can't allocate i/o page\n");
+ return -EINVAL;
+ }
+ base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ return -EINVAL;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!r)
+ return -EINVAL;
+
+ irq = r->start;
+
+ /*
+ * Exchange the versions with the host device
+ *
+ * Note: v1 driver used to not report its version, so we write it before
+ * reading device version back: this allows the host implementation to
+ * detect the old driver (if there was no version write before read).
+ */
+ writel((u32)PIPE_DRIVER_VERSION, base + PIPE_REG_VERSION);
+ version = readl(base + PIPE_REG_VERSION);
+
+ if (WARN_ON(version < PIPE_CURRENT_DEVICE_VERSION))
+ return -EINVAL;
+
+ return goldfish_pipe_device_init(pdev, base, irq);
+}
+
+static int goldfish_pipe_remove(struct platform_device *pdev)
+{
+ struct goldfish_pipe_dev_base *dev = platform_get_drvdata(pdev);
+
+ return dev->deinit(dev, pdev);
+}
+
+static const struct acpi_device_id goldfish_pipe_acpi_match[] = {
+ { "GFSH0003", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, goldfish_pipe_acpi_match);
+
+static const struct of_device_id goldfish_pipe_of_match[] = {
+ { .compatible = "google,android-pipe", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match);
+
+static struct platform_driver goldfish_pipe_driver = {
+ .probe = goldfish_pipe_probe,
+ .remove = goldfish_pipe_remove,
+ .driver = {
+ .name = "goldfish_pipe",
+ .of_match_table = goldfish_pipe_of_match,
+ .acpi_match_table = ACPI_PTR(goldfish_pipe_acpi_match),
+ }
+};
+
+module_platform_driver(goldfish_pipe_driver);
+MODULE_AUTHOR("David Turner <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/goldfish/goldfish_pipe.h b/drivers/platform/goldfish/goldfish_pipe.h
new file mode 100644
index 000000000000..41e831f59eff
--- /dev/null
+++ b/drivers/platform/goldfish/goldfish_pipe.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef GOLDFISH_PIPE_H
+#define GOLDFISH_PIPE_H
+
+struct goldfish_pipe_dev_base {
+ /* the destructor, the pointer is set in init */
+ int (*deinit)(void *pipe_dev, struct platform_device *pdev);
+};
+
+#endif /* GOLDFISH_PIPE_H */
diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index 7187b2e603d4..d653e5a2ffcc 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -47,8 +47,6 @@
* exchange is properly mapped during a transfer.
*/

-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
@@ -61,10 +59,10 @@
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
-#include <linux/acpi.h>
#include <linux/bug.h>
#include <uapi/linux/goldfish/goldfish_dma.h>
#include "goldfish_pipe_qemu.h"
+#include "goldfish_pipe.h"

/*
* Update this when something changes in the driver's behavior so the host
@@ -89,6 +87,9 @@ enum {

struct goldfish_pipe_dev;

+static int goldfish_pipe_device_deinit(void *raw_dev,
+ struct platform_device *pdev);
+
/* A per-pipe command structure, shared with the host */
struct goldfish_pipe_command {
s32 cmd; /* PipeCmdCode, guest -> host */
@@ -202,8 +203,8 @@ struct goldfish_pipe {
* waiting to be awoken.
*/
struct goldfish_pipe_dev {
- /* A magic number to check if this is an instance of this struct */
- void *magic;
+ /* Needed for 'remove' */
+ struct goldfish_pipe_dev_base super;

/*
* Global device spinlock. Protects the following members:
@@ -646,9 +647,6 @@ static void goldfish_interrupt_task(unsigned long dev_addr)
}
}

-static void goldfish_pipe_device_deinit(struct platform_device *pdev,
- struct goldfish_pipe_dev *dev);
-
/*
* The general idea of the interrupt handling:
*
@@ -669,7 +667,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
unsigned long flags;
struct goldfish_pipe_dev *dev = dev_id;

- if (dev->magic != &goldfish_pipe_device_deinit)
+ if (dev->super.deinit != &goldfish_pipe_device_deinit)
return IRQ_NONE;

/* Request the signalled pipes from the device */
@@ -1122,9 +1120,9 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
writel(lower_32_bits(paddr), portl);
}

-static int goldfish_pipe_device_init(struct platform_device *pdev,
- char __iomem *base,
- int irq)
+int goldfish_pipe_device_init(struct platform_device *pdev,
+ char __iomem *base,
+ int irq)
{
struct goldfish_pipe_dev *dev;
int err;
@@ -1133,7 +1131,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev,
if (!dev)
return -ENOMEM;

- dev->magic = &goldfish_pipe_device_deinit;
+ dev->super.deinit = &goldfish_pipe_device_deinit;
spin_lock_init(&dev->lock);

tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task,
@@ -1193,9 +1191,11 @@ static int goldfish_pipe_device_init(struct platform_device *pdev,
return 0;
}

-static int goldfish_pipe_device_deinit(struct platform_device *pdev,
- struct goldfish_pipe_dev *dev)
+static int goldfish_pipe_device_deinit(void *raw_dev,
+ struct platform_device *pdev)
{
+ struct goldfish_pipe_dev *dev = raw_dev;
+
misc_deregister(&dev->miscdev);
tasklet_kill(&dev->irq_tasklet);
kfree(dev->pipes);
@@ -1203,75 +1203,3 @@ static int goldfish_pipe_device_deinit(struct platform_device *pdev,

return 0;
}
-
-static int goldfish_pipe_probe(struct platform_device *pdev)
-{
- struct resource *r;
- char __iomem *base;
- int irq;
- int version;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r || resource_size(r) < PAGE_SIZE) {
- dev_err(&pdev->dev, "can't allocate i/o page\n");
- return -EINVAL;
- }
- base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
- if (!base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- return -EINVAL;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!r)
- return -EINVAL;
-
- irq = r->start;
-
- /*
- * Exchange the versions with the host device
- *
- * Note: v1 driver used to not report its version, so we write it before
- * reading device version back: this allows the host implementation to
- * detect the old driver (if there was no version write before read).
- */
- writel((u32)PIPE_DRIVER_VERSION, base + PIPE_REG_VERSION);
- version = readl(base + PIPE_REG_VERSION);
- if (WARN_ON(version < PIPE_CURRENT_DEVICE_VERSION))
- return -EINVAL;
-
- return goldfish_pipe_device_init(pdev, base, irq);
-}
-
-static int goldfish_pipe_remove(struct platform_device *pdev)
-{
- struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev);
-
- return goldfish_pipe_device_deinit(pdev, dev);
-}
-
-static const struct acpi_device_id goldfish_pipe_acpi_match[] = {
- { "GFSH0003", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(acpi, goldfish_pipe_acpi_match);
-
-static const struct of_device_id goldfish_pipe_of_match[] = {
- { .compatible = "google,android-pipe", },
- {},
-};
-MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match);
-
-static struct platform_driver goldfish_pipe_driver = {
- .probe = goldfish_pipe_probe,
- .remove = goldfish_pipe_remove,
- .driver = {
- .name = "goldfish_pipe",
- .of_match_table = goldfish_pipe_of_match,
- .acpi_match_table = ACPI_PTR(goldfish_pipe_acpi_match),
- }
-};
-
-module_platform_driver(goldfish_pipe_driver);
-MODULE_AUTHOR("David Turner <[email protected]>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.h b/drivers/platform/goldfish/goldfish_pipe_v2.h
new file mode 100644
index 000000000000..679d863774a8
--- /dev/null
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef GOLDFISH_PIPE_V2_H
+#define GOLDFISH_PIPE_V2_H
+
+/* The entry point to the pipe v2 driver */
+int goldfish_pipe_device_init(struct platform_device *pdev,
+ char __iomem *base,
+ int irq);
+
+#endif /* #define GOLDFISH_PIPE_V2_H */
--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:54:57

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 14/21] platform: goldfish: pipe: Add a blank line to separate varibles and code

From: Roman Kiryanov <[email protected]>

checkpacth: Missing a blank line after declarations

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe_v2.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index d653e5a2ffcc..6a8641c7c36e 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -747,6 +747,7 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file)

/* Allocate new pipe kernel object */
struct goldfish_pipe *pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
+
if (!pipe)
return -ENOMEM;

--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:55:07

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 16/21] platform: goldfish: pipe: Call misc_deregister if init fails

From: Roman Kiryanov <[email protected]>

Undo effects of misc_register if driver's init fails after
misc_register.

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/goldfish_pipe_v2.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/goldfish/goldfish_pipe_v2.c b/drivers/platform/goldfish/goldfish_pipe_v2.c
index 9fa5136be909..e3358c682562 100644
--- a/drivers/platform/goldfish/goldfish_pipe_v2.c
+++ b/drivers/platform/goldfish/goldfish_pipe_v2.c
@@ -1159,8 +1159,10 @@ int goldfish_pipe_device_v2_init(struct platform_device *pdev,
dev->pipes_capacity = INITIAL_PIPES_CAPACITY;
dev->pipes = kcalloc(dev->pipes_capacity, sizeof(*dev->pipes),
GFP_KERNEL);
- if (!dev->pipes)
+ if (!dev->pipes) {
+ misc_deregister(&dev->miscdev);
return -ENOMEM;
+ }

/*
* We're going to pass two buffers, open_command_params and
@@ -1173,6 +1175,7 @@ int goldfish_pipe_device_v2_init(struct platform_device *pdev,
__get_free_page(GFP_KERNEL);
if (!dev->buffers) {
kfree(dev->pipes);
+ misc_deregister(&dev->miscdev);
return -ENOMEM;
}

--
2.19.0.397.gdd90340f6a-goog


2018-09-14 17:55:17

by Roman Kiryanov

[permalink] [raw]
Subject: [PATCH 21/21] platform: goldfish: pipe: Fix allmodconfig build

From: Roman Kiryanov <[email protected]>

The changes fixes these errors:

WARNING: modpost: missing MODULE_LICENSE() in drivers/platform/goldfish/goldfish_pipe_v1.o
see include/linux/module.h for more information
WARNING: modpost: missing MODULE_LICENSE() in drivers/platform/goldfish/goldfish_pipe_v2.o
see include/linux/module.h for more information
ERROR: "goldfish_pipe_device_v2_init" [drivers/platform/goldfish/goldfish_pipe.ko] undefined!
ERROR: "goldfish_pipe_device_v1_init" [drivers/platform/goldfish/goldfish_pipe.ko] undefined!
scripts/Makefile.modpost:92: recipe for target '__modpost' failed
make[1]: *** [__modpost] Error 1
Makefile:1206: recipe for target 'modules' failed
make: *** [modules] Error 2

Signed-off-by: Roman Kiryanov <[email protected]>
---
drivers/platform/goldfish/Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/goldfish/Makefile b/drivers/platform/goldfish/Makefile
index acb105dbd9fd..354b4a7d18bb 100644
--- a/drivers/platform/goldfish/Makefile
+++ b/drivers/platform/goldfish/Makefile
@@ -1,5 +1,5 @@
#
# Makefile for Goldfish platform specific drivers
#
-obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o \
- goldfish_pipe_v1.o goldfish_pipe_v2.o
+obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe_all.o
+goldfish_pipe_all-objs := goldfish_pipe.o goldfish_pipe_v1.o goldfish_pipe_v2.o
--
2.19.0.397.gdd90340f6a-goog


2018-09-25 18:29:41

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 21/21] platform: goldfish: pipe: Fix allmodconfig build

On Fri, Sep 14, 2018 at 10:51:22AM -0700, [email protected] wrote:
> From: Roman Kiryanov <[email protected]>
>
> The changes fixes these errors:
>
> WARNING: modpost: missing MODULE_LICENSE() in drivers/platform/goldfish/goldfish_pipe_v1.o
> see include/linux/module.h for more information
> WARNING: modpost: missing MODULE_LICENSE() in drivers/platform/goldfish/goldfish_pipe_v2.o
> see include/linux/module.h for more information
> ERROR: "goldfish_pipe_device_v2_init" [drivers/platform/goldfish/goldfish_pipe.ko] undefined!
> ERROR: "goldfish_pipe_device_v1_init" [drivers/platform/goldfish/goldfish_pipe.ko] undefined!
> scripts/Makefile.modpost:92: recipe for target '__modpost' failed
> make[1]: *** [__modpost] Error 1
> Makefile:1206: recipe for target 'modules' failed
> make: *** [modules] Error 2
>
> Signed-off-by: Roman Kiryanov <[email protected]>
> ---
> drivers/platform/goldfish/Makefile | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)

You can not break the build on one patch, and then fix it up on a later
one. Each patch has to be self-contained and able to be built with no
errors or warnings. So please redo this in the proper place where the
error happened.

thanks,

greg k-h

2018-09-25 18:32:47

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 06/21] platform: goldfish: pipe: Add DMA support to goldfish pipe

On Fri, Sep 14, 2018 at 10:51:07AM -0700, [email protected] wrote:
> From: Roman Kiryanov <[email protected]>
>
> Goldfish DMA is an extension to the pipe device and is designed
> to facilitate high-speed RAM->RAM transfers from guest to host.
>
> See uapi/linux/goldfish/goldfish_dma.h for more details.
>
> Signed-off-by: Roman Kiryanov <[email protected]>
> ---
> drivers/platform/goldfish/goldfish_pipe.c | 312 +++++++++++++++++-
> .../platform/goldfish/goldfish_pipe_qemu.h | 2 +
> include/uapi/linux/goldfish/goldfish_dma.h | 84 +++++
> 3 files changed, 396 insertions(+), 2 deletions(-)
> create mode 100644 include/uapi/linux/goldfish/goldfish_dma.h

A whole new api needs some others to review it becides just me. Please
get some more signed off by on this.

Also, some minor comments:

> --- /dev/null
> +++ b/include/uapi/linux/goldfish/goldfish_dma.h
> @@ -0,0 +1,84 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2018 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.

If you have a spdx line, you don't need the gpl boiler-plate text
either.

But, this is a uapi file, so gpl2 is not probably the license you want
here, right? That should be fixed before you end up doing something
foolish with a userspace program that includes this :)

> +/* GOLDFISH DMA
> + *
> + * Goldfish DMA is an extension to the pipe device
> + * and is designed to facilitate high-speed RAM->RAM
> + * transfers from guest to host.
> + *
> + * Interface (guest side):
> + *
> + * The guest user calls goldfish_dma_alloc (ioctls)
> + * and then mmap() on a goldfish pipe fd,
> + * which means that it wants high-speed access to
> + * host-visible memory.
> + *
> + * The guest can then write into the pointer
> + * returned by mmap(), and these writes
> + * become immediately visible on the host without BQL
> + * or otherweise context switching.
> + *
> + * dma_alloc_coherent() is used to obtain contiguous
> + * physical memory regions, and we allocate and interact
> + * with this region on both guest and host through
> + * the following ioctls:
> + *
> + * - LOCK: lock the region for data access.
> + * - UNLOCK: unlock the region. This may also be done from the host
> + * through the WAKE_ON_UNLOCK_DMA procedure.
> + * - CREATE_REGION: initialize size info for a dma region.
> + * - GETOFF: send physical address to guest drivers.
> + * - (UN)MAPHOST: uses goldfish_pipe_cmd to tell the host to
> + * (un)map to the guest physical address associated
> + * with the current dma context. This makes the physically
> + * contiguous memory (in)visible to the host.
> + *
> + * Guest userspace obtains a pointer to the DMA memory
> + * through mmap(), which also lazily allocates the memory
> + * with dma_alloc_coherent. (On last pipe close(), the region is freed).
> + * The mmaped() region can handle very high bandwidth
> + * transfers, and pipe operations can be used at the same
> + * time to handle synchronization and command communication.
> + */
> +
> +#define GOLDFISH_DMA_BUFFER_SIZE (32 * 1024 * 1024)
> +
> +struct goldfish_dma_ioctl_info {
> + __u64 phys_begin;
> + __u64 size;
> +};

Don't we have a dma userspace api? What does virtio use? What about
uio? Why can't one of the existing interfaces work for you?

> +/* There is an ioctl associated with goldfish dma driver.
> + * Make it conflict with ioctls that are not likely to be used
> + * in the emulator.
> + * 'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict!
> + * 'G' 00-0F linux/gigaset_dev.h conflict!

Causing known conflicts is not wise.

thanks,

greg k-h

2018-09-25 23:06:58

by Roman Kiryanov

[permalink] [raw]
Subject: Re: [PATCH 06/21] platform: goldfish: pipe: Add DMA support to goldfish pipe

Hi, thank you for looking into my patches.

> A whole new api needs some others to review it becides just me. Please
> get some more signed off by on this.

Yes, I will find more people.

> If you have a spdx line, you don't need the gpl boiler-plate text
> either.

Agree.

> But, this is a uapi file, so gpl2 is not probably the license you want
> here, right? That should be fixed before you end up doing something
> foolish with a userspace program that includes this :)

I will confirm which license works for us.

> Don't we have a dma userspace api? What does virtio use? What about
> uio? Why can't one of the existing interfaces work for you?

Yes, I learned we have other tools to do the same as our driver does,
but we already have
userland using DMA through out driver. Maybe I will retire this driver
completely.

> > + * 'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict!
> > + * 'G' 00-0F linux/gigaset_dev.h conflict!
>
> Causing known conflicts is not wise.

Goldfish devices are used only in Android emulator. We can pick other
numbers to avoid conflicts,
but this breaks our userland. We are ok with conflicts with drivers we
don't expect to be used.

2018-09-26 22:29:55

by Roman Kiryanov

[permalink] [raw]
Subject: Re: [PATCH 21/21] platform: goldfish: pipe: Fix allmodconfig build

Hi, thank you for looking into my patches.

> You can not break the build on one patch, and then fix it up on a later
> one.

Thank you catching this. Please drop this patch.