p9_sbe.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // SPDX-License-Identifier: GPL-2.0+
  2. // Copyright IBM Corp 2019
  3. #include <linux/device.h>
  4. #include <linux/errno.h>
  5. #include <linux/slab.h>
  6. #include <linux/fsi-occ.h>
  7. #include <linux/mm.h>
  8. #include <linux/module.h>
  9. #include <linux/mod_devicetable.h>
  10. #include <linux/mutex.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/string.h>
  13. #include <linux/sysfs.h>
  14. #include "common.h"
  15. #define OCC_CHECKSUM_RETRIES 3
  16. struct p9_sbe_occ {
  17. struct occ occ;
  18. bool sbe_error;
  19. void *ffdc;
  20. size_t ffdc_len;
  21. size_t ffdc_size;
  22. struct mutex sbe_error_lock; /* lock access to ffdc data */
  23. struct device *sbe;
  24. };
  25. #define to_p9_sbe_occ(x) container_of((x), struct p9_sbe_occ, occ)
  26. static ssize_t ffdc_read(struct file *filp, struct kobject *kobj,
  27. struct bin_attribute *battr, char *buf, loff_t pos,
  28. size_t count)
  29. {
  30. ssize_t rc = 0;
  31. struct occ *occ = dev_get_drvdata(kobj_to_dev(kobj));
  32. struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);
  33. mutex_lock(&ctx->sbe_error_lock);
  34. if (ctx->sbe_error) {
  35. rc = memory_read_from_buffer(buf, count, &pos, ctx->ffdc,
  36. ctx->ffdc_len);
  37. if (pos >= ctx->ffdc_len)
  38. ctx->sbe_error = false;
  39. }
  40. mutex_unlock(&ctx->sbe_error_lock);
  41. return rc;
  42. }
  43. static BIN_ATTR_RO(ffdc, OCC_MAX_RESP_WORDS * 4);
  44. static bool p9_sbe_occ_save_ffdc(struct p9_sbe_occ *ctx, const void *resp,
  45. size_t resp_len)
  46. {
  47. bool notify = false;
  48. mutex_lock(&ctx->sbe_error_lock);
  49. if (!ctx->sbe_error) {
  50. if (resp_len > ctx->ffdc_size) {
  51. kvfree(ctx->ffdc);
  52. ctx->ffdc = kvmalloc(resp_len, GFP_KERNEL);
  53. if (!ctx->ffdc) {
  54. ctx->ffdc_len = 0;
  55. ctx->ffdc_size = 0;
  56. goto done;
  57. }
  58. ctx->ffdc_size = resp_len;
  59. }
  60. notify = true;
  61. ctx->sbe_error = true;
  62. ctx->ffdc_len = resp_len;
  63. memcpy(ctx->ffdc, resp, resp_len);
  64. }
  65. done:
  66. mutex_unlock(&ctx->sbe_error_lock);
  67. return notify;
  68. }
  69. static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len,
  70. void *resp, size_t resp_len)
  71. {
  72. size_t original_resp_len = resp_len;
  73. struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);
  74. int rc, i;
  75. for (i = 0; i < OCC_CHECKSUM_RETRIES; ++i) {
  76. rc = fsi_occ_submit(ctx->sbe, cmd, len, resp, &resp_len);
  77. if (rc >= 0)
  78. break;
  79. if (resp_len) {
  80. if (p9_sbe_occ_save_ffdc(ctx, resp, resp_len))
  81. sysfs_notify(&occ->bus_dev->kobj, NULL,
  82. bin_attr_ffdc.attr.name);
  83. return rc;
  84. }
  85. if (rc != -EBADE)
  86. return rc;
  87. resp_len = original_resp_len;
  88. }
  89. switch (((struct occ_response *)resp)->return_status) {
  90. case OCC_RESP_CMD_IN_PRG:
  91. rc = -ETIMEDOUT;
  92. break;
  93. case OCC_RESP_SUCCESS:
  94. rc = 0;
  95. break;
  96. case OCC_RESP_CMD_INVAL:
  97. case OCC_RESP_CMD_LEN_INVAL:
  98. case OCC_RESP_DATA_INVAL:
  99. case OCC_RESP_CHKSUM_ERR:
  100. rc = -EINVAL;
  101. break;
  102. case OCC_RESP_INT_ERR:
  103. case OCC_RESP_BAD_STATE:
  104. case OCC_RESP_CRIT_EXCEPT:
  105. case OCC_RESP_CRIT_INIT:
  106. case OCC_RESP_CRIT_WATCHDOG:
  107. case OCC_RESP_CRIT_OCB:
  108. case OCC_RESP_CRIT_HW:
  109. rc = -EREMOTEIO;
  110. break;
  111. default:
  112. rc = -EPROTO;
  113. }
  114. return rc;
  115. }
  116. static int p9_sbe_occ_probe(struct platform_device *pdev)
  117. {
  118. int rc;
  119. struct occ *occ;
  120. struct p9_sbe_occ *ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx),
  121. GFP_KERNEL);
  122. if (!ctx)
  123. return -ENOMEM;
  124. mutex_init(&ctx->sbe_error_lock);
  125. ctx->sbe = pdev->dev.parent;
  126. occ = &ctx->occ;
  127. occ->bus_dev = &pdev->dev;
  128. platform_set_drvdata(pdev, occ);
  129. occ->powr_sample_time_us = 500;
  130. occ->poll_cmd_data = 0x20; /* P9 OCC poll data */
  131. occ->send_cmd = p9_sbe_occ_send_cmd;
  132. rc = occ_setup(occ);
  133. if (rc == -ESHUTDOWN)
  134. rc = -ENODEV; /* Host is shutdown, don't spew errors */
  135. if (!rc) {
  136. rc = device_create_bin_file(occ->bus_dev, &bin_attr_ffdc);
  137. if (rc) {
  138. dev_warn(occ->bus_dev,
  139. "failed to create SBE error ffdc file\n");
  140. rc = 0;
  141. }
  142. }
  143. return rc;
  144. }
  145. static int p9_sbe_occ_remove(struct platform_device *pdev)
  146. {
  147. struct occ *occ = platform_get_drvdata(pdev);
  148. struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);
  149. device_remove_bin_file(occ->bus_dev, &bin_attr_ffdc);
  150. ctx->sbe = NULL;
  151. occ_shutdown(occ);
  152. kvfree(ctx->ffdc);
  153. return 0;
  154. }
  155. static const struct of_device_id p9_sbe_occ_of_match[] = {
  156. { .compatible = "ibm,p9-occ-hwmon" },
  157. { .compatible = "ibm,p10-occ-hwmon" },
  158. {}
  159. };
  160. MODULE_DEVICE_TABLE(of, p9_sbe_occ_of_match);
  161. static struct platform_driver p9_sbe_occ_driver = {
  162. .driver = {
  163. .name = "occ-hwmon",
  164. .of_match_table = p9_sbe_occ_of_match,
  165. },
  166. .probe = p9_sbe_occ_probe,
  167. .remove = p9_sbe_occ_remove,
  168. };
  169. module_platform_driver(p9_sbe_occ_driver);
  170. MODULE_AUTHOR("Eddie James <[email protected]>");
  171. MODULE_DESCRIPTION("BMC P9 OCC hwmon driver");
  172. MODULE_LICENSE("GPL");