root/drivers/net/wireless/ath/ath9k/rng.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath9k_rng_data_read
  2. ath9k_rng_delay_get
  3. ath9k_rng_kthread
  4. ath9k_rng_start
  5. ath9k_rng_stop

   1 /*
   2  * Copyright (c) 2015 Qualcomm Atheros, Inc.
   3  *
   4  * Permission to use, copy, modify, and/or distribute this software for any
   5  * purpose with or without fee is hereby granted, provided that the above
   6  * copyright notice and this permission notice appear in all copies.
   7  *
   8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15  */
  16 
  17 #include <linux/hw_random.h>
  18 #include <linux/kthread.h>
  19 
  20 #include "ath9k.h"
  21 #include "hw.h"
  22 #include "ar9003_phy.h"
  23 
  24 #define ATH9K_RNG_BUF_SIZE      320
  25 #define ATH9K_RNG_ENTROPY(x)    (((x) * 8 * 10) >> 5) /* quality: 10/32 */
  26 
  27 static DECLARE_WAIT_QUEUE_HEAD(rng_queue);
  28 
  29 static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size)
  30 {
  31         int i, j;
  32         u32  v1, v2, rng_last = sc->rng_last;
  33         struct ath_hw *ah = sc->sc_ah;
  34 
  35         ath9k_ps_wakeup(sc);
  36 
  37         REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
  38         REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
  39         REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0);
  40 
  41         for (i = 0, j = 0; i < buf_size; i++) {
  42                 v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
  43                 v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
  44 
  45                 /* wait for data ready */
  46                 if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff &&
  47                     v2 != 0xffff)
  48                         buf[j++] = (v1 << 16) | v2;
  49 
  50                 rng_last = v2;
  51         }
  52 
  53         ath9k_ps_restore(sc);
  54 
  55         sc->rng_last = rng_last;
  56 
  57         return j << 2;
  58 }
  59 
  60 static u32 ath9k_rng_delay_get(u32 fail_stats)
  61 {
  62         u32 delay;
  63 
  64         if (fail_stats < 100)
  65                 delay = 10;
  66         else if (fail_stats < 105)
  67                 delay = 1000;
  68         else
  69                 delay = 10000;
  70 
  71         return delay;
  72 }
  73 
  74 static int ath9k_rng_kthread(void *data)
  75 {
  76         int bytes_read;
  77         struct ath_softc *sc = data;
  78         u32 *rng_buf;
  79         u32 delay, fail_stats = 0;
  80 
  81         rng_buf = kmalloc_array(ATH9K_RNG_BUF_SIZE, sizeof(u32), GFP_KERNEL);
  82         if (!rng_buf)
  83                 goto out;
  84 
  85         while (!kthread_should_stop()) {
  86                 bytes_read = ath9k_rng_data_read(sc, rng_buf,
  87                                                  ATH9K_RNG_BUF_SIZE);
  88                 if (unlikely(!bytes_read)) {
  89                         delay = ath9k_rng_delay_get(++fail_stats);
  90                         wait_event_interruptible_timeout(rng_queue,
  91                                                          kthread_should_stop(),
  92                                                          msecs_to_jiffies(delay));
  93                         continue;
  94                 }
  95 
  96                 fail_stats = 0;
  97 
  98                 /* sleep until entropy bits under write_wakeup_threshold */
  99                 add_hwgenerator_randomness((void *)rng_buf, bytes_read,
 100                                            ATH9K_RNG_ENTROPY(bytes_read));
 101         }
 102 
 103         kfree(rng_buf);
 104 out:
 105         sc->rng_task = NULL;
 106 
 107         return 0;
 108 }
 109 
 110 void ath9k_rng_start(struct ath_softc *sc)
 111 {
 112         struct ath_hw *ah = sc->sc_ah;
 113 
 114         if (sc->rng_task)
 115                 return;
 116 
 117         if (!AR_SREV_9300_20_OR_LATER(ah))
 118                 return;
 119 
 120         sc->rng_task = kthread_run(ath9k_rng_kthread, sc, "ath9k-hwrng");
 121         if (IS_ERR(sc->rng_task))
 122                 sc->rng_task = NULL;
 123 }
 124 
 125 void ath9k_rng_stop(struct ath_softc *sc)
 126 {
 127         if (sc->rng_task) {
 128                 kthread_stop(sc->rng_task);
 129                 sc->rng_task = NULL;
 130         }
 131 }

/* [<][>][^][v][top][bottom][index][help] */