cregit-Linux how code gets into the kernel

Release 4.14 arch/powerpc/platforms/powernv/rng.c

/*
 * Copyright 2013, Michael Ellerman, IBM Corporation.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */


#define pr_fmt(fmt)	"powernv-rng: " fmt

#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <asm/archrandom.h>
#include <asm/cputable.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/smp.h>


#define DARN_ERR 0xFFFFFFFFFFFFFFFFul


struct powernv_rng {
	
void __iomem *regs;
	
void __iomem *regs_real;
	
unsigned long mask;
};

static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);



int powernv_hwrng_present(void) { struct powernv_rng *rng; rng = get_cpu_var(powernv_rng); put_cpu_var(rng); return rng != NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman29100.00%1100.00%
Total29100.00%1100.00%


static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) { unsigned long parity; /* Calculate the parity of the value */ asm ("popcntd %0,%1" : "=r" (parity) : "r" (val)); /* xor our value with the previous mask */ val ^= rng->mask; /* update the mask based on the parity of this value */ rng->mask = (rng->mask << 1) | (parity & 1); return val; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman51100.00%1100.00%
Total51100.00%1100.00%


int powernv_get_random_real_mode(unsigned long *v) { struct powernv_rng *rng; rng = raw_cpu_read(powernv_rng); *v = rng_whiten(rng, __raw_rm_readq(rng->regs_real)); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman3997.50%150.00%
Benjamin Herrenschmidt12.50%150.00%
Total40100.00%2100.00%


int powernv_get_random_darn(unsigned long *v) { unsigned long val; /* Using DARN with L=1 - 64-bit conditioned random number */ asm volatile(PPC_DARN(%0, 1) : "=r"(val)); if (val == DARN_ERR) return 0; *v = val; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Matt Brown35100.00%1100.00%
Total35100.00%1100.00%


static int initialise_darn(void) { unsigned long val; int i; if (!cpu_has_feature(CPU_FTR_ARCH_300)) return -ENODEV; for (i = 0; i < 10; i++) { if (powernv_get_random_darn(&val)) { ppc_md.get_random_seed = powernv_get_random_darn; return 0; } } pr_warn("Unable to use DARN for get_random_seed()\n"); return -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Matt Brown70100.00%1100.00%
Total70100.00%1100.00%


int powernv_get_random_long(unsigned long *v) { struct powernv_rng *rng; rng = get_cpu_var(powernv_rng); *v = rng_whiten(rng, in_be64(rng->regs)); put_cpu_var(rng); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman45100.00%1100.00%
Total45100.00%1100.00%

EXPORT_SYMBOL_GPL(powernv_get_random_long);
static __init void rng_init_per_cpu(struct powernv_rng *rng, struct device_node *dn) { int chip_id, cpu; chip_id = of_get_ibm_chip_id(dn); if (chip_id == -1) pr_warn("No ibm,chip-id found for %pOF.\n", dn); for_each_possible_cpu(cpu) { if (per_cpu(powernv_rng, cpu) == NULL || cpu_to_chip_id(cpu) == chip_id) { per_cpu(powernv_rng, cpu) = rng; } } }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman7798.72%150.00%
Rob Herring11.28%150.00%
Total78100.00%2100.00%


static __init int rng_create(struct device_node *dn) { struct powernv_rng *rng; struct resource res; unsigned long val; rng = kzalloc(sizeof(*rng), GFP_KERNEL); if (!rng) return -ENOMEM; if (of_address_to_resource(dn, 0, &res)) { kfree(rng); return -ENXIO; } rng->regs_real = (void __iomem *)res.start; rng->regs = of_iomap(dn, 0); if (!rng->regs) { kfree(rng); return -ENXIO; } val = in_be64(rng->regs); rng->mask = val; rng_init_per_cpu(rng, dn); pr_info_once("Registering arch random hook.\n"); ppc_md.get_random_seed = powernv_get_random_long; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman14799.32%266.67%
Paul Mackerras10.68%133.33%
Total148100.00%3100.00%


static __init int rng_init(void) { struct device_node *dn; int rc; for_each_compatible_node(dn, NULL, "ibm,power-rng") { rc = rng_create(dn); if (rc) { pr_err("Failed creating rng for %pOF (%d).\n", dn, rc); continue; } /* Create devices for hwrng driver */ of_platform_device_create(dn, NULL, NULL); } initialise_darn(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman6293.94%133.33%
Matt Brown34.55%133.33%
Rob Herring11.52%133.33%
Total66100.00%3100.00%

machine_subsys_initcall(powernv, rng_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman52380.34%444.44%
Matt Brown11517.67%111.11%
Stephen Rothwell91.38%111.11%
Rob Herring20.31%111.11%
Paul Mackerras10.15%111.11%
Benjamin Herrenschmidt10.15%111.11%
Total651100.00%9100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.