goldfish_pipe.c revision 17c4c9db4a33ae0a8dcfafab3dc59a83ccaf6076
1c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 2c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Copyright (C) 2011 Google, Inc. 3c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Copyright (C) 2012 Intel, Inc. 4c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Copyright (C) 2013 Intel, Inc. 5c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 6c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This software is licensed under the terms of the GNU General Public 7c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * License version 2, as published by the Free Software Foundation, and 8c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * may be copied, distributed, and modified under those terms. 9c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 10c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This program is distributed in the hope that it will be useful, 11c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * GNU General Public License for more details. 14c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 15c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 16c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 17c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This source file contains the implementation of a special device driver 18c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * that intends to provide a *very* fast communication channel between the 19c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * guest system and the QEMU emulator. 20c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 21c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Usage from the guest is simply the following (error handling simplified): 22c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 23c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * int fd = open("/dev/qemu_pipe",O_RDWR); 24c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * .... write() or read() through the pipe. 25c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 26c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This driver doesn't deal with the exact protocol used during the session. 27c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * It is intended to be as simple as something like: 28c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 29c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // do this _just_ after opening the fd to connect to a specific 30c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // emulator service. 31c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * const char* msg = "<pipename>"; 32c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * if (write(fd, msg, strlen(msg)+1) < 0) { 33c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * ... could not connect to <pipename> service 34c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * close(fd); 35c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * } 36c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 37c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // after this, simply read() and write() to communicate with the 38c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // service. Exact protocol details left as an exercise to the reader. 39c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 40c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This driver is very fast because it doesn't copy any data through 41c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * intermediate buffers, since the emulator is capable of translating 42c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * guest user addresses into host ones. 43c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 44c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Note that we must however ensure that each user page involved in the 45c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * exchange is properly mapped during a transfer. 46c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 47c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 48c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/module.h> 49c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/interrupt.h> 50c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/kernel.h> 51c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/spinlock.h> 52c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/miscdevice.h> 53c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/platform_device.h> 54c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/poll.h> 55c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/sched.h> 56c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/bitops.h> 57c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/slab.h> 58c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/io.h> 59c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 60c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 61c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * IMPORTANT: The following constants must match the ones used and defined 62c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * in external/qemu/hw/goldfish_pipe.c in the Android source tree. 63c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 64c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 65c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* pipe device registers */ 66c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_COMMAND 0x00 /* write: value = command */ 67c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_STATUS 0x04 /* read */ 68c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_CHANNEL 0x08 /* read/write: channel id */ 69c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_SIZE 0x0c /* read/write: buffer size */ 70c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_ADDRESS 0x10 /* write: physical address */ 71c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_WAKES 0x14 /* read: wake flags */ 72c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_PARAMS_ADDR_LOW 0x18 /* read/write: batch data address */ 73c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_PARAMS_ADDR_HIGH 0x1c /* read/write: batch data address */ 74c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_ACCESS_PARAMS 0x20 /* write: batch access */ 75c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 76c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* list of commands for PIPE_REG_COMMAND */ 77c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_OPEN 1 /* open new channel */ 78c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_CLOSE 2 /* close channel (from guest) */ 79c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_POLL 3 /* poll read/write status */ 80c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 81c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* List of bitflags returned in status of CMD_POLL command */ 82c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_POLL_IN (1 << 0) 83c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_POLL_OUT (1 << 1) 84c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_POLL_HUP (1 << 2) 85c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 86c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* The following commands are related to write operations */ 87c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_WRITE_BUFFER 4 /* send a user buffer to the emulator */ 88c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_WAKE_ON_WRITE 5 /* tell the emulator to wake us when writing 89c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner is possible */ 90c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 91c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* The following commands are related to read operations, they must be 92c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * listed in the same order than the corresponding write ones, since we 93c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * will use (CMD_READ_BUFFER - CMD_WRITE_BUFFER) as a special offset 94c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * in goldfish_pipe_read_write() below. 95c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 96c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_READ_BUFFER 6 /* receive a user buffer from the emulator */ 97c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_WAKE_ON_READ 7 /* tell the emulator to wake us when reading 98c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * is possible */ 99c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 100c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* Possible status values used to signal errors - see goldfish_pipe_error_convert */ 101c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_INVAL -1 102c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_AGAIN -2 103c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_NOMEM -3 104c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_IO -4 105c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 106c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* Bit-flags used to signal events from the emulator */ 107c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_WAKE_CLOSED (1 << 0) /* emulator closed pipe */ 108c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_WAKE_READ (1 << 1) /* pipe can now be read from */ 109c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_WAKE_WRITE (1 << 2) /* pipe can now be written to */ 110c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 111c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstruct access_params { 112c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 channel; 113c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 size; 114c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 address; 115c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 cmd; 116c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 result; 117c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* reserved for future extension */ 118c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 flags; 119c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 120c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 121c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* The global driver data. Holds a reference to the i/o page used to 122c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * communicate with the emulator, and a wake queue for blocked tasks 123c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * waiting to be awoken. 124c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 125c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstruct goldfish_pipe_dev { 126c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spinlock_t lock; 127c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned char __iomem *base; 128c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps; 129c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int irq; 130c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 131c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 132c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic struct goldfish_pipe_dev pipe_dev[1]; 133c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 134c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This data type models a given pipe instance */ 135c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstruct goldfish_pipe { 136c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev; 137c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct mutex lock; 138c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long flags; 139c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wait_queue_head_t wake_queue; 140c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 141c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 142c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 143c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* Bit flags for the 'flags' field */ 144c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerenum { 145c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */ 146c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */ 147c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner BIT_WAKE_ON_READ = 2, /* want to be woken on reads */ 148c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 149c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 150c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 151c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic u32 goldfish_cmd_status(struct goldfish_pipe *pipe, u32 cmd) 152c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 153c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long flags; 154c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 status; 155c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe->dev; 156c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 157c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, flags); 158c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel((u32)pipe, dev->base + PIPE_REG_CHANNEL); 159c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(cmd, dev->base + PIPE_REG_COMMAND); 160c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = readl(dev->base + PIPE_REG_STATUS); 161c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, flags); 162c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return status; 163c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 164c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 165c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic void goldfish_cmd(struct goldfish_pipe *pipe, u32 cmd) 166c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 167c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long flags; 168c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe->dev; 169c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 170c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, flags); 171c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel((u32)pipe, dev->base + PIPE_REG_CHANNEL); 172c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(cmd, dev->base + PIPE_REG_COMMAND); 173c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, flags); 174c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 175c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 176c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This function converts an error code returned by the emulator through 177c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * the PIPE_REG_STATUS i/o register into a valid negative errno value. 178c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 179c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_error_convert(int status) 180c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 181c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner switch (status) { 182c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner case PIPE_ERROR_AGAIN: 183c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EAGAIN; 184c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner case PIPE_ERROR_NOMEM: 185c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ENOMEM; 186c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner case PIPE_ERROR_IO: 187c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EIO; 188c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner default: 189c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EINVAL; 190c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 191c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 192c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 193c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 194c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Notice: QEMU will return 0 for un-known register access, indicating 195c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * param_acess is supported or not 196c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 197c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int valid_batchbuffer_addr(struct goldfish_pipe_dev *dev, 198c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps) 199c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 200c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 aph, apl; 201c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u64 paddr; 202c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aph = readl(dev->base + PIPE_REG_PARAMS_ADDR_HIGH); 203c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner apl = readl(dev->base + PIPE_REG_PARAMS_ADDR_LOW); 204c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 205c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner paddr = ((u64)aph << 32) | apl; 206c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (paddr != (__pa(aps))) 207c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 208c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 1; 209c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 210c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 211c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 0 on success */ 212c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int setup_access_params_addr(struct platform_device *pdev, 213c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev) 214c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 215c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u64 paddr; 216c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps; 217c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 218c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps = devm_kzalloc(&pdev->dev, sizeof(struct access_params), GFP_KERNEL); 219c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!aps) 220c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 221c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 222c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* FIXME */ 223c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner paddr = __pa(aps); 224c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel((u32)(paddr >> 32), dev->base + PIPE_REG_PARAMS_ADDR_HIGH); 225c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel((u32)paddr, dev->base + PIPE_REG_PARAMS_ADDR_LOW); 226c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 227c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (valid_batchbuffer_addr(dev, aps)) { 228c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->aps = aps; 229c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 230c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } else 231c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 232c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 233c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 234c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* A value that will not be set by qemu emulator */ 235c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define INITIAL_BATCH_RESULT (0xdeadbeaf) 236c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int access_with_param(struct goldfish_pipe_dev *dev, const int cmd, 237c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long address, unsigned long avail, 238c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe, int *status) 239c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 240c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps = dev->aps; 241c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 242c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (aps == NULL) 243c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 244c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 245c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->result = INITIAL_BATCH_RESULT; 246c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->channel = (unsigned long)pipe; 247c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->size = avail; 248c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->address = address; 249c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->cmd = cmd; 250c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(cmd, dev->base + PIPE_REG_ACCESS_PARAMS); 251c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* 252c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * If the aps->result has not changed, that means 253c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * that the batch command failed 254c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 255c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (aps->result == INITIAL_BATCH_RESULT) 256c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 257c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner *status = aps->result; 258c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 259c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 260c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 261c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This function is used for both reading from and writing to a given 262c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * pipe. 263c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 264c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer, 265c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner size_t bufflen, int is_write) 266c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 267c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long irq_flags; 268c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe = filp->private_data; 269c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe->dev; 270c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner const int cmd_offset = is_write ? 0 271c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner : (CMD_READ_BUFFER - CMD_WRITE_BUFFER); 272c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long address, address_end; 273c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int ret = 0; 274c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 275c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* If the emulator already closed the pipe, no need to go further */ 276c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) 277c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EIO; 278c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 279c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Null reads or writes succeeds */ 280c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (unlikely(bufflen) == 0) 281c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 282c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 283c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Check the buffer range for access */ 284c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ, 285c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner buffer, bufflen)) 286c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EFAULT; 287c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 288c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Serialize access to the pipe */ 289c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (mutex_lock_interruptible(&pipe->lock)) 290c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ERESTARTSYS; 291c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 292c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address = (unsigned long)(void *)buffer; 293c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address_end = address + bufflen; 294c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 295c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner while (address < address_end) { 296c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE; 297c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long next = page_end < address_end ? page_end 298c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner : address_end; 299c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long avail = next - address; 300c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int status, wakeBit; 301c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 302c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Ensure that the corresponding page is properly mapped */ 30317c4c9db4a33ae0a8dcfafab3dc59a83ccaf6076Alan Cox /* FIXME: this isn't safe or sufficient - use get_user_pages */ 304c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (is_write) { 305c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner char c; 306c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Ensure that the page is mapped and readable */ 307c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (__get_user(c, (char __user *)address)) { 308c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!ret) 309c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret = -EFAULT; 310c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 311c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 312c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } else { 313c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Ensure that the page is mapped and writable */ 314c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (__put_user(0, (char __user *)address)) { 315c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!ret) 316c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret = -EFAULT; 317c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 318c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 319c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 320c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 321c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Now, try to transfer the bytes in the current page */ 322c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, irq_flags); 323c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (access_with_param(dev, CMD_WRITE_BUFFER + cmd_offset, 324c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address, avail, pipe, &status)) { 325c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel((u32)pipe, dev->base + PIPE_REG_CHANNEL); 326c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(avail, dev->base + PIPE_REG_SIZE); 327c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(address, dev->base + PIPE_REG_ADDRESS); 328c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(CMD_WRITE_BUFFER + cmd_offset, 329c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base + PIPE_REG_COMMAND); 330c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = readl(dev->base + PIPE_REG_STATUS); 331c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 332c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, irq_flags); 333c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 334c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status > 0) { /* Correct transfer */ 335c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret += status; 336c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address += status; 337c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner continue; 338c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 339c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 340c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status == 0) /* EOF */ 341c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 342c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 343c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* An error occured. If we already transfered stuff, just 344c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * return with its count. We expect the next call to return 345c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * an error code */ 346c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (ret > 0) 347c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 348c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 349c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* If the error is not PIPE_ERROR_AGAIN, or if we are not in 350c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * non-blocking mode, just return the error code. 351c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 352c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status != PIPE_ERROR_AGAIN || 353c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner (filp->f_flags & O_NONBLOCK) != 0) { 354c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret = goldfish_pipe_error_convert(status); 355c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 356c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 357c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 358c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* We will have to wait until more data/space is available. 359c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * First, mark the pipe as waiting for a specific wake signal. 360c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 361c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ; 362c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner set_bit(wakeBit, &pipe->flags); 363c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 364c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Tell the emulator we're going to wait for a wake event */ 365c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goldfish_cmd(pipe, CMD_WAKE_ON_WRITE + cmd_offset); 366c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 367c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Unlock the pipe, then wait for the wake signal */ 368c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_unlock(&pipe->lock); 369c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 370c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner while (test_bit(wakeBit, &pipe->flags)) { 371c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wait_event_interruptible( 372c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe->wake_queue, 373c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner !test_bit(wakeBit, &pipe->flags))) 374c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ERESTARTSYS; 375c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 376c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) 377c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EIO; 378c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 379c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 380c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Try to re-acquire the lock */ 381c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (mutex_lock_interruptible(&pipe->lock)) 382c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ERESTARTSYS; 383c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 384c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Try the transfer again */ 385c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner continue; 386c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 387c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_unlock(&pipe->lock); 388c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return ret; 389c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 390c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 391c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer, 392c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner size_t bufflen, loff_t *ppos) 393c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 394c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return goldfish_pipe_read_write(filp, buffer, bufflen, 0); 395c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 396c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 397c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic ssize_t goldfish_pipe_write(struct file *filp, 398c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner const char __user *buffer, size_t bufflen, 399c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner loff_t *ppos) 400c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 401c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return goldfish_pipe_read_write(filp, (char __user *)buffer, 402c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner bufflen, 1); 403c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 404c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 405c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 406c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic unsigned int goldfish_pipe_poll(struct file *filp, poll_table *wait) 407c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 408c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe = filp->private_data; 409c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned int mask = 0; 410c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int status; 411c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 412c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_lock(&pipe->lock); 413c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 414c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner poll_wait(filp, &pipe->wake_queue, wait); 415c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 416c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = goldfish_cmd_status(pipe, CMD_POLL); 417c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 418c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_unlock(&pipe->lock); 419c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 420c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status & PIPE_POLL_IN) 421c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLIN | POLLRDNORM; 422c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 423c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status & PIPE_POLL_OUT) 424c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLOUT | POLLWRNORM; 425c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 426c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status & PIPE_POLL_HUP) 427c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLHUP; 428c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 429c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) 430c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLERR; 431c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 432c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return mask; 433c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 434c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 435c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) 436c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 437c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = dev_id; 438c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long irq_flags; 439c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int count = 0; 440c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 441c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* We're going to read from the emulator a list of (channel,flags) 442c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * pairs corresponding to the wake events that occured on each 443c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * blocked pipe (i.e. channel). 444c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 445c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, irq_flags); 446c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner for (;;) { 447c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* First read the channel, 0 means the end of the list */ 448c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe; 449c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long wakes; 450c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long channel = readl(dev->base + PIPE_REG_CHANNEL); 451c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 452c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (channel == 0) 453c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 454c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 455c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Convert channel to struct pipe pointer + read wake flags */ 456c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wakes = readl(dev->base + PIPE_REG_WAKES); 457c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe = (struct goldfish_pipe *)(ptrdiff_t)channel; 458c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 459c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Did the emulator just closed a pipe? */ 460c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wakes & PIPE_WAKE_CLOSED) { 461c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner set_bit(BIT_CLOSED_ON_HOST, &pipe->flags); 462c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wakes |= PIPE_WAKE_READ | PIPE_WAKE_WRITE; 463c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 464c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wakes & PIPE_WAKE_READ) 465c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner clear_bit(BIT_WAKE_ON_READ, &pipe->flags); 466c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wakes & PIPE_WAKE_WRITE) 467c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner clear_bit(BIT_WAKE_ON_WRITE, &pipe->flags); 468c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 469c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wake_up_interruptible(&pipe->wake_queue); 470c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner count++; 471c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 472c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, irq_flags); 473c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 474c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return (count == 0) ? IRQ_NONE : IRQ_HANDLED; 475c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 476c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 477c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/** 478c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * goldfish_pipe_open - open a channel to the AVD 479c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * @inode: inode of device 480c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * @file: file struct of opener 481c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 482c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Create a new pipe link between the emulator and the use application. 483c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Each new request produces a new pipe. 484c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 485c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Note: we use the pipe ID as a mux. All goldfish emulations are 32bit 486c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * right now so this is fine. A move to 64bit will need this addressing 487c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 488c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_open(struct inode *inode, struct file *file) 489c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 490c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe; 491c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe_dev; 492c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int32_t status; 493c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 494c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Allocate new pipe kernel object */ 495c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); 496c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (pipe == NULL) 497c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ENOMEM; 498c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 499c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe->dev = dev; 500c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_init(&pipe->lock); 501c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner init_waitqueue_head(&pipe->wake_queue); 502c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 503c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* 504c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Now, tell the emulator we're opening a new pipe. We use the 505c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * pipe object's address as the channel identifier for simplicity. 506c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 507c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 508c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = goldfish_cmd_status(pipe, CMD_OPEN); 509c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status < 0) { 510c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner kfree(pipe); 511c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return status; 512c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 513c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 514c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* All is done, save the pipe into the file's private data field */ 515c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner file->private_data = pipe; 516c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 517c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 518c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 519c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_release(struct inode *inode, struct file *filp) 520c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 521c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe = filp->private_data; 522c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 523c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* The guest is closing the channel, so tell the emulator right now */ 524c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goldfish_cmd(pipe, CMD_CLOSE); 525c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner kfree(pipe); 526c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner filp->private_data = NULL; 527c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 528c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 529c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 530c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic const struct file_operations goldfish_pipe_fops = { 531c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .owner = THIS_MODULE, 532c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .read = goldfish_pipe_read, 533c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .write = goldfish_pipe_write, 534c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .poll = goldfish_pipe_poll, 535c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .open = goldfish_pipe_open, 536c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .release = goldfish_pipe_release, 537c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 538c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 539c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic struct miscdevice goldfish_pipe_device = { 540c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .minor = MISC_DYNAMIC_MINOR, 541c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .name = "goldfish_pipe", 542c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .fops = &goldfish_pipe_fops, 543c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 544c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 545c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_probe(struct platform_device *pdev) 546c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 547c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int err; 548c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct resource *r; 549c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe_dev; 550c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 551c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* not thread safe, but this should not happen */ 552c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner WARN_ON(dev->base != NULL); 553c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 554c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_init(&dev->lock); 555c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 556c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 557c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (r == NULL || resource_size(r) < PAGE_SIZE) { 558c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "can't allocate i/o page\n"); 559c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EINVAL; 560c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 561c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); 562c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (dev->base == NULL) { 563c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "ioremap failed\n"); 564c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EINVAL; 565c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 566c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 567c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 568c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (r == NULL) { 569c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner err = -EINVAL; 570c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goto error; 571c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 572c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->irq = r->start; 573c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 574c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt, 575c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner IRQF_SHARED, "goldfish_pipe", dev); 576c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (err) { 577c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "unable to allocate IRQ\n"); 578c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goto error; 579c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 580c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 581c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner err = misc_register(&goldfish_pipe_device); 582c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (err) { 583c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "unable to register device\n"); 584c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goto error; 585c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 586c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner setup_access_params_addr(pdev, dev); 587c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 588c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 589c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnererror: 590c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base = NULL; 591c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return err; 592c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 593c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 594c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_remove(struct platform_device *pdev) 595c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 596c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe_dev; 597c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner misc_deregister(&goldfish_pipe_device); 598c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base = NULL; 599c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 600c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 601c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 602c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic struct platform_driver goldfish_pipe = { 603c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .probe = goldfish_pipe_probe, 604c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .remove = goldfish_pipe_remove, 605c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .driver = { 606c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .name = "goldfish_pipe" 607c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 608c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 609c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 610c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnermodule_platform_driver(goldfish_pipe); 611c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' TurnerMODULE_AUTHOR("David Turner <digit@google.com>"); 612c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' TurnerMODULE_LICENSE("GPL"); 613