1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Generic driver for the OLPC Embedded Controller. 4 * 5 * Author: Andres Salomon <dilinger@queued.net> 6 * 7 * Copyright (C) 2011-2012 One Laptop per Child Foundation. 8 */ 9 #include <linux/completion.h> 10 #include <linux/debugfs.h> 11 #include <linux/spinlock.h> 12 #include <linux/mutex.h> 13 #include <linux/platform_device.h> 14 #include <linux/slab.h> 15 #include <linux/workqueue.h> 16 #include <linux/init.h> 17 #include <linux/list.h> 18 #include <linux/olpc-ec.h> 19 #include <asm/olpc.h> 20 21 struct ec_cmd_desc { 22 u8 cmd; 23 u8 *inbuf, *outbuf; 24 size_t inlen, outlen; 25 26 int err; 27 struct completion finished; 28 struct list_head node; 29 30 void *priv; 31 }; 32 33 struct olpc_ec_priv { 34 struct olpc_ec_driver *drv; 35 struct work_struct worker; 36 struct mutex cmd_lock; 37 38 /* Pending EC commands */ 39 struct list_head cmd_q; 40 spinlock_t cmd_q_lock; 41 42 struct dentry *dbgfs_dir; 43 44 /* 45 * Running an EC command while suspending means we don't always finish 46 * the command before the machine suspends. This means that the EC 47 * is expecting the command protocol to finish, but we after a period 48 * of time (while the OS is asleep) the EC times out and restarts its 49 * idle loop. Meanwhile, the OS wakes up, thinks it's still in the 50 * middle of the command protocol, starts throwing random things at 51 * the EC... and everyone's uphappy. 52 */ 53 bool suspended; 54 }; 55 56 static struct olpc_ec_driver *ec_driver; 57 static struct olpc_ec_priv *ec_priv; 58 static void *ec_cb_arg; 59 60 void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg) 61 { 62 ec_driver = drv; 63 ec_cb_arg = arg; 64 } 65 EXPORT_SYMBOL_GPL(olpc_ec_driver_register); 66 67 static void olpc_ec_worker(struct work_struct *w) 68 { 69 struct olpc_ec_priv *ec = container_of(w, struct olpc_ec_priv, worker); 70 struct ec_cmd_desc *desc = NULL; 71 unsigned long flags; 72 73 /* Grab the first pending command from the queue */ 74 spin_lock_irqsave(&ec->cmd_q_lock, flags); 75 if (!list_empty(&ec->cmd_q)) { 76 desc = list_first_entry(&ec->cmd_q, struct ec_cmd_desc, node); 77 list_del(&desc->node); 78 } 79 spin_unlock_irqrestore(&ec->cmd_q_lock, flags); 80 81 /* Do we actually have anything to do? */ 82 if (!desc) 83 return; 84 85 /* Protect the EC hw with a mutex; only run one cmd at a time */ 86 mutex_lock(&ec->cmd_lock); 87 desc->err = ec_driver->ec_cmd(desc->cmd, desc->inbuf, desc->inlen, 88 desc->outbuf, desc->outlen, ec_cb_arg); 89 mutex_unlock(&ec->cmd_lock); 90 91 /* Finished, wake up olpc_ec_cmd() */ 92 complete(&desc->finished); 93 94 /* Run the worker thread again in case there are more cmds pending */ 95 schedule_work(&ec->worker); 96 } 97 98 /* 99 * Throw a cmd descripter onto the list. We now have SMP OLPC machines, so 100 * locking is pretty critical. 101 */ 102 static void queue_ec_descriptor(struct ec_cmd_desc *desc, 103 struct olpc_ec_priv *ec) 104 { 105 unsigned long flags; 106 107 INIT_LIST_HEAD(&desc->node); 108 109 spin_lock_irqsave(&ec->cmd_q_lock, flags); 110 list_add_tail(&desc->node, &ec->cmd_q); 111 spin_unlock_irqrestore(&ec->cmd_q_lock, flags); 112 113 schedule_work(&ec->worker); 114 } 115 116 int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen) 117 { 118 struct olpc_ec_priv *ec = ec_priv; 119 struct ec_cmd_desc desc; 120 121 /* Ensure a driver and ec hook have been registered */ 122 if (WARN_ON(!ec_driver || !ec_driver->ec_cmd)) 123 return -ENODEV; 124 125 if (!ec) 126 return -ENOMEM; 127 128 /* Suspending in the middle of a command hoses things really badly */ 129 if (WARN_ON(ec->suspended)) 130 return -EBUSY; 131 132 might_sleep(); 133 134 desc.cmd = cmd; 135 desc.inbuf = inbuf; 136 desc.outbuf = outbuf; 137 desc.inlen = inlen; 138 desc.outlen = outlen; 139 desc.err = 0; 140 init_completion(&desc.finished); 141 142 queue_ec_descriptor(&desc, ec); 143 144 /* Timeouts must be handled in the platform-specific EC hook */ 145 wait_for_completion(&desc.finished); 146 147 /* The worker thread dequeues the cmd; no need to do anything here */ 148 return desc.err; 149 } 150 EXPORT_SYMBOL_GPL(olpc_ec_cmd); 151 152 #ifdef CONFIG_DEBUG_FS 153 154 /* 155 * debugfs support for "generic commands", to allow sending 156 * arbitrary EC commands from userspace. 157 */ 158 159 #define EC_MAX_CMD_ARGS (5 + 1) /* cmd byte + 5 args */ 160 #define EC_MAX_CMD_REPLY (8) 161 162 static DEFINE_MUTEX(ec_dbgfs_lock); 163 static unsigned char ec_dbgfs_resp[EC_MAX_CMD_REPLY]; 164 static unsigned int ec_dbgfs_resp_bytes; 165 166 static ssize_t ec_dbgfs_cmd_write(struct file *file, const char __user *buf, 167 size_t size, loff_t *ppos) 168 { 169 int i, m; 170 unsigned char ec_cmd[EC_MAX_CMD_ARGS]; 171 unsigned int ec_cmd_int[EC_MAX_CMD_ARGS]; 172 char cmdbuf[64]; 173 int ec_cmd_bytes; 174 175 mutex_lock(&ec_dbgfs_lock); 176 177 size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size); 178 179 m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0], 180 &ec_dbgfs_resp_bytes, &ec_cmd_int[1], &ec_cmd_int[2], 181 &ec_cmd_int[3], &ec_cmd_int[4], &ec_cmd_int[5]); 182 if (m < 2 || ec_dbgfs_resp_bytes > EC_MAX_CMD_REPLY) { 183 /* reset to prevent overflow on read */ 184 ec_dbgfs_resp_bytes = 0; 185 186 pr_debug("olpc-ec: bad ec cmd: cmd:response-count [arg1 [arg2 ...]]\n"); 187 size = -EINVAL; 188 goto out; 189 } 190 191 /* convert scanf'd ints to char */ 192 ec_cmd_bytes = m - 2; 193 for (i = 0; i <= ec_cmd_bytes; i++) 194 ec_cmd[i] = ec_cmd_int[i]; 195 196 pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %5ph, want %d returns\n", 197 ec_cmd[0], ec_cmd_bytes, ec_cmd + 1, 198 ec_dbgfs_resp_bytes); 199 200 olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1], 201 ec_cmd_bytes, ec_dbgfs_resp, ec_dbgfs_resp_bytes); 202 203 pr_debug("olpc-ec: response %8ph (%d bytes expected)\n", 204 ec_dbgfs_resp, ec_dbgfs_resp_bytes); 205 206 out: 207 mutex_unlock(&ec_dbgfs_lock); 208 return size; 209 } 210 211 static ssize_t ec_dbgfs_cmd_read(struct file *file, char __user *buf, 212 size_t size, loff_t *ppos) 213 { 214 unsigned int i, r; 215 char *rp; 216 char respbuf[64]; 217 218 mutex_lock(&ec_dbgfs_lock); 219 rp = respbuf; 220 rp += sprintf(rp, "%02x", ec_dbgfs_resp[0]); 221 for (i = 1; i < ec_dbgfs_resp_bytes; i++) 222 rp += sprintf(rp, ", %02x", ec_dbgfs_resp[i]); 223 mutex_unlock(&ec_dbgfs_lock); 224 rp += sprintf(rp, "\n"); 225 226 r = rp - respbuf; 227 return simple_read_from_buffer(buf, size, ppos, respbuf, r); 228 } 229 230 static const struct file_operations ec_dbgfs_ops = { 231 .write = ec_dbgfs_cmd_write, 232 .read = ec_dbgfs_cmd_read, 233 }; 234 235 static struct dentry *olpc_ec_setup_debugfs(void) 236 { 237 struct dentry *dbgfs_dir; 238 239 dbgfs_dir = debugfs_create_dir("olpc-ec", NULL); 240 if (IS_ERR_OR_NULL(dbgfs_dir)) 241 return NULL; 242 243 debugfs_create_file("cmd", 0600, dbgfs_dir, NULL, &ec_dbgfs_ops); 244 245 return dbgfs_dir; 246 } 247 248 #else 249 250 static struct dentry *olpc_ec_setup_debugfs(void) 251 { 252 return NULL; 253 } 254 255 #endif /* CONFIG_DEBUG_FS */ 256 257 static int olpc_ec_probe(struct platform_device *pdev) 258 { 259 struct olpc_ec_priv *ec; 260 int err; 261 262 if (!ec_driver) 263 return -ENODEV; 264 265 ec = kzalloc(sizeof(*ec), GFP_KERNEL); 266 if (!ec) 267 return -ENOMEM; 268 269 ec->drv = ec_driver; 270 INIT_WORK(&ec->worker, olpc_ec_worker); 271 mutex_init(&ec->cmd_lock); 272 273 INIT_LIST_HEAD(&ec->cmd_q); 274 spin_lock_init(&ec->cmd_q_lock); 275 276 ec_priv = ec; 277 platform_set_drvdata(pdev, ec); 278 279 err = ec_driver->probe ? ec_driver->probe(pdev) : 0; 280 if (err) { 281 ec_priv = NULL; 282 kfree(ec); 283 } else { 284 ec->dbgfs_dir = olpc_ec_setup_debugfs(); 285 } 286 287 return err; 288 } 289 290 static int olpc_ec_suspend(struct device *dev) 291 { 292 struct platform_device *pdev = to_platform_device(dev); 293 struct olpc_ec_priv *ec = platform_get_drvdata(pdev); 294 int err = 0; 295 296 if (ec_driver->suspend) 297 err = ec_driver->suspend(pdev); 298 if (!err) 299 ec->suspended = true; 300 301 return err; 302 } 303 304 static int olpc_ec_resume(struct device *dev) 305 { 306 struct platform_device *pdev = to_platform_device(dev); 307 struct olpc_ec_priv *ec = platform_get_drvdata(pdev); 308 309 ec->suspended = false; 310 return ec_driver->resume ? ec_driver->resume(pdev) : 0; 311 } 312 313 static const struct dev_pm_ops olpc_ec_pm_ops = { 314 .suspend_late = olpc_ec_suspend, 315 .resume_early = olpc_ec_resume, 316 }; 317 318 static struct platform_driver olpc_ec_plat_driver = { 319 .probe = olpc_ec_probe, 320 .driver = { 321 .name = "olpc-ec", 322 .pm = &olpc_ec_pm_ops, 323 }, 324 }; 325 326 static int __init olpc_ec_init_module(void) 327 { 328 return platform_driver_register(&olpc_ec_plat_driver); 329 } 330 arch_initcall(olpc_ec_init_module); 331