Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From a95f49b0c480da1a9d9cdbe0cf1aee6de3828eb5 Mon Sep 17 00:00:00 2001
- From: Brendan Shanks <mrpippy@gmail.com>
- Date: Sat, 6 Feb 2010 23:53:54 -0800
- Subject: [PATCH] Make donut/eclair hw3d a config choice
- Make donut/eclair hw3d driver a config choice. Donut hw3d is tested and
- working, and Eclair hw3d is also tested and working. For Eclair hw3d, I
- had to make gpu0 smaller so it wouldn't run into ramconsole.
- ---
- arch/arm/configs/htc_msm_android_defconfig | 6 +-
- arch/arm/mach-msm/Kconfig | 14 +-
- arch/arm/mach-msm/Makefile | 1 +
- arch/arm/mach-msm/hw3d.c | 832 +++++++++++++++++++++++-----
- arch/arm/mach-msm/hw3d_donut.c | 213 +++++++
- arch/arm/mach-msm/pmem.c | 51 ++-
- 6 files changed, 985 insertions(+), 132 deletions(-)
- create mode 100644 arch/arm/mach-msm/hw3d_donut.c
- diff --git a/arch/arm/configs/htc_msm_android_defconfig b/arch/arm/configs/htc_msm_android_defconfig
- index 4bb2457..f4fa3f2 100644
- --- a/arch/arm/configs/htc_msm_android_defconfig
- +++ b/arch/arm/configs/htc_msm_android_defconfig
- @@ -1,7 +1,7 @@
- #
- # Automatically generated make config: don't edit
- # Linux kernel version: 2.6.27
- -# Mon Feb 1 22:52:21 2010
- +# Sun Feb 7 00:18:24 2010
- #
- CONFIG_ARM=y
- CONFIG_SYS_SUPPORTS_APM_EMULATION=y
- @@ -246,6 +246,7 @@ CONFIG_MSM_CPU_FREQ_ONDEMAND=y
- # CONFIG_MSM_CPU_FREQ_SCREEN is not set
- CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX=528000
- CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN=128000
- +# CONFIG_MSM_HW3D_DONUT is not set
- CONFIG_MSM_HW3D=y
- CONFIG_MSM_ADSP=y
- # CONFIG_HTC_FB_CONSOLE is not set
- @@ -293,7 +294,8 @@ CONFIG_PREEMPT=y
- CONFIG_HZ=100
- CONFIG_AEABI=y
- # CONFIG_OABI_COMPAT is not set
- -CONFIG_ARCH_FLATMEM_HAS_HOLES=y
- +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
- +CONFIG_HOLES_IN_ZONE=y
- # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
- CONFIG_SELECT_MEMORY_MODEL=y
- CONFIG_FLATMEM_MANUAL=y
- diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
- index 4df8fbf..5e359c8 100644
- --- a/arch/arm/mach-msm/Kconfig
- +++ b/arch/arm/mach-msm/Kconfig
- @@ -397,13 +397,21 @@ config MSM_CPU_FREQ_ONDEMAND_MIN
- endif # MSM_CPU_FREQ_ONDEMAND
- +choice
- +prompt "MSM Hardware 3D Register Driver"
- +config MSM_HW3D_DONUT
- + depends on ANDROID_PMEM
- + bool "Android 1.6 (Cupcake or Donut)"
- + help
- + Provides access to registers needed by the userspace OpenGL|ES
- + library for Cupcake and Donut.
- config MSM_HW3D
- depends on ANDROID_PMEM
- - tristate "MSM Hardware 3D Register Driver"
- - default y
- + bool "Android 2.0+ (Eclair)"
- help
- Provides access to registers needed by the userspace OpenGL|ES
- - library.
- + library for Eclair.
- +endchoice
- config MSM_ADSP
- tristate "MSM ADSP driver"
- diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
- index a109e7f..090265c 100644
- --- a/arch/arm/mach-msm/Makefile
- +++ b/arch/arm/mach-msm/Makefile
- @@ -27,6 +27,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
- #obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o
- obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o
- obj-$(CONFIG_MSM_ADSP) += qdsp5/
- +obj-$(CONFIG_MSM_HW3D_DONUT) += hw3d_donut.o
- obj-$(CONFIG_MSM_HW3D) += hw3d.o
- obj-$(CONFIG_PM) += pm.o
- obj-$(CONFIG_MSM_CPU_FREQ) += cpufreq.o
- diff --git a/arch/arm/mach-msm/hw3d.c b/arch/arm/mach-msm/hw3d.c
- index b013b57..8fd46c5 100644
- --- a/arch/arm/mach-msm/hw3d.c
- +++ b/arch/arm/mach-msm/hw3d.c
- @@ -4,6 +4,7 @@
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
- + * Heavily modified: Dima Zavin <dima@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- @@ -16,80 +17,189 @@
- *
- */
- -#include <linux/module.h>
- +#define DEBUG
- +#define VERBOSE
- +
- +#include <linux/clk.h>
- +#include <linux/earlysuspend.h>
- +#include <linux/file.h>
- #include <linux/fs.h>
- +#include <linux/interrupt.h>
- +#include <linux/irq.h>
- #include <linux/miscdevice.h>
- -#include <linux/uaccess.h>
- +#include <linux/mm.h>
- +#include <linux/module.h>
- +#include <linux/msm_hw3d.h>
- +#include <linux/mutex.h>
- +#include <linux/platform_device.h>
- #include <linux/poll.h>
- +#include <linux/sched.h>
- #include <linux/time.h>
- -#include <linux/irq.h>
- -#include <linux/interrupt.h>
- +#include <linux/uaccess.h>
- #include <linux/wait.h>
- -#include <linux/mm.h>
- -#include <linux/clk.h>
- -#include <linux/android_pmem.h>
- +#include <linux/wakelock.h>
- +#include <asm/io.h>
- +
- #include <mach/board.h>
- -static DEFINE_SPINLOCK(hw3d_lock);
- -static DECLARE_WAIT_QUEUE_HEAD(hw3d_queue);
- -static int hw3d_pending;
- -static int hw3d_disabled;
- +#if defined(VERBOSE)
- +#define VDBG(x...) pr_debug(x)
- +#else
- +#define VDBG(x...) do {} while(0)
- +#endif
- -static struct clk *grp_clk;
- -static struct clk *imem_clk;
- -DECLARE_MUTEX(hw3d_sem);
- -static unsigned int hw3d_granted;
- -static struct file *hw3d_granted_file;
- +struct mem_region {
- + unsigned long pbase;
- + unsigned long size;
- + void __iomem *vbase;
- +};
- -static irqreturn_t hw3d_irq_handler(int irq, void *data)
- +struct hw3d_info {
- + struct miscdevice master_dev;
- + struct miscdevice client_dev;
- +
- + struct clk *grp_clk;
- + struct clk *imem_clk;
- + int irq;
- +
- + struct mem_region regions[HW3D_NUM_REGIONS];
- +
- + wait_queue_head_t irq_wq;
- + bool irq_pending;
- + bool irq_en;
- + bool suspending;
- + bool revoking;
- + bool enabled;
- +
- + struct timer_list revoke_timer;
- + wait_queue_head_t revoke_wq;
- + wait_queue_head_t revoke_done_wq;
- +
- + spinlock_t lock;
- +
- + struct file *client_file;
- + struct task_struct *client_task;
- +
- + struct early_suspend early_suspend;
- + struct wake_lock wake_lock;
- +};
- +static struct hw3d_info *hw3d_info;
- +
- +struct hw3d_data {
- + struct vm_area_struct *vmas[HW3D_NUM_REGIONS];
- + struct mutex mutex;
- + bool closing;
- +};
- +
- +#define REGION_PAGE_ID(addr) \
- + ((((uint32_t)(addr)) >> (28 - PAGE_SHIFT)) & 0xf)
- +#define REGION_PAGE_OFFS(addr) \
- + ((((uint32_t)(addr)) & ~(0xf << (28 - PAGE_SHIFT))))
- +
- +static int hw3d_open(struct inode *, struct file *);
- +static int hw3d_release(struct inode *, struct file *);
- +static int hw3d_mmap(struct file *, struct vm_area_struct *);
- +static int hw3d_flush(struct file *, fl_owner_t);
- +static long hw3d_ioctl(struct file *, unsigned int, unsigned long);
- +
- +static void hw3d_vma_open(struct vm_area_struct *);
- +static void hw3d_vma_close(struct vm_area_struct *);
- +
- +static struct file_operations hw3d_fops = {
- + .open = hw3d_open,
- + .release = hw3d_release,
- + .mmap = hw3d_mmap,
- + .flush = hw3d_flush,
- + .unlocked_ioctl = hw3d_ioctl,
- +};
- +
- +static struct vm_operations_struct hw3d_vm_ops = {
- + .open = hw3d_vma_open,
- + .close = hw3d_vma_close,
- +};
- +
- +static bool is_master(struct hw3d_info *info, struct file *file)
- {
- - unsigned long flags;
- + int fmin = MINOR(file->f_dentry->d_inode->i_rdev);
- + return fmin == info->master_dev.minor;
- +}
- +
- +static bool is_client(struct hw3d_info *info, struct file *file)
- +{
- + int fmin = MINOR(file->f_dentry->d_inode->i_rdev);
- + return fmin == info->client_dev.minor;
- +}
- - spin_lock_irqsave(&hw3d_lock, flags);
- - if (!hw3d_disabled) {
- - disable_irq(INT_GRAPHICS);
- - hw3d_disabled = 1;
- +inline static void locked_hw3d_irq_disable(struct hw3d_info *info)
- +{
- + if (info->irq_en) {
- + disable_irq_nosync(info->irq);
- + info->irq_en = 0;
- }
- - hw3d_pending = 1;
- - spin_unlock_irqrestore(&hw3d_lock, flags);
- +}
- - wake_up(&hw3d_queue);
- +inline static void locked_hw3d_irq_enable(struct hw3d_info *info)
- +{
- + if (!info->irq_en) {
- + enable_irq(info->irq);
- + info->irq_en = 1;
- + }
- +}
- - return IRQ_HANDLED;
- +static void hw3d_disable_interrupt(struct hw3d_info *info)
- +{
- + unsigned long flags;
- +
- + spin_lock_irqsave(&info->lock, flags);
- + locked_hw3d_irq_disable(info);
- + spin_unlock_irqrestore(&info->lock, flags);
- }
- -static void hw3d_disable_interrupt(void)
- +static irqreturn_t hw3d_irq_handler(int irq, void *data)
- {
- + struct hw3d_info *info = data;
- unsigned long flags;
- - spin_lock_irqsave(&hw3d_lock, flags);
- - if (!hw3d_disabled) {
- - disable_irq(INT_GRAPHICS);
- - hw3d_disabled = 1;
- - }
- - spin_unlock_irqrestore(&hw3d_lock, flags);
- +
- + spin_lock_irqsave(&info->lock, flags);
- + locked_hw3d_irq_disable(info);
- + info->irq_pending = 1;
- + spin_unlock_irqrestore(&info->lock, flags);
- +
- + wake_up(&info->irq_wq);
- +
- + return IRQ_HANDLED;
- }
- -static long hw3d_wait_for_interrupt(void)
- +static long hw3d_wait_for_interrupt(struct hw3d_info *info, struct file *filp)
- {
- + struct hw3d_data *data = filp->private_data;
- unsigned long flags;
- int ret;
- + if (is_master(info, filp)) {
- + pr_err("%s: cannot wait for irqs on master node\n", __func__);
- + return -EPERM;
- + }
- +
- for (;;) {
- - spin_lock_irqsave(&hw3d_lock, flags);
- - if (hw3d_pending) {
- - hw3d_pending = 0;
- - spin_unlock_irqrestore(&hw3d_lock, flags);
- + spin_lock_irqsave(&info->lock, flags);
- + if (info->irq_pending) {
- + info->irq_pending = 0;
- + spin_unlock_irqrestore(&info->lock, flags);
- return 0;
- }
- - if (hw3d_disabled) {
- - hw3d_disabled = 0;
- - enable_irq(INT_GRAPHICS);
- - }
- - spin_unlock_irqrestore(&hw3d_lock, flags);
- + locked_hw3d_irq_enable(info);
- + spin_unlock_irqrestore(&info->lock, flags);
- - ret = wait_event_interruptible(hw3d_queue, hw3d_pending);
- + ret = wait_event_interruptible(info->irq_wq,
- + info->irq_pending ||
- + info->revoking ||
- + data->closing);
- + /* always make sure the irq gets disabled */
- + if (ret == 0 && !info->irq_pending)
- + ret = -EPIPE;
- if (ret < 0) {
- - hw3d_disable_interrupt();
- + hw3d_disable_interrupt(info);
- return ret;
- }
- }
- @@ -97,117 +207,589 @@ static long hw3d_wait_for_interrupt(void)
- return 0;
- }
- -#define HW3D_REGS_LEN 0x100000
- +static long hw3d_wait_for_revoke(struct hw3d_info *info, struct file *filp)
- +{
- + struct hw3d_data *data = filp->private_data;
- + int ret;
- +
- + if (is_master(info, filp)) {
- + pr_err("%s: cannot revoke on master node\n", __func__);
- + return -EPERM;
- + }
- +
- + ret = wait_event_interruptible(info->revoke_wq,
- + info->revoking ||
- + data->closing);
- + if (ret == 0 && data->closing)
- + ret = -EPIPE;
- + if (ret < 0)
- + return ret;
- + return 0;
- +}
- +
- +static void locked_hw3d_client_done(struct hw3d_info *info, int had_timer)
- +{
- + if (info->enabled) {
- + pr_debug("hw3d: was enabled\n");
- + info->enabled = 0;
- + clk_disable(info->grp_clk);
- + clk_disable(info->imem_clk);
- + }
- + info->revoking = 0;
- + info->client_file = NULL;
- +
- + /* double check that the irqs are disabled */
- + locked_hw3d_irq_disable(info);
- +
- + if (had_timer)
- + wake_unlock(&info->wake_lock);
- + wake_up(&info->revoke_done_wq);
- +}
- +
- +static void do_force_revoke(struct hw3d_info *info)
- +{
- + unsigned long flags;
- +
- + /* at this point, the task had a chance to relinquish the gpu, but
- + * it hasn't. So, we kill it */
- + spin_lock_irqsave(&info->lock, flags);
- + pr_debug("hw3d: forcing revoke\n");
- + locked_hw3d_irq_disable(info);
- + if (info->client_task) {
- + pr_info("hw3d: force revoke from pid=%d\n",
- + info->client_task->pid);
- + force_sig(SIGKILL, info->client_task);
- + put_task_struct(info->client_task);
- + info->client_task = NULL;
- + }
- + locked_hw3d_client_done(info, 1);
- + pr_debug("hw3d: done forcing revoke\n");
- + spin_unlock_irqrestore(&info->lock, flags);
- +}
- +
- +#define REVOKE_TIMEOUT (HZ / 2)
- +static void locked_hw3d_revoke(struct hw3d_info *info)
- +{
- + /* force us to wait to suspend until the revoke is done. If the
- + * user doesn't release the gpu, the timer will turn off the gpu,
- + * and force kill the process. */
- + wake_lock(&info->wake_lock);
- + info->revoking = 1;
- + wake_up(&info->revoke_wq);
- + mod_timer(&info->revoke_timer, jiffies + REVOKE_TIMEOUT);
- +}
- -static long hw3d_revoke_gpu(struct file *file)
- +bool is_msm_hw3d_file(struct file *file)
- {
- + struct hw3d_info *info = hw3d_info;
- + if(!file || !file->f_dentry || !file->f_dentry->d_inode)
- + return 0;
- + if (MAJOR(file->f_dentry->d_inode->i_rdev) == MISC_MAJOR &&
- + (is_master(info, file) || is_client(info, file)))
- + return 1;
- + return 0;
- +}
- +
- +void put_msm_hw3d_file(struct file *file)
- +{
- + if (!is_msm_hw3d_file(file))
- + return;
- + fput(file);
- +}
- +
- +int get_msm_hw3d_file(int fd, int region, uint32_t offs, unsigned long *pbase,
- + unsigned long *len, struct file **filp)
- +{
- + struct hw3d_info *info = hw3d_info;
- + struct file *file;
- + struct hw3d_data *data;
- int ret = 0;
- - unsigned long user_start, user_len;
- - struct pmem_region region = {.offset = 0x0, .len = HW3D_REGS_LEN};
- -
- - down(&hw3d_sem);
- - if (!hw3d_granted) {
- - goto end;
- - }
- - /* revoke the pmem region completely */
- - if ((ret = pmem_remap(®ion, file, PMEM_UNMAP)))
- - goto end;
- - get_pmem_user_addr(file, &user_start, &user_len);
- - /* reset the gpu */
- - clk_disable(grp_clk);
- - clk_disable(imem_clk);
- - hw3d_granted = 0;
- -end:
- - up(&hw3d_sem);
- +
- + if (unlikely(region >= HW3D_NUM_REGIONS)) {
- + VDBG("hw3d: invalid region %d requested\n", region);
- + return -EINVAL;
- + } else if (unlikely(offs >= info->regions[region].size)) {
- + VDBG("hw3d: offset %08x outside of the requested region %d\n",
- + offs, region);
- + return -EINVAL;
- + }
- +
- + file = fget(fd);
- + if (unlikely(file == NULL)) {
- + pr_info("%s: requested data from file descriptor that doesn't "
- + "exist.", __func__);
- + return -EINVAL;
- + } else if (!is_msm_hw3d_file(file)) {
- + ret = -1;
- + goto err;
- + }
- +
- + data = file->private_data;
- + if (unlikely(!data)) {
- + VDBG("hw3d: invalid file\n");
- + ret = -EINVAL;
- + goto err;
- + }
- +
- + mutex_lock(&data->mutex);
- + if (unlikely(!data->vmas[region])) {
- + mutex_unlock(&data->mutex);
- + VDBG("hw3d: requested hw3d region is not mapped\n");
- + ret = -ENOENT;
- + goto err;
- + }
- +
- + *pbase = info->regions[region].pbase;
- + *filp = file;
- + *len = data->vmas[region]->vm_end - data->vmas[region]->vm_start;
- + mutex_unlock(&data->mutex);
- + return 0;
- +
- +err:
- + fput(file);
- return ret;
- }
- -static long hw3d_grant_gpu(struct file *file)
- +static int hw3d_flush(struct file *filp, fl_owner_t id)
- {
- + struct hw3d_info *info = hw3d_info;
- + struct hw3d_data *data = filp->private_data;
- +
- + if (!data) {
- + pr_err("%s: no private data\n", __func__);
- + return -EINVAL;
- + }
- +
- + if (is_master(info, filp))
- + return 0;
- + pr_debug("hw3d: closing\n");
- + /* releases any blocked ioctls */
- + data->closing = 1;
- + wake_up(&info->revoke_wq);
- + wake_up(&info->irq_wq);
- + return 0;
- +}
- +
- +
- +static int hw3d_open(struct inode *inode, struct file *file)
- +{
- + struct hw3d_info *info = hw3d_info;
- + struct hw3d_data *data;
- + unsigned long flags;
- int ret = 0;
- - struct pmem_region region = {.offset = 0x0, .len = HW3D_REGS_LEN};
- - down(&hw3d_sem);
- - if (hw3d_granted) {
- - ret = -1;
- - goto end;
- - }
- - /* map the registers */
- - if ((ret = pmem_remap(®ion, file, PMEM_MAP)))
- - goto end;
- - clk_enable(grp_clk);
- - clk_enable(imem_clk);
- - hw3d_granted = 1;
- - hw3d_granted_file = file;
- -end:
- - up(&hw3d_sem);
- + pr_info("%s: pid %d tid %d opening %s node\n", __func__,
- + current->group_leader->pid, current->pid,
- + is_master(info, file) ? "master" : "client");
- +
- + if (file->private_data != NULL)
- + return -EINVAL;
- +
- + data = kzalloc(sizeof(struct hw3d_data), GFP_KERNEL);
- + if (!data) {
- + pr_err("%s: unable to allocate memory for hw3d_data.\n",
- + __func__);
- + return -ENOMEM;
- + }
- +
- + mutex_init(&data->mutex);
- + file->private_data = data;
- +
- + /* master always succeeds, so we are done */
- + if (is_master(info, file))
- + return 0;
- +
- + spin_lock_irqsave(&info->lock, flags);
- + if (info->suspending) {
- + pr_warning("%s: can't open hw3d while suspending\n", __func__);
- + ret = -EPERM;
- + spin_unlock_irqrestore(&info->lock, flags);
- + goto err;
- + }
- +
- + if (info->client_file) {
- + pr_debug("hw3d: have client_file, need revoke\n");
- + locked_hw3d_revoke(info);
- + spin_unlock_irqrestore(&info->lock, flags);
- + ret = wait_event_interruptible(info->revoke_done_wq,
- + !info->client_file);
- + if (ret < 0)
- + goto err;
- + spin_lock_irqsave(&info->lock, flags);
- + if (info->client_file) {
- + /* between is waking up and grabbing the lock,
- + * someone else tried to open the gpu, and got here
- + * first, let them have it. */
- + spin_unlock_irqrestore(&info->lock, flags);
- + ret = -EBUSY;
- + goto err;
- + }
- + }
- +
- + info->client_file = file;
- + get_task_struct(current->group_leader);
- + info->client_task = current->group_leader;
- +
- + /* XXX: we enable these clocks if the client connects..
- + * probably not right? Should only turn the clocks on when the user
- + * tries to map the registers? */
- + clk_enable(info->imem_clk);
- + clk_enable(info->grp_clk);
- + info->enabled = 1;
- +
- + spin_unlock_irqrestore(&info->lock, flags);
- + return 0;
- +
- +err:
- + file->private_data = NULL;
- + kfree(data);
- return ret;
- +
- }
- static int hw3d_release(struct inode *inode, struct file *file)
- {
- - down(&hw3d_sem);
- - /* if the gpu is in use, and its inuse by the file that was released */
- - if (hw3d_granted && (file == hw3d_granted_file)) {
- - clk_disable(grp_clk);
- - clk_disable(imem_clk);
- - hw3d_granted = 0;
- - hw3d_granted_file = NULL;
- + struct hw3d_info *info = hw3d_info;
- + struct hw3d_data *data = file->private_data;
- + unsigned long flags;
- +
- + BUG_ON(!data);
- +
- + file->private_data = NULL;
- +
- + if (is_master(info, file))
- + goto done;
- +
- + pr_info("%s: in release for pid=%d tid=%d\n", __func__,
- + current->group_leader->pid, current->pid);
- + spin_lock_irqsave(&info->lock, flags);
- +
- + if (info->client_task && info->client_task == current->group_leader) {
- + pr_debug("hw3d: releasing %d\n", info->client_task->pid);
- + put_task_struct(info->client_task);
- + info->client_task = NULL;
- }
- - up(&hw3d_sem);
- +
- + if (info->client_file && info->client_file == file) {
- + int pending;
- + /* this will be true if we are still the "owner" of the gpu */
- + pr_debug("hw3d: had file\n");
- + pending = del_timer(&info->revoke_timer);
- + locked_hw3d_client_done(info, pending);
- + }
- + spin_unlock_irqrestore(&info->lock, flags);
- +
- +done:
- + kfree(data);
- return 0;
- }
- +static void hw3d_vma_open(struct vm_area_struct *vma)
- +{
- + /* XXX: should the master be allowed to fork and keep the mappings? */
- +
- + /* TODO: remap garbage page into here.
- + *
- + * For now, just pull the mapping. The user shouldn't be forking
- + * and using it anyway. */
- + zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, NULL);
- +}
- +
- +static void hw3d_vma_close(struct vm_area_struct *vma)
- +{
- + struct file *file = vma->vm_file;
- + struct hw3d_data *data = file->private_data;
- + int i;
- +
- + pr_debug("hw3d: current %u ppid %u file %p count %ld\n",
- + current->pid, current->parent->pid, file, file_count(file));
- +
- + BUG_ON(!data);
- +
- + mutex_lock(&data->mutex);
- + for (i = 0; i < HW3D_NUM_REGIONS; ++i) {
- + if (data->vmas[i] == vma) {
- + data->vmas[i] = NULL;
- + goto done;
- + }
- + }
- + pr_warning("%s: vma %p not of ours during vma_close\n", __func__, vma);
- +done:
- + mutex_unlock(&data->mutex);
- +}
- +
- +static int hw3d_mmap(struct file *file, struct vm_area_struct *vma)
- +{
- + struct hw3d_info *info = hw3d_info;
- + struct hw3d_data *data = file->private_data;
- + unsigned long vma_size = vma->vm_end - vma->vm_start;
- + int ret = 0;
- + int region = REGION_PAGE_ID(vma->vm_pgoff);
- +
- + if (region >= HW3D_NUM_REGIONS) {
- + pr_err("%s: Trying to mmap unknown region %d\n", __func__,
- + region);
- + return -EINVAL;
- + } else if (REGION_PAGE_OFFS(vma->vm_pgoff) != 0 ||
- + (vma_size & ~PAGE_MASK)) {
- + pr_err("%s: Can't remap part of the region %d\n", __func__,
- + region);
- + return -EINVAL;
- + } else if (!is_master(info, file) &&
- + current->group_leader != info->client_task) {
- + pr_err("%s: current(%d) != client_task(%d)\n", __func__,
- + current->group_leader->pid, info->client_task->pid);
- + return -EPERM;
- + } else if (!is_master(info, file) &&
- + (info->revoking || info->suspending)) {
- + pr_err("%s: cannot mmap while revoking(%d) or suspending(%d)\n",
- + __func__, info->revoking, info->suspending);
- + return -EPERM;
- + }
- +
- + mutex_lock(&data->mutex);
- + if (data->vmas[region] != NULL) {
- + pr_err("%s: Region %d already mapped (pid=%d tid=%d)\n",
- + __func__, region, current->group_leader->pid,
- + current->pid);
- + ret = -EBUSY;
- + goto done;
- + }
- +
- + /* our mappings are always noncached */
- +#ifdef pgprot_noncached
- + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- +#endif
- +
- + ret = io_remap_pfn_range(vma, vma->vm_start,
- + info->regions[region].pbase >> PAGE_SHIFT,
- + vma_size, vma->vm_page_prot);
- + if (ret) {
- + pr_err("%s: Cannot remap page range for region %d!\n", __func__,
- + region);
- + ret = -EAGAIN;
- + goto done;
- + }
- +
- + vma->vm_ops = &hw3d_vm_ops;
- +
- + /* mark this region as mapped */
- + data->vmas[region] = vma;
- +
- +done:
- + mutex_unlock(&data->mutex);
- + return ret;
- +}
- +
- static long hw3d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- + struct hw3d_info *info = hw3d_info;
- + struct hw3d_region regions[HW3D_NUM_REGIONS];
- + int i;
- +
- + if (!file->private_data)
- + return -EINVAL;
- +
- switch (cmd) {
- - case HW3D_REVOKE_GPU:
- - return hw3d_revoke_gpu(file);
- - break;
- - case HW3D_GRANT_GPU:
- - return hw3d_grant_gpu(file);
- - break;
- - case HW3D_WAIT_FOR_INTERRUPT:
- - return hw3d_wait_for_interrupt();
- - break;
- - default:
- - return -EINVAL;
- + case HW3D_WAIT_FOR_REVOKE:
- + return hw3d_wait_for_revoke(info, file);
- +
- + case HW3D_WAIT_FOR_INTERRUPT:
- + return hw3d_wait_for_interrupt(info, file);
- +
- + case HW3D_GET_REGIONS:
- + for (i = 0; i < HW3D_NUM_REGIONS; ++i) {
- + regions[i].phys = info->regions[i].pbase;
- + regions[i].map_offset = HW3D_REGION_OFFSET(i);
- + regions[i].len = info->regions[i].size;
- + }
- + if (copy_to_user((void __user *)arg, regions, sizeof(regions)))
- + return -EFAULT;
- + break;
- +
- + default:
- + return -EINVAL;
- }
- +
- return 0;
- }
- -static struct android_pmem_platform_data pmem_data = {
- - .name = "hw3d",
- - .start = 0xA0000000,
- - .size = 0x100000,
- - .no_allocator = 1,
- - .cached = 0,
- -};
- +static void hw3d_early_suspend(struct early_suspend *h)
- +{
- + unsigned long flags;
- + struct hw3d_info *info;
- + info = container_of(h, struct hw3d_info, early_suspend);
- -static int __init hw3d_init(void)
- + spin_lock_irqsave(&info->lock, flags);
- + info->suspending = 1;
- + if (info->client_file) {
- + pr_debug("hw3d: Requesting revoke for suspend\n");
- + locked_hw3d_revoke(info);
- + }
- + spin_unlock_irqrestore(&info->lock, flags);
- +}
- +
- +static void hw3d_late_resume(struct early_suspend *h)
- {
- - int ret;
- + unsigned long flags;
- + struct hw3d_info *info;
- + info = container_of(h, struct hw3d_info, early_suspend);
- +
- + spin_lock_irqsave(&info->lock, flags);
- + pr_info("%s: resuming\n", __func__);
- + info->suspending = 0;
- + spin_unlock_irqrestore(&info->lock, flags);
- +}
- +
- +static int hw3d_resume(struct platform_device *pdev)
- +{
- + struct hw3d_info *info = platform_get_drvdata(pdev);
- + unsigned long flags;
- +
- + spin_lock_irqsave(&info->lock, flags);
- + pr_info("%s: resuming\n", __func__);
- + info->suspending = 0;
- + spin_unlock_irqrestore(&info->lock, flags);
- + return 0;
- +}
- +
- +static int __init hw3d_probe(struct platform_device *pdev)
- +{
- + struct hw3d_info *info;
- + struct resource *res[HW3D_NUM_REGIONS];
- + int i;
- + int irq;
- + int ret = 0;
- +
- + res[HW3D_REGS] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- + "regs");
- + res[HW3D_SMI] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- + "smi");
- + res[HW3D_EBI] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- + "ebi");
- + irq = platform_get_irq(pdev, 0);
- + if (!res[HW3D_REGS] || !res[HW3D_SMI] || !res[HW3D_EBI] || irq < 0) {
- + pr_err("%s: incomplete resources\n", __func__);
- + return -EINVAL;
- + }
- +
- + info = kzalloc(sizeof(struct hw3d_info), GFP_KERNEL);
- + if (info == NULL) {
- + pr_err("%s: Cannot allocate memory for hw3d_info\n", __func__);
- + ret = -ENOMEM;
- + goto err_alloc;
- + }
- +
- + info->irq = irq;
- + wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND, "hw3d_revoke_lock");
- + spin_lock_init(&info->lock);
- + init_waitqueue_head(&info->irq_wq);
- + init_waitqueue_head(&info->revoke_wq);
- + init_waitqueue_head(&info->revoke_done_wq);
- + setup_timer(&info->revoke_timer,
- + (void (*)(unsigned long))do_force_revoke,
- + (unsigned long)info);
- +
- + platform_set_drvdata(pdev, info);
- +
- + info->grp_clk = clk_get(NULL, "grp_clk");
- + if (IS_ERR(info->grp_clk)) {
- + pr_err("%s: Cannot get grp_clk\n", __func__);
- + ret = PTR_ERR(info->grp_clk);
- + goto err_get_grp_clk;
- + }
- +
- + info->imem_clk = clk_get(NULL, "imem_clk");
- + if (IS_ERR(info->imem_clk)) {
- + pr_err("%s: Cannot get imem_clk\n", __func__);
- + ret = PTR_ERR(info->imem_clk);
- + goto err_get_imem_clk;
- + }
- - grp_clk = clk_get(NULL, "grp_clk");
- - if (IS_ERR(grp_clk))
- - return PTR_ERR(grp_clk);
- -
- - imem_clk = clk_get(NULL, "imem_clk");
- - if (IS_ERR(imem_clk)) {
- - clk_put(grp_clk);
- - return PTR_ERR(imem_clk);
- - }
- - ret = request_irq(INT_GRAPHICS, hw3d_irq_handler,
- - IRQF_TRIGGER_HIGH, "hw3d", 0);
- + for (i = 0; i < HW3D_NUM_REGIONS; ++i) {
- + info->regions[i].pbase = res[i]->start;
- + info->regions[i].size = res[i]->end - res[i]->start + 1;
- + info->regions[i].vbase = ioremap(info->regions[i].pbase,
- + info->regions[i].size);
- + if (info->regions[i].vbase == 0) {
- + pr_err("%s: Cannot remap region %d\n", __func__, i);
- + goto err_remap_region;
- + }
- + }
- +
- + /* register the master/client devices */
- + info->master_dev.name = "msm_hw3dm";
- + info->master_dev.minor = MISC_DYNAMIC_MINOR;
- + info->master_dev.fops = &hw3d_fops;
- + info->master_dev.parent = &pdev->dev;
- + ret = misc_register(&info->master_dev);
- if (ret) {
- - clk_put(grp_clk);
- - clk_put(imem_clk);
- - return ret;
- + pr_err("%s: Cannot register master device node\n", __func__);
- + goto err_misc_reg_master;
- + }
- +
- + info->client_dev.name = "msm_hw3dc";
- + info->client_dev.minor = MISC_DYNAMIC_MINOR;
- + info->client_dev.fops = &hw3d_fops;
- + info->client_dev.parent = &pdev->dev;
- + ret = misc_register(&info->client_dev);
- + if (ret) {
- + pr_err("%s: Cannot register client device node\n", __func__);
- + goto err_misc_reg_client;
- }
- - hw3d_disable_interrupt();
- - hw3d_granted = 0;
- - return pmem_setup(&pmem_data, hw3d_ioctl, hw3d_release);
- + info->early_suspend.suspend = hw3d_early_suspend;
- + info->early_suspend.resume = hw3d_late_resume;
- + info->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
- + register_early_suspend(&info->early_suspend);
- +
- + info->irq_en = 1;
- + ret = request_irq(info->irq, hw3d_irq_handler, IRQF_TRIGGER_HIGH,
- + "hw3d", info);
- + if (ret != 0) {
- + pr_err("%s: Cannot request irq\n", __func__);
- + goto err_req_irq;
- + }
- + hw3d_disable_interrupt(info);
- +
- + hw3d_info = info;
- +
- + return 0;
- +
- +err_req_irq:
- + unregister_early_suspend(&info->early_suspend);
- + misc_deregister(&info->client_dev);
- +err_misc_reg_client:
- + misc_deregister(&info->master_dev);
- +err_misc_reg_master:
- +err_remap_region:
- + for (i = 0; i < HW3D_NUM_REGIONS; ++i)
- + if (info->regions[i].vbase != 0)
- + iounmap(info->regions[i].vbase);
- + clk_put(info->imem_clk);
- +err_get_imem_clk:
- + clk_put(info->grp_clk);
- +err_get_grp_clk:
- + wake_lock_destroy(&info->wake_lock);
- + kfree(info);
- + platform_set_drvdata(pdev, NULL);
- +err_alloc:
- + hw3d_info = NULL;
- + return ret;
- +}
- +
- +static struct platform_driver msm_hw3d_driver = {
- + .probe = hw3d_probe,
- + .resume = hw3d_resume,
- + .driver = {
- + .name = "msm_hw3d",
- + .owner = THIS_MODULE,
- + },
- +};
- +
- +static int __init hw3d_init(void)
- +{
- + return platform_driver_register(&msm_hw3d_driver);
- }
- device_initcall(hw3d_init);
- diff --git a/arch/arm/mach-msm/hw3d_donut.c b/arch/arm/mach-msm/hw3d_donut.c
- new file mode 100644
- index 0000000..b013b57
- --- /dev/null
- +++ b/arch/arm/mach-msm/hw3d_donut.c
- @@ -0,0 +1,213 @@
- +/* arch/arm/mach-msm/hw3d.c
- + *
- + * Register/Interrupt access for userspace 3D library.
- + *
- + * Copyright (C) 2007 Google, Inc.
- + * Author: Brian Swetland <swetland@google.com>
- + *
- + * 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.
- + *
- + */
- +
- +#include <linux/module.h>
- +#include <linux/fs.h>
- +#include <linux/miscdevice.h>
- +#include <linux/uaccess.h>
- +#include <linux/poll.h>
- +#include <linux/time.h>
- +#include <linux/irq.h>
- +#include <linux/interrupt.h>
- +#include <linux/wait.h>
- +#include <linux/mm.h>
- +#include <linux/clk.h>
- +#include <linux/android_pmem.h>
- +#include <mach/board.h>
- +
- +static DEFINE_SPINLOCK(hw3d_lock);
- +static DECLARE_WAIT_QUEUE_HEAD(hw3d_queue);
- +static int hw3d_pending;
- +static int hw3d_disabled;
- +
- +static struct clk *grp_clk;
- +static struct clk *imem_clk;
- +DECLARE_MUTEX(hw3d_sem);
- +static unsigned int hw3d_granted;
- +static struct file *hw3d_granted_file;
- +
- +static irqreturn_t hw3d_irq_handler(int irq, void *data)
- +{
- + unsigned long flags;
- +
- + spin_lock_irqsave(&hw3d_lock, flags);
- + if (!hw3d_disabled) {
- + disable_irq(INT_GRAPHICS);
- + hw3d_disabled = 1;
- + }
- + hw3d_pending = 1;
- + spin_unlock_irqrestore(&hw3d_lock, flags);
- +
- + wake_up(&hw3d_queue);
- +
- + return IRQ_HANDLED;
- +}
- +
- +static void hw3d_disable_interrupt(void)
- +{
- + unsigned long flags;
- + spin_lock_irqsave(&hw3d_lock, flags);
- + if (!hw3d_disabled) {
- + disable_irq(INT_GRAPHICS);
- + hw3d_disabled = 1;
- + }
- + spin_unlock_irqrestore(&hw3d_lock, flags);
- +}
- +
- +static long hw3d_wait_for_interrupt(void)
- +{
- + unsigned long flags;
- + int ret;
- +
- + for (;;) {
- + spin_lock_irqsave(&hw3d_lock, flags);
- + if (hw3d_pending) {
- + hw3d_pending = 0;
- + spin_unlock_irqrestore(&hw3d_lock, flags);
- + return 0;
- + }
- + if (hw3d_disabled) {
- + hw3d_disabled = 0;
- + enable_irq(INT_GRAPHICS);
- + }
- + spin_unlock_irqrestore(&hw3d_lock, flags);
- +
- + ret = wait_event_interruptible(hw3d_queue, hw3d_pending);
- + if (ret < 0) {
- + hw3d_disable_interrupt();
- + return ret;
- + }
- + }
- +
- + return 0;
- +}
- +
- +#define HW3D_REGS_LEN 0x100000
- +
- +static long hw3d_revoke_gpu(struct file *file)
- +{
- + int ret = 0;
- + unsigned long user_start, user_len;
- + struct pmem_region region = {.offset = 0x0, .len = HW3D_REGS_LEN};
- +
- + down(&hw3d_sem);
- + if (!hw3d_granted) {
- + goto end;
- + }
- + /* revoke the pmem region completely */
- + if ((ret = pmem_remap(®ion, file, PMEM_UNMAP)))
- + goto end;
- + get_pmem_user_addr(file, &user_start, &user_len);
- + /* reset the gpu */
- + clk_disable(grp_clk);
- + clk_disable(imem_clk);
- + hw3d_granted = 0;
- +end:
- + up(&hw3d_sem);
- + return ret;
- +}
- +
- +static long hw3d_grant_gpu(struct file *file)
- +{
- + int ret = 0;
- + struct pmem_region region = {.offset = 0x0, .len = HW3D_REGS_LEN};
- +
- + down(&hw3d_sem);
- + if (hw3d_granted) {
- + ret = -1;
- + goto end;
- + }
- + /* map the registers */
- + if ((ret = pmem_remap(®ion, file, PMEM_MAP)))
- + goto end;
- + clk_enable(grp_clk);
- + clk_enable(imem_clk);
- + hw3d_granted = 1;
- + hw3d_granted_file = file;
- +end:
- + up(&hw3d_sem);
- + return ret;
- +}
- +
- +static int hw3d_release(struct inode *inode, struct file *file)
- +{
- + down(&hw3d_sem);
- + /* if the gpu is in use, and its inuse by the file that was released */
- + if (hw3d_granted && (file == hw3d_granted_file)) {
- + clk_disable(grp_clk);
- + clk_disable(imem_clk);
- + hw3d_granted = 0;
- + hw3d_granted_file = NULL;
- + }
- + up(&hw3d_sem);
- + return 0;
- +}
- +
- +static long hw3d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- +{
- + switch (cmd) {
- + case HW3D_REVOKE_GPU:
- + return hw3d_revoke_gpu(file);
- + break;
- + case HW3D_GRANT_GPU:
- + return hw3d_grant_gpu(file);
- + break;
- + case HW3D_WAIT_FOR_INTERRUPT:
- + return hw3d_wait_for_interrupt();
- + break;
- + default:
- + return -EINVAL;
- + }
- + return 0;
- +}
- +
- +static struct android_pmem_platform_data pmem_data = {
- + .name = "hw3d",
- + .start = 0xA0000000,
- + .size = 0x100000,
- + .no_allocator = 1,
- + .cached = 0,
- +};
- +
- +static int __init hw3d_init(void)
- +{
- + int ret;
- +
- + grp_clk = clk_get(NULL, "grp_clk");
- + if (IS_ERR(grp_clk))
- + return PTR_ERR(grp_clk);
- +
- + imem_clk = clk_get(NULL, "imem_clk");
- + if (IS_ERR(imem_clk)) {
- + clk_put(grp_clk);
- + return PTR_ERR(imem_clk);
- + }
- + ret = request_irq(INT_GRAPHICS, hw3d_irq_handler,
- + IRQF_TRIGGER_HIGH, "hw3d", 0);
- + if (ret) {
- + clk_put(grp_clk);
- + clk_put(imem_clk);
- + return ret;
- + }
- + hw3d_disable_interrupt();
- + hw3d_granted = 0;
- +
- + return pmem_setup(&pmem_data, hw3d_ioctl, hw3d_release);
- +}
- +
- +device_initcall(hw3d_init);
- diff --git a/arch/arm/mach-msm/pmem.c b/arch/arm/mach-msm/pmem.c
- index bdc3989..dd5d828 100644
- --- a/arch/arm/mach-msm/pmem.c
- +++ b/arch/arm/mach-msm/pmem.c
- @@ -15,6 +15,7 @@
- #include <linux/kernel.h>
- #include <linux/init.h>
- +#include <linux/fs.h>
- #include <linux/platform_device.h>
- #include <linux/android_pmem.h>
- #include <mach/board_htc.h>
- @@ -104,6 +105,38 @@ static struct platform_device ram_console_device = {
- .resource = ram_console_resource,
- };
- +/* Eclair hw3d */
- +static struct resource resources_hw3d[] = {
- + {
- + .start = 0xA0000000,
- + .end = 0xA00fffff,
- + .flags = IORESOURCE_MEM,
- + .name = "regs",
- + },
- + {
- + .flags = IORESOURCE_MEM,
- + .name = "smi",
- + },
- + {
- + .flags = IORESOURCE_MEM,
- + .name = "ebi",
- + },
- + {
- + .start = INT_GRAPHICS,
- + .end = INT_GRAPHICS,
- + .flags = IORESOURCE_IRQ,
- + .name = "gfx",
- + },
- +};
- +
- +static struct platform_device hw3d_device = {
- + .name = "msm_hw3d",
- + .id = 0,
- + .num_resources = ARRAY_SIZE(resources_hw3d),
- + .resource = resources_hw3d,
- +};
- +
- +
- void __init msm_add_mem_devices(struct msm_pmem_setting *setting)
- {
- if (setting->pmem_size) {
- @@ -130,6 +163,18 @@ void __init msm_add_mem_devices(struct msm_pmem_setting *setting)
- platform_device_register(&pmem_gpu1_device);
- }
- + /* Eclair hw3d */
- + if (setting->pmem_gpu0_size || setting->pmem_gpu1_size) {
- + struct resource *res;
- + res=platform_get_resource_byname(&hw3d_device, IORESOURCE_MEM, "smi");
- + res->start=setting->pmem_gpu0_start;
- + res->end=setting->pmem_gpu0_start+setting->pmem_gpu0_size-1;
- + res=platform_get_resource_byname(&hw3d_device, IORESOURCE_MEM, "ebi");
- + res->start=setting->pmem_gpu1_start;
- + res->end=setting->pmem_gpu1_start+setting->pmem_gpu1_size-1;
- + platform_device_register(&hw3d_device);
- + }
- +
- if (setting->pmem_camera_size) {
- pmem_camera_pdata.start = setting->pmem_camera_start;
- pmem_camera_pdata.size = setting->pmem_camera_size;
- @@ -172,7 +217,7 @@ struct resource resources_msm_fb[]={
- pmem_setting.name## _size = size;
- -static void __init msm_pmem_init() {
- +static int __init msm_pmem_init() {
- switch(__machine_arch_type) {
- case MACH_TYPE_HTCDIAMOND:
- //SMI 64 + EBI 128
- @@ -226,11 +271,13 @@ static void __init msm_pmem_init() {
- }
- //GPU0 must be in SMI1
- pmem_setting.pmem_gpu0_start=MSM_SMI_BASE+0x100000;//1MB for wince SPL
- - pmem_setting.pmem_gpu0_size=0x800000;
- + pmem_setting.pmem_gpu0_size=0x700000;
- resources_msm_fb[0].start=pmem_setting.fb_start;
- resources_msm_fb[0].end=pmem_setting.fb_start+pmem_setting.fb_size;
- resources_msm_fb[0].flags=IORESOURCE_MEM;
- msm_add_mem_devices(&pmem_setting);
- +
- + return 0;
- }
- module_init(msm_pmem_init);
- --
- 1.6.1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement