Skip to content

Commit

Permalink
hwrng: cavium - Add Cavium HWRNG driver for ThunderX SoC.
Browse files Browse the repository at this point in the history
The Cavium ThunderX SoC has a hardware random number generator.
This driver provides support using the HWRNG framework.

Signed-off-by: Omer Khaliq <okhaliq@caviumnetworks.com>
Signed-off-by: Ananth Jasty <Ananth.Jasty@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
Omer Khaliq authored and herbertx committed Aug 31, 2016
1 parent 21b5b8e commit cc2f190
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 0 deletions.
13 changes: 13 additions & 0 deletions drivers/char/hw_random/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,19 @@ config HW_RANDOM_MESON

If unsure, say Y.

config HW_RANDOM_CAVIUM
tristate "Cavium ThunderX Random Number Generator support"
depends on HW_RANDOM && PCI && (ARM64 || (COMPILE_TEST && 64BIT))
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Cavium SoCs.

To compile this driver as a module, choose M here: the
module will be called cavium_rng.

If unsure, say Y.

endif # HW_RANDOM

config UML_RANDOM
Expand Down
1 change: 1 addition & 0 deletions drivers/char/hw_random/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o
obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o
obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o
obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
99 changes: 99 additions & 0 deletions drivers/char/hw_random/cavium-rng-vf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Hardware Random Number Generator support for Cavium, Inc.
* Thunder processor family.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2016 Cavium, Inc.
*/

#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>

struct cavium_rng {
struct hwrng ops;
void __iomem *result;
};

/* Read data from the RNG unit */
static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait)
{
struct cavium_rng *p = container_of(rng, struct cavium_rng, ops);
unsigned int size = max;

while (size >= 8) {
*((u64 *)dat) = readq(p->result);
size -= 8;
dat += 8;
}
while (size > 0) {
*((u8 *)dat) = readb(p->result);
size--;
dat++;
}
return max;
}

/* Map Cavium RNG to an HWRNG object */
static int cavium_rng_probe_vf(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct cavium_rng *rng;
int ret;

rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
if (!rng)
return -ENOMEM;

/* Map the RNG result */
rng->result = pcim_iomap(pdev, 0, 0);
if (!rng->result) {
dev_err(&pdev->dev, "Error iomap failed retrieving result.\n");
return -ENOMEM;
}

rng->ops.name = "cavium rng";
rng->ops.read = cavium_rng_read;
rng->ops.quality = 1000;

pci_set_drvdata(pdev, rng);

ret = hwrng_register(&rng->ops);
if (ret) {
dev_err(&pdev->dev, "Error registering device as HWRNG.\n");
return ret;
}

return 0;
}

/* Remove the VF */
void cavium_rng_remove_vf(struct pci_dev *pdev)
{
struct cavium_rng *rng;

rng = pci_get_drvdata(pdev);
hwrng_unregister(&rng->ops);
}

static const struct pci_device_id cavium_rng_vf_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa033), 0, 0, 0},
{0,},
};
MODULE_DEVICE_TABLE(pci, cavium_rng_vf_id_table);

static struct pci_driver cavium_rng_vf_driver = {
.name = "cavium_rng_vf",
.id_table = cavium_rng_vf_id_table,
.probe = cavium_rng_probe_vf,
.remove = cavium_rng_remove_vf,
};
module_pci_driver(cavium_rng_vf_driver);

MODULE_AUTHOR("Omer Khaliq <okhaliq@caviumnetworks.com>");
MODULE_LICENSE("GPL");
94 changes: 94 additions & 0 deletions drivers/char/hw_random/cavium-rng.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Hardware Random Number Generator support for Cavium Inc.
* Thunder processor family.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2016 Cavium, Inc.
*/

#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>

#define THUNDERX_RNM_ENT_EN 0x1
#define THUNDERX_RNM_RNG_EN 0x2

struct cavium_rng_pf {
void __iomem *control_status;
};

/* Enable the RNG hardware and activate the VF */
static int cavium_rng_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct cavium_rng_pf *rng;
int iov_err;

rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
if (!rng)
return -ENOMEM;

/*Map the RNG control */
rng->control_status = pcim_iomap(pdev, 0, 0);
if (!rng->control_status) {
dev_err(&pdev->dev,
"Error iomap failed retrieving control_status.\n");
return -ENOMEM;
}

/* Enable the RNG hardware and entropy source */
writeq(THUNDERX_RNM_RNG_EN | THUNDERX_RNM_ENT_EN,
rng->control_status);

pci_set_drvdata(pdev, rng);

/* Enable the Cavium RNG as a VF */
iov_err = pci_enable_sriov(pdev, 1);
if (iov_err != 0) {
/* Disable the RNG hardware and entropy source */
writeq(0, rng->control_status);
dev_err(&pdev->dev,
"Error initializing RNG virtual function,(%i).\n",
iov_err);
return iov_err;
}

return 0;
}

/* Disable VF and RNG Hardware */
void cavium_rng_remove(struct pci_dev *pdev)
{
struct cavium_rng_pf *rng;

rng = pci_get_drvdata(pdev);

/* Remove the VF */
pci_disable_sriov(pdev);

/* Disable the RNG hardware and entropy source */
writeq(0, rng->control_status);
}

static const struct pci_device_id cavium_rng_pf_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa018), 0, 0, 0}, /* Thunder RNM */
{0,},
};

MODULE_DEVICE_TABLE(pci, cavium_rng_pf_id_table);

static struct pci_driver cavium_rng_pf_driver = {
.name = "cavium_rng_pf",
.id_table = cavium_rng_pf_id_table,
.probe = cavium_rng_probe,
.remove = cavium_rng_remove,
};

module_pci_driver(cavium_rng_pf_driver);
MODULE_AUTHOR("Omer Khaliq <okhaliq@caviumnetworks.com>");
MODULE_LICENSE("GPL");

0 comments on commit cc2f190

Please sign in to comment.