1 /* 2 * 3 * Intel Management Engine Interface (Intel MEI) Linux driver 4 * Copyright (c) 2012-2013, Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 */ 16 #include <linux/slab.h> 17 #include <linux/kernel.h> 18 #include <linux/device.h> 19 #include <linux/debugfs.h> 20 21 #include <linux/mei.h> 22 23 #include "mei_dev.h" 24 #include "hw.h" 25 26 static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, 27 size_t cnt, loff_t *ppos) 28 { 29 struct mei_device *dev = fp->private_data; 30 struct mei_me_client *me_cl; 31 size_t bufsz = 1; 32 char *buf; 33 int i = 0; 34 int pos = 0; 35 int ret; 36 37 #define HDR " |id|addr| UUID |con|msg len|sb|\n" 38 39 mutex_lock(&dev->device_lock); 40 41 list_for_each_entry(me_cl, &dev->me_clients, list) 42 bufsz++; 43 44 bufsz *= sizeof(HDR) + 1; 45 buf = kzalloc(bufsz, GFP_KERNEL); 46 if (!buf) { 47 mutex_unlock(&dev->device_lock); 48 return -ENOMEM; 49 } 50 51 pos += scnprintf(buf + pos, bufsz - pos, HDR); 52 53 /* if the driver is not enabled the list won't be consistent */ 54 if (dev->dev_state != MEI_DEV_ENABLED) 55 goto out; 56 57 list_for_each_entry(me_cl, &dev->me_clients, list) { 58 59 /* skip me clients that cannot be connected */ 60 if (me_cl->props.max_number_of_connections == 0) 61 continue; 62 63 pos += scnprintf(buf + pos, bufsz - pos, 64 "%2d|%2d|%4d|%pUl|%3d|%7d|%2d|\n", 65 i++, me_cl->client_id, 66 me_cl->props.fixed_address, 67 &me_cl->props.protocol_name, 68 me_cl->props.max_number_of_connections, 69 me_cl->props.max_msg_length, 70 me_cl->props.single_recv_buf); 71 } 72 out: 73 mutex_unlock(&dev->device_lock); 74 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 75 kfree(buf); 76 return ret; 77 } 78 79 static const struct file_operations mei_dbgfs_fops_meclients = { 80 .open = simple_open, 81 .read = mei_dbgfs_read_meclients, 82 .llseek = generic_file_llseek, 83 }; 84 85 static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf, 86 size_t cnt, loff_t *ppos) 87 { 88 struct mei_device *dev = fp->private_data; 89 struct mei_cl *cl; 90 const size_t bufsz = 1024; 91 char *buf; 92 int i = 0; 93 int pos = 0; 94 int ret; 95 96 if (!dev) 97 return -ENODEV; 98 99 buf = kzalloc(bufsz, GFP_KERNEL); 100 if (!buf) 101 return -ENOMEM; 102 103 pos += scnprintf(buf + pos, bufsz - pos, 104 " |me|host|state|rd|wr|\n"); 105 106 mutex_lock(&dev->device_lock); 107 108 /* if the driver is not enabled the list won't b consitent */ 109 if (dev->dev_state != MEI_DEV_ENABLED) 110 goto out; 111 112 list_for_each_entry(cl, &dev->file_list, link) { 113 114 pos += scnprintf(buf + pos, bufsz - pos, 115 "%2d|%2d|%4d|%5d|%2d|%2d|\n", 116 i, cl->me_client_id, cl->host_client_id, cl->state, 117 cl->reading_state, cl->writing_state); 118 i++; 119 } 120 out: 121 mutex_unlock(&dev->device_lock); 122 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 123 kfree(buf); 124 return ret; 125 } 126 127 static const struct file_operations mei_dbgfs_fops_active = { 128 .open = simple_open, 129 .read = mei_dbgfs_read_active, 130 .llseek = generic_file_llseek, 131 }; 132 133 static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, 134 size_t cnt, loff_t *ppos) 135 { 136 struct mei_device *dev = fp->private_data; 137 const size_t bufsz = 1024; 138 char *buf = kzalloc(bufsz, GFP_KERNEL); 139 int pos = 0; 140 int ret; 141 142 if (!buf) 143 return -ENOMEM; 144 145 pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n", 146 mei_dev_state_str(dev->dev_state)); 147 pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n", 148 mei_hbm_state_str(dev->hbm_state)); 149 pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", 150 mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED", 151 mei_pg_state_str(mei_pg_state(dev))); 152 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 153 kfree(buf); 154 return ret; 155 } 156 static const struct file_operations mei_dbgfs_fops_devstate = { 157 .open = simple_open, 158 .read = mei_dbgfs_read_devstate, 159 .llseek = generic_file_llseek, 160 }; 161 162 /** 163 * mei_dbgfs_deregister - Remove the debugfs files and directories 164 * @mei - pointer to mei device private data 165 */ 166 void mei_dbgfs_deregister(struct mei_device *dev) 167 { 168 if (!dev->dbgfs_dir) 169 return; 170 debugfs_remove_recursive(dev->dbgfs_dir); 171 dev->dbgfs_dir = NULL; 172 } 173 174 /** 175 * Add the debugfs files 176 * 177 */ 178 int mei_dbgfs_register(struct mei_device *dev, const char *name) 179 { 180 struct dentry *dir, *f; 181 182 dir = debugfs_create_dir(name, NULL); 183 if (!dir) 184 return -ENOMEM; 185 186 f = debugfs_create_file("meclients", S_IRUSR, dir, 187 dev, &mei_dbgfs_fops_meclients); 188 if (!f) { 189 dev_err(dev->dev, "meclients: registration failed\n"); 190 goto err; 191 } 192 f = debugfs_create_file("active", S_IRUSR, dir, 193 dev, &mei_dbgfs_fops_active); 194 if (!f) { 195 dev_err(dev->dev, "meclients: registration failed\n"); 196 goto err; 197 } 198 f = debugfs_create_file("devstate", S_IRUSR, dir, 199 dev, &mei_dbgfs_fops_devstate); 200 if (!f) { 201 dev_err(dev->dev, "devstate: registration failed\n"); 202 goto err; 203 } 204 dev->dbgfs_dir = dir; 205 return 0; 206 err: 207 mei_dbgfs_deregister(dev); 208 return -ENODEV; 209 } 210 211