Initial Contribution
msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142 Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
This commit is contained in:
138
mm/ashmem.c
138
mm/ashmem.c
@@ -29,6 +29,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#define ASHMEM_NAME_PREFIX "dev/ashmem/"
|
||||
#define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1)
|
||||
@@ -45,6 +46,8 @@ struct ashmem_area {
|
||||
struct list_head unpinned_list; /* list of all ashmem areas */
|
||||
struct file *file; /* the shmem-based backing file */
|
||||
size_t size; /* size of the mapping, in bytes */
|
||||
unsigned long vm_start; /* Start address of vm_area
|
||||
* which maps this ashmem */
|
||||
unsigned long prot_mask; /* allowed prot bits, as vm_flags */
|
||||
};
|
||||
|
||||
@@ -326,6 +329,7 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
vma->vm_file = asma->file;
|
||||
}
|
||||
vma->vm_flags |= VM_CAN_NONLINEAR;
|
||||
asma->vm_start = vma->vm_start;
|
||||
|
||||
out:
|
||||
mutex_unlock(&ashmem_mutex);
|
||||
@@ -626,6 +630,84 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OUTER_CACHE
|
||||
static unsigned int kgsl_virtaddr_to_physaddr(unsigned int virtaddr)
|
||||
{
|
||||
unsigned int physaddr = 0;
|
||||
pgd_t *pgd_ptr = NULL;
|
||||
pmd_t *pmd_ptr = NULL;
|
||||
pte_t *pte_ptr = NULL, pte;
|
||||
|
||||
pgd_ptr = pgd_offset(current->mm, virtaddr);
|
||||
if (pgd_none(*pgd) || pgd_bad(*pgd)) {
|
||||
pr_info
|
||||
("Invalid pgd entry found while trying to convert virtual "
|
||||
"address to physical\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pmd_ptr = pmd_offset(pgd_ptr, virtaddr);
|
||||
if (pmd_none(*pmd_ptr) || pmd_bad(*pmd_ptr)) {
|
||||
pr_info
|
||||
("Invalid pmd entry found while trying to convert virtual "
|
||||
"address to physical\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pte_ptr = pte_offset_map(pmd_ptr, virtaddr);
|
||||
if (!pte_ptr) {
|
||||
pr_info
|
||||
("Unable to map pte entry while trying to convert virtual "
|
||||
"address to physical\n");
|
||||
return 0;
|
||||
}
|
||||
pte = *pte_ptr;
|
||||
physaddr = pte_pfn(pte);
|
||||
pte_unmap(pte_ptr);
|
||||
physaddr <<= PAGE_SHIFT;
|
||||
return physaddr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ashmem_flush_cache_range(struct ashmem_area *asma)
|
||||
{
|
||||
#ifdef CONFIG_OUTER_CACHE
|
||||
unsigned long end;
|
||||
#endif
|
||||
unsigned long addr;
|
||||
unsigned int size, result = 0;
|
||||
|
||||
mutex_lock(&ashmem_mutex);
|
||||
|
||||
size = asma->size;
|
||||
addr = asma->vm_start;
|
||||
if (!addr || (addr & (PAGE_SIZE - 1)) || !size ||
|
||||
(size & (PAGE_SIZE - 1))) {
|
||||
result = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OUTER_CACHE
|
||||
flush_cache_user_range(addr, addr + size);
|
||||
for (end = addr; end < (addr + size); end += PAGE_SIZE) {
|
||||
unsigned long physaddr;
|
||||
physaddr = kgsl_virtaddr_to_physaddr(end);
|
||||
if (!physaddr) {
|
||||
result = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
outer_flush_range(physaddr, physaddr + PAGE_SIZE);
|
||||
}
|
||||
mb();
|
||||
#else
|
||||
clean_and_invalidate_caches(addr, size, 0);
|
||||
#endif
|
||||
done:
|
||||
mutex_unlock(&ashmem_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct ashmem_area *asma = file->private_data;
|
||||
@@ -671,11 +753,67 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
ashmem_shrink(&ashmem_shrinker, &sc);
|
||||
}
|
||||
break;
|
||||
case ASHMEM_CACHE_FLUSH_RANGE:
|
||||
ret = ashmem_flush_cache_range(asma);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_ashmem_file(struct file *file)
|
||||
{
|
||||
char fname[256], *name;
|
||||
name = dentry_path(file->f_dentry, fname, 256);
|
||||
return strcmp(name, "/ashmem") ? 0 : 1;
|
||||
}
|
||||
|
||||
int get_ashmem_file(int fd, struct file **filp, struct file **vm_file,
|
||||
unsigned long *len)
|
||||
{
|
||||
int ret = -1;
|
||||
struct file *file = fget(fd);
|
||||
*filp = NULL;
|
||||
*vm_file = NULL;
|
||||
if (unlikely(file == NULL)) {
|
||||
pr_err("ashmem: %s: requested data from file "
|
||||
"descriptor that doesn't exist.\n", __func__);
|
||||
} else {
|
||||
char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
|
||||
pr_debug("filp %p rdev %d pid %u(%s) file %p(%ld)"
|
||||
" dev id: %d\n", filp,
|
||||
file->f_dentry->d_inode->i_rdev,
|
||||
current->pid, get_task_comm(currtask_name, current),
|
||||
file, file_count(file),
|
||||
MINOR(file->f_dentry->d_inode->i_rdev));
|
||||
if (is_ashmem_file(file)) {
|
||||
struct ashmem_area *asma = file->private_data;
|
||||
*filp = file;
|
||||
*vm_file = asma->file;
|
||||
*len = asma->size;
|
||||
ret = 0;
|
||||
} else {
|
||||
pr_err("file descriptor is not an ashmem "
|
||||
"region fd: %d\n", fd);
|
||||
fput(file);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(get_ashmem_file);
|
||||
|
||||
void put_ashmem_file(struct file *file)
|
||||
{
|
||||
char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
|
||||
pr_debug("rdev %d pid %u(%s) file %p(%ld)" " dev id: %d\n",
|
||||
file->f_dentry->d_inode->i_rdev, current->pid,
|
||||
get_task_comm(currtask_name, current), file,
|
||||
file_count(file), MINOR(file->f_dentry->d_inode->i_rdev));
|
||||
if (file && is_ashmem_file(file))
|
||||
fput(file);
|
||||
}
|
||||
EXPORT_SYMBOL(put_ashmem_file);
|
||||
|
||||
static struct file_operations ashmem_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ashmem_open,
|
||||
|
||||
Reference in New Issue
Block a user