aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc/lib/memcpy.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc/lib/memcpy.c')
-rw-r--r--arch/parisc/lib/memcpy.c79
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 */
159static 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) 164static 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
261handle_load_error: 266handle_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
268handle_store_error: 270handle_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.
278static 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. */
279static 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
406unaligned_copy: 404unaligned_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
455handle_load_error: 452handle_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
462handle_store_error: 456handle_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. */
463static 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__