forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Showing
4 changed files
with
207 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); |