| .. | .. | 
|---|
 | 1 | +// SPDX-License-Identifier: GPL-2.0  | 
|---|
| 1 | 2 |  /* | 
|---|
| 2 |  | - *  | 
|---|
 | 3 | + * Copyright (c) 2012-2016, Intel Corporation. All rights reserved  | 
|---|
| 3 | 4 |   * 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 | 5 |   */ | 
|---|
 | 6 | +  | 
|---|
| 16 | 7 |  #include <linux/slab.h> | 
|---|
| 17 | 8 |  #include <linux/kernel.h> | 
|---|
| 18 | 9 |  #include <linux/device.h> | 
|---|
| 19 | 10 |  #include <linux/debugfs.h> | 
|---|
 | 11 | +#include <linux/seq_file.h>  | 
|---|
| 20 | 12 |   | 
|---|
| 21 | 13 |  #include <linux/mei.h> | 
|---|
| 22 | 14 |   | 
|---|
| .. | .. | 
|---|
| 24 | 16 |  #include "client.h" | 
|---|
| 25 | 17 |  #include "hw.h" | 
|---|
| 26 | 18 |   | 
|---|
| 27 |  | -static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,  | 
|---|
| 28 |  | -					size_t cnt, loff_t *ppos)  | 
|---|
 | 19 | +static int mei_dbgfs_meclients_show(struct seq_file *m, void *unused)  | 
|---|
| 29 | 20 |  { | 
|---|
| 30 |  | -	struct mei_device *dev = fp->private_data;  | 
|---|
 | 21 | +	struct mei_device *dev = m->private;  | 
|---|
| 31 | 22 |  	struct mei_me_client *me_cl; | 
|---|
| 32 |  | -	size_t bufsz = 1;  | 
|---|
| 33 |  | -	char *buf;  | 
|---|
| 34 | 23 |  	int i = 0; | 
|---|
| 35 |  | -	int pos = 0;  | 
|---|
| 36 |  | -	int ret;  | 
|---|
| 37 | 24 |   | 
|---|
| 38 |  | -#define HDR \  | 
|---|
| 39 |  | -"  |id|fix|         UUID                       |con|msg len|sb|refc|\n"  | 
|---|
 | 25 | +	if (!dev)  | 
|---|
 | 26 | +		return -ENODEV;  | 
|---|
| 40 | 27 |   | 
|---|
| 41 | 28 |  	down_read(&dev->me_clients_rwsem); | 
|---|
| 42 |  | -	list_for_each_entry(me_cl, &dev->me_clients, list)  | 
|---|
| 43 |  | -		bufsz++;  | 
|---|
| 44 | 29 |   | 
|---|
| 45 |  | -	bufsz *= sizeof(HDR) + 1;  | 
|---|
| 46 |  | -	buf = kzalloc(bufsz, GFP_KERNEL);  | 
|---|
| 47 |  | -	if (!buf) {  | 
|---|
| 48 |  | -		up_read(&dev->me_clients_rwsem);  | 
|---|
| 49 |  | -		return -ENOMEM;  | 
|---|
| 50 |  | -	}  | 
|---|
| 51 |  | -  | 
|---|
| 52 |  | -	pos += scnprintf(buf + pos, bufsz - pos, HDR);  | 
|---|
| 53 |  | -#undef HDR  | 
|---|
 | 30 | +	seq_puts(m, "  |id|fix|         UUID                       |con|msg len|sb|refc|vt|\n");  | 
|---|
| 54 | 31 |   | 
|---|
| 55 | 32 |  	/*  if the driver is not enabled the list won't be consistent */ | 
|---|
| 56 | 33 |  	if (dev->dev_state != MEI_DEV_ENABLED) | 
|---|
| 57 | 34 |  		goto out; | 
|---|
| 58 | 35 |   | 
|---|
| 59 | 36 |  	list_for_each_entry(me_cl, &dev->me_clients, list) { | 
|---|
 | 37 | +		if (!mei_me_cl_get(me_cl))  | 
|---|
 | 38 | +			continue;  | 
|---|
| 60 | 39 |   | 
|---|
| 61 |  | -		if (mei_me_cl_get(me_cl)) {  | 
|---|
| 62 |  | -			pos += scnprintf(buf + pos, bufsz - pos,  | 
|---|
| 63 |  | -				"%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",  | 
|---|
| 64 |  | -				i++, me_cl->client_id,  | 
|---|
| 65 |  | -				me_cl->props.fixed_address,  | 
|---|
| 66 |  | -				&me_cl->props.protocol_name,  | 
|---|
| 67 |  | -				me_cl->props.max_number_of_connections,  | 
|---|
| 68 |  | -				me_cl->props.max_msg_length,  | 
|---|
| 69 |  | -				me_cl->props.single_recv_buf,  | 
|---|
| 70 |  | -				kref_read(&me_cl->refcnt));  | 
|---|
| 71 |  | -  | 
|---|
| 72 |  | -			mei_me_cl_put(me_cl);  | 
|---|
| 73 |  | -		}  | 
|---|
 | 40 | +		seq_printf(m, "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|%2d|\n",  | 
|---|
 | 41 | +			   i++, me_cl->client_id,  | 
|---|
 | 42 | +			   me_cl->props.fixed_address,  | 
|---|
 | 43 | +			   &me_cl->props.protocol_name,  | 
|---|
 | 44 | +			   me_cl->props.max_number_of_connections,  | 
|---|
 | 45 | +			   me_cl->props.max_msg_length,  | 
|---|
 | 46 | +			   me_cl->props.single_recv_buf,  | 
|---|
 | 47 | +			   kref_read(&me_cl->refcnt),  | 
|---|
 | 48 | +			   me_cl->props.vt_supported);  | 
|---|
 | 49 | +		mei_me_cl_put(me_cl);  | 
|---|
| 74 | 50 |  	} | 
|---|
| 75 | 51 |   | 
|---|
| 76 | 52 |  out: | 
|---|
| 77 | 53 |  	up_read(&dev->me_clients_rwsem); | 
|---|
| 78 |  | -	ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);  | 
|---|
| 79 |  | -	kfree(buf);  | 
|---|
| 80 |  | -	return ret;  | 
|---|
 | 54 | +	return 0;  | 
