cn10k-rng.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. struct cn10k_rng {
  23. void __iomem *reg_base;
  24. struct hwrng ops;
  25. struct pci_dev *pdev;
  26. };
  27. #define PLAT_OCTEONTX_RESET_RNG_EBG_HEALTH_STATE 0xc2000b0f
  28. static unsigned long reset_rng_health_state(struct cn10k_rng *rng)
  29. {
  30. struct arm_smccc_res res;
  31. /* Send SMC service call to reset EBG health state */
  32. arm_smccc_smc(PLAT_OCTEONTX_RESET_RNG_EBG_HEALTH_STATE, 0, 0, 0, 0, 0, 0, 0, &res);
  33. return res.a0;
  34. }
  35. static int check_rng_health(struct cn10k_rng *rng)
  36. {
  37. u64 status;
  38. unsigned long err;
  39. /* Skip checking health */
  40. if (!rng->reg_base)
  41. return -ENODEV;
  42. status = readq(rng->reg_base + RNM_PF_EBG_HEALTH);
  43. if (status & BIT_ULL(20)) {
  44. err = reset_rng_health_state(rng);
  45. if (err) {
  46. dev_err(&rng->pdev->dev, "HWRNG: Health test failed (status=%llx)\n",
  47. status);
  48. dev_err(&rng->pdev->dev, "HWRNG: error during reset (error=%lx)\n",
  49. err);
  50. return -EIO;
  51. }
  52. }
  53. return 0;
  54. }
  55. static void cn10k_read_trng(struct cn10k_rng *rng, u64 *value)
  56. {
  57. u64 upper, lower;
  58. *value = readq(rng->reg_base + RNM_PF_RANDOM);
  59. /* HW can run out of entropy if large amount random data is read in
  60. * quick succession. Zeros may not be real random data from HW.
  61. */
  62. if (!*value) {
  63. upper = readq(rng->reg_base + RNM_PF_RANDOM);
  64. lower = readq(rng->reg_base + RNM_PF_RANDOM);
  65. while (!(upper & 0x00000000FFFFFFFFULL))
  66. upper = readq(rng->reg_base + RNM_PF_RANDOM);
  67. while (!(lower & 0xFFFFFFFF00000000ULL))
  68. lower = readq(rng->reg_base + RNM_PF_RANDOM);
  69. *value = (upper & 0xFFFFFFFF00000000) | (lower & 0xFFFFFFFF);
  70. }
  71. }
  72. static int cn10k_rng_read(struct hwrng *hwrng, void *data,
  73. size_t max, bool wait)
  74. {
  75. struct cn10k_rng *rng = (struct cn10k_rng *)hwrng->priv;
  76. unsigned int size;
  77. u8 *pos = data;
  78. int err = 0;
  79. u64 value;
  80. err = check_rng_health(rng);
  81. if (err)
  82. return err;
  83. size = max;
  84. while (size >= 8) {
  85. cn10k_read_trng(rng, &value);
  86. *((u64 *)pos) = value;
  87. size -= 8;
  88. pos += 8;
  89. }
  90. if (size > 0) {
  91. cn10k_read_trng(rng, &value);
  92. while (size > 0) {
  93. *pos = (u8)value;
  94. value >>= 8;
  95. size--;
  96. pos++;
  97. }
  98. }
  99. return max - size;
  100. }
  101. static int cn10k_rng_probe(struct pci_dev *pdev, const struct pci_device_id *id)
  102. {
  103. struct cn10k_rng *rng;
  104. int err;
  105. rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
  106. if (!rng)
  107. return -ENOMEM;
  108. rng->pdev = pdev;
  109. pci_set_drvdata(pdev, rng);
  110. rng->reg_base = pcim_iomap(pdev, 0, 0);
  111. if (!rng->reg_base) {
  112. dev_err(&pdev->dev, "Error while mapping CSRs, exiting\n");
  113. return -ENOMEM;
  114. }
  115. rng->ops.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
  116. "cn10k-rng-%s", dev_name(&pdev->dev));
  117. if (!rng->ops.name)
  118. return -ENOMEM;
  119. rng->ops.read = cn10k_rng_read;
  120. rng->ops.quality = 1000;
  121. rng->ops.priv = (unsigned long)rng;
  122. reset_rng_health_state(rng);
  123. err = devm_hwrng_register(&pdev->dev, &rng->ops);
  124. if (err) {
  125. dev_err(&pdev->dev, "Could not register hwrng device.\n");
  126. return err;
  127. }
  128. return 0;
  129. }
  130. static void cn10k_rng_remove(struct pci_dev *pdev)
  131. {
  132. /* Nothing to do */
  133. }
  134. static const struct pci_device_id cn10k_rng_id_table[] = {
  135. { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xA098) }, /* RNG PF */
  136. {0,},
  137. };
  138. MODULE_DEVICE_TABLE(pci, cn10k_rng_id_table);
  139. static struct pci_driver cn10k_rng_driver = {
  140. .name = "cn10k_rng",
  141. .id_table = cn10k_rng_id_table,
  142. .probe = cn10k_rng_probe,
  143. .remove = cn10k_rng_remove,
  144. };
  145. module_pci_driver(cn10k_rng_driver);
  146. MODULE_AUTHOR("Sunil Goutham <[email protected]>");
  147. MODULE_DESCRIPTION("Marvell CN10K HW RNG Driver");
  148. MODULE_LICENSE("GPL v2");