cn10k-rng.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Marvell CN10K RVU Hardware Random Number Generator.
  3. *
  4. * Copyright (C) 2021 Marvell.
  5. *
  6. */
  7. #include <linux/hw_random.h>
  8. #include <linux/io.h>
  9. #include <linux/module.h>
  10. #include <linux/pci.h>
  11. #include <linux/pci_ids.h>
  12. #include <linux/delay.h>
  13. #include <linux/arm-smccc.h>
  14. /* CSRs */
  15. #define RNM_CTL_STATUS 0x000
  16. #define RNM_ENTROPY_STATUS 0x008
  17. #define RNM_CONST 0x030
  18. #define RNM_EBG_ENT 0x048
  19. #define RNM_PF_EBG_HEALTH 0x050
  20. #define RNM_PF_RANDOM 0x400
  21. #define RNM_TRNG_RESULT 0x408
  22. /* Extended TRNG Read and Status Registers */
  23. #define RNM_PF_TRNG_DAT 0x1000
  24. #define RNM_PF_TRNG_RES 0x1008
  25. struct cn10k_rng {
  26. void __iomem *reg_base;
  27. struct hwrng ops;
  28. struct pci_dev *pdev;
  29. /* Octeon CN10K-A A0/A1, CNF10K-A A0/A1 and CNF10K-B A0/B0
  30. * does not support extended TRNG registers
  31. */
  32. bool extended_trng_regs;
  33. };
  34. #define PLAT_OCTEONTX_RESET_RNG_EBG_HEALTH_STATE 0xc2000b0f
  35. #define PCI_SUBSYS_DEVID_CN10K_A_RNG 0xB900
  36. #define PCI_SUBSYS_DEVID_CNF10K_A_RNG 0xBA00
  37. #define PCI_SUBSYS_DEVID_CNF10K_B_RNG 0xBC00
  38. static bool cn10k_is_extended_trng_regs_supported(struct pci_dev *pdev)
  39. {
  40. /* CN10K-A A0/A1 */
  41. if ((pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_RNG) &&
  42. (!pdev->revision || (pdev->revision & 0xff) == 0x50 ||
  43. (pdev->revision & 0xff) == 0x51))
  44. return false;
  45. /* CNF10K-A A0 */
  46. if ((pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_RNG) &&
  47. (!pdev->revision || (pdev->revision & 0xff) == 0x60 ||
  48. (pdev->revision & 0xff) == 0x61))
  49. return false;
  50. /* CNF10K-B A0/B0 */
  51. if ((pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_B_RNG) &&
  52. (!pdev->revision || (pdev->revision & 0xff) == 0x70 ||
  53. (pdev->revision & 0xff) == 0x74))
  54. return false;
  55. return true;
  56. }
  57. static unsigned long reset_rng_health_state(struct cn10k_rng *rng)
  58. {
  59. struct arm_smccc_res res;
  60. /* Send SMC service call to reset EBG health state */
  61. arm_smccc_smc(PLAT_OCTEONTX_RESET_RNG_EBG_HEALTH_STATE, 0, 0, 0, 0, 0, 0, 0, &res);
  62. return res.a0;
  63. }
  64. static int check_rng_health(struct cn10k_rng *rng)
  65. {
  66. u64 status;
  67. unsigned long err;
  68. /* Skip checking health */
  69. if (!rng->reg_base)
  70. return -ENODEV;
  71. status = readq(rng->reg_base + RNM_PF_EBG_HEALTH);
  72. if (status & BIT_ULL(20)) {
  73. err = reset_rng_health_state(rng);
  74. if (err) {
  75. dev_err(&rng->pdev->dev, "HWRNG: Health test failed (status=%llx)\n",
  76. status);
  77. dev_err(&rng->pdev->dev, "HWRNG: error during reset (error=%lx)\n",
  78. err);
  79. return -EIO;
  80. }
  81. }
  82. return 0;
  83. }
  84. /* Returns true when valid data available otherwise return false */
  85. static bool cn10k_read_trng(struct cn10k_rng *rng, u64 *value)
  86. {
  87. u16 retry_count = 0;
  88. u64 upper, lower;
  89. u64 status;
  90. if (rng->extended_trng_regs) {
  91. do {
  92. *value = readq(rng->reg_base + RNM_PF_TRNG_DAT);
  93. if (*value)
  94. return true;
  95. status = readq(rng->reg_base + RNM_PF_TRNG_RES);
  96. if (!status && (retry_count++ > 0x1000))
  97. return false;
  98. } while (!status);
  99. }
  100. *value = readq(rng->reg_base + RNM_PF_RANDOM);
  101. /* HW can run out of entropy if large amount random data is read in
  102. * quick succession. Zeros may not be real random data from HW.
  103. */
  104. if (!*value) {
  105. upper = readq(rng->reg_base + RNM_PF_RANDOM);
  106. lower = readq(rng->reg_base + RNM_PF_RANDOM);
  107. while (!(upper & 0x00000000FFFFFFFFULL))
  108. upper = readq(rng->reg_base + RNM_PF_RANDOM);
  109. while (!(lower & 0xFFFFFFFF00000000ULL))
  110. lower = readq(rng->reg_base + RNM_PF_RANDOM);
  111. *value = (upper & 0xFFFFFFFF00000000) | (lower & 0xFFFFFFFF);
  112. }
  113. return true;
  114. }
  115. static int cn10k_rng_read(struct hwrng *hwrng, void *data,
  116. size_t max, bool wait)
  117. {
  118. struct cn10k_rng *rng = (struct cn10k_rng *)hwrng->priv;
  119. unsigned int size;
  120. u8 *pos = data;
  121. int err = 0;
  122. u64 value;
  123. err = check_rng_health(rng);
  124. if (err)
  125. return err;
  126. size = max;
  127. while (size >= 8) {
  128. if (!cn10k_read_trng(rng, &value))
  129. goto out;
  130. *((u64 *)pos) = value;
  131. size -= 8;
  132. pos += 8;
  133. }
  134. if (size > 0) {
  135. if (!cn10k_read_trng(rng, &value))
  136. goto out;
  137. while (size > 0) {
  138. *pos = (u8)value;
  139. value >>= 8;
  140. size--;
  141. pos++;
  142. }
  143. }
  144. out:
  145. return max - size;
  146. }
  147. static int cn10k_rng_probe(struct pci_dev *pdev, const struct pci_device_id *id)
  148. {
  149. struct cn10k_rng *rng;
  150. int err;
  151. rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
  152. if (!rng)
  153. return -ENOMEM;
  154. rng->pdev = pdev;
  155. pci_set_drvdata(pdev, rng);
  156. rng->reg_base = pcim_iomap(pdev, 0, 0);
  157. if (!rng->reg_base)
  158. return dev_err_probe(&pdev->dev, -ENOMEM, "Error while mapping CSRs, exiting\n");
  159. rng->ops.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
  160. "cn10k-rng-%s", dev_name(&pdev->dev));
  161. if (!rng->ops.name)
  162. return -ENOMEM;
  163. rng->ops.read = cn10k_rng_read;
  164. rng->ops.priv = (unsigned long)rng;
  165. rng->extended_trng_regs = cn10k_is_extended_trng_regs_supported(pdev);
  166. reset_rng_health_state(rng);
  167. err = devm_hwrng_register(&pdev->dev, &rng->ops);
  168. if (err)
  169. return dev_err_probe(&pdev->dev, err, "Could not register hwrng device.\n");
  170. return 0;
  171. }
  172. static const struct pci_device_id cn10k_rng_id_table[] = {
  173. { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xA098) }, /* RNG PF */
  174. {0,},
  175. };
  176. MODULE_DEVICE_TABLE(pci, cn10k_rng_id_table);
  177. static struct pci_driver cn10k_rng_driver = {
  178. .name = "cn10k_rng",
  179. .id_table = cn10k_rng_id_table,
  180. .probe = cn10k_rng_probe,
  181. };
  182. module_pci_driver(cn10k_rng_driver);
  183. MODULE_AUTHOR("Sunil Goutham <sgoutham@marvell.com>");
  184. MODULE_DESCRIPTION("Marvell CN10K HW RNG Driver");
  185. MODULE_LICENSE("GPL v2");