diff options
author | Roman Kiryanov <rkir@google.com> | 2024-01-11 13:46:22 -0800 |
---|---|---|
committer | Roman Kiryanov <rkir@google.com> | 2024-01-19 12:10:13 -0800 |
commit | 1b0a7d01bb5935588db85a54b5d80c5eabbaedf5 (patch) | |
tree | 2eeeead293a03491ab7c77e6eb498de3652377de | |
parent | 7638ffeafee0adb892909545f95efad331b2fd11 (diff) | |
download | virtual-device-1b0a7d01bb5935588db85a54b5d80c5eabbaedf5.tar.gz |
Retire DMA from goldfish_pipe
replaced by goldfish_address_space
Bug: 319713048
Test: boot emulator with the updated kernel
Change-Id: Ic075712c9481c2c9d27bf8e1ed32f404e64d9088
Signed-off-by: Roman Kiryanov <rkir@google.com>
-rw-r--r-- | goldfish_drivers/goldfish_pipe.c | 319 | ||||
-rw-r--r-- | uapi/goldfish/goldfish_dma.h | 84 |
2 files changed, 16 insertions, 387 deletions
diff --git a/goldfish_drivers/goldfish_pipe.c b/goldfish_drivers/goldfish_pipe.c index 4c6fb21..a9eaefc 100644 --- a/goldfish_drivers/goldfish_pipe.c +++ b/goldfish_drivers/goldfish_pipe.c @@ -53,7 +53,6 @@ #include <linux/acpi.h> #include <linux/bitops.h> #include <linux/bug.h> -#include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> @@ -68,8 +67,6 @@ #include <linux/sched.h> #include <linux/slab.h> -#include <goldfish/goldfish_dma.h> - static const char DEVICE_NAME[] = "goldfish_pipe_dprctd"; /* @@ -77,8 +74,11 @@ static const char DEVICE_NAME[] = "goldfish_pipe_dprctd"; * 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. + * version 3 is goldfish_pipe_v2 without DMA support. + * version 4 (current) is goldfish_pipe_v2 with DMA support. + * + * goldfish_address_space replaces DMA in goldfish_pipe, + * DMA is retired in goldfish_pipe. */ enum { PIPE_DRIVER_VERSION = 4, @@ -89,8 +89,6 @@ enum { MAX_BUFFERS_PER_COMMAND = 336, MAX_SIGNALLED_PIPES = 64, INITIAL_PIPES_CAPACITY = 64, - DMA_REGION_MIN_SIZE = PAGE_SIZE, - DMA_REGION_MAX_SIZE = 256 << 20 }; /* List of bitflags returned in status of CMD_POLL command */ @@ -116,10 +114,6 @@ enum PipeWakeFlags { PIPE_WAKE_READ = 1 << 1, /* pipe can now be written to */ PIPE_WAKE_WRITE = 1 << 2, - /* unlock this pipe's DMA buffer */ - PIPE_WAKE_UNLOCK_DMA = 1 << 3, - /* unlock DMA buffer of the pipe shared to this pipe */ - PIPE_WAKE_UNLOCK_DMA_SHARED = 1 << 4, }; /* Bit flags for the 'flags' field */ @@ -181,14 +175,6 @@ enum PipeCmdCode { PIPE_CMD_WAKE_ON_WRITE, PIPE_CMD_READ, PIPE_CMD_WAKE_ON_READ, - - /* - * TODO(zyy): implement a deferred read/write execution to allow - * parallel processing of pipe operations on the host. - */ - PIPE_CMD_WAKE_ON_DONE_IO, - PIPE_CMD_DMA_HOST_MAP, - PIPE_CMD_DMA_HOST_UNMAP, }; @@ -200,24 +186,17 @@ struct goldfish_pipe_command { s32 id; /* pipe id, guest -> host */ s32 status; /* command execution status, host -> guest */ s32 reserved; /* to pad to 64-bit boundary */ - union { - /* Parameters for PIPE_CMD_{READ,WRITE} */ - struct { - /* number of buffers, guest -> host */ - u32 buffers_count; - /* number of consumed bytes, host -> guest */ - s32 consumed_size; - /* buffer pointers, guest -> host */ - u64 ptrs[MAX_BUFFERS_PER_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; - }; + /* Parameters for PIPE_CMD_{READ,WRITE} */ + struct { + /* number of buffers, guest -> host */ + u32 buffers_count; + /* number of consumed bytes, host -> guest */ + s32 consumed_size; + /* buffer pointers, guest -> host */ + u64 ptrs[MAX_BUFFERS_PER_COMMAND]; + /* buffer sizes, guest -> host */ + u32 sizes[MAX_BUFFERS_PER_COMMAND]; + } rw_params; }; /* A single signalled pipe information */ @@ -239,24 +218,6 @@ 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 */ @@ -297,9 +258,6 @@ 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 @@ -346,9 +304,6 @@ struct goldfish_pipe_dev { unsigned char __iomem *base; struct miscdevice miscdev; - - /* DMA info */ - size_t dma_alloc_total; }; static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe, @@ -874,7 +829,6 @@ 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; @@ -891,40 +845,6 @@ err_pipe: 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; @@ -932,7 +852,6 @@ 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); @@ -942,14 +861,6 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp) 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); @@ -987,200 +898,6 @@ static const struct vm_operations_struct goldfish_dma_vm_ops = { .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; - - goldfish_pipe_cmd_locked(pipe, PIPE_CMD_DMA_HOST_MAP); - /* A workaround for b/110152998 */ - return 0; -} - -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(sizeof_field(struct goldfish_dma_ioctl_info, phys_begin) < - sizeof_field(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, @@ -1188,10 +905,6 @@ 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 void init_miscdevice(struct miscdevice *miscdev) diff --git a/uapi/goldfish/goldfish_dma.h b/uapi/goldfish/goldfish_dma.h deleted file mode 100644 index a901902..0000000 --- a/uapi/goldfish/goldfish_dma.h +++ /dev/null @@ -1,84 +0,0 @@ -/* 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 */ |