1 // SPDX-License-Identifier: GPL-2.0 2 /* Marvell CN10K RVU Hardware Random Number Generator. 3 * 4 * Copyright (C) 2021 Marvell. 5 * 6 */ 7 8 #include <linux/hw_random.h> 9 #include <linux/io.h> 10 #include <linux/module.h> 11 #include <linux/pci.h> 12 #include <linux/pci_ids.h> 13 #include <linux/delay.h> 14 15 #include <linux/arm-smccc.h> 16 17 /* CSRs */ 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 25 26 /* Extended TRNG Read and Status Registers */ 27 #define RNM_PF_TRNG_DAT 0x1000 28 #define RNM_PF_TRNG_RES 0x1008 29 30 struct cn10k_rng { 31 void __iomem *reg_base; 32 struct hwrng ops; 33 struct pci_dev *pdev; 34 /* Octeon CN10K-A A0/A1, CNF10K-A A0/A1 and CNF10K-B A0/B0 35 * does not support extended TRNG registers 36 */ 37 bool extended_trng_regs; 38 }; 39 40 #define PLAT_OCTEONTX_RESET_RNG_EBG_HEALTH_STATE 0xc2000b0f 41 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 45 46 static bool cn10k_is_extended_trng_regs_supported(struct pci_dev *pdev) 47 { 48 /* CN10K-A A0/A1 */ 49 if ((pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_RNG) && 50 (!pdev->revision || (pdev->revision & 0xff) == 0x50 || 51 (pdev->revision & 0xff) == 0x51)) 52 return false; 53 54 /* CNF10K-A A0 */ 55 if ((pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_RNG) && 56 (!pdev->revision || (pdev->revision & 0xff) == 0x60 || 57 (pdev->revision & 0xff) == 0x61)) 58 return false; 59 60 /* CNF10K-B A0/B0 */ 61 if ((pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_B_RNG) && 62 (!pdev->revision || (pdev->revision & 0xff) == 0x70 || 63 (pdev->revision & 0xff) == 0x74)) 64 return false; 65 66 return true; 67 } 68 69 static unsigned long reset_rng_health_state(struct cn10k_rng *rng) 70 { 71 struct arm_smccc_res res; 72 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); 75 return res.a0; 76 } 77 78 static int check_rng_health(struct cn10k_rng *rng) 79 { 80 u64 status; 81 unsigned long err; 82 83 /* Skip checking health */ 84 if (!rng->reg_base) 85 return -ENODEV; 86 87 status = readq(rng->reg_base + RNM_PF_EBG_HEALTH); 88 if (status & BIT_ULL(20)) { 89 err = reset_rng_health_state(rng); 90 if (err) { 91 dev_err(&rng->pdev->dev, "HWRNG: Health test failed (status=%llx)\n", 92 status); 93 dev_err(&rng->pdev->dev, "HWRNG: error during reset (error=%lx)\n", 94 err); 95 return -EIO; 96 } 97 } 98 return 0; 99 } 100 101 /* Returns true when valid data available otherwise return false */ 102 static bool cn10k_read_trng(struct cn10k_rng *rng, u64 *value) 103 { 104 u16 retry_count = 0; 105 u64 upper, lower; 106 u64 status; 107 108 if (rng->extended_trng_regs) { 109 do { 110 *value = readq(rng->reg_base + RNM_PF_TRNG_DAT); 111 if (*value) 112 return true; 113 status = readq(rng->reg_base + RNM_PF_TRNG_RES); 114 if (!status && (retry_count++ > 0x1000)) 115 return false; 116 } while (!status); 117 } 118 119 *value = readq(rng->reg_base + RNM_PF_RANDOM); 120 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. 123 */ 124 if (!*value) { 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); 131 132 *value = (upper & 0xFFFFFFFF00000000) | (lower & 0xFFFFFFFF); 133 } 134 return true; 135 } 136 137 static int cn10k_rng_read(struct hwrng *hwrng, void *data, 138 size_t max, bool wait) 139 { 140 struct cn10k_rng *rng = (struct cn10k_rng *)hwrng->priv; 141 unsigned int size; 142 u8 *pos = data; 143 int err = 0; 144 u64 value; 145 146 err = check_rng_health(rng); 147 if (err) 148 return err; 149 150 size = max; 151 152 while (size >= 8) { 153 if (!cn10k_read_trng(rng, &value)) 154 goto out; 155 156 *((u64 *)pos) = value; 157 size -= 8; 158 pos += 8; 159 } 160 161 if (size > 0) { 162 if (!cn10k_read_trng(rng, &value)) 163 goto out; 164 165 while (size > 0) { 166 *pos = (u8)value; 167 value >>= 8; 168 size--; 169 pos++; 170 } 171 } 172 173 out: 174 return max - size; 175 } 176 177 static int cn10k_rng_probe(struct pci_dev *pdev, const struct pci_device_id *id) 178 { 179 struct cn10k_rng *rng; 180 int err; 181 182 rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); 183 if (!rng) 184 return -ENOMEM; 185 186 rng->pdev = pdev; 187 pci_set_drvdata(pdev, rng); 188 189 rng->reg_base = pcim_iomap(pdev, 0, 0); 190 if (!rng->reg_base) 191 return dev_err_probe(&pdev->dev, -ENOMEM, "Error while mapping CSRs, exiting\n"); 192 193 rng->ops.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 194 "cn10k-rng-%s", dev_name(&pdev->dev)); 195 if (!rng->ops.name) 196 return -ENOMEM; 197 198 rng->ops.read = cn10k_rng_read; 199 rng->ops.priv = (unsigned long)rng; 200 201 rng->extended_trng_regs = cn10k_is_extended_trng_regs_supported(pdev); 202 203 reset_rng_health_state(rng); 204 205 err = devm_hwrng_register(&pdev->dev, &rng->ops); 206 if (err) 207 return dev_err_probe(&pdev->dev, err, "Could not register hwrng device.\n"); 208 209 return 0; 210 } 211 212 static const struct pci_device_id cn10k_rng_id_table[] = { 213 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xA098) }, /* RNG PF */ 214 {0,}, 215 }; 216 217 MODULE_DEVICE_TABLE(pci, cn10k_rng_id_table); 218 219 static struct pci_driver cn10k_rng_driver = { 220 .name = "cn10k_rng", 221 .id_table = cn10k_rng_id_table, 222 .probe = cn10k_rng_probe, 223 }; 224 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"); 229