zephyr/subsys/bluetooth/controller/hal/nrf5/rand.c
Alberto Escolar Piedras ec7727077b native: nrf52 changes to HAL to support running on simulated HW
Conditionally compiled changes to the NRF52 HAL so it can
run on simulated HW on the native port.
(HW models are not included in this commit)

All changes are under ifdefs and therefore will not have any
effect on normal builds

Signed-off-by: Alberto Escolar Piedras <alpi@oticon.com>
2018-01-29 16:02:29 +01:00

218 lines
3.5 KiB
C

/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <soc.h>
#include "hal/rand.h"
#include "common/log.h"
#include "hal/debug.h"
struct rand {
u8_t count;
u8_t threshold;
u8_t first;
u8_t last;
u8_t rand[1];
};
static struct rand *rng_isr;
static struct rand *rng_thr;
static void init(struct rand **rng, u8_t *context, u8_t len, u8_t threshold)
{
struct rand *p;
LL_ASSERT(len > (offsetof(struct rand, rand) + threshold));
*rng = (struct rand *)context;
p = *rng;
p->count = len - offsetof(struct rand, rand);
p->threshold = threshold;
p->first = p->last = 0;
if (!rng_isr || !rng_thr) {
NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk;
NRF_RNG->EVENTS_VALRDY = 0;
NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk;
NRF_RNG->TASKS_START = 1;
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
NRF_RNG_regw_sideeffects();
#endif
}
}
void rand_init(u8_t *context, u8_t context_len, u8_t threshold)
{
init(&rng_thr, context, context_len, threshold);
}
void rand_isr_init(u8_t *context, u8_t context_len, u8_t threshold)
{
init(&rng_isr, context, context_len, threshold);
}
static size_t get(struct rand *rng, size_t octets, u8_t *rand)
{
u8_t first, last, remaining;
LL_ASSERT(rng);
first = rng->first;
last = rng->last;
if (first <= last) {
u8_t *d, *s;
u8_t avail;
d = &rand[octets];
s = &rng->rand[first];
avail = last - first;
if (octets < avail) {
remaining = avail - octets;
avail = octets;
} else {
remaining = 0;
}
first += avail;
octets -= avail;
while (avail--) {
*(--d) = *s++;
}
rng->first = first;
} else {
u8_t *d, *s;
u8_t avail;
d = &rand[octets];
s = &rng->rand[first];
avail = rng->count - first;
if (octets < avail) {
remaining = avail + last - octets;
avail = octets;
first += avail;
} else {
remaining = last;
first = 0;
}
octets -= avail;
while (avail--) {
*(--d) = *s++;
}
if (octets && last) {
s = &rng->rand[0];
if (octets < last) {
remaining = last - octets;
last = octets;
} else {
remaining = 0;
}
first = last;
octets -= last;
while (last--) {
*(--d) = *s++;
}
}
rng->first = first;
}
if (remaining < rng->threshold) {
NRF_RNG->TASKS_START = 1;
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
NRF_RNG_regw_sideeffects();
#endif
}
return octets;
}
size_t rand_get(size_t octets, u8_t *rand)
{
return get(rng_thr, octets, rand);
}
size_t rand_isr_get(size_t octets, u8_t *rand)
{
return get(rng_isr, octets, rand);
}
static int isr(struct rand *rng, bool store)
{
u8_t last;
if (!rng) {
return -ENOBUFS;
}
last = rng->last + 1;
if (last == rng->count) {
last = 0;
}
if (last == rng->first) {
/* this condition should not happen, but due to probable race,
* new value could be generated before NRF_RNG task is stopped.
*/
return -ENOBUFS;
}
if (!store) {
return -EBUSY;
}
rng->rand[rng->last] = NRF_RNG->VALUE;
rng->last = last;
last = rng->last + 1;
if (last == rng->count) {
last = 0;
}
if (last == rng->first) {
return 0;
}
return -EBUSY;
}
void isr_rand(void *param)
{
ARG_UNUSED(param);
if (NRF_RNG->EVENTS_VALRDY) {
int ret;
ret = isr(rng_isr, true);
if (ret != -EBUSY) {
ret = isr(rng_thr, (ret == -ENOBUFS));
}
NRF_RNG->EVENTS_VALRDY = 0;
if (ret != -EBUSY) {
NRF_RNG->TASKS_STOP = 1;
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
NRF_RNG_regw_sideeffects();
#endif
}
}
}