680efb3354
This RNG device is present on Marvell OcteonTx2 silicons as well and also provides entropy health status. HW continuously checks health condition of entropy and reports faults. Fault is in terms of co-processor cycles since last fault detected. This doesn't get cleared and only updated when new fault is detected. Also there are chances of detecting false positives. So to detect a entropy failure SW has to check if failures are persistent ie cycles elapsed is frequently updated by HW. This patch adds support to detect health failures using below algo. 1. Consider any fault detected before 10ms as a false positive and ignore. 10ms is chosen randomly, no significance. 2. Upon first failure detection make a note of cycles elapsed and when this error happened in realtime (cntvct). 3. Upon subsequent failure, check if this is new or a old one by comparing current cycles with the ones since last failure. cycles or time since last failure is calculated using cycles and time info captured at (2). HEALTH_CHECK status register is not available to VF, hence had to map PF registers. Also since cycles are in terms of co-processor cycles, had to retrieve co-processor clock rate from RST device. Signed-off-by: Sunil Goutham <sgoutham@marvell.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
92 lines
2.1 KiB
C
92 lines
2.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Hardware Random Number Generator support.
|
|
* Cavium Thunder, Marvell OcteonTx/Tx2 processor families.
|
|
*
|
|
* 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 */
|
|
static 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 v2");
|