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 be consistent */ 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 * 165 * @dev: the mei device structure 166 */ 167 void mei_dbgfs_deregister(struct mei_device *dev) 168 { 169 if (!dev->dbgfs_dir) 170 return; 171 debugfs_remove_recursive(dev->dbgfs_dir); 172 dev->dbgfs_dir = NULL; 173 } 174 175 /** 176 * mei_dbgfs_register - Add the debugfs files 177 * 178 * @dev: the mei device structure 179 * @name: the mei device name 180 * 181 * Return: 0 on success, <0 on failure. 182 */ 183 int mei_dbgfs_register(struct mei_device *dev, const char *name) 184 { 185 struct dentry *dir, *f; 186 187 dir = debugfs_create_dir(name, NULL); 188 if (!dir) 189 return -ENOMEM; 190 191 f = debugfs_create_file("meclients", S_IRUSR, dir, 192 dev, &mei_dbgfs_fops_meclients); 193 if (!f) { 194 dev_err(dev->dev, "meclients: registration failed\n"); 195 goto err; 196 } 197 f = debugfs_create_file("active", S_IRUSR, dir, 198 dev, &mei_dbgfs_fops_active); 199 if (!f) { 200 dev_err(dev->dev, "meclients: registration failed\n"); 201 goto err; 202 } 203 f = debugfs_create_file("devstate", S_IRUSR, dir, 204 dev, &mei_dbgfs_fops_devstate); 205 if (!f) { 206 dev_err(dev->dev, "devstate: registration failed\n"); 207 goto err; 208 } 209 dev->dbgfs_dir = dir; 210 return 0; 211 err: 212 mei_dbgfs_deregister(dev); 213 return -ENODEV; 214 } 215 216