Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2015 Qualcomm Atheros, Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <linux/hw_random.h>
0018 #include <linux/kthread.h>
0019 
0020 #include "ath9k.h"
0021 #include "hw.h"
0022 #include "ar9003_phy.h"
0023 
0024 static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size)
0025 {
0026     int i, j;
0027     u32  v1, v2, rng_last = sc->rng_last;
0028     struct ath_hw *ah = sc->sc_ah;
0029 
0030     ath9k_ps_wakeup(sc);
0031 
0032     REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
0033     REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
0034     REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0);
0035 
0036     for (i = 0, j = 0; i < buf_size; i++) {
0037         v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
0038         v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
0039 
0040         /* wait for data ready */
0041         if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff &&
0042             v2 != 0xffff)
0043             buf[j++] = (v1 << 16) | v2;
0044 
0045         rng_last = v2;
0046     }
0047 
0048     ath9k_ps_restore(sc);
0049 
0050     sc->rng_last = rng_last;
0051 
0052     return j << 2;
0053 }
0054 
0055 static u32 ath9k_rng_delay_get(u32 fail_stats)
0056 {
0057     u32 delay;
0058 
0059     if (fail_stats < 100)
0060         delay = 10;
0061     else if (fail_stats < 105)
0062         delay = 1000;
0063     else
0064         delay = 10000;
0065 
0066     return delay;
0067 }
0068 
0069 static int ath9k_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
0070 {
0071     struct ath_softc *sc = container_of(rng, struct ath_softc, rng_ops);
0072     u32 fail_stats = 0, word;
0073     int bytes_read = 0;
0074 
0075     for (;;) {
0076         if (max & ~3UL)
0077             bytes_read = ath9k_rng_data_read(sc, buf, max >> 2);
0078         if ((max & 3UL) && ath9k_rng_data_read(sc, &word, 1)) {
0079             memcpy(buf + bytes_read, &word, max & 3UL);
0080             bytes_read += max & 3UL;
0081             memzero_explicit(&word, sizeof(word));
0082         }
0083         if (!wait || !max || likely(bytes_read) || fail_stats > 110)
0084             break;
0085 
0086         msleep_interruptible(ath9k_rng_delay_get(++fail_stats));
0087     }
0088 
0089     if (wait && !bytes_read && max)
0090         bytes_read = -EIO;
0091     return bytes_read;
0092 }
0093 
0094 void ath9k_rng_start(struct ath_softc *sc)
0095 {
0096     static atomic_t serial = ATOMIC_INIT(0);
0097     struct ath_hw *ah = sc->sc_ah;
0098 
0099     if (sc->rng_ops.read)
0100         return;
0101 
0102     if (!AR_SREV_9300_20_OR_LATER(ah))
0103         return;
0104 
0105     snprintf(sc->rng_name, sizeof(sc->rng_name), "ath9k_%u",
0106          (atomic_inc_return(&serial) - 1) & U16_MAX);
0107     sc->rng_ops.name = sc->rng_name;
0108     sc->rng_ops.read = ath9k_rng_read;
0109     sc->rng_ops.quality = 320;
0110 
0111     if (devm_hwrng_register(sc->dev, &sc->rng_ops))
0112         sc->rng_ops.read = NULL;
0113 }
0114 
0115 void ath9k_rng_stop(struct ath_softc *sc)
0116 {
0117     if (sc->rng_ops.read) {
0118         devm_hwrng_unregister(sc->dev, &sc->rng_ops);
0119         sc->rng_ops.read = NULL;
0120     }
0121 }