opal-xscom.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * PowerNV SCOM bus debugfs interface
  4. *
  5. * Copyright 2010 Benjamin Herrenschmidt, IBM Corp
  6. * <[email protected]>
  7. * and David Gibson, IBM Corporation.
  8. * Copyright 2013 IBM Corp.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/of.h>
  12. #include <linux/bug.h>
  13. #include <linux/gfp.h>
  14. #include <linux/slab.h>
  15. #include <linux/uaccess.h>
  16. #include <linux/debugfs.h>
  17. #include <asm/machdep.h>
  18. #include <asm/firmware.h>
  19. #include <asm/opal.h>
  20. #include <asm/prom.h>
  21. static u64 opal_scom_unmangle(u64 addr)
  22. {
  23. u64 tmp;
  24. /*
  25. * XSCOM addresses use the top nibble to set indirect mode and
  26. * its form. Bits 4-11 are always 0.
  27. *
  28. * Because the debugfs interface uses signed offsets and shifts
  29. * the address left by 3, we basically cannot use the top 4 bits
  30. * of the 64-bit address, and thus cannot use the indirect bit.
  31. *
  32. * To deal with that, we support the indirect bits being in
  33. * bits 4-7 (IBM notation) instead of bit 0-3 in this API, we
  34. * do the conversion here.
  35. *
  36. * For in-kernel use, we don't need to do this mangling. In
  37. * kernel won't have bits 4-7 set.
  38. *
  39. * So:
  40. * debugfs will always set 0-3 = 0 and clear 4-7
  41. * kernel will always clear 0-3 = 0 and set 4-7
  42. */
  43. tmp = addr;
  44. tmp &= 0x0f00000000000000;
  45. addr &= 0xf0ffffffffffffff;
  46. addr |= tmp << 4;
  47. return addr;
  48. }
  49. static int opal_scom_read(uint32_t chip, uint64_t addr, u64 reg, u64 *value)
  50. {
  51. int64_t rc;
  52. __be64 v;
  53. reg = opal_scom_unmangle(addr + reg);
  54. rc = opal_xscom_read(chip, reg, (__be64 *)__pa(&v));
  55. if (rc) {
  56. *value = 0xfffffffffffffffful;
  57. return -EIO;
  58. }
  59. *value = be64_to_cpu(v);
  60. return 0;
  61. }
  62. static int opal_scom_write(uint32_t chip, uint64_t addr, u64 reg, u64 value)
  63. {
  64. int64_t rc;
  65. reg = opal_scom_unmangle(addr + reg);
  66. rc = opal_xscom_write(chip, reg, value);
  67. if (rc)
  68. return -EIO;
  69. return 0;
  70. }
  71. struct scom_debug_entry {
  72. u32 chip;
  73. struct debugfs_blob_wrapper path;
  74. char name[16];
  75. };
  76. static ssize_t scom_debug_read(struct file *filp, char __user *ubuf,
  77. size_t count, loff_t *ppos)
  78. {
  79. struct scom_debug_entry *ent = filp->private_data;
  80. u64 __user *ubuf64 = (u64 __user *)ubuf;
  81. loff_t off = *ppos;
  82. ssize_t done = 0;
  83. u64 reg, reg_base, reg_cnt, val;
  84. int rc;
  85. if (off < 0 || (off & 7) || (count & 7))
  86. return -EINVAL;
  87. reg_base = off >> 3;
  88. reg_cnt = count >> 3;
  89. for (reg = 0; reg < reg_cnt; reg++) {
  90. rc = opal_scom_read(ent->chip, reg_base, reg, &val);
  91. if (!rc)
  92. rc = put_user(val, ubuf64);
  93. if (rc) {
  94. if (!done)
  95. done = rc;
  96. break;
  97. }
  98. ubuf64++;
  99. *ppos += 8;
  100. done += 8;
  101. }
  102. return done;
  103. }
  104. static ssize_t scom_debug_write(struct file *filp, const char __user *ubuf,
  105. size_t count, loff_t *ppos)
  106. {
  107. struct scom_debug_entry *ent = filp->private_data;
  108. u64 __user *ubuf64 = (u64 __user *)ubuf;
  109. loff_t off = *ppos;
  110. ssize_t done = 0;
  111. u64 reg, reg_base, reg_cnt, val;
  112. int rc;
  113. if (off < 0 || (off & 7) || (count & 7))
  114. return -EINVAL;
  115. reg_base = off >> 3;
  116. reg_cnt = count >> 3;
  117. for (reg = 0; reg < reg_cnt; reg++) {
  118. rc = get_user(val, ubuf64);
  119. if (!rc)
  120. rc = opal_scom_write(ent->chip, reg_base, reg, val);
  121. if (rc) {
  122. if (!done)
  123. done = rc;
  124. break;
  125. }
  126. ubuf64++;
  127. done += 8;
  128. }
  129. return done;
  130. }
  131. static const struct file_operations scom_debug_fops = {
  132. .read = scom_debug_read,
  133. .write = scom_debug_write,
  134. .open = simple_open,
  135. .llseek = default_llseek,
  136. };
  137. static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
  138. int chip)
  139. {
  140. struct scom_debug_entry *ent;
  141. struct dentry *dir;
  142. ent = kzalloc(sizeof(*ent), GFP_KERNEL);
  143. if (!ent)
  144. return -ENOMEM;
  145. ent->chip = chip;
  146. snprintf(ent->name, 16, "%08x", chip);
  147. ent->path.data = (void *)kasprintf(GFP_KERNEL, "%pOF", dn);
  148. ent->path.size = strlen((char *)ent->path.data);
  149. dir = debugfs_create_dir(ent->name, root);
  150. if (!dir) {
  151. kfree(ent->path.data);
  152. kfree(ent);
  153. return -1;
  154. }
  155. debugfs_create_blob("devspec", 0400, dir, &ent->path);
  156. debugfs_create_file("access", 0600, dir, ent, &scom_debug_fops);
  157. return 0;
  158. }
  159. static int scom_debug_init(void)
  160. {
  161. struct device_node *dn;
  162. struct dentry *root;
  163. int chip, rc;
  164. if (!firmware_has_feature(FW_FEATURE_OPAL))
  165. return 0;
  166. root = debugfs_create_dir("scom", arch_debugfs_dir);
  167. if (!root)
  168. return -1;
  169. rc = 0;
  170. for_each_node_with_property(dn, "scom-controller") {
  171. chip = of_get_ibm_chip_id(dn);
  172. WARN_ON(chip == -1);
  173. rc |= scom_debug_init_one(root, dn, chip);
  174. }
  175. return rc;
  176. }
  177. device_initcall(scom_debug_init);