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|fix| 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 pos += scnprintf(buf + pos, bufsz - pos, 60 "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|\n", 61 i++, me_cl->client_id, 62 me_cl->props.fixed_address, 63 &me_cl->props.protocol_name, 64 me_cl->props.max_number_of_connections, 65 me_cl->props.max_msg_length, 66 me_cl->props.single_recv_buf); 67 } 68 out: 69 mutex_unlock(&dev->device_lock); 70 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 71 kfree(buf); 72 return ret; 73 } 74 75 static const struct file_operations mei_dbgfs_fops_meclients = { 76 .open = simple_open, 77 .read = mei_dbgfs_read_meclients, 78 .llseek = generic_file_llseek, 79 }; 80 81 static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf, 82 size_t cnt, loff_t *ppos) 83 { 84 struct mei_device *dev = fp->private_data; 85 struct mei_cl *cl; 86 const size_t bufsz = 1024; 87 char *buf; 88 int i = 0; 89 int pos = 0; 90 int ret; 91 92 if (!dev) 93 return -ENODEV; 94 95 buf = kzalloc(bufsz, GFP_KERNEL); 96 if (!buf) 97 return -ENOMEM; 98 99 pos += scnprintf(buf + pos, bufsz - pos, 100 " |me|host|state|rd|wr|\n"); 101 102 mutex_lock(&dev->device_lock); 103 104 /* if the driver is not enabled the list won't be consistent */ 105 if (dev->dev_state != MEI_DEV_ENABLED) 106 goto out; 107 108 list_for_each_entry(cl, &dev->file_list, link) { 109 110 pos += scnprintf(buf + pos, bufsz - pos, 111 "%2d|%2d|%4d|%5d|%2d|%2d|\n", 112 i, cl->me_client_id, cl->host_client_id, cl->state, 113 cl->reading_state, cl->writing_state); 114 i++; 115 } 116 out: 117 mutex_unlock(&dev->device_lock); 118 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 119 kfree(buf); 120 return ret; 121 } 122 123 static const struct file_operations mei_dbgfs_fops_active = { 124 .open = simple_open, 125 .read = mei_dbgfs_read_active, 126 .llseek = generic_file_llseek, 127 }; 128 129 static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, 130 size_t cnt, loff_t *ppos) 131 { 132 struct mei_device *dev = fp->private_data; 133 const size_t bufsz = 1024; 134 char *buf = kzalloc(bufsz, GFP_KERNEL); 135 int pos = 0; 136 int ret; 137 138 if (!buf) 139 return -ENOMEM; 140 141 pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n", 142 mei_dev_state_str(dev->dev_state)); 143 pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n", 144 mei_hbm_state_str(dev->hbm_state)); 145 pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", 146 mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED", 147 mei_pg_state_str(mei_pg_state(dev))); 148 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 149 kfree(buf); 150 return ret; 151 } 152 static const struct file_operations mei_dbgfs_fops_devstate = { 153 .open = simple_open, 154 .read = mei_dbgfs_read_devstate, 155 .llseek = generic_file_llseek, 156 }; 157 158 /** 159 * mei_dbgfs_deregister - Remove the debugfs files and directories 160 * 161 * @dev: the mei device structure 162 */ 163 void mei_dbgfs_deregister(struct mei_device *dev) 164 { 165 if (!dev->dbgfs_dir) 166 return; 167 debugfs_remove_recursive(dev->dbgfs_dir); 168 dev->dbgfs_dir = NULL; 169 } 170 171 /** 172 * mei_dbgfs_register - Add the debugfs files 173 * 174 * @dev: the mei device structure 175 * @name: the mei device name 176 * 177 * Return: 0 on success, <0 on failure. 178 */ 179 int mei_dbgfs_register(struct mei_device *dev, const char *name) 180 { 181 struct dentry *dir, *f; 182 183 dir = debugfs_create_dir(name, NULL); 184 if (!dir) 185 return -ENOMEM; 186 187 f = debugfs_create_file("meclients", S_IRUSR, dir, 188 dev, &mei_dbgfs_fops_meclients); 189 if (!f) { 190 dev_err(dev->dev, "meclients: registration failed\n"); 191 goto err; 192 } 193 f = debugfs_create_file("active", S_IRUSR, dir, 194 dev, &mei_dbgfs_fops_active); 195 if (!f) { 196 dev_err(dev->dev, "meclients: registration failed\n"); 197 goto err; 198 } 199 f = debugfs_create_file("devstate", S_IRUSR, dir, 200 dev, &mei_dbgfs_fops_devstate); 201 if (!f) { 202 dev_err(dev->dev, "devstate: registration failed\n"); 203 goto err; 204 } 205 dev->dbgfs_dir = dir; 206 return 0; 207 err: 208 mei_dbgfs_deregister(dev); 209 return -ENODEV; 210 } 211 212