1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PowerNV SCOM bus debugfs interface
5 * Copyright 2010 Benjamin Herrenschmidt, IBM Corp
6 * <benh@kernel.crashing.org>
7 * and David Gibson, IBM Corporation.
8 * Copyright 2013 IBM Corp.
11 #include <linux/kernel.h>
13 #include <linux/bug.h>
14 #include <linux/gfp.h>
15 #include <linux/slab.h>
16 #include <linux/uaccess.h>
18 #include <asm/machdep.h>
19 #include <asm/firmware.h>
21 #include <asm/debugfs.h>
24 static u64
opal_scom_unmangle(u64 addr
)
29 * XSCOM addresses use the top nibble to set indirect mode and
30 * its form. Bits 4-11 are always 0.
32 * Because the debugfs interface uses signed offsets and shifts
33 * the address left by 3, we basically cannot use the top 4 bits
34 * of the 64-bit address, and thus cannot use the indirect bit.
36 * To deal with that, we support the indirect bits being in
37 * bits 4-7 (IBM notation) instead of bit 0-3 in this API, we
38 * do the conversion here.
40 * For in-kernel use, we don't need to do this mangling. In
41 * kernel won't have bits 4-7 set.
44 * debugfs will always set 0-3 = 0 and clear 4-7
45 * kernel will always clear 0-3 = 0 and set 4-7
48 tmp
&= 0x0f00000000000000;
49 addr
&= 0xf0ffffffffffffff;
55 static int opal_scom_read(uint32_t chip
, uint64_t addr
, u64 reg
, u64
*value
)
60 reg
= opal_scom_unmangle(addr
+ reg
);
61 rc
= opal_xscom_read(chip
, reg
, (__be64
*)__pa(&v
));
63 *value
= 0xfffffffffffffffful
;
66 *value
= be64_to_cpu(v
);
70 static int opal_scom_write(uint32_t chip
, uint64_t addr
, u64 reg
, u64 value
)
74 reg
= opal_scom_unmangle(addr
+ reg
);
75 rc
= opal_xscom_write(chip
, reg
, value
);
81 struct scom_debug_entry
{
83 struct debugfs_blob_wrapper path
;
87 static ssize_t
scom_debug_read(struct file
*filp
, char __user
*ubuf
,
88 size_t count
, loff_t
*ppos
)
90 struct scom_debug_entry
*ent
= filp
->private_data
;
91 u64 __user
*ubuf64
= (u64 __user
*)ubuf
;
94 u64 reg
, reg_base
, reg_cnt
, val
;
97 if (off
< 0 || (off
& 7) || (count
& 7))
100 reg_cnt
= count
>> 3;
102 for (reg
= 0; reg
< reg_cnt
; reg
++) {
103 rc
= opal_scom_read(ent
->chip
, reg_base
, reg
, &val
);
105 rc
= put_user(val
, ubuf64
);
118 static ssize_t
scom_debug_write(struct file
*filp
, const char __user
*ubuf
,
119 size_t count
, loff_t
*ppos
)
121 struct scom_debug_entry
*ent
= filp
->private_data
;
122 u64 __user
*ubuf64
= (u64 __user
*)ubuf
;
125 u64 reg
, reg_base
, reg_cnt
, val
;
128 if (off
< 0 || (off
& 7) || (count
& 7))
131 reg_cnt
= count
>> 3;
133 for (reg
= 0; reg
< reg_cnt
; reg
++) {
134 rc
= get_user(val
, ubuf64
);
136 rc
= opal_scom_write(ent
->chip
, reg_base
, reg
, val
);
148 static const struct file_operations scom_debug_fops
= {
149 .read
= scom_debug_read
,
150 .write
= scom_debug_write
,
152 .llseek
= default_llseek
,
155 static int scom_debug_init_one(struct dentry
*root
, struct device_node
*dn
,
158 struct scom_debug_entry
*ent
;
161 ent
= kzalloc(sizeof(*ent
), GFP_KERNEL
);
166 snprintf(ent
->name
, 16, "%08x", chip
);
167 ent
->path
.data
= (void *)kasprintf(GFP_KERNEL
, "%pOF", dn
);
168 ent
->path
.size
= strlen((char *)ent
->path
.data
);
170 dir
= debugfs_create_dir(ent
->name
, root
);
172 kfree(ent
->path
.data
);
177 debugfs_create_blob("devspec", 0400, dir
, &ent
->path
);
178 debugfs_create_file("access", 0600, dir
, ent
, &scom_debug_fops
);
183 static int scom_debug_init(void)
185 struct device_node
*dn
;
189 if (!firmware_has_feature(FW_FEATURE_OPAL
))
192 root
= debugfs_create_dir("scom", powerpc_debugfs_root
);
197 for_each_node_with_property(dn
, "scom-controller") {
198 chip
= of_get_ibm_chip_id(dn
);
200 rc
|= scom_debug_init_one(root
, dn
, chip
);
205 device_initcall(scom_debug_init
);