0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/of.h>
0013 #include <linux/bug.h>
0014 #include <linux/gfp.h>
0015 #include <linux/slab.h>
0016 #include <linux/uaccess.h>
0017 #include <linux/debugfs.h>
0018
0019 #include <asm/machdep.h>
0020 #include <asm/firmware.h>
0021 #include <asm/opal.h>
0022 #include <asm/prom.h>
0023
0024 static u64 opal_scom_unmangle(u64 addr)
0025 {
0026 u64 tmp;
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 tmp = addr;
0048 tmp &= 0x0f00000000000000;
0049 addr &= 0xf0ffffffffffffff;
0050 addr |= tmp << 4;
0051
0052 return addr;
0053 }
0054
0055 static int opal_scom_read(uint32_t chip, uint64_t addr, u64 reg, u64 *value)
0056 {
0057 int64_t rc;
0058 __be64 v;
0059
0060 reg = opal_scom_unmangle(addr + reg);
0061 rc = opal_xscom_read(chip, reg, (__be64 *)__pa(&v));
0062 if (rc) {
0063 *value = 0xfffffffffffffffful;
0064 return -EIO;
0065 }
0066 *value = be64_to_cpu(v);
0067 return 0;
0068 }
0069
0070 static int opal_scom_write(uint32_t chip, uint64_t addr, u64 reg, u64 value)
0071 {
0072 int64_t rc;
0073
0074 reg = opal_scom_unmangle(addr + reg);
0075 rc = opal_xscom_write(chip, reg, value);
0076 if (rc)
0077 return -EIO;
0078 return 0;
0079 }
0080
0081 struct scom_debug_entry {
0082 u32 chip;
0083 struct debugfs_blob_wrapper path;
0084 char name[16];
0085 };
0086
0087 static ssize_t scom_debug_read(struct file *filp, char __user *ubuf,
0088 size_t count, loff_t *ppos)
0089 {
0090 struct scom_debug_entry *ent = filp->private_data;
0091 u64 __user *ubuf64 = (u64 __user *)ubuf;
0092 loff_t off = *ppos;
0093 ssize_t done = 0;
0094 u64 reg, reg_base, reg_cnt, val;
0095 int rc;
0096
0097 if (off < 0 || (off & 7) || (count & 7))
0098 return -EINVAL;
0099 reg_base = off >> 3;
0100 reg_cnt = count >> 3;
0101
0102 for (reg = 0; reg < reg_cnt; reg++) {
0103 rc = opal_scom_read(ent->chip, reg_base, reg, &val);
0104 if (!rc)
0105 rc = put_user(val, ubuf64);
0106 if (rc) {
0107 if (!done)
0108 done = rc;
0109 break;
0110 }
0111 ubuf64++;
0112 *ppos += 8;
0113 done += 8;
0114 }
0115 return done;
0116 }
0117
0118 static ssize_t scom_debug_write(struct file *filp, const char __user *ubuf,
0119 size_t count, loff_t *ppos)
0120 {
0121 struct scom_debug_entry *ent = filp->private_data;
0122 u64 __user *ubuf64 = (u64 __user *)ubuf;
0123 loff_t off = *ppos;
0124 ssize_t done = 0;
0125 u64 reg, reg_base, reg_cnt, val;
0126 int rc;
0127
0128 if (off < 0 || (off & 7) || (count & 7))
0129 return -EINVAL;
0130 reg_base = off >> 3;
0131 reg_cnt = count >> 3;
0132
0133 for (reg = 0; reg < reg_cnt; reg++) {
0134 rc = get_user(val, ubuf64);
0135 if (!rc)
0136 rc = opal_scom_write(ent->chip, reg_base, reg, val);
0137 if (rc) {
0138 if (!done)
0139 done = rc;
0140 break;
0141 }
0142 ubuf64++;
0143 done += 8;
0144 }
0145 return done;
0146 }
0147
0148 static const struct file_operations scom_debug_fops = {
0149 .read = scom_debug_read,
0150 .write = scom_debug_write,
0151 .open = simple_open,
0152 .llseek = default_llseek,
0153 };
0154
0155 static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
0156 int chip)
0157 {
0158 struct scom_debug_entry *ent;
0159 struct dentry *dir;
0160
0161 ent = kzalloc(sizeof(*ent), GFP_KERNEL);
0162 if (!ent)
0163 return -ENOMEM;
0164
0165 ent->chip = chip;
0166 snprintf(ent->name, 16, "%08x", chip);
0167 ent->path.data = (void *)kasprintf(GFP_KERNEL, "%pOF", dn);
0168 ent->path.size = strlen((char *)ent->path.data);
0169
0170 dir = debugfs_create_dir(ent->name, root);
0171 if (!dir) {
0172 kfree(ent->path.data);
0173 kfree(ent);
0174 return -1;
0175 }
0176
0177 debugfs_create_blob("devspec", 0400, dir, &ent->path);
0178 debugfs_create_file("access", 0600, dir, ent, &scom_debug_fops);
0179
0180 return 0;
0181 }
0182
0183 static int scom_debug_init(void)
0184 {
0185 struct device_node *dn;
0186 struct dentry *root;
0187 int chip, rc;
0188
0189 if (!firmware_has_feature(FW_FEATURE_OPAL))
0190 return 0;
0191
0192 root = debugfs_create_dir("scom", arch_debugfs_dir);
0193 if (!root)
0194 return -1;
0195
0196 rc = 0;
0197 for_each_node_with_property(dn, "scom-controller") {
0198 chip = of_get_ibm_chip_id(dn);
0199 WARN_ON(chip == -1);
0200 rc |= scom_debug_init_one(root, dn, chip);
0201 }
0202
0203 return rc;
0204 }
0205 device_initcall(scom_debug_init);