|---|
| 81 | 55 |  } | 
|---|
 | 56 | +DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_meclients);  | 
|---|
| 82 | 57 |   | 
|---|
| 83 |  | -static const struct file_operations mei_dbgfs_fops_meclients = {  | 
|---|
| 84 |  | -	.open = simple_open,  | 
|---|
| 85 |  | -	.read = mei_dbgfs_read_meclients,  | 
|---|
| 86 |  | -	.llseek = generic_file_llseek,  | 
|---|
| 87 |  | -};  | 
|---|
| 88 |  | -  | 
|---|
| 89 |  | -static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,  | 
|---|
| 90 |  | -					size_t cnt, loff_t *ppos)  | 
|---|
 | 58 | +static int mei_dbgfs_active_show(struct seq_file *m, void *unused)  | 
|---|
| 91 | 59 |  { | 
|---|
| 92 |  | -	struct mei_device *dev = fp->private_data;  | 
|---|
 | 60 | +	struct mei_device *dev = m->private;  | 
|---|
| 93 | 61 |  	struct mei_cl *cl; | 
|---|
| 94 |  | -	size_t bufsz = 1;  | 
|---|
| 95 |  | -	char *buf;  | 
|---|
| 96 | 62 |  	int i = 0; | 
|---|
| 97 |  | -	int pos = 0;  | 
|---|
| 98 |  | -	int ret;  | 
|---|
| 99 |  | -  | 
|---|
| 100 |  | -#define HDR "   |me|host|state|rd|wr|wrq\n"  | 
|---|
| 101 | 63 |   | 
|---|
| 102 | 64 |  	if (!dev) | 
|---|
| 103 | 65 |  		return -ENODEV; | 
|---|
| 104 | 66 |   | 
|---|
| 105 | 67 |  	mutex_lock(&dev->device_lock); | 
|---|
| 106 | 68 |   | 
|---|
| 107 |  | -	/*  | 
|---|
| 108 |  | -	 * if the driver is not enabled the list won't be consistent,  | 
|---|
| 109 |  | -	 * we output empty table  | 
|---|
| 110 |  | -	 */  | 
|---|
| 111 |  | -	if (dev->dev_state == MEI_DEV_ENABLED)  | 
|---|
| 112 |  | -		list_for_each_entry(cl, &dev->file_list, link)  | 
|---|
| 113 |  | -			bufsz++;  | 
|---|
| 114 |  | -  | 
|---|
| 115 |  | -	bufsz *= sizeof(HDR) + 1;  | 
|---|
| 116 |  | -  | 
|---|
| 117 |  | -	buf = kzalloc(bufsz, GFP_KERNEL);  | 
|---|
| 118 |  | -	if  (!buf) {  | 
|---|
| 119 |  | -		mutex_unlock(&dev->device_lock);  | 
|---|
| 120 |  | -		return -ENOMEM;  | 
|---|
| 121 |  | -	}  | 
|---|
| 122 |  | -  | 
|---|
| 123 |  | -	pos += scnprintf(buf + pos, bufsz - pos, HDR);  | 
|---|
| 124 |  | -#undef HDR  | 
|---|
 | 69 | +	seq_puts(m, "   |me|host|state|rd|wr|wrq\n");  | 
|---|
| 125 | 70 |   | 
|---|
| 126 | 71 |  	/*  if the driver is not enabled the list won't be consistent */ | 
|---|
| 127 | 72 |  	if (dev->dev_state != MEI_DEV_ENABLED) | 
|---|
| .. | .. | 
|---|
| 129 | 74 |   | 
|---|
| 130 | 75 |  	list_for_each_entry(cl, &dev->file_list, link) { | 
|---|
| 131 | 76 |   | 
|---|
| 132 |  | -		pos += scnprintf(buf + pos, bufsz - pos,  | 
|---|
| 133 |  | -			"%3d|%2d|%4d|%5d|%2d|%2d|%3u\n",  | 
|---|
| 134 |  | -			i, mei_cl_me_id(cl), cl->host_client_id, cl->state,  | 
|---|
| 135 |  | -			!list_empty(&cl->rd_completed), cl->writing_state,  | 
|---|
| 136 |  | -			cl->tx_cb_queued);  | 
|---|
 | 77 | +		seq_printf(m, "%3d|%2d|%4d|%5d|%2d|%2d|%3u\n",  | 
|---|
 | 78 | +			   i, mei_cl_me_id(cl), cl->host_client_id, cl->state,  | 
|---|
 | 79 | +			   !list_empty(&cl->rd_completed), cl->writing_state,  | 
|---|
 | 80 | +			   cl->tx_cb_queued);  | 
|---|
| 137 | 81 |  		i++; | 
|---|
| 138 | 82 |  	} | 
|---|
| 139 | 83 |  out: | 
|---|
| 140 | 84 |  	mutex_unlock(&dev->device_lock); | 
|---|
| 141 |  | -	ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);  | 
|---|
| 142 |  | -	kfree(buf);  | 
|---|
| 143 |  | -	return ret;  | 
|---|
 | 85 | +	return 0;  | 
