| 1 | |
| 2 | * This file is subject to the terms and conditions of the GNU General Public
|
| 3 | * License. See the file "COPYING" in the main directory of this archive
|
| 4 | * for more details.
|
| 5 | *
|
| 6 | * Copyright (C) 1998, 1999, 2003 by Ralf Baechle
|
| 7 | * Copyright (C) 2014 by Maciej W. Rozycki
|
| 8 |
|
| 9 | #ifndef _ASM_TIMEX_H
|
| 10 | #define _ASM_TIMEX_H
|
| 11 |
|
| 12 | #ifdef __KERNEL__
|
| 13 |
|
| 14 | #include <linux/compiler.h>
|
| 15 |
|
| 16 | #include <asm/cpu.h>
|
| 17 | #include <asm/cpu-features.h>
|
| 18 | #include <asm/mipsregs.h>
|
| 19 | #include <asm/cpu-type.h>
|
| 20 |
|
| 21 | |
| 22 | * Standard way to access the cycle counter.
|
| 23 | * Currently only used on SMP for scheduling.
|
| 24 | *
|
| 25 | * Only the low 32 bits are available as a continuously counting entity.
|
| 26 | * But this only means we'll force a reschedule every 8 seconds or so,
|
| 27 | * which isn't an evil thing.
|
| 28 | *
|
| 29 | * We know that all SMP capable CPUs have cycle counters.
|
| 30 |
|
| 31 |
|
| 32 | typedef unsigned int cycles_t;
|
| 33 |
|
| 34 | |
| 35 | * On R4000/R4400 an erratum exists such that if the cycle counter is
|
| 36 | * read in the exact moment that it is matching the compare register,
|
| 37 | * no interrupt will be generated.
|
| 38 | *
|
| 39 | * There is a suggested workaround and also the erratum can't strike if
|
| 40 | * the compare interrupt isn't being used as the clock source device.
|
| 41 | * However for now the implementation of this function doesn't get these
|
| 42 | * fine details right.
|
| 43 |
|
| 44 | static inline int can_use_mips_counter(unsigned int prid)
|
| 45 | {
|
| 46 | int comp = (prid & PRID_COMP_MASK) != PRID_COMP_LEGACY;
|
| 47 |
|
| 48 | if (__builtin_constant_p(cpu_has_counter) && !cpu_has_counter)
|
| 49 | return 0;
|
| 50 | else if (__builtin_constant_p(cpu_has_mips_r) && cpu_has_mips_r)
|
| 51 | return 1;
|
| 52 | else if (likely(!__builtin_constant_p(cpu_has_mips_r) && comp))
|
| 53 | return 1;
|
| 54 |
|
| 55 | if (!__builtin_constant_p(cpu_has_counter))
|
| 56 | asm volatile("" : "=m" (cpu_data[0].options));
|
| 57 | if (likely(cpu_has_counter &&
|
| 58 | prid > (PRID_IMP_R4000 | PRID_REV_ENCODE_44(15, 15))))
|
| 59 | return 1;
|
| 60 | else
|
| 61 | return 0;
|
| 62 | }
|
| 63 |
|
| 64 | static inline cycles_t get_cycles(void)
|
| 65 | {
|
| 66 | if (can_use_mips_counter(read_c0_prid()))
|
| 67 | return read_c0_count();
|
| 68 | else
|
| 69 | return 0;
|
| 70 | }
|
| 71 | #define get_cycles get_cycles
|
| 72 |
|
| 73 | |
| 74 | * Like get_cycles - but where c0_count is not available we desperately
|
| 75 | * use c0_random in an attempt to get at least a little bit of entropy.
|
| 76 |
|
| 77 | static inline unsigned long random_get_entropy(void)
|
| 78 | {
|
| 79 | unsigned int c0_random;
|
| 80 |
|
| 81 | if (can_use_mips_counter(read_c0_prid()))
|
| 82 | return read_c0_count();
|
| 83 |
|
| 84 | if (cpu_has_3kex)
|
| 85 | c0_random = (read_c0_random() >> 8) & 0x3f;
|
| 86 | else
|
| 87 | c0_random = read_c0_random() & 0x3f;
|
| 88 | return (random_get_entropy_fallback() << 6) | (0x3f - c0_random);
|
| 89 | }
|
| 90 | #define random_get_entropy random_get_entropy
|
| 91 |
|
| 92 | #endif
|
| 93 |
|
| 94 | #endif
|