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 b consitent */ 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_devstate(struct file *fp, char __user *ubuf, 79 size_t cnt, loff_t *ppos) 80 { 81 struct mei_device *dev = fp->private_data; 82 const size_t bufsz = 1024; 83 char *buf = kzalloc(bufsz, GFP_KERNEL); 84 int pos = 0; 85 int ret; 86 87 if (!buf) 88 return -ENOMEM; 89 90 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", 91 mei_dev_state_str(dev->dev_state)); 92 ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); 93 kfree(buf); 94 return ret; 95 } 96 static const struct file_operations mei_dbgfs_fops_devstate = { 97 .open = simple_open, 98 .read = mei_dbgfs_read_devstate, 99 .llseek = generic_file_llseek, 100 }; 101 102 /** 103 * mei_dbgfs_deregister - Remove the debugfs files and directories 104 * @mei - pointer to mei device private dat 105 */ 106 void mei_dbgfs_deregister(struct mei_device *dev) 107 { 108 if (!dev->dbgfs_dir) 109 return; 110 debugfs_remove_recursive(dev->dbgfs_dir); 111 dev->dbgfs_dir = NULL; 112 } 113 114 /** 115 * Add the debugfs files 116 * 117 */ 118 int mei_dbgfs_register(struct mei_device *dev, const char *name) 119 { 120 struct dentry *dir, *f; 121 dir = debugfs_create_dir(name, NULL); 122 if (!dir) 123 return -ENOMEM; 124 125 f = debugfs_create_file("meclients", S_IRUSR, dir, 126 dev, &mei_dbgfs_fops_meclients); 127 if (!f) { 128 dev_err(&dev->pdev->dev, "meclients: registration failed\n"); 129 goto err; 130 } 131 f = debugfs_create_file("devstate", S_IRUSR, dir, 132 dev, &mei_dbgfs_fops_devstate); 133 if (!f) { 134 dev_err(&dev->pdev->dev, "devstate: registration failed\n"); 135 goto err; 136 } 137 dev->dbgfs_dir = dir; 138 return 0; 139 err: 140 mei_dbgfs_deregister(dev); 141 return -ENODEV; 142 } 143 144