Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 149320
b: refs/heads/master
c: 39ec58f
h: refs/heads/master
v: v3
  • Loading branch information
Lennert Buytenhek authored and Nicolas Pitre committed May 30, 2009
1 parent dfcfc43 commit 7a92235
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a1f98849fdf2f2fef3ef1c260178cd5fc662b773
refs/heads/master: 39ec58f3fea47c242724109cc1da999f74810bbc
16 changes: 16 additions & 0 deletions trunk/arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,22 @@ config ALIGNMENT_TRAP
correct operation of some network protocols. With an IP-only
configuration it is safe to say N, otherwise say Y.

config UACCESS_WITH_MEMCPY
bool "Use kernel mem{cpy,set}() for {copy_to,clear}_user() (EXPERIMENTAL)"
depends on MMU && EXPERIMENTAL
default y if CPU_FEROCEON
help
Implement faster copy_to_user and clear_user methods for CPU
cores where a 8-word STM instruction give significantly higher
memory write throughput than a sequence of individual 32bit stores.

A possible side effect is a slight increase in scheduling latency
between threads sharing the same address space if they invoke
such copy operations with large buffers.

However, if the CPU data cache is using a write-allocate mode,
this option is unlikely to provide any performance gain.

endmenu

menu "Boot options"
Expand Down
3 changes: 3 additions & 0 deletions trunk/arch/arm/lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ else
endif
endif

# using lib_ here won't override already available weak symbols
obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o

lib-$(CONFIG_MMU) += $(mmu-y)

ifeq ($(CONFIG_CPU_32v3),y)
Expand Down
139 changes: 139 additions & 0 deletions trunk/arch/arm/lib/uaccess_with_memcpy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* linux/arch/arm/lib/uaccess_with_memcpy.c
*
* Written by: Lennert Buytenhek and Nicolas Pitre
* Copyright (C) 2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/uaccess.h>
#include <linux/rwsem.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/hardirq.h> /* for in_atomic() */
#include <asm/current.h>
#include <asm/page.h>

static int
pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
{
unsigned long addr = (unsigned long)_addr;
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
spinlock_t *ptl;

pgd = pgd_offset(current->mm, addr);
if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
return 0;

pmd = pmd_offset(pgd, addr);
if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
return 0;

pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
if (unlikely(!pte_present(*pte) || !pte_young(*pte) ||
!pte_write(*pte) || !pte_dirty(*pte))) {
pte_unmap_unlock(pte, ptl);
return 0;
}

*ptep = pte;
*ptlp = ptl;

return 1;
}

unsigned long
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
int atomic;

if (n < 1024)
return __copy_to_user_std(to, from, n);

if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
memcpy((void *)to, from, n);
return 0;
}

/* the mmap semaphore is taken only if not in an atomic context */
atomic = in_atomic();

if (!atomic)
down_read(&current->mm->mmap_sem);
while (n) {
pte_t *pte;
spinlock_t *ptl;
int tocopy;

while (!pin_page_for_write(to, &pte, &ptl)) {
if (!atomic)
up_read(&current->mm->mmap_sem);
if (__put_user(0, (char __user *)to))
goto out;
if (!atomic)
down_read(&current->mm->mmap_sem);
}

tocopy = (~(unsigned long)to & ~PAGE_MASK) + 1;
if (tocopy > n)
tocopy = n;

memcpy((void *)to, from, tocopy);
to += tocopy;
from += tocopy;
n -= tocopy;

pte_unmap_unlock(pte, ptl);
}
if (!atomic)
up_read(&current->mm->mmap_sem);

out:
return n;
}

unsigned long __clear_user(void __user *addr, unsigned long n)
{
if (n < 256)
return __clear_user_std(addr, n);

if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
memset((void *)addr, 0, n);
return 0;
}

down_read(&current->mm->mmap_sem);
while (n) {
pte_t *pte;
spinlock_t *ptl;
int tocopy;

while (!pin_page_for_write(addr, &pte, &ptl)) {
up_read(&current->mm->mmap_sem);
if (__put_user(0, (char __user *)addr))
goto out;
down_read(&current->mm->mmap_sem);
}

tocopy = (~(unsigned long)addr & ~PAGE_MASK) + 1;
if (tocopy > n)
tocopy = n;

memset((void *)addr, 0, tocopy);
addr += tocopy;
n -= tocopy;

pte_unmap_unlock(pte, ptl);
}
up_read(&current->mm->mmap_sem);

out:
return n;
}

0 comments on commit 7a92235

Please sign in to comment.