hc
2023-11-06 1622ff3442ff6aecc1f538cda437379d1f6a4a93
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * 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 = devm_kasprintf(&pdev->dev, GFP_KERNEL,
                      "cavium-rng-%s", dev_name(&pdev->dev));
   if (!rng->ops.name)
       return -ENOMEM;
 
   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 */
static 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");