|---|
| 144 | 86 |  } | 
|---|
 | 87 | +DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_active);  | 
|---|
| 145 | 88 |   | 
|---|
| 146 |  | -static const struct file_operations mei_dbgfs_fops_active = {  | 
|---|
| 147 |  | -	.open = simple_open,  | 
|---|
| 148 |  | -	.read = mei_dbgfs_read_active,  | 
|---|
| 149 |  | -	.llseek = generic_file_llseek,  | 
|---|
| 150 |  | -};  | 
|---|
| 151 |  | -  | 
|---|
| 152 |  | -static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,  | 
|---|
| 153 |  | -					size_t cnt, loff_t *ppos)  | 
|---|
 | 89 | +static int mei_dbgfs_devstate_show(struct seq_file *m, void *unused)  | 
|---|
| 154 | 90 |  { | 
|---|
| 155 |  | -	struct mei_device *dev = fp->private_data;  | 
|---|
| 156 |  | -	const size_t bufsz = 1024;  | 
|---|
| 157 |  | -	char *buf = kzalloc(bufsz, GFP_KERNEL);  | 
|---|
| 158 |  | -	int pos = 0;  | 
|---|
| 159 |  | -	int ret;  | 
|---|
 | 91 | +	struct mei_device *dev = m->private;  | 
|---|
| 160 | 92 |   | 
|---|
| 161 |  | -	if  (!buf)  | 
|---|
| 162 |  | -		return -ENOMEM;  | 
|---|
| 163 |  | -  | 
|---|
| 164 |  | -	pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n",  | 
|---|
| 165 |  | -			mei_dev_state_str(dev->dev_state));  | 
|---|
| 166 |  | -	pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",  | 
|---|
| 167 |  | -			mei_hbm_state_str(dev->hbm_state));  | 
|---|
 | 93 | +	seq_printf(m, "dev: %s\n", mei_dev_state_str(dev->dev_state));  | 
|---|
 | 94 | +	seq_printf(m, "hbm: %s\n", mei_hbm_state_str(dev->hbm_state));  | 
