hwrng: cavium - Add Cavium HWRNG driver for ThunderX SoC.
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>
This commit is contained in:
parent
21b5b8eebb
commit
cc2f1908c6
@ -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
|
||||
|
@ -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
drivers/char/hw_random/cavium-rng-vf.c
Normal file
99
drivers/char/hw_random/cavium-rng-vf.c
Normal file
@ -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
drivers/char/hw_random/cavium-rng.c
Normal file
94
drivers/char/hw_random/cavium-rng.c
Normal file
@ -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");
|
Loading…
Reference in New Issue
Block a user