1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell CN10K RVU Hardware Random Number Generator.
4 * Copyright (C) 2021 Marvell.
8 #include <linux/hw_random.h>
10 #include <linux/module.h>
11 #include <linux/pci.h>
12 #include <linux/pci_ids.h>
13 #include <linux/delay.h>
15 #include <linux/arm-smccc.h>
18 #define RNM_CTL_STATUS 0x000
19 #define RNM_ENTROPY_STATUS 0x008
20 #define RNM_CONST 0x030
21 #define RNM_EBG_ENT 0x048
22 #define RNM_PF_EBG_HEALTH 0x050
23 #define RNM_PF_RANDOM 0x400
24 #define RNM_TRNG_RESULT 0x408
26 /* Extended TRNG Read and Status Registers */
27 #define RNM_PF_TRNG_DAT 0x1000
28 #define RNM_PF_TRNG_RES 0x1008
31 void __iomem
*reg_base
;
34 /* Octeon CN10K-A A0/A1, CNF10K-A A0/A1 and CNF10K-B A0/B0
35 * does not support extended TRNG registers
37 bool extended_trng_regs
;
40 #define PLAT_OCTEONTX_RESET_RNG_EBG_HEALTH_STATE 0xc2000b0f
42 #define PCI_SUBSYS_DEVID_CN10K_A_RNG 0xB900
43 #define PCI_SUBSYS_DEVID_CNF10K_A_RNG 0xBA00
44 #define PCI_SUBSYS_DEVID_CNF10K_B_RNG 0xBC00
46 static bool cn10k_is_extended_trng_regs_supported(struct pci_dev
*pdev
)
49 if ((pdev
->subsystem_device
== PCI_SUBSYS_DEVID_CN10K_A_RNG
) &&
50 (!pdev
->revision
|| (pdev
->revision
& 0xff) == 0x50 ||
51 (pdev
->revision
& 0xff) == 0x51))
55 if ((pdev
->subsystem_device
== PCI_SUBSYS_DEVID_CNF10K_A_RNG
) &&
56 (!pdev
->revision
|| (pdev
->revision
& 0xff) == 0x60 ||
57 (pdev
->revision
& 0xff) == 0x61))
61 if ((pdev
->subsystem_device
== PCI_SUBSYS_DEVID_CNF10K_B_RNG
) &&
62 (!pdev
->revision
|| (pdev
->revision
& 0xff) == 0x70 ||
63 (pdev
->revision
& 0xff) == 0x74))
69 static unsigned long reset_rng_health_state(struct cn10k_rng
*rng
)
71 struct arm_smccc_res res
;
73 /* Send SMC service call to reset EBG health state */
74 arm_smccc_smc(PLAT_OCTEONTX_RESET_RNG_EBG_HEALTH_STATE
, 0, 0, 0, 0, 0, 0, 0, &res
);
78 static int check_rng_health(struct cn10k_rng
*rng
)
83 /* Skip checking health */
87 status
= readq(rng
->reg_base
+ RNM_PF_EBG_HEALTH
);
88 if (status
& BIT_ULL(20)) {
89 err
= reset_rng_health_state(rng
);
91 dev_err(&rng
->pdev
->dev
, "HWRNG: Health test failed (status=%llx)\n",
93 dev_err(&rng
->pdev
->dev
, "HWRNG: error during reset (error=%lx)\n",
101 /* Returns true when valid data available otherwise return false */
102 static bool cn10k_read_trng(struct cn10k_rng
*rng
, u64
*value
)
108 if (rng
->extended_trng_regs
) {
110 *value
= readq(rng
->reg_base
+ RNM_PF_TRNG_DAT
);
113 status
= readq(rng
->reg_base
+ RNM_PF_TRNG_RES
);
114 if (!status
&& (retry_count
++ > 0x1000))
119 *value
= readq(rng
->reg_base
+ RNM_PF_RANDOM
);
121 /* HW can run out of entropy if large amount random data is read in
122 * quick succession. Zeros may not be real random data from HW.
125 upper
= readq(rng
->reg_base
+ RNM_PF_RANDOM
);
126 lower
= readq(rng
->reg_base
+ RNM_PF_RANDOM
);
127 while (!(upper
& 0x00000000FFFFFFFFULL
))
128 upper
= readq(rng
->reg_base
+ RNM_PF_RANDOM
);
129 while (!(lower
& 0xFFFFFFFF00000000ULL
))
130 lower
= readq(rng
->reg_base
+ RNM_PF_RANDOM
);
132 *value
= (upper
& 0xFFFFFFFF00000000) | (lower
& 0xFFFFFFFF);
137 static int cn10k_rng_read(struct hwrng
*hwrng
, void *data
,
138 size_t max
, bool wait
)
140 struct cn10k_rng
*rng
= (struct cn10k_rng
*)hwrng
->priv
;
146 err
= check_rng_health(rng
);
153 if (!cn10k_read_trng(rng
, &value
))
156 *((u64
*)pos
) = value
;
162 if (!cn10k_read_trng(rng
, &value
))
177 static int cn10k_rng_probe(struct pci_dev
*pdev
, const struct pci_device_id
*id
)
179 struct cn10k_rng
*rng
;
182 rng
= devm_kzalloc(&pdev
->dev
, sizeof(*rng
), GFP_KERNEL
);
187 pci_set_drvdata(pdev
, rng
);
189 rng
->reg_base
= pcim_iomap(pdev
, 0, 0);
191 return dev_err_probe(&pdev
->dev
, -ENOMEM
, "Error while mapping CSRs, exiting\n");
193 rng
->ops
.name
= devm_kasprintf(&pdev
->dev
, GFP_KERNEL
,
194 "cn10k-rng-%s", dev_name(&pdev
->dev
));
198 rng
->ops
.read
= cn10k_rng_read
;
199 rng
->ops
.priv
= (unsigned long)rng
;
201 rng
->extended_trng_regs
= cn10k_is_extended_trng_regs_supported(pdev
);
203 reset_rng_health_state(rng
);
205 err
= devm_hwrng_register(&pdev
->dev
, &rng
->ops
);
207 return dev_err_probe(&pdev
->dev
, err
, "Could not register hwrng device.\n");
212 static const struct pci_device_id cn10k_rng_id_table
[] = {
213 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM
, 0xA098) }, /* RNG PF */
217 MODULE_DEVICE_TABLE(pci
, cn10k_rng_id_table
);
219 static struct pci_driver cn10k_rng_driver
= {
221 .id_table
= cn10k_rng_id_table
,
222 .probe
= cn10k_rng_probe
,
225 module_pci_driver(cn10k_rng_driver
);
226 MODULE_AUTHOR("Sunil Goutham <sgoutham@marvell.com>");
227 MODULE_DESCRIPTION("Marvell CN10K HW RNG Driver");
228 MODULE_LICENSE("GPL v2");