|---|
| 168 | 95 |   | 
|---|
| 169 | 96 |  	if (dev->hbm_state >= MEI_HBM_ENUM_CLIENTS && | 
|---|
| 170 | 97 |  	    dev->hbm_state <= MEI_HBM_STARTED) { | 
|---|
| 171 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n");  | 
|---|
| 172 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n",  | 
|---|
| 173 |  | -				 dev->hbm_f_pg_supported);  | 
|---|
| 174 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",  | 
|---|
| 175 |  | -				 dev->hbm_f_dc_supported);  | 
|---|
| 176 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tIE: %01d\n",  | 
|---|
| 177 |  | -				 dev->hbm_f_ie_supported);  | 
|---|
| 178 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",  | 
|---|
| 179 |  | -				 dev->hbm_f_dot_supported);  | 
|---|
| 180 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n",  | 
|---|
| 181 |  | -				 dev->hbm_f_ev_supported);  | 
|---|
| 182 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n",  | 
|---|
| 183 |  | -				 dev->hbm_f_fa_supported);  | 
|---|
| 184 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tOS: %01d\n",  | 
|---|
| 185 |  | -				 dev->hbm_f_os_supported);  | 
|---|
| 186 |  | -		pos += scnprintf(buf + pos, bufsz - pos, "\tDR: %01d\n",  | 
|---|
| 187 |  | -				 dev->hbm_f_dr_supported);  | 
|---|
 | 98 | +		seq_puts(m, "hbm features:\n");  | 
|---|
 | 99 | +		seq_printf(m, "\tPG: %01d\n", dev->hbm_f_pg_supported);  | 
|---|
 | 100 | +		seq_printf(m, "\tDC: %01d\n", dev->hbm_f_dc_supported);  | 
|---|
 | 101 | +		seq_printf(m, "\tIE: %01d\n", dev->hbm_f_ie_supported);  | 
|---|
 | 102 | +		seq_printf(m, "\tDOT: %01d\n", dev->hbm_f_dot_supported);  | 
|---|
 | 103 | +		seq_printf(m, "\tEV: %01d\n", dev->hbm_f_ev_supported);  | 
|---|
 | 104 | +		seq_printf(m, "\tFA: %01d\n", dev->hbm_f_fa_supported);  | 
|---|
 | 105 | +		seq_printf(m, "\tOS: %01d\n", dev->hbm_f_os_supported);  | 
|---|
 | 106 | +		seq_printf(m, "\tDR: %01d\n", dev->hbm_f_dr_supported);  | 
|---|
 | 107 | +		seq_printf(m, "\tVT: %01d\n", dev->hbm_f_vt_supported);  | 
|---|
 | 108 | +		seq_printf(m, "\tCAP: %01d\n", dev->hbm_f_cap_supported);  | 
|---|
| 188 | 109 |  	} | 
|---|
| 189 | 110 |   | 
|---|
| 190 |  | -	pos += scnprintf(buf + pos, bufsz - pos, "pg:  %s, %s\n",  | 
|---|
| 191 |  | -			mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",  | 
|---|
| 192 |  | -			mei_pg_state_str(mei_pg_state(dev)));  | 
|---|
| 193 |  | -	ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);  | 
|---|
| 194 |  | -	kfree(buf);  | 
|---|
| 195 |  | -	return ret;  | 
|---|
 | 111 | +	seq_printf(m, "pg:  %s, %s\n",  | 
|---|
 | 112 | +		   mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",  | 
|---|
 | 113 | +		   mei_pg_state_str(mei_pg_state(dev)));  | 
|---|
 | 114 | +	return 0;  | 
|---|
| 196 | 115 |  } | 
|---|
| 197 |  | -static const struct file_operations mei_dbgfs_fops_devstate = {  | 
|---|
| 198 |  | -	.open = simple_open,  | 
|---|
| 199 |  | -	.read = mei_dbgfs_read_devstate,  | 
|---|
| 200 |  | -	.llseek = generic_file_llseek,  | 
|---|
| 201 |  | -};  | 
|---|
 | 116 | +DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_devstate);  | 
