ingenic_rng.c revision 1.1
11.1Smacallan/* $NetBSD: ingenic_rng.c,v 1.1 2015/08/07 17:39:58 macallan Exp $ */ 21.1Smacallan 31.1Smacallan/*- 41.1Smacallan * Copyright (c) 2015 Michael McConville 51.1Smacallan * All rights reserved. 61.1Smacallan * 71.1Smacallan * Redistribution and use in source and binary forms, with or without 81.1Smacallan * modification, are permitted provided that the following conditions 91.1Smacallan * are met: 101.1Smacallan * 1. Redistributions of source code must retain the above copyright 111.1Smacallan * notice, this list of conditions and the following disclaimer. 121.1Smacallan * 2. Redistributions in binary form must reproduce the above copyright 131.1Smacallan * notice, this list of conditions and the following disclaimer in the 141.1Smacallan * documentation and/or other materials provided with the distribution. 151.1Smacallan * 161.1Smacallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 171.1Smacallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 181.1Smacallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 191.1Smacallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 201.1Smacallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 211.1Smacallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 221.1Smacallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 231.1Smacallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 241.1Smacallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 251.1Smacallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 261.1Smacallan * POSSIBILITY OF SUCH DAMAGE. 271.1Smacallan */ 281.1Smacallan 291.1Smacallan#include <sys/cdefs.h> 301.1Smacallan__KERNEL_RCSID(0, "$NetBSD: ingenic_rng.c,v 1.1 2015/08/07 17:39:58 macallan Exp $"); 311.1Smacallan 321.1Smacallan#include <sys/param.h> 331.1Smacallan#include <sys/systm.h> 341.1Smacallan#include <sys/device.h> 351.1Smacallan#include <sys/mutex.h> 361.1Smacallan#include <sys/kernel.h> 371.1Smacallan#include <sys/mutex.h> 381.1Smacallan#include <sys/callout.h> 391.1Smacallan#include <sys/bus.h> 401.1Smacallan#include <sys/workqueue.h> 411.1Smacallan#include <sys/rndpool.h> 421.1Smacallan#include <sys/rndsource.h> 431.1Smacallan 441.1Smacallan#include <mips/ingenic/ingenic_var.h> 451.1Smacallan#include <mips/ingenic/ingenic_regs.h> 461.1Smacallan 471.1Smacallan#include "opt_ingenic.h" 481.1Smacallan 491.1Smacallanstruct ingenic_rng_softc; 501.1Smacallan 511.1Smacallanstatic int ingenic_rng_match(device_t, cfdata_t, void *); 521.1Smacallanstatic void ingenic_rng_attach(device_t, device_t, void *); 531.1Smacallan 541.1Smacallanstatic void ingenic_rng_get(struct ingenic_rng_softc *); 551.1Smacallanstatic void ingenic_rng_get_intr(void *); 561.1Smacallanstatic void ingenic_rng_get_cb(size_t, void *); 571.1Smacallan 581.1Smacallanstruct ingenic_rng_softc { 591.1Smacallan device_t sc_dev; 601.1Smacallan bus_space_tag_t sc_bst; 611.1Smacallan bus_space_handle_t sc_bsh; 621.1Smacallan 631.1Smacallan void * sc_sih; 641.1Smacallan 651.1Smacallan krndsource_t sc_rndsource; 661.1Smacallan size_t sc_bytes_wanted; 671.1Smacallan 681.1Smacallan kmutex_t sc_intr_lock; 691.1Smacallan kmutex_t sc_rnd_lock; 701.1Smacallan}; 711.1Smacallan 721.1SmacallanCFATTACH_DECL_NEW(ingenic_rng, sizeof(struct ingenic_rng_softc), 731.1Smacallan ingenic_rng_match, ingenic_rng_attach, NULL, NULL); 741.1Smacallan 751.1Smacallanstatic int 761.1Smacallaningenic_rng_match(device_t parent, cfdata_t cf, void *aux) 771.1Smacallan{ 781.1Smacallan struct apbus_attach_args *aa = aux; 791.1Smacallan 801.1Smacallan if (strcmp(aa->aa_name, "jzrng") == 0) { 811.1Smacallan return 1; 821.1Smacallan } else { 831.1Smacallan return 0; 841.1Smacallan } 851.1Smacallan} 861.1Smacallan 871.1Smacallanstatic void 881.1Smacallaningenic_rng_attach(device_t parent, device_t self, void *aux) 891.1Smacallan{ 901.1Smacallan struct ingenic_rng_softc * const sc = device_private(self); 911.1Smacallan struct apbus_attach_args * const aa = aux; 921.1Smacallan int error; 931.1Smacallan 941.1Smacallan sc->sc_dev = self; 951.1Smacallan sc->sc_bst = aa->aa_bst; 961.1Smacallan if (aa->aa_addr == 0) { 971.1Smacallan aa->aa_addr = JZ_RNG; 981.1Smacallan } 991.1Smacallan 1001.1Smacallan error = bus_space_map(aa->aa_bst, aa->aa_addr, 4, 0, &sc->sc_bsh); 1011.1Smacallan if (error) { 1021.1Smacallan aprint_error_dev(self, 1031.1Smacallan "can't map registers for %s: %d\n", aa->aa_name, error); 1041.1Smacallan return; 1051.1Smacallan } 1061.1Smacallan 1071.1Smacallan mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SERIAL); 1081.1Smacallan mutex_init(&sc->sc_rnd_lock, MUTEX_DEFAULT, IPL_SERIAL); 1091.1Smacallan 1101.1Smacallan aprint_naive(": Ingenic random number generator\n"); 1111.1Smacallan aprint_normal(": Ingenic random number generator\n"); 1121.1Smacallan 1131.1Smacallan sc->sc_sih = softint_establish(SOFTINT_SERIAL|SOFTINT_MPSAFE, 1141.1Smacallan ingenic_rng_get_intr, sc); 1151.1Smacallan if (sc->sc_sih == NULL) { 1161.1Smacallan aprint_error_dev(self, "couldn't establish softint\n"); 1171.1Smacallan return; 1181.1Smacallan } 1191.1Smacallan 1201.1Smacallan rndsource_setcb(&sc->sc_rndsource, ingenic_rng_get_cb, sc); 1211.1Smacallan rnd_attach_source(&sc->sc_rndsource, device_xname(self), RND_TYPE_RNG, 1221.1Smacallan RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB); 1231.1Smacallan 1241.1Smacallan ingenic_rng_get_cb(RND_POOLBITS / NBBY, sc); 1251.1Smacallan} 1261.1Smacallan 1271.1Smacallanstatic void 1281.1Smacallaningenic_rng_get(struct ingenic_rng_softc *sc) 1291.1Smacallan{ 1301.1Smacallan uint32_t data; 1311.1Smacallan 1321.1Smacallan mutex_spin_enter(&sc->sc_intr_lock); 1331.1Smacallan while (sc->sc_bytes_wanted) { 1341.1Smacallan bus_space_read_region_4(sc->sc_bst, sc->sc_bsh, 0, &data, 1); 1351.1Smacallan#if 0 1361.1Smacallan device_printf(sc->sc_dev, "random output: %x\n", data); 1371.1Smacallan#endif 1381.1Smacallan mutex_spin_exit(&sc->sc_intr_lock); 1391.1Smacallan mutex_spin_enter(&sc->sc_rnd_lock); 1401.1Smacallan rnd_add_data(&sc->sc_rndsource, &data, sizeof(data), 1411.1Smacallan sizeof(data) * NBBY); 1421.1Smacallan mutex_spin_exit(&sc->sc_rnd_lock); 1431.1Smacallan mutex_spin_enter(&sc->sc_intr_lock); 1441.1Smacallan sc->sc_bytes_wanted -= MIN(sc->sc_bytes_wanted, sizeof(data)); 1451.1Smacallan } 1461.1Smacallan explicit_memset(&data, 0, sizeof(data)); 1471.1Smacallan mutex_spin_exit(&sc->sc_intr_lock); 1481.1Smacallan} 1491.1Smacallan 1501.1Smacallanstatic void 1511.1Smacallaningenic_rng_get_cb(size_t bytes_wanted, void *priv) 1521.1Smacallan{ 1531.1Smacallan struct ingenic_rng_softc * const sc = priv; 1541.1Smacallan 1551.1Smacallan mutex_spin_enter(&sc->sc_intr_lock); 1561.1Smacallan if (sc->sc_bytes_wanted == 0) { 1571.1Smacallan softint_schedule(sc->sc_sih); 1581.1Smacallan } 1591.1Smacallan if (bytes_wanted > (UINT_MAX - sc->sc_bytes_wanted)) { 1601.1Smacallan sc->sc_bytes_wanted = UINT_MAX; 1611.1Smacallan } else { 1621.1Smacallan sc->sc_bytes_wanted += bytes_wanted; 1631.1Smacallan } 1641.1Smacallan mutex_spin_exit(&sc->sc_intr_lock); 1651.1Smacallan} 1661.1Smacallan 1671.1Smacallanstatic void 1681.1Smacallaningenic_rng_get_intr(void *priv) 1691.1Smacallan{ 1701.1Smacallan struct ingenic_rng_softc * const sc = priv; 1711.1Smacallan 1721.1Smacallan ingenic_rng_get(sc); 1731.1Smacallan} 174