Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  iproc-rng200.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom Corporation
*
*/

/*
 * DESCRIPTION: The Broadcom iProc RNG200 Driver
 */


#include <linux/hw_random.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/delay.h>

/* Registers */
#define RNG_CTRL_OFFSET     0x00
#define RNG_CTRL_RNG_RBGEN_MASK    0x00001FFF
#define RNG_CTRL_RNG_RBGEN_ENABLE   0x00000001

#define RNG_SOFT_RESET_OFFSET    0x04
#define RNG_SOFT_RESET     0x00000001

#define RBG_SOFT_RESET_OFFSET    0x08
#define RBG_SOFT_RESET     0x00000001

#define RNG_INT_STATUS_OFFSET    0x18
#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
#define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000
#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK  0x00000020
#define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001

#define RNG_FIFO_DATA_OFFSET    0x20

#define RNG_FIFO_COUNT_OFFSET    0x24
#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK  0x000000FF

struct iproc_rng200_dev {
 struct hwrng rng;
 void __iomem *base;
};

#define to_rng_priv(rng) container_of(rng, struct iproc_rng200_dev, rng)

static void iproc_rng200_enable_set(void __iomem *rng_base, bool enable)
{
 u32 val;

 val = ioread32(rng_base + RNG_CTRL_OFFSET);
 val &= ~RNG_CTRL_RNG_RBGEN_MASK;

 if (enable)
  val |= RNG_CTRL_RNG_RBGEN_ENABLE;

 iowrite32(val, rng_base + RNG_CTRL_OFFSET);
}

static void iproc_rng200_restart(void __iomem *rng_base)
{
 uint32_t val;

 iproc_rng200_enable_set(rng_base, false);

 /* Clear all interrupt status */
 iowrite32(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET);

 /* Reset RNG and RBG */
 val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
 val |= RBG_SOFT_RESET;
 iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);

 val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
 val |= RNG_SOFT_RESET;
 iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);

 val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
 val &= ~RNG_SOFT_RESET;
 iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);

 val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
 val &= ~RBG_SOFT_RESET;
 iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);

 iproc_rng200_enable_set(rng_base, true);
}

static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max,
        bool wait)
{
 struct iproc_rng200_dev *priv = to_rng_priv(rng);
 uint32_t num_remaining = max;
 uint32_t status;

 #define MAX_RESETS_PER_READ 1
 uint32_t num_resets = 0;

 #define MAX_IDLE_TIME (1 * HZ)
 unsigned long idle_endtime = jiffies + MAX_IDLE_TIME;

 while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {

  /* Is RNG sane? If not, reset it. */
  status = ioread32(priv->base + RNG_INT_STATUS_OFFSET);
  if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK |
   RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) {

   if (num_resets >= MAX_RESETS_PER_READ)
    return max - num_remaining;

   iproc_rng200_restart(priv->base);
   num_resets++;
  }

  /* Are there any random numbers available? */
  if ((ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
    RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {

   if (num_remaining >= sizeof(uint32_t)) {
    /* Buffer has room to store entire word */
    *(uint32_t *)buf = ioread32(priv->base +
       RNG_FIFO_DATA_OFFSET);
    buf += sizeof(uint32_t);
    num_remaining -= sizeof(uint32_t);
   } else {
    /* Buffer can only store partial word */
    uint32_t rnd_number = ioread32(priv->base +
       RNG_FIFO_DATA_OFFSET);
    memcpy(buf, &rnd_number, num_remaining);
    buf += num_remaining;
    num_remaining = 0;
   }

   /* Reset the IDLE timeout */
   idle_endtime = jiffies + MAX_IDLE_TIME;
  } else {
   if (!wait)
    /* Cannot wait, return immediately */
    return max - num_remaining;

   /* Can wait, give others chance to run */
   usleep_range(min(num_remaining * 10, 500U), 500);
  }
 }

 return max - num_remaining;
}

static int iproc_rng200_init(struct hwrng *rng)
{
 struct iproc_rng200_dev *priv = to_rng_priv(rng);

 iproc_rng200_enable_set(priv->base, true);

 return 0;
}

static void iproc_rng200_cleanup(struct hwrng *rng)
{
 struct iproc_rng200_dev *priv = to_rng_priv(rng);

 iproc_rng200_enable_set(priv->base, false);
}

static int iproc_rng200_probe(struct platform_device *pdev)
{
 struct iproc_rng200_dev *priv;
 struct device *dev = &pdev->dev;
 int ret;

 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 if (!priv)
  return -ENOMEM;

 /* Map peripheral */
 priv->base = devm_platform_ioremap_resource(pdev, 0);
 if (IS_ERR(priv->base)) {
  dev_err(dev, "failed to remap rng regs\n");
  return PTR_ERR(priv->base);
 }

 dev_set_drvdata(dev, priv);

 priv->rng.name = "iproc-rng200";
 priv->rng.read = iproc_rng200_read;
 priv->rng.init = iproc_rng200_init;
 priv->rng.cleanup = iproc_rng200_cleanup;

 /* Register driver */
 ret = devm_hwrng_register(dev, &priv->rng);
 if (ret) {
  dev_err(dev, "hwrng registration failed\n");
  return ret;
 }

 dev_info(dev, "hwrng registered\n");

 return 0;
}

static int __maybe_unused iproc_rng200_suspend(struct device *dev)
{
 struct iproc_rng200_dev *priv = dev_get_drvdata(dev);

 iproc_rng200_cleanup(&priv->rng);

 return 0;
}

static int __maybe_unused iproc_rng200_resume(struct device *dev)
{
 struct iproc_rng200_dev *priv =  dev_get_drvdata(dev);

 iproc_rng200_init(&priv->rng);

 return 0;
}

static const struct dev_pm_ops iproc_rng200_pm_ops = {
 SET_SYSTEM_SLEEP_PM_OPS(iproc_rng200_suspend, iproc_rng200_resume)
};

static const struct of_device_id iproc_rng200_of_match[] = {
 { .compatible = "brcm,bcm2711-rng200", },
 { .compatible = "brcm,bcm7211-rng200", },
 { .compatible = "brcm,bcm7278-rng200", },
 { .compatible = "brcm,iproc-rng200", },
 {},
};
MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);

static struct platform_driver iproc_rng200_driver = {
 .driver = {
  .name  = "iproc-rng200",
  .of_match_table = iproc_rng200_of_match,
  .pm  = &iproc_rng200_pm_ops,
 },
 .probe  = iproc_rng200_probe,
};
module_platform_driver(iproc_rng200_driver);

MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("iProc RNG200 Random Number Generator driver");
MODULE_LICENSE("GPL v2");

Messung V0.5
C=93 H=91 G=91

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge