// SPDX-License-Identifier: GPL-2.0-only /* * drivers/char/hw_random/timeriomem-rng.c * * Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk> * * Derived from drivers/char/hw_random/omap-rng.c * Copyright 2005 (c) MontaVista Software, Inc. * Author: Deepak Saxena <dsaxena@plexity.net> * * Overview: * This driver is useful for platforms that have an IO range that provides * periodic random data from a single IO memory address. All the platform * has to do is provide the address and 'wait time' that new data becomes * available. * * TODO: add support for reading sizes other than 32bits and masking
*/
/* * There may not have been enough time for new data to be generated * since the last request. If the caller doesn't want to wait, let them * bail out. Otherwise, wait for the completion. If the new data has * already been generated, the completion should already be available.
*/ if (!wait && !priv->present) return 0;
wait_for_completion(&priv->completion);
do { /* * After the first read, all additional reads will need to wait * for the RNG to generate new data. Since the period can have * a wide range of values (1us to 1s have been observed), allow * for 1% tolerance in the sleep time rather than a fixed value.
*/ if (retval > 0)
usleep_range(period_us,
period_us + max(1, period_us / 100));
*(u32 *)data = readl(priv->io_base);
retval += sizeof(u32);
data += sizeof(u32);
max -= sizeof(u32);
} while (wait && max > sizeof(u32));
/* * Block any new callers until the RNG has had time to generate new * data.
*/
priv->present = 0;
reinit_completion(&priv->completion);
hrtimer_forward_now(&priv->timer, priv->period);
hrtimer_restart(&priv->timer);
if (!pdev->dev.of_node && !pdata) {
dev_err(&pdev->dev, "timeriomem_rng_data is missing\n"); return -EINVAL;
}
/* Allocate memory for the device structure (and zero it) */
priv = devm_kzalloc(&pdev->dev, sizeof(struct timeriomem_rng_private), GFP_KERNEL); if (!priv) return -ENOMEM;
platform_set_drvdata(pdev, priv);
priv->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(priv->io_base)) return PTR_ERR(priv->io_base);
if (res->start % 4 != 0 || resource_size(res) < 4) {
dev_err(&pdev->dev, "address must be at least four bytes wide and 32-bit aligned\n"); return -EINVAL;
}
if (pdev->dev.of_node) { int i;
if (!of_property_read_u32(pdev->dev.of_node, "period", &i))
period = i; else {
dev_err(&pdev->dev, "missing period\n"); return -EINVAL;
}
if (!of_property_read_u32(pdev->dev.of_node, "quality", &i))
priv->rng_ops.quality = i;
} else {
period = pdata->period;
priv->rng_ops.quality = pdata->quality;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.