Commit 479ba603 authored by Robin Getz's avatar Robin Getz Committed by Mike Frysinger

Blackfin: move string functions to normal lib/ assembly

Since 'extern inline' doesn't work correctly in the context of the Linux
kernel (too many overriding defines), move the string functions to normal
lib/ assembly files (like the existing mem funcs).  This avoids the forced
inline all over the kernel and allows us to place them constantly in L1.

This also avoids some module failures when gcc inserts calls to string
functions but the kernel build system doesn't fully consult the library
archives.
Signed-off-by: default avatarRobin Getz <robin.getz@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
parent 80fcdb95
......@@ -791,6 +791,34 @@ config MEMCPY_L1
If enabled, the memcpy function is linked
into L1 instruction memory. (less latency)
config STRCMP_L1
bool "locate strcmp function in L1 Memory"
default y
help
If enabled, the strcmp function is linked
into L1 instruction memory (less latency).
config STRNCMP_L1
bool "locate strncmp function in L1 Memory"
default y
help
If enabled, the strncmp function is linked
into L1 instruction memory (less latency).
config STRCPY_L1
bool "locate strcpy function in L1 Memory"
default y
help
If enabled, the strcpy function is linked
into L1 instruction memory (less latency).
config STRNCPY_L1
bool "locate strncpy function in L1 Memory"
default y
help
If enabled, the strncpy function is linked
into L1 instruction memory (less latency).
config SYS_BFIN_SPINLOCK_L1
bool "Locate sys_bfin_spinlock function in L1 Memory"
default y
......
......@@ -12,121 +12,16 @@
#ifdef __KERNEL__ /* only set these up for kernel code */
#define __HAVE_ARCH_STRCPY
extern inline char *strcpy(char *dest, const char *src)
{
char *xdest = dest;
char temp = 0;
__asm__ __volatile__ (
"1:"
"%2 = B [%1++] (Z);"
"B [%0++] = %2;"
"CC = %2;"
"if cc jump 1b (bp);"
: "+&a" (dest), "+&a" (src), "=&d" (temp)
:
: "memory", "CC");
return xdest;
}
extern char *strcpy(char *dest, const char *src);
#define __HAVE_ARCH_STRNCPY
extern inline char *strncpy(char *dest, const char *src, size_t n)
{
char *xdest = dest;
char temp = 0;
if (n == 0)
return xdest;
__asm__ __volatile__ (
"1:"
"%3 = B [%1++] (Z);"
"B [%0++] = %3;"
"CC = %3;"
"if ! cc jump 2f;"
"%2 += -1;"
"CC = %2 == 0;"
"if ! cc jump 1b (bp);"
"jump 4f;"
"2:"
/* if src is shorter than n, we need to null pad bytes now */
"%3 = 0;"
"3:"
"%2 += -1;"
"CC = %2 == 0;"
"if cc jump 4f;"
"B [%0++] = %3;"
"jump 3b;"
"4:"
: "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp)
:
: "memory", "CC");
return xdest;
}
extern char *strncpy(char *dest, const char *src, size_t n);
#define __HAVE_ARCH_STRCMP
extern inline int strcmp(const char *cs, const char *ct)
{
/* need to use int's here so the char's in the assembly don't get
* sign extended incorrectly when we don't want them to be
*/
int __res1, __res2;
__asm__ __volatile__ (
"1:"
"%2 = B[%0++] (Z);" /* get *cs */
"%3 = B[%1++] (Z);" /* get *ct */
"CC = %2 == %3;" /* compare a byte */
"if ! cc jump 2f;" /* not equal, break out */
"CC = %2;" /* at end of cs? */
"if cc jump 1b (bp);" /* no, keep going */
"jump.s 3f;" /* strings are equal */
"2:"
"%2 = %2 - %3;" /* *cs - *ct */
"3:"
: "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2)
:
: "memory", "CC");
return __res1;
}
extern int strcmp(const char *cs, const char *ct);
#define __HAVE_ARCH_STRNCMP
extern inline int strncmp(const char *cs, const char *ct, size_t count)
{
/* need to use int's here so the char's in the assembly don't get
* sign extended incorrectly when we don't want them to be
*/
int __res1, __res2;
if (!count)
return 0;
__asm__ __volatile__ (
"1:"
"%3 = B[%0++] (Z);" /* get *cs */
"%4 = B[%1++] (Z);" /* get *ct */
"CC = %3 == %4;" /* compare a byte */
"if ! cc jump 3f;" /* not equal, break out */
"CC = %3;" /* at end of cs? */
"if ! cc jump 4f;" /* yes, all done */
"%2 += -1;" /* no, adjust count */
"CC = %2 == 0;"
"if ! cc jump 1b;" /* more to do, keep going */
"2:"
"%3 = 0;" /* strings are equal */
"jump.s 4f;"
"3:"
"%3 = %3 - %4;" /* *cs - *ct */
"4:"
: "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2)
:
: "memory", "CC");
return __res1;
}
extern int strncmp(const char *cs, const char *ct, size_t count);
#define __HAVE_ARCH_MEMSET
extern void *memset(void *s, int c, size_t count);
......
......@@ -32,6 +32,18 @@ EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(memchr);
/*
* Because string functions are both inline and exported functions and
* folder arch/blackfin/lib is configured as a library path in Makefile,
* symbols exported in folder lib is not linked into built-in.o but
* inlined only. In order to export string symbols to kernel module
* properly, they should be exported here.
*/
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strncmp);
/*
* libgcc functions - functions that are used internally by the
* compiler... (prototypes are not correct though, but that
......
/*
* Copyright 2005-2010 Analog Devices Inc.
*
* Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
/* void *strcmp(char *s1, const char *s2);
* R0 = address (s1)
* R1 = address (s2)
*
* Returns an integer less than, equal to, or greater than zero if s1
* (or the first n bytes thereof) is found, respectively, to be less
* than, to match, or be greater than s2.
*/
#ifdef CONFIG_STRCMP_L1
.section .l1.text
#else
.text
#endif
.align 2
ENTRY(_strcmp)
P0 = R0 ; /* s1 */
P1 = R1 ; /* s2 */
1:
R0 = B[P0++] (Z); /* get *s1 */
R1 = B[P1++] (Z); /* get *s2 */
CC = R0 == R1; /* compare a byte */
if ! cc jump 2f; /* not equal, break out */
CC = R0; /* at end of s1? */
if cc jump 1b (bp); /* no, keep going */
jump.s 3f; /* strings are equal */
2:
R0 = R0 - R1; /* *s1 - *s2 */
3:
RTS;
ENDPROC(_strcmp)
/*
* Provide symbol in case str func is not inlined.
*
* Copyright (c) 2006-2007 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#define strcmp __inline_strcmp
#include <asm/string.h>
#undef strcmp
#include <linux/module.h>
int strcmp(const char *dest, const char *src)
{
return __inline_strcmp(dest, src);
}
EXPORT_SYMBOL(strcmp);
/*
* Copyright 2005-2010 Analog Devices Inc.
*
* Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
/* void *strcpy(char *dest, const char *src);
* R0 = address (dest)
* R1 = address (src)
*
* Returns a pointer to the destination string dest
*/
#ifdef CONFIG_STRCPY_L1
.section .l1.text
#else
.text
#endif
.align 2
ENTRY(_strcpy)
P0 = R0 ; /* dst*/
P1 = R1 ; /* src*/
1:
R1 = B [P1++] (Z);
B [P0++] = R1;
CC = R1;
if cc jump 1b (bp);
RTS;
ENDPROC(_strcpy)
/*
* Provide symbol in case str func is not inlined.
*
* Copyright (c) 2006-2007 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#define strcpy __inline_strcpy
#include <asm/string.h>
#undef strcpy
#include <linux/module.h>
char *strcpy(char *dest, const char *src)
{
return __inline_strcpy(dest, src);
}
EXPORT_SYMBOL(strcpy);
/*
* Copyright 2005-2010 Analog Devices Inc.
*
* Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
/* void *strncpy(char *s1, const char *s2, size_t n);
* R0 = address (dest)
* R1 = address (src)
* R2 = size (n)
* Returns a pointer to the destination string dest
*/
#ifdef CONFIG_STRNCMP_L1
.section .l1.text
#else
.text
#endif
.align 2
ENTRY(_strncmp)
CC = R2 == 0;
if CC JUMP 5f;
P0 = R0 ; /* s1 */
P1 = R1 ; /* s2 */
1:
R0 = B[P0++] (Z); /* get *s1 */
R1 = B[P1++] (Z); /* get *s2 */
CC = R0 == R1; /* compare a byte */
if ! cc jump 3f; /* not equal, break out */
CC = R0; /* at end of s1? */
if ! cc jump 4f; /* yes, all done */
R2 += -1; /* no, adjust count */
CC = R2 == 0;
if ! cc jump 1b (bp); /* more to do, keep going */
2:
R0 = 0; /* strings are equal */
jump.s 4f;
3:
R0 = R0 - R1; /* *s1 - *s2 */
4:
RTS;
5:
R0 = 0;
RTS;
ENDPROC(_strncmp)
/*
* Provide symbol in case str func is not inlined.
*
* Copyright (c) 2006-2007 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#define strncmp __inline_strncmp
#include <asm/string.h>
#include <linux/module.h>
#undef strncmp
int strncmp(const char *cs, const char *ct, size_t count)
{
return __inline_strncmp(cs, ct, count);
}
EXPORT_SYMBOL(strncmp);
/*
* Copyright 2005-2010 Analog Devices Inc.
*
* Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
/* void *strncpy(char *dest, const char *src, size_t n);
* R0 = address (dest)
* R1 = address (src)
* R2 = size
* Returns a pointer to the destination string dest
*/
#ifdef CONFIG_STRNCPY_L1
.section .l1.text
#else
.text
#endif
.align 2
ENTRY(_strncpy)
CC = R2 == 0;
if CC JUMP 4f;
P0 = R0 ; /* dst*/
P1 = R1 ; /* src*/
1:
R1 = B [P1++] (Z);
B [P0++] = R1;
CC = R1;
if ! cc jump 2f;
R2 += -1;
CC = R2 == 0;
if ! cc jump 1b (bp);
jump 4f;
2:
/* if src is shorter than n, we need to null pad bytes in dest */
R1 = 0;
3:
R2 += -1;
CC = R2 == 0;
if cc jump 4f;
B [P0++] = R1;
jump 3b;
4:
RTS;
ENDPROC(_strncpy)
/*
* Provide symbol in case str func is not inlined.
*
* Copyright (c) 2006-2007 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#define strncpy __inline_strncpy
#include <asm/string.h>
#undef strncpy
#include <linux/module.h>
char *strncpy(char *dest, const char *src, size_t n)
{
return __inline_strncpy(dest, src, n);
}
EXPORT_SYMBOL(strncpy);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment