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 #include <linux/pci.h> 21 22 #include <linux/mei.h> 23 24 #include "mei_dev.h" 25 #include "hw.h" 26 27 static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, 28 size_t cnt, loff_t *ppos) 29 { 30 struct mei_device *dev = fp->private_data; 31 struct mei_me_client *me_cl; 32 const size_t bufsz = 1024; 33 char *buf = kzalloc(bufsz, GFP_KERNEL); 34 int i = 0; 35 int pos = 0; 36 int ret; 37 38 if (!buf) 39 return -ENOMEM; 40 41 pos += scnprintf(buf + pos, bufsz - pos, 42 " |id|addr| UUID |con|msg len|\n"); 43 44 mutex_lock(&dev->device_lock); 45 46 /* if the driver is not enabled the list won't be consistent */ 47 if (dev->dev_state != MEI_DEV_ENABLED) 48 goto out; 49 50 list_for_each_entry(me_cl, &dev->me_clients, list) { 51 52 /* skip me clients that cannot be connected */ 53 if (me_cl->props.max_number_of_connections == 0) 54 continue; 55 56 pos += scnprintf(buf + pos, bufsz - pos, 57 "%2d|%2d|%4d|%pUl|%3d|%7d|\n", 58 i++, me_cl->client_id, 59 me_cl->props.fixed_address, 60 &me_cl->props.protocol_name, 61 me_cl->props.max_number_of_connections, 62 me_cl->props.max_msg_length); 63 } 64 out: 65 mutex_unlock(&dev->device_lock); 66 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 67 kfree(buf); 68 return ret; 69 } 70 71 static const struct file_operations mei_dbgfs_fops_meclients = { 72 .open = simple_open, 73 .read = mei_dbgfs_read_meclients, 74 .llseek = generic_file_llseek, 75 }; 76 77 static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf, 78 size_t cnt, loff_t *ppos) 79 { 80 struct mei_device *dev = fp->private_data; 81 struct mei_cl *cl; 82 const size_t bufsz = 1024; 83 char *buf; 84 int i = 0; 85 int pos = 0; 86 int ret; 87 88 if (!dev) 89 return -ENODEV; 90 91 buf = kzalloc(bufsz, GFP_KERNEL); 92 if (!buf) 93 return -ENOMEM; 94 95 pos += scnprintf(buf + pos, bufsz - pos, 96 " |me|host|state|rd|wr|\n"); 97 98 mutex_lock(&dev->device_lock); 99 100 /* if the driver is not enabled the list won't b consitent */ 101 if (dev->dev_state != MEI_DEV_ENABLED) 102 goto out; 103 104 list_for_each_entry(cl, &dev->file_list, link) { 105 106 pos += scnprintf(buf + pos, bufsz - pos, 107 "%2d|%2d|%4d|%5d|%2d|%2d|\n", 108 i, cl->me_client_id, cl->host_client_id, cl->state, 109 cl->reading_state, cl->writing_state); 110 i++; 111 } 112 out: 113 mutex_unlock(&dev->device_lock); 114 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 115 kfree(buf); 116 return ret; 117 } 118 119 static const struct file_operations mei_dbgfs_fops_active = { 120 .open = simple_open, 121 .read = mei_dbgfs_read_active, 122 .llseek = generic_file_llseek, 123 }; 124 125 static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, 126 size_t cnt, loff_t *ppos) 127 { 128 struct mei_device *dev = fp->private_data; 129 const size_t bufsz = 1024; 130 char *buf = kzalloc(bufsz, GFP_KERNEL); 131 int pos = 0; 132 int ret; 133 134 if (!buf) 135 return -ENOMEM; 136 137 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", 138 mei_dev_state_str(dev->dev_state)); 139 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 140 kfree(buf); 141 return ret; 142 } 143 static const struct file_operations mei_dbgfs_fops_devstate = { 144 .open = simple_open, 145 .read = mei_dbgfs_read_devstate, 146 .llseek = generic_file_llseek, 147 }; 148 149 /** 150 * mei_dbgfs_deregister - Remove the debugfs files and directories 151 * @mei - pointer to mei device private data 152 */ 153 void mei_dbgfs_deregister(struct mei_device *dev) 154 { 155 if (!dev->dbgfs_dir) 156 return; 157 debugfs_remove_recursive(dev->dbgfs_dir); 158 dev->dbgfs_dir = NULL; 159 } 160 161 /** 162 * Add the debugfs files 163 * 164 */ 165 int mei_dbgfs_register(struct mei_device *dev, const char *name) 166 { 167 struct dentry *dir, *f; 168 dir = debugfs_create_dir(name, NULL); 169 if (!dir) 170 return -ENOMEM; 171 172 f = debugfs_create_file("meclients", S_IRUSR, dir, 173 dev, &mei_dbgfs_fops_meclients); 174 if (!f) { 175 dev_err(&dev->pdev->dev, "meclients: registration failed\n"); 176 goto err; 177 } 178 f = debugfs_create_file("active", S_IRUSR, dir, 179 dev, &mei_dbgfs_fops_active); 180 if (!f) { 181 dev_err(&dev->pdev->dev, "meclients: registration failed\n"); 182 goto err; 183 } 184 f = debugfs_create_file("devstate", S_IRUSR, dir, 185 dev, &mei_dbgfs_fops_devstate); 186 if (!f) { 187 dev_err(&dev->pdev->dev, "devstate: registration failed\n"); 188 goto err; 189 } 190 dev->dbgfs_dir = dir; 191 return 0; 192 err: 193 mei_dbgfs_deregister(dev); 194 return -ENODEV; 195 } 196 197