0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <linux/bitops.h>
0026 #include <linux/kernel.h>
0027 #include <linux/random.h>
0028 #include <linux/slab.h>
0029 #include <linux/types.h>
0030
0031 #include "i915_random.h"
0032 #include "i915_utils.h"
0033
0034 u64 i915_prandom_u64_state(struct rnd_state *rnd)
0035 {
0036 u64 x;
0037
0038 x = prandom_u32_state(rnd);
0039 x <<= 32;
0040 x |= prandom_u32_state(rnd);
0041
0042 return x;
0043 }
0044
0045 void i915_prandom_shuffle(void *arr, size_t elsz, size_t count,
0046 struct rnd_state *state)
0047 {
0048 char stack[128];
0049
0050 if (WARN_ON(elsz > sizeof(stack) || count > U32_MAX))
0051 return;
0052
0053 if (!elsz || !count)
0054 return;
0055
0056
0057 while (--count) {
0058 size_t swp;
0059
0060 swp = i915_prandom_u32_max_state(count + 1, state);
0061 if (swp == count)
0062 continue;
0063
0064 memcpy(stack, arr + count * elsz, elsz);
0065 memcpy(arr + count * elsz, arr + swp * elsz, elsz);
0066 memcpy(arr + swp * elsz, stack, elsz);
0067 }
0068 }
0069
0070 void i915_random_reorder(unsigned int *order, unsigned int count,
0071 struct rnd_state *state)
0072 {
0073 i915_prandom_shuffle(order, sizeof(*order), count, state);
0074 }
0075
0076 unsigned int *i915_random_order(unsigned int count, struct rnd_state *state)
0077 {
0078 unsigned int *order, i;
0079
0080 order = kmalloc_array(count, sizeof(*order),
0081 GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
0082 if (!order)
0083 return order;
0084
0085 for (i = 0; i < count; i++)
0086 order[i] = i;
0087
0088 i915_random_reorder(order, count, state);
0089 return order;
0090 }
0091
0092 u64 igt_random_offset(struct rnd_state *state,
0093 u64 start, u64 end,
0094 u64 len, u64 align)
0095 {
0096 u64 range, addr;
0097
0098 BUG_ON(range_overflows(start, len, end));
0099 BUG_ON(round_up(start, align) > round_down(end - len, align));
0100
0101 range = round_down(end - len, align) - round_up(start, align);
0102 if (range) {
0103 addr = i915_prandom_u64_state(state);
0104 div64_u64_rem(addr, range, &addr);
0105 start += addr;
0106 }
0107
0108 return round_up(start, align);
0109 }