|---|
| 202 | 117 |   | 
|---|
| 203 | 118 |  static ssize_t mei_dbgfs_write_allow_fa(struct file *file, | 
|---|
| 204 | 119 |  					const char __user *user_buf, | 
|---|
| .. | .. | 
|---|
| 217 | 132 |  	return ret; | 
|---|
| 218 | 133 |  } | 
|---|
| 219 | 134 |   | 
|---|
| 220 |  | -static const struct file_operations mei_dbgfs_fops_allow_fa = {  | 
|---|
 | 135 | +static const struct file_operations mei_dbgfs_allow_fa_fops = {  | 
|---|
| 221 | 136 |  	.open = simple_open, | 
|---|
| 222 | 137 |  	.read = debugfs_read_file_bool, | 
|---|
| 223 | 138 |  	.write = mei_dbgfs_write_allow_fa, | 
|---|
| .. | .. | 
|---|
| 242 | 157 |   * | 
|---|
| 243 | 158 |   * @dev: the mei device structure | 
|---|
| 244 | 159 |   * @name: the mei device name | 
|---|
| 245 |  | - *  | 
|---|
| 246 |  | - * Return: 0 on success, <0 on failure.  | 
|---|
| 247 | 160 |   */ | 
|---|
| 248 |  | -int mei_dbgfs_register(struct mei_device *dev, const char *name)  | 
|---|
 | 161 | +void mei_dbgfs_register(struct mei_device *dev, const char *name)  | 
|---|
| 249 | 162 |  { | 
|---|
| 250 |  | -	struct dentry *dir, *f;  | 
|---|
 | 163 | +	struct dentry *dir;  | 
|---|
| 251 | 164 |   | 
|---|
| 252 | 165 |  	dir = debugfs_create_dir(name, NULL); | 
|---|
| 253 |  | -	if (!dir)  | 
|---|
| 254 |  | -		return -ENOMEM;  | 
|---|
| 255 |  | -  | 
|---|
| 256 | 166 |  	dev->dbgfs_dir = dir; | 
|---|
| 257 | 167 |   | 
|---|
| 258 |  | -	f = debugfs_create_file("meclients", S_IRUSR, dir,  | 
|---|
| 259 |  | -				dev, &mei_dbgfs_fops_meclients);  | 
|---|
| 260 |  | -	if (!f) {  | 
|---|
| 261 |  | -		dev_err(dev->dev, "meclients: registration failed\n");  | 
|---|
| 262 |  | -		goto err;  | 
|---|
| 263 |  | -	}  | 
|---|
| 264 |  | -	f = debugfs_create_file("active", S_IRUSR, dir,  | 
|---|
| 265 |  | -				dev, &mei_dbgfs_fops_active);  | 
|---|
| 266 |  | -	if (!f) {  | 
|---|
| 267 |  | -		dev_err(dev->dev, "active: registration failed\n");  | 
|---|
| 268 |  | -		goto err;  | 
|---|
| 269 |  | -	}  | 
|---|
| 270 |  | -	f = debugfs_create_file("devstate", S_IRUSR, dir,  | 
|---|
| 271 |  | -				dev, &mei_dbgfs_fops_devstate);  | 
|---|
| 272 |  | -	if (!f) {  | 
|---|
| 273 |  | -		dev_err(dev->dev, "devstate: registration failed\n");  | 
|---|
| 274 |  | -		goto err;  | 
|---|
| 275 |  | -	}  | 
|---|
| 276 |  | -	f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,  | 
|---|
| 277 |  | -				&dev->allow_fixed_address,  | 
|---|
| 278 |  | -				&mei_dbgfs_fops_allow_fa);  | 
|---|
| 279 |  | -	if (!f) {  | 
|---|
| 280 |  | -		dev_err(dev->dev, "allow_fixed_address: registration failed\n");  | 
|---|
| 281 |  | -		goto err;  | 
|---|
| 282 |  | -	}  | 
|---|
| 283 |  | -	return 0;  | 
|---|
| 284 |  | -err:  | 
|---|
| 285 |  | -	mei_dbgfs_deregister(dev);  | 
|---|
| 286 |  | -	return -ENODEV;  | 
|---|
 | 168 | +	debugfs_create_file("meclients", S_IRUSR, dir, dev,  | 
|---|
 | 169 | +			    &mei_dbgfs_meclients_fops);  | 
|---|
 | 170 | +	debugfs_create_file("active", S_IRUSR, dir, dev,  | 
|---|
 | 171 | +			    &mei_dbgfs_active_fops);  | 
|---|
 | 172 | +	debugfs_create_file("devstate", S_IRUSR, dir, dev,  | 
|---|
 | 173 | +			    &mei_dbgfs_devstate_fops);  | 
|---|
 | 174 | +	debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,  | 
|---|
 | 175 | +			    &dev->allow_fixed_address,  | 
|---|
 | 176 | +			    &mei_dbgfs_allow_fa_fops);  | 
|---|
| 287 | 177 |  } | 
|---|
| 288 |  | -  | 
|---|