drivers: entropy: add get_entropy_isr() for CC13x2/CC26x2
A non-blocking, isr-safe version of get_entropy() is necessary in order to be called during boot time before POST_KERNEL initialization. Otherwise a crash is seen as the existing get_entropy() implementation uses k_sem and relies on interrupts. Fixes #18629 Signed-off-by: Vincent Wan <vincent.wan@linaro.org>
This commit is contained in:
parent
83d0c0a53e
commit
e7a85ddef9
1 changed files with 88 additions and 12 deletions
|
@ -16,6 +16,11 @@
|
||||||
#include <driverlib/prcm.h>
|
#include <driverlib/prcm.h>
|
||||||
#include <driverlib/trng.h>
|
#include <driverlib/trng.h>
|
||||||
|
|
||||||
|
#define CPU_FREQ DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency)
|
||||||
|
|
||||||
|
#define US_PER_SAMPLE (1000000ULL * \
|
||||||
|
CONFIG_ENTROPY_CC13XX_CC26XX_SAMPLES_PER_CYCLE / CPU_FREQ + 1ULL)
|
||||||
|
|
||||||
struct entropy_cc13xx_cc26xx_data {
|
struct entropy_cc13xx_cc26xx_data {
|
||||||
struct k_sem lock;
|
struct k_sem lock;
|
||||||
struct k_sem sync;
|
struct k_sem sync;
|
||||||
|
@ -31,6 +36,23 @@ get_dev_data(struct device *dev)
|
||||||
return dev->driver_data;
|
return dev->driver_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_shutdown_ovf(void)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
|
||||||
|
/* Clear shutdown */
|
||||||
|
TRNGIntClear(TRNG_FRO_SHUTDOWN);
|
||||||
|
/* Disabled FROs */
|
||||||
|
off = sys_read32(TRNG_BASE + TRNG_O_ALARMSTOP);
|
||||||
|
/* Clear alarms */
|
||||||
|
sys_write32(0, TRNG_BASE + TRNG_O_ALARMMASK);
|
||||||
|
sys_write32(0, TRNG_BASE + TRNG_O_ALARMSTOP);
|
||||||
|
/* De-tune FROs */
|
||||||
|
sys_write32(off, TRNG_BASE + TRNG_O_FRODETUNE);
|
||||||
|
/* Re-enable FROs */
|
||||||
|
sys_write32(off, TRNG_BASE + TRNG_O_FROEN);
|
||||||
|
}
|
||||||
|
|
||||||
static int entropy_cc13xx_cc26xx_get_entropy(struct device *dev, uint8_t *buf,
|
static int entropy_cc13xx_cc26xx_get_entropy(struct device *dev, uint8_t *buf,
|
||||||
uint16_t len)
|
uint16_t len)
|
||||||
{
|
{
|
||||||
|
@ -58,7 +80,7 @@ static int entropy_cc13xx_cc26xx_get_entropy(struct device *dev, uint8_t *buf,
|
||||||
static void entropy_cc13xx_cc26xx_isr(void *arg)
|
static void entropy_cc13xx_cc26xx_isr(void *arg)
|
||||||
{
|
{
|
||||||
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(arg);
|
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(arg);
|
||||||
uint32_t src, cnt, off;
|
uint32_t src, cnt;
|
||||||
uint32_t num[2];
|
uint32_t num[2];
|
||||||
|
|
||||||
/* Interrupt service routine as described in TRM section 18.6.1.3.2 */
|
/* Interrupt service routine as described in TRM section 18.6.1.3.2 */
|
||||||
|
@ -83,20 +105,73 @@ static void entropy_cc13xx_cc26xx_isr(void *arg)
|
||||||
* prevent further locking on to the sampling clock frequncy.
|
* prevent further locking on to the sampling clock frequncy.
|
||||||
*/
|
*/
|
||||||
if (src & TRNG_FRO_SHUTDOWN) {
|
if (src & TRNG_FRO_SHUTDOWN) {
|
||||||
/* Clear shutdown */
|
handle_shutdown_ovf();
|
||||||
TRNGIntClear(TRNG_FRO_SHUTDOWN);
|
|
||||||
/* Disabled FROs */
|
|
||||||
off = sys_read32(TRNG_BASE + TRNG_O_ALARMSTOP);
|
|
||||||
/* Clear alarms */
|
|
||||||
sys_write32(0, TRNG_BASE + TRNG_O_ALARMMASK);
|
|
||||||
sys_write32(0, TRNG_BASE + TRNG_O_ALARMSTOP);
|
|
||||||
/* De-tune FROs */
|
|
||||||
sys_write32(off, TRNG_BASE + TRNG_O_FRODETUNE);
|
|
||||||
/* Re-enable FROs */
|
|
||||||
sys_write32(off, TRNG_BASE + TRNG_O_FROEN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int entropy_cc13xx_cc26xx_get_entropy_isr(struct device *dev,
|
||||||
|
uint8_t *buf, uint16_t len, uint32_t flags)
|
||||||
|
{
|
||||||
|
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(dev);
|
||||||
|
uint16_t cnt;
|
||||||
|
uint16_t read = len;
|
||||||
|
uint32_t src;
|
||||||
|
uint32_t num[2];
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
key = irq_lock();
|
||||||
|
cnt = ring_buf_get(&data->pool, buf, len);
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
if ((cnt != len) && ((flags & ENTROPY_BUSYWAIT) != 0U)) {
|
||||||
|
buf += cnt;
|
||||||
|
len -= cnt;
|
||||||
|
|
||||||
|
/* Allowed to busy-wait. We should use a polling approach */
|
||||||
|
while (len) {
|
||||||
|
key = irq_lock();
|
||||||
|
|
||||||
|
src = TRNGStatusGet();
|
||||||
|
if (src & TRNG_NUMBER_READY) {
|
||||||
|
/*
|
||||||
|
* This function acknowledges the ready
|
||||||
|
* status
|
||||||
|
*/
|
||||||
|
num[1] = TRNGNumberGet(TRNG_HI_WORD);
|
||||||
|
num[0] = TRNGNumberGet(TRNG_LOW_WORD);
|
||||||
|
|
||||||
|
ring_buf_put(&data->pool, (uint8_t *)num,
|
||||||
|
sizeof(num));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If interrupts were enabled during busy wait, this
|
||||||
|
* would allow us to pick up anything that has been put
|
||||||
|
* in by the ISR as well.
|
||||||
|
*/
|
||||||
|
cnt = ring_buf_get(&data->pool, buf, len);
|
||||||
|
|
||||||
|
if (src & TRNG_FRO_SHUTDOWN) {
|
||||||
|
handle_shutdown_ovf();
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
if (cnt) {
|
||||||
|
buf += cnt;
|
||||||
|
len -= cnt;
|
||||||
|
} else {
|
||||||
|
k_busy_wait(US_PER_SAMPLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
read = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
static int entropy_cc13xx_cc26xx_init(struct device *dev)
|
static int entropy_cc13xx_cc26xx_init(struct device *dev)
|
||||||
{
|
{
|
||||||
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(dev);
|
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(dev);
|
||||||
|
@ -159,6 +234,7 @@ static int entropy_cc13xx_cc26xx_init(struct device *dev)
|
||||||
|
|
||||||
static const struct entropy_driver_api entropy_cc13xx_cc26xx_driver_api = {
|
static const struct entropy_driver_api entropy_cc13xx_cc26xx_driver_api = {
|
||||||
.get_entropy = entropy_cc13xx_cc26xx_get_entropy,
|
.get_entropy = entropy_cc13xx_cc26xx_get_entropy,
|
||||||
|
.get_entropy_isr = entropy_cc13xx_cc26xx_get_entropy_isr,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct entropy_cc13xx_cc26xx_data entropy_cc13xx_cc26xx_data = {
|
static struct entropy_cc13xx_cc26xx_data entropy_cc13xx_cc26xx_data = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue