diff --git a/Documentation/genlock.txt b/Documentation/genlock.txt index 6f24a769..cd826146 100644 --- a/Documentation/genlock.txt +++ b/Documentation/genlock.txt @@ -34,6 +34,12 @@ instance for a lock known as a handle. Handles can be shared between user space and kernel space to allow a kernel driver to unlock or lock a buffer on behalf of a user process. +Locks within a process using a single genlock handle follow the same rules for +exclusive write locks with multiple readers. Genlock cannot provide deadlock +protection because the same handle can be used simultaneously by a producer and +consumer. In practice in the event that the client creates a deadlock an error +will still be generated when the timeout expires. + Kernel API Access to the genlock API can either be via the in-kernel API or via an @@ -137,7 +143,12 @@ genlock_lock.op: * GENLOCK_UNLOCK - unlock an existing lock Pass flags in genlock_lock.flags: - * GENLOCK_NOBLOCK - Do not block if the lock is already taken + * GENLOCK_NOBLOCK - Do not block if the lock is already taken + * GENLOCK_WRITE_TO_READ - Convert a write lock that the handle owns to a read + lock. For instance graphics may hold a write lock + while rendering the back buffer then when swapping + convert the lock to a read lock to copy the front + buffer in the next frame for preserved buffers. Pass a timeout value in milliseconds in genlock_lock.timeout. genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK. diff --git a/arch/arm/boot/compressed/ashldi3.S b/arch/arm/boot/compressed/ashldi3.S new file mode 100644 index 00000000..638deb13 --- /dev/null +++ b/arch/arm/boot/compressed/ashldi3.S @@ -0,0 +1,53 @@ +/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005 + Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file 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. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +#include + +#ifdef __ARMEB__ +#define al r1 +#define ah r0 +#else +#define al r0 +#define ah r1 +#endif + +ENTRY(__ashldi3) +ENTRY(__aeabi_llsl) + + subs r3, r2, #32 + rsb ip, r2, #32 + movmi ah, ah, lsl r2 + movpl ah, al, lsl r3 + ARM( orrmi ah, ah, al, lsr ip ) + THUMB( lsrmi r3, al, ip ) + THUMB( orrmi ah, ah, r3 ) + mov al, al, lsl r2 + mov pc, lr + +ENDPROC(__ashldi3) +ENDPROC(__aeabi_llsl) diff --git a/arch/arm/boot/compressed/piggy.xzkern b/arch/arm/boot/compressed/piggy.xzkern new file mode 100644 index 00000000..92c9262a Binary files /dev/null and b/arch/arm/boot/compressed/piggy.xzkern differ diff --git a/arch/arm/configs/mediapad_defconfig b/arch/arm/configs/mediapad_defconfig index a199d9e3..8402605b 100644 --- a/arch/arm/configs/mediapad_defconfig +++ b/arch/arm/configs/mediapad_defconfig @@ -36,7 +36,7 @@ CONFIG_IRQ_WORK=y CONFIG_EXPERIMENTAL=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_CROSS_COMPILE="" -CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION="-aftersilence" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y @@ -480,7 +480,7 @@ CONFIG_MSM_QDSP6_APR=y # CONFIG_MSM_RPC_VIBRATOR is not set CONFIG_MSM_SPM_V1=y # CONFIG_MSM_SPM_V2 is not set -# CONFIG_MSM_MULTIMEDIA_USE_ION is not set +CONFIG_MSM_MULTIMEDIA_USE_ION=y # CONFIG_MSM_RTB is not set CONFIG_S7_FEATURE_OEMINFO=y # CONFIG_S7_FEATURE_HANDSET is not set diff --git a/arch/arm/mach-msm/board-msm8x60_s7pro.c b/arch/arm/mach-msm/board-msm8x60_s7pro.c index 0667c7b3..55658c4c 100644 --- a/arch/arm/mach-msm/board-msm8x60_s7pro.c +++ b/arch/arm/mach-msm/board-msm8x60_s7pro.c @@ -3507,10 +3507,10 @@ static void __init msm8x60_init_dsps(void) #define MSM_ION_SF_SIZE 0x1800000 /* 24MB */ #define MSM_ION_CAMERA_SIZE MSM_PMEM_ADSP_SIZE #define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */ -#define MSM_ION_MM_SIZE 0x3600000 /* (54MB) */ Must be a multiple of 64K */ #define MSM_ION_MFC_SIZE SZ_8K #define MSM_ION_WB_SIZE 0x600000 /* 6MB */ #define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE +#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION #define MSM_ION_HEAP_NUM 8 @@ -6803,7 +6803,7 @@ static struct ion_cp_heap_pdata cp_mm_ion_pdata = { .release_region = release_smi_region, .setup_region = setup_smi_region, .iommu_map_all = 1, - .iommu_2x_map_domain = VIDEO_DOMAIN, + //.iommu_2x_map_domain = VIDEO_DOMAIN, }; static struct ion_cp_heap_pdata cp_mfc_ion_pdata = { @@ -7560,7 +7560,7 @@ static struct pm8xxx_vibrator_platform_data pm8058_vib_pdata = { }; static struct pm8xxx_rtc_platform_data pm8058_rtc_pdata = { - .rtc_write_enable = false, + .rtc_write_enable = true, .rtc_alarm_powerup = false, }; @@ -9759,7 +9759,7 @@ static int msm_sdcc_vreg_enable(struct sdcc_reg *vreg) int rc=0; if (!vreg->enabled) { rc = regulator_enable(vreg->reg); - if (rc) { + if (rc) { pr_err("%s: regulator_enable(%s) failed. rc=%d\n", __func__, vreg->reg_name, rc); goto out; diff --git a/build.sh b/build.sh index 99607b39..e706c08b 100755 --- a/build.sh +++ b/build.sh @@ -1,28 +1,16 @@ -export KBUILD_BUILD_VERSION="3.0.38" -export KBUILD_BUILD_USER="Mediapad EX" -export CROSS_COMPILE="/home/ubu/arm-eabi-4.4.3/bin/arm-eabi-" +#export KBUILD_BUILD_VERSION="3.0.38" +#export KBUILD_BUILD_USER="Mediapad EX" +export CROSS_COMPILE="~/android/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-" -ROOTFS_PATH="/home/ubu/mediapad/ramdisk" -ramdisk_dir=/home/ubu/mediapad/ramdisk/ramdisk.gz -CMDLINE="console=console=ttyHSL0,115200,n8 androidboot.hardware=hws7300u vmalloc=578M kgsl.ptcount=16" -BASE="0x40300000" +#ROOTFS_PATH="/home/ubu/mediapad/ramdisk" +#ramdisk_dir=/home/ubu/mediapad/ramdisk/ramdisk.gz +#CMDLINE="console=console=ttyHSL0,115200,n8 androidboot.hardware=hws7300u vmalloc=578M kgsl.ptcount=16" +#BASE="0x40300000" # Do not modify below this line - NB_CPU=`grep processor /proc/cpuinfo | wc -l` - let NB_CPU+=1 - -CONFIG=$1 - -make $CONFIG - +CONFIG='mediapad_defconfig' +make ARCH=arm $CONFIG make ARCH=arm -j$NB_CPU CROSS_COMPILE=$CROSS_COMPILE -cp arch/arm/boot/zImage . - -find -name '*.ko' -exec cp -av {} $ROOTFS_PATH/lib/modules/ \; - -# Make boot.img - -./mkbootimg --cmdline "$CMDLINE" --base $BASE --kernel zImage --ramdisk $ramdisk_dir -o boot_new.img diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c index 15079155..c7467159 100644 --- a/drivers/base/genlock.c +++ b/drivers/base/genlock.c @@ -34,7 +34,15 @@ #define GENLOCK_LOG_ERR(fmt, args...) \ pr_err("genlock: %s: " fmt, __func__, ##args) +/* The genlock magic stored in the kernel private data is used to protect + * against the possibility of user space passing a valid fd to a + * non-genlock file for genlock_attach_lock() + */ +#define GENLOCK_MAGIC_OK 0xD2EAD10C +#define GENLOCK_MAGIC_BAD 0xD2EADBAD + struct genlock { + unsigned int magic; /* Magic for attach verification */ struct list_head active; /* List of handles holding lock */ spinlock_t lock; /* Spinlock to protect the lock internals */ wait_queue_head_t queue; /* Holding pen for processes pending lock */ @@ -56,7 +64,7 @@ struct genlock_handle { * released while another process tries to attach it */ -static DEFINE_SPINLOCK(genlock_file_lock); +static DEFINE_SPINLOCK(genlock_ref_lock); static void genlock_destroy(struct kref *kref) { @@ -68,10 +76,9 @@ static void genlock_destroy(struct kref *kref) * still active after the lock gets released */ - spin_lock(&genlock_file_lock); if (lock->file) lock->file->private_data = NULL; - spin_unlock(&genlock_file_lock); + lock->magic = GENLOCK_MAGIC_BAD; kfree(lock); } @@ -130,6 +137,7 @@ struct genlock *genlock_create_lock(struct genlock_handle *handle) init_waitqueue_head(&lock->queue); spin_lock_init(&lock->lock); + lock->magic = GENLOCK_MAGIC_OK; lock->state = _UNLOCKED; /* @@ -203,21 +211,30 @@ struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd) * released and then attached */ - spin_lock(&genlock_file_lock); + spin_lock(&genlock_ref_lock); lock = file->private_data; - spin_unlock(&genlock_file_lock); fput(file); if (lock == NULL) { GENLOCK_LOG_ERR("File descriptor is invalid\n"); - return ERR_PTR(-EINVAL); + goto fail_invalid; + } + + if (lock->magic != GENLOCK_MAGIC_OK) { + GENLOCK_LOG_ERR("Magic is invalid - 0x%X\n", lock->magic); + goto fail_invalid; } handle->lock = lock; kref_get(&lock->refcount); + spin_unlock(&genlock_ref_lock); return lock; + +fail_invalid: + spin_unlock(&genlock_ref_lock); + return ERR_PTR(-EINVAL); } EXPORT_SYMBOL(genlock_attach_lock); @@ -307,13 +324,17 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle, if (handle_has_lock(lock, handle)) { /* - * If the handle already holds the lock and the type matches, - * then just increment the active pointer. This allows the - * handle to do recursive locks + * If the handle already holds the lock and the lock type is + * a read lock then just increment the active pointer. This + * allows the handle to do recursive read locks. Recursive + * write locks are not allowed in order to support + * synchronization within a process using a single gralloc + * handle. */ - if (lock->state == op) { + if (lock->state == _RDLOCK && op == _RDLOCK) { handle->active++; + goto done; } @@ -321,32 +342,45 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle, * If the handle holds a write lock then the owner can switch * to a read lock if they want. Do the transition atomically * then wake up any pending waiters in case they want a read - * lock too. + * lock too. In order to support synchronization within a + * process the caller must explicity request to convert the + * lock type with the GENLOCK_WRITE_TO_READ flag. */ - if (op == _RDLOCK && handle->active == 1) { - lock->state = _RDLOCK; - wake_up(&lock->queue); - goto done; + if (flags & GENLOCK_WRITE_TO_READ) { + if (lock->state == _WRLOCK && op == _RDLOCK) { + lock->state = _RDLOCK; + wake_up(&lock->queue); + goto done; + } else { + GENLOCK_LOG_ERR("Invalid state to convert" + "write to read\n"); + ret = -EINVAL; + goto done; + } } + } else { /* - * Otherwise the user tried to turn a read into a write, and we - * don't allow that. + * Check to ensure the caller has not attempted to convert a + * write to a read without holding the lock. */ - GENLOCK_LOG_ERR("Trying to upgrade a read lock to a write" - "lock\n"); - ret = -EINVAL; - goto done; - } - /* - * If we request a read and the lock is held by a read, then go - * ahead and share the lock - */ + if (flags & GENLOCK_WRITE_TO_READ) { + GENLOCK_LOG_ERR("Handle must have lock to convert" + "write to read\n"); + ret = -EINVAL; + goto done; + } - if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK) - goto dolock; + /* + * If we request a read and the lock is held by a read, then go + * ahead and share the lock + */ + + if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK) + goto dolock; + } /* Treat timeout 0 just like a NOBLOCK flag and return if the lock cannot be aquired without blocking */ @@ -356,15 +390,26 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle, goto done; } - /* Wait while the lock remains in an incompatible state */ + /* + * Wait while the lock remains in an incompatible state + * state op wait + * ------------------- + * unlocked n/a no + * read read no + * read write yes + * write n/a yes + */ - while (lock->state != _UNLOCKED) { - unsigned int elapsed; + while ((lock->state == _RDLOCK && op == _WRLOCK) || + lock->state == _WRLOCK) { + signed long elapsed; spin_unlock_irqrestore(&lock->lock, irqflags); elapsed = wait_event_interruptible_timeout(lock->queue, - lock->state == _UNLOCKED, ticks); + lock->state == _UNLOCKED || + (lock->state == _RDLOCK && op == _RDLOCK), + ticks); spin_lock_irqsave(&lock->lock, irqflags); @@ -381,7 +426,7 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle, list_add_tail(&handle->entry, &lock->active); lock->state = op; - handle->active = 1; + handle->active++; done: spin_unlock_irqrestore(&lock->lock, irqflags); @@ -390,7 +435,7 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle, } /** - * genlock_lock - Acquire or release a lock + * genlock_lock - Acquire or release a lock (depreciated) * @handle - pointer to the genlock handle that is requesting the lock * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK) * @flags - flags to control the operation @@ -403,6 +448,7 @@ int genlock_lock(struct genlock_handle *handle, int op, int flags, uint32_t timeout) { struct genlock *lock; + unsigned long irqflags; int ret = 0; @@ -423,6 +469,13 @@ int genlock_lock(struct genlock_handle *handle, int op, int flags, ret = _genlock_unlock(lock, handle); break; case GENLOCK_RDLOCK: + spin_lock_irqsave(&lock->lock, irqflags); + if (handle_has_lock(lock, handle)) { + /* request the WRITE_TO_READ flag for compatibility */ + flags |= GENLOCK_WRITE_TO_READ; + } + spin_unlock_irqrestore(&lock->lock, irqflags); + /* fall through to take lock */ case GENLOCK_WRLOCK: ret = _genlock_lock(lock, handle, op, flags, timeout); break; @@ -436,6 +489,53 @@ int genlock_lock(struct genlock_handle *handle, int op, int flags, } EXPORT_SYMBOL(genlock_lock); +/** + * genlock_dreadlock - Acquire or release a lock + * @handle - pointer to the genlock handle that is requesting the lock + * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK) + * @flags - flags to control the operation + * @timeout - optional timeout to wait for the lock to come free + * + * Returns: 0 on success or error code on failure + */ + +int genlock_dreadlock(struct genlock_handle *handle, int op, int flags, + uint32_t timeout) +{ + struct genlock *lock; + + int ret = 0; + + if (IS_ERR_OR_NULL(handle)) { + GENLOCK_LOG_ERR("Invalid handle\n"); + return -EINVAL; + } + + lock = handle->lock; + + if (lock == NULL) { + GENLOCK_LOG_ERR("Handle does not have a lock attached\n"); + return -EINVAL; + } + + switch (op) { + case GENLOCK_UNLOCK: + ret = _genlock_unlock(lock, handle); + break; + case GENLOCK_RDLOCK: + case GENLOCK_WRLOCK: + ret = _genlock_lock(lock, handle, op, flags, timeout); + break; + default: + GENLOCK_LOG_ERR("Invalid lock operation\n"); + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL(genlock_dreadlock); + /** * genlock_wait - Wait for the lock to be released * @handle - pointer to the genlock handle that is waiting for the lock @@ -513,7 +613,9 @@ static void genlock_release_lock(struct genlock_handle *handle) } spin_unlock_irqrestore(&handle->lock->lock, flags); + spin_lock(&genlock_ref_lock); kref_put(&handle->lock->refcount, genlock_destroy); + spin_unlock(&genlock_ref_lock); handle->lock = NULL; handle->active = 0; } @@ -657,6 +759,14 @@ static long genlock_dev_ioctl(struct file *filep, unsigned int cmd, return genlock_lock(handle, param.op, param.flags, param.timeout); } + case GENLOCK_IOC_DREADLOCK: { + if (copy_from_user(¶m, (void __user *) arg, + sizeof(param))) + return -EFAULT; + + return genlock_dreadlock(handle, param.op, param.flags, + param.timeout); + } case GENLOCK_IOC_WAIT: { if (copy_from_user(¶m, (void __user *) arg, sizeof(param))) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 744c35f5..8293cb6b 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1167,7 +1167,7 @@ kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv, goto error; } - result = kgsl_sharedmem_page_alloc_user(&entry->memdesc, + result = kgsl_sharedmem_vmalloc_user(&entry->memdesc, private->pagetable, len, param->flags); if (result != 0) @@ -1178,7 +1178,7 @@ kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv, result = kgsl_sharedmem_map_vma(vma, &entry->memdesc); if (result) { KGSL_CORE_ERR("kgsl_sharedmem_map_vma failed: %d\n", result); - goto error_free_alloc; + goto error_free_vmalloc; } param->gpuaddr = entry->memdesc.gpuaddr; @@ -1193,7 +1193,7 @@ kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv, kgsl_check_idle(dev_priv->device); return 0; -error_free_alloc: +error_free_vmalloc: kgsl_sharedmem_free(&entry->memdesc); error_free_entry: diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 6241a70b..9bbea06f 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -711,7 +711,7 @@ _nap(struct kgsl_device *device) } kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP); - kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP); + kgsl_pwrctrl_set_state(device, device->requested_state); if (device->idle_wakelock.name) wake_unlock(&device->idle_wakelock); case KGSL_STATE_NAP: diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index e3d64d02..3848fd5c 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -306,60 +306,32 @@ static void outer_cache_range_op_sg(struct scatterlist *sg, int sglen, int op) } #endif -static int kgsl_page_alloc_vmfault(struct kgsl_memdesc *memdesc, - struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - unsigned long offset; - struct page *page; - int i; - - offset = (unsigned long) vmf->virtual_address - vma->vm_start; - - i = offset >> PAGE_SHIFT; - page = sg_page(&memdesc->sg[i]); - if (page == NULL) - return VM_FAULT_SIGBUS; - - get_page(page); - - vmf->page = page; - return 0; -} - -static int kgsl_page_alloc_vmflags(struct kgsl_memdesc *memdesc) +static int kgsl_vmalloc_vmflags(struct kgsl_memdesc *memdesc) { return VM_RESERVED | VM_DONTEXPAND; } -static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc) +static void kgsl_vmalloc_free(struct kgsl_memdesc *memdesc) { int i = 0; struct scatterlist *sg; - kgsl_driver.stats.page_alloc -= memdesc->size; - if (memdesc->hostptr) { + kgsl_driver.stats.vmalloc -= memdesc->size; + if (memdesc->hostptr) vunmap(memdesc->hostptr); - kgsl_driver.stats.vmalloc -= memdesc->size; - } if (memdesc->sg) for_each_sg(memdesc->sg, sg, memdesc->sglen, i) __free_page(sg_page(sg)); } -static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc) -{ - return VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND; -} /* - * kgsl_page_alloc_map_kernel - Map the memory in memdesc to kernel address - * space + * kgsl_vmalloc_map_kernel - Map the memory in memdesc to kernel address space * * @memdesc - The memory descriptor which contains information about the memory * * Return: 0 on success else error code */ -static int kgsl_page_alloc_map_kernel(struct kgsl_memdesc *memdesc) +static int kgsl_vmalloc_map_kernel(struct kgsl_memdesc *memdesc) { if (!memdesc->hostptr) { pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL); @@ -377,8 +349,7 @@ static int kgsl_page_alloc_map_kernel(struct kgsl_memdesc *memdesc) pages[i] = sg_page(sg); memdesc->hostptr = vmap(pages, memdesc->sglen, VM_IOREMAP, page_prot); - KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.vmalloc, - kgsl_driver.stats.vmalloc_max); + vfree(pages); } if (!memdesc->hostptr) @@ -425,14 +396,40 @@ static void kgsl_coherent_free(struct kgsl_memdesc *memdesc) memdesc->hostptr, memdesc->physaddr); } +static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc) +{ + return VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND; +} + +static int kgsl_vmalloc_vmfault(struct kgsl_memdesc *memdesc, + struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + unsigned long offset; + struct page *page; + int i; + + offset = (unsigned long) vmf->virtual_address - vma->vm_start; + + i = offset >> PAGE_SHIFT; + page = sg_page(&memdesc->sg[i]); + if (page == NULL) + return VM_FAULT_SIGBUS; + + get_page(page); + + vmf->page = page; + return 0; +} + /* Global - also used by kgsl_drm.c */ -struct kgsl_memdesc_ops kgsl_page_alloc_ops = { - .free = kgsl_page_alloc_free, - .vmflags = kgsl_page_alloc_vmflags, - .vmfault = kgsl_page_alloc_vmfault, - .map_kernel_mem = kgsl_page_alloc_map_kernel, +struct kgsl_memdesc_ops kgsl_vmalloc_ops = { + .free = kgsl_vmalloc_free, + .vmflags = kgsl_vmalloc_vmflags, + .vmfault = kgsl_vmalloc_vmfault, + .map_kernel_mem = kgsl_vmalloc_map_kernel, }; -EXPORT_SYMBOL(kgsl_page_alloc_ops); +EXPORT_SYMBOL(kgsl_vmalloc_ops); static struct kgsl_memdesc_ops kgsl_ebimem_ops = { .free = kgsl_ebimem_free, @@ -440,6 +437,7 @@ static struct kgsl_memdesc_ops kgsl_ebimem_ops = { .vmfault = kgsl_contiguous_vmfault, }; + static struct kgsl_memdesc_ops kgsl_coherent_ops = { .free = kgsl_coherent_free, }; @@ -465,8 +463,9 @@ void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op) } EXPORT_SYMBOL(kgsl_cache_range_op); + static int -_kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, +_kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size, unsigned int protflags) { @@ -477,13 +476,10 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, memdesc->size = size; memdesc->pagetable = pagetable; memdesc->priv = KGSL_MEMFLAGS_CACHED; - memdesc->ops = &kgsl_page_alloc_ops; - - memdesc->sg = kgsl_sg_alloc(sglen); + memdesc->ops = &kgsl_vmalloc_ops; + memdesc->sg = vmalloc(sglen * sizeof(struct scatterlist)); if (memdesc->sg == NULL) { - KGSL_CORE_ERR("vmalloc(%d) failed\n", - sglen * sizeof(struct scatterlist)); ret = -ENOMEM; goto done; } @@ -512,34 +508,9 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, if (ret) goto done; - KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc, - kgsl_driver.stats.page_alloc_max); + KGSL_STATS_ADD(size, kgsl_driver.stats.vmalloc, + kgsl_driver.stats.vmalloc_max); -#if CONFIG_MSM_KGSL_VM_THRESHOLD > 0 -#if 0 //def CONFIG_KGSL_PER_PROCESS_PAGE_TABLE - allocated_pagetables = bitmap_weight(kgsl_driver.ptpool.bitmap, kgsl_pagetable_count); - - if ((kgsl_driver.stats.vmalloc > CONFIG_MSM_KGSL_VM_THRESHOLD) || - (allocated_pagetables >= KGSL_PAGETABLE_THRESHOLD)) { -/* - printk(KERN_ALERT "kgsl: vmalloc=%x, ptcnt=%d, map=%lx\n", - kgsl_driver.stats.vmalloc, - allocated_pagetables, - *kgsl_driver.ptpool.bitmap); -*/ - if (kgsl_shrink != (void *)0) - (*kgsl_shrink)(allocated_pagetables < KGSL_PAGETABLE_THRESHOLD, - CONFIG_MSM_KGSL_VM_RSS_THRESHOLD); - } -#else - if (kgsl_driver.stats.vmalloc > CONFIG_MSM_KGSL_VM_THRESHOLD) { - printk(KERN_ALERT "kgsl shrink: vmalloc=%x\n", - kgsl_driver.stats.vmalloc); - if (kgsl_shrink != (void *)0) - (*kgsl_shrink)(0, CONFIG_MSM_KGSL_VM_RSS_THRESHOLD); - } -#endif -#endif order = get_order(size); if (order < 16) @@ -553,7 +524,7 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, } int -kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, +kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size) { int ret = 0; @@ -561,18 +532,18 @@ kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, size = ALIGN(size, PAGE_SIZE * 2); - ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size, + ret = _kgsl_sharedmem_vmalloc(memdesc, pagetable, size, GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); if (!ret) - ret = kgsl_page_alloc_map_kernel(memdesc); + ret = kgsl_vmalloc_map_kernel(memdesc); if (ret) kgsl_sharedmem_free(memdesc); return ret; } -EXPORT_SYMBOL(kgsl_sharedmem_page_alloc); +EXPORT_SYMBOL(kgsl_sharedmem_vmalloc); int -kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, +kgsl_sharedmem_vmalloc_user(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size, int flags) { @@ -584,10 +555,10 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, if (!(flags & KGSL_MEMFLAGS_GPUREADONLY)) protflags |= GSL_PT_PAGE_WV; - return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size, + return _kgsl_sharedmem_vmalloc(memdesc, pagetable, size, protflags); } -EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user); +EXPORT_SYMBOL(kgsl_sharedmem_vmalloc_user); int kgsl_sharedmem_alloc_coherent(struct kgsl_memdesc *memdesc, size_t size) @@ -768,7 +739,6 @@ kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc, unsigned int offsetbytes, } EXPORT_SYMBOL(kgsl_sharedmem_set); - /* * kgsl_sharedmem_map_vma - Map a user vma to physical memory * @@ -813,3 +783,4 @@ void kgsl_unregister_shrinker(void) EXPORT_SYMBOL(kgsl_register_shrinker); EXPORT_SYMBOL(kgsl_unregister_shrinker); #endif + diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index a67d9c65..f5197edd 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -30,11 +30,15 @@ struct kgsl_process_private; /** Set if the memdesc describes cached memory */ #define KGSL_MEMFLAGS_CACHED 0x00000001 -extern struct kgsl_memdesc_ops kgsl_page_alloc_ops; +extern struct kgsl_memdesc_ops kgsl_vmalloc_ops; -int kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, +int kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size); +int kgsl_sharedmem_vmalloc_user(struct kgsl_memdesc *memdesc, + struct kgsl_pagetable *pagetable, + size_t size, int flags); + int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size, int flags); @@ -132,7 +136,7 @@ kgsl_allocate(struct kgsl_memdesc *memdesc, { if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE) return kgsl_sharedmem_ebimem(memdesc, pagetable, size); - return kgsl_sharedmem_page_alloc(memdesc, pagetable, size); + return kgsl_sharedmem_vmalloc(memdesc, pagetable, size); } static inline int @@ -143,7 +147,7 @@ kgsl_allocate_user(struct kgsl_memdesc *memdesc, if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE) return kgsl_sharedmem_ebimem_user(memdesc, pagetable, size, flags); - return kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size, flags); + return kgsl_sharedmem_vmalloc_user(memdesc, pagetable, size, flags); } static inline int diff --git a/include/linux/genlock.h b/include/linux/genlock.h index 9351a156..587c49df 100644 --- a/include/linux/genlock.h +++ b/include/linux/genlock.h @@ -21,7 +21,8 @@ int genlock_lock(struct genlock_handle *handle, int op, int flags, #define GENLOCK_WRLOCK 1 #define GENLOCK_RDLOCK 2 -#define GENLOCK_NOBLOCK (1 << 0) +#define GENLOCK_NOBLOCK (1 << 0) +#define GENLOCK_WRITE_TO_READ (1 << 1) struct genlock_lock { int fd; @@ -37,6 +38,8 @@ struct genlock_lock { struct genlock_lock) #define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \ struct genlock_lock) + +/* Deprecated */ #define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \ struct genlock_lock) @@ -44,4 +47,6 @@ struct genlock_lock { #define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4) #define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \ struct genlock_lock) +#define GENLOCK_IOC_DREADLOCK _IOW(GENLOCK_IOC_MAGIC, 6, \ + struct genlock_lock) #endif