diff options
Diffstat (limited to 'arch/parisc/lib/memcpy.c')
-rw-r--r-- | arch/parisc/lib/memcpy.c | 79 |
1 files changed, 50 insertions, 29 deletions
diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c index a49cc812df8a..ac4370b1ca40 100644 --- a/arch/parisc/lib/memcpy.c +++ b/arch/parisc/lib/memcpy.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * Optimized memory copy routines. | 2 | * Optimized memory copy routines. |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Randolph Chung <tausq@debian.org> | 4 | * Copyright (C) 2004 Randolph Chung <tausq@debian.org> |
5 | * Copyright (C) 2013 Helge Deller <deller@gmx.de> | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -153,17 +154,21 @@ static inline void prefetch_dst(const void *addr) | |||
153 | #define prefetch_dst(addr) do { } while(0) | 154 | #define prefetch_dst(addr) do { } while(0) |
154 | #endif | 155 | #endif |
155 | 156 | ||
157 | #define PA_MEMCPY_OK 0 | ||
158 | #define PA_MEMCPY_LOAD_ERROR 1 | ||
159 | #define PA_MEMCPY_STORE_ERROR 2 | ||
160 | |||
156 | /* Copy from a not-aligned src to an aligned dst, using shifts. Handles 4 words | 161 | /* Copy from a not-aligned src to an aligned dst, using shifts. Handles 4 words |
157 | * per loop. This code is derived from glibc. | 162 | * per loop. This code is derived from glibc. |
158 | */ | 163 | */ |
159 | static inline unsigned long copy_dstaligned(unsigned long dst, unsigned long src, unsigned long len, unsigned long o_dst, unsigned long o_src, unsigned long o_len) | 164 | static inline unsigned long copy_dstaligned(unsigned long dst, |
165 | unsigned long src, unsigned long len) | ||
160 | { | 166 | { |
161 | /* gcc complains that a2 and a3 may be uninitialized, but actually | 167 | /* gcc complains that a2 and a3 may be uninitialized, but actually |
162 | * they cannot be. Initialize a2/a3 to shut gcc up. | 168 | * they cannot be. Initialize a2/a3 to shut gcc up. |
163 | */ | 169 | */ |
164 | register unsigned int a0, a1, a2 = 0, a3 = 0; | 170 | register unsigned int a0, a1, a2 = 0, a3 = 0; |
165 | int sh_1, sh_2; | 171 | int sh_1, sh_2; |
166 | struct exception_data *d; | ||
167 | 172 | ||
168 | /* prefetch_src((const void *)src); */ | 173 | /* prefetch_src((const void *)src); */ |
169 | 174 | ||
@@ -197,7 +202,7 @@ static inline unsigned long copy_dstaligned(unsigned long dst, unsigned long src | |||
197 | goto do2; | 202 | goto do2; |
198 | case 0: | 203 | case 0: |
199 | if (len == 0) | 204 | if (len == 0) |
200 | return 0; | 205 | return PA_MEMCPY_OK; |
201 | /* a3 = ((unsigned int *) src)[0]; | 206 | /* a3 = ((unsigned int *) src)[0]; |
202 | a0 = ((unsigned int *) src)[1]; */ | 207 | a0 = ((unsigned int *) src)[1]; */ |
203 | ldw(s_space, 0, src, a3, cda_ldw_exc); | 208 | ldw(s_space, 0, src, a3, cda_ldw_exc); |
@@ -256,42 +261,35 @@ do0: | |||
256 | preserve_branch(handle_load_error); | 261 | preserve_branch(handle_load_error); |
257 | preserve_branch(handle_store_error); | 262 | preserve_branch(handle_store_error); |
258 | 263 | ||
259 | return 0; | 264 | return PA_MEMCPY_OK; |
260 | 265 | ||
261 | handle_load_error: | 266 | handle_load_error: |
262 | __asm__ __volatile__ ("cda_ldw_exc:\n"); | 267 | __asm__ __volatile__ ("cda_ldw_exc:\n"); |
263 | d = &__get_cpu_var(exception_data); | 268 | return PA_MEMCPY_LOAD_ERROR; |
264 | DPRINTF("cda_ldw_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n", | ||
265 | o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src); | ||
266 | return o_len * 4 - d->fault_addr + o_src; | ||
267 | 269 | ||
268 | handle_store_error: | 270 | handle_store_error: |
269 | __asm__ __volatile__ ("cda_stw_exc:\n"); | 271 | __asm__ __volatile__ ("cda_stw_exc:\n"); |
270 | d = &__get_cpu_var(exception_data); | 272 | return PA_MEMCPY_STORE_ERROR; |
271 | DPRINTF("cda_stw_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n", | ||
272 | o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst); | ||
273 | return o_len * 4 - d->fault_addr + o_dst; | ||
274 | } | 273 | } |
275 | 274 | ||
276 | 275 | ||
277 | /* Returns 0 for success, otherwise, returns number of bytes not transferred. */ | 276 | /* Returns PA_MEMCPY_OK, PA_MEMCPY_LOAD_ERROR or PA_MEMCPY_STORE_ERROR. |
278 | static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len) | 277 | * In case of an access fault the faulty address can be read from the per_cpu |
278 | * exception data struct. */ | ||
279 | static unsigned long pa_memcpy_internal(void *dstp, const void *srcp, | ||
280 | unsigned long len) | ||
279 | { | 281 | { |
280 | register unsigned long src, dst, t1, t2, t3; | 282 | register unsigned long src, dst, t1, t2, t3; |
281 | register unsigned char *pcs, *pcd; | 283 | register unsigned char *pcs, *pcd; |
282 | register unsigned int *pws, *pwd; | 284 | register unsigned int *pws, *pwd; |
283 | register double *pds, *pdd; | 285 | register double *pds, *pdd; |
284 | unsigned long ret = 0; | 286 | unsigned long ret; |
285 | unsigned long o_dst, o_src, o_len; | ||
286 | struct exception_data *d; | ||
287 | 287 | ||
288 | src = (unsigned long)srcp; | 288 | src = (unsigned long)srcp; |
289 | dst = (unsigned long)dstp; | 289 | dst = (unsigned long)dstp; |
290 | pcs = (unsigned char *)srcp; | 290 | pcs = (unsigned char *)srcp; |
291 | pcd = (unsigned char *)dstp; | 291 | pcd = (unsigned char *)dstp; |
292 | 292 | ||
293 | o_dst = dst; o_src = src; o_len = len; | ||
294 | |||
295 | /* prefetch_src((const void *)srcp); */ | 293 | /* prefetch_src((const void *)srcp); */ |
296 | 294 | ||
297 | if (len < THRESHOLD) | 295 | if (len < THRESHOLD) |
@@ -401,7 +399,7 @@ byte_copy: | |||
401 | len--; | 399 | len--; |
402 | } | 400 | } |
403 | 401 | ||
404 | return 0; | 402 | return PA_MEMCPY_OK; |
405 | 403 | ||
406 | unaligned_copy: | 404 | unaligned_copy: |
407 | /* possibly we are aligned on a word, but not on a double... */ | 405 | /* possibly we are aligned on a word, but not on a double... */ |
@@ -438,8 +436,7 @@ unaligned_copy: | |||
438 | src = (unsigned long)pcs; | 436 | src = (unsigned long)pcs; |
439 | } | 437 | } |
440 | 438 | ||
441 | ret = copy_dstaligned(dst, src, len / sizeof(unsigned int), | 439 | ret = copy_dstaligned(dst, src, len / sizeof(unsigned int)); |
442 | o_dst, o_src, o_len); | ||
443 | if (ret) | 440 | if (ret) |
444 | return ret; | 441 | return ret; |
445 | 442 | ||
@@ -454,17 +451,41 @@ unaligned_copy: | |||
454 | 451 | ||
455 | handle_load_error: | 452 | handle_load_error: |
456 | __asm__ __volatile__ ("pmc_load_exc:\n"); | 453 | __asm__ __volatile__ ("pmc_load_exc:\n"); |
457 | d = &__get_cpu_var(exception_data); | 454 | return PA_MEMCPY_LOAD_ERROR; |
458 | DPRINTF("pmc_load_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n", | ||
459 | o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src); | ||
460 | return o_len - d->fault_addr + o_src; | ||
461 | 455 | ||
462 | handle_store_error: | 456 | handle_store_error: |
463 | __asm__ __volatile__ ("pmc_store_exc:\n"); | 457 | __asm__ __volatile__ ("pmc_store_exc:\n"); |
458 | return PA_MEMCPY_STORE_ERROR; | ||
459 | } | ||
460 | |||
461 | |||
462 | /* Returns 0 for success, otherwise, returns number of bytes not transferred. */ | ||
463 | static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len) | ||
464 | { | ||
465 | unsigned long ret, fault_addr, reference; | ||
466 | struct exception_data *d; | ||
467 | |||
468 | ret = pa_memcpy_internal(dstp, srcp, len); | ||
469 | if (likely(ret == PA_MEMCPY_OK)) | ||
470 | return 0; | ||
471 | |||
472 | /* if a load or store fault occured we can get the faulty addr */ | ||
464 | d = &__get_cpu_var(exception_data); | 473 | d = &__get_cpu_var(exception_data); |
465 | DPRINTF("pmc_store_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n", | 474 | fault_addr = d->fault_addr; |
466 | o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst); | 475 | |
467 | return o_len - d->fault_addr + o_dst; | 476 | /* error in load or store? */ |
477 | if (ret == PA_MEMCPY_LOAD_ERROR) | ||
478 | reference = (unsigned long) srcp; | ||
479 | else | ||
480 | reference = (unsigned long) dstp; | ||
481 | |||
482 | DPRINTF("pa_memcpy: fault type = %lu, len=%lu fault_addr=%lu ref=%lu\n", | ||
483 | ret, len, fault_addr, reference); | ||
484 | |||
485 | if (fault_addr >= reference) | ||
486 | return len - (fault_addr - reference); | ||
487 | else | ||
488 | return len; | ||
468 | } | 489 | } |
469 | 490 | ||
470 | #ifdef __KERNEL__ | 491 | #ifdef __KERNEL__ |