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