~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/powernv/opal-xscom.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  *                <benh@kernel.crashing.org>
  7  *     and        David Gibson, IBM Corporation.
  8  * Copyright 2013 IBM Corp.
  9  */
 10 
 11 #include <linux/kernel.h>
 12 #include <linux/of.h>
 13 #include <linux/bug.h>
 14 #include <linux/gfp.h>
 15 #include <linux/slab.h>
 16 #include <linux/uaccess.h>
 17 #include <linux/debugfs.h>
 18 
 19 #include <asm/machdep.h>
 20 #include <asm/firmware.h>
 21 #include <asm/opal.h>
 22 #include <asm/prom.h>
 23 
 24 static u64 opal_scom_unmangle(u64 addr)
 25 {
 26         u64 tmp;
 27 
 28         /*
 29          * XSCOM addresses use the top nibble to set indirect mode and
 30          * its form.  Bits 4-11 are always 0.
 31          *
 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.
 35          *
 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.
 39          *
 40          * For in-kernel use, we don't need to do this mangling.  In
 41          * kernel won't have bits 4-7 set.
 42          *
 43          * So:
 44          *   debugfs will always   set 0-3 = 0 and clear 4-7
 45          *    kernel will always clear 0-3 = 0 and   set 4-7
 46          */
 47         tmp = addr;
 48         tmp  &= 0x0f00000000000000;
 49         addr &= 0xf0ffffffffffffff;
 50         addr |= tmp << 4;
 51 
 52         return addr;
 53 }
 54 
 55 static int opal_scom_read(uint32_t chip, uint64_t addr, u64 reg, u64 *value)
 56 {
 57         int64_t rc;
 58         __be64 v;
 59 
 60         reg = opal_scom_unmangle(addr + reg);
 61         rc = opal_xscom_read(chip, reg, (__be64 *)__pa(&v));
 62         if (rc) {
 63                 *value = 0xfffffffffffffffful;
 64                 return -EIO;
 65         }
 66         *value = be64_to_cpu(v);
 67         return 0;
 68 }
 69 
 70 static int opal_scom_write(uint32_t chip, uint64_t addr, u64 reg, u64 value)
 71 {
 72         int64_t rc;
 73 
 74         reg = opal_scom_unmangle(addr + reg);
 75         rc = opal_xscom_write(chip, reg, value);
 76         if (rc)
 77                 return -EIO;
 78         return 0;
 79 }
 80 
 81 struct scom_debug_entry {
 82         u32 chip;
 83         struct debugfs_blob_wrapper path;
 84         char name[16];
 85 };
 86 
 87 static ssize_t scom_debug_read(struct file *filp, char __user *ubuf,
 88                                size_t count, loff_t *ppos)
 89 {
 90         struct scom_debug_entry *ent = filp->private_data;
 91         u64 __user *ubuf64 = (u64 __user *)ubuf;
 92         loff_t off = *ppos;
 93         ssize_t done = 0;
 94         u64 reg, reg_base, reg_cnt, val;
 95         int rc;
 96 
 97         if (off < 0 || (off & 7) || (count & 7))
 98                 return -EINVAL;
 99         reg_base = off >> 3;
100         reg_cnt = count >> 3;
101 
102         for (reg = 0; reg < reg_cnt; reg++) {
103                 rc = opal_scom_read(ent->chip, reg_base, reg, &val);
104                 if (!rc)
105                         rc = put_user(val, ubuf64);
106                 if (rc) {
107                         if (!done)
108                                 done = rc;
109                         break;
110                 }
111                 ubuf64++;
112                 *ppos += 8;
113                 done += 8;
114         }
115         return done;
116 }
117 
118 static ssize_t scom_debug_write(struct file *filp, const char __user *ubuf,
119                                 size_t count, loff_t *ppos)
120 {
121         struct scom_debug_entry *ent = filp->private_data;
122         u64 __user *ubuf64 = (u64 __user *)ubuf;
123         loff_t off = *ppos;
124         ssize_t done = 0;
125         u64 reg, reg_base, reg_cnt, val;
126         int rc;
127 
128         if (off < 0 || (off & 7) || (count & 7))
129                 return -EINVAL;
130         reg_base = off >> 3;
131         reg_cnt = count >> 3;
132 
133         for (reg = 0; reg < reg_cnt; reg++) {
134                 rc = get_user(val, ubuf64);
135                 if (!rc)
136                         rc = opal_scom_write(ent->chip, reg_base, reg,  val);
137                 if (rc) {
138                         if (!done)
139                                 done = rc;
140                         break;
141                 }
142                 ubuf64++;
143                 done += 8;
144         }
145         return done;
146 }
147 
148 static const struct file_operations scom_debug_fops = {
149         .read =         scom_debug_read,
150         .write =        scom_debug_write,
151         .open =         simple_open,
152         .llseek =       default_llseek,
153 };
154 
155 static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
156                                int chip)
157 {
158         struct scom_debug_entry *ent;
159         struct dentry *dir;
160 
161         ent = kzalloc(sizeof(*ent), GFP_KERNEL);
162         if (!ent)
163                 return -ENOMEM;
164 
165         ent->chip = chip;
166         snprintf(ent->name, 16, "%08x", chip);
167         ent->path.data = (void *)kasprintf(GFP_KERNEL, "%pOF", dn);
168         if (!ent->path.data) {
169                 kfree(ent);
170                 return -ENOMEM;
171         }
172 
173         ent->path.size = strlen((char *)ent->path.data);
174 
175         dir = debugfs_create_dir(ent->name, root);
176         if (IS_ERR(dir)) {
177                 kfree(ent->path.data);
178                 kfree(ent);
179                 return -1;
180         }
181 
182         debugfs_create_blob("devspec", 0400, dir, &ent->path);
183         debugfs_create_file("access", 0600, dir, ent, &scom_debug_fops);
184 
185         return 0;
186 }
187 
188 static int scom_debug_init(void)
189 {
190         struct device_node *dn;
191         struct dentry *root;
192         int chip, rc;
193 
194         if (!firmware_has_feature(FW_FEATURE_OPAL))
195                 return 0;
196 
197         root = debugfs_create_dir("scom", arch_debugfs_dir);
198         if (IS_ERR(root))
199                 return -1;
200 
201         rc = 0;
202         for_each_node_with_property(dn, "scom-controller") {
203                 chip = of_get_ibm_chip_id(dn);
204                 WARN_ON(chip == -1);
205                 rc |= scom_debug_init_one(root, dn, chip);
206         }
207 
208         return rc;
209 }
210 device_initcall(scom_debug_init);
211 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php