cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debugfs.c (12773B)


      1/*
      2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
      3 *
      4 * This software is available to you under a choice of one of two
      5 * licenses.  You may choose to be licensed under the terms of the GNU
      6 * General Public License (GPL) Version 2, available from the file
      7 * COPYING in the main directory of this source tree, or the
      8 * OpenIB.org BSD license below:
      9 *
     10 *     Redistribution and use in source and binary forms, with or
     11 *     without modification, are permitted provided that the following
     12 *     conditions are met:
     13 *
     14 *      - Redistributions of source code must retain the above
     15 *        copyright notice, this list of conditions and the following
     16 *        disclaimer.
     17 *
     18 *      - Redistributions in binary form must reproduce the above
     19 *        copyright notice, this list of conditions and the following
     20 *        disclaimer in the documentation and/or other materials
     21 *        provided with the distribution.
     22 *
     23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     30 * SOFTWARE.
     31 */
     32
     33#include <linux/debugfs.h>
     34#include <linux/mlx5/qp.h>
     35#include <linux/mlx5/cq.h>
     36#include <linux/mlx5/driver.h>
     37#include "mlx5_core.h"
     38#include "lib/eq.h"
     39
     40enum {
     41	QP_PID,
     42	QP_STATE,
     43	QP_XPORT,
     44	QP_MTU,
     45	QP_N_RECV,
     46	QP_RECV_SZ,
     47	QP_N_SEND,
     48	QP_LOG_PG_SZ,
     49	QP_RQPN,
     50};
     51
     52static char *qp_fields[] = {
     53	[QP_PID]	= "pid",
     54	[QP_STATE]	= "state",
     55	[QP_XPORT]	= "transport",
     56	[QP_MTU]	= "mtu",
     57	[QP_N_RECV]	= "num_recv",
     58	[QP_RECV_SZ]	= "rcv_wqe_sz",
     59	[QP_N_SEND]	= "num_send",
     60	[QP_LOG_PG_SZ]	= "log2_page_sz",
     61	[QP_RQPN]	= "remote_qpn",
     62};
     63
     64enum {
     65	EQ_NUM_EQES,
     66	EQ_INTR,
     67	EQ_LOG_PG_SZ,
     68};
     69
     70static char *eq_fields[] = {
     71	[EQ_NUM_EQES]	= "num_eqes",
     72	[EQ_INTR]	= "intr",
     73	[EQ_LOG_PG_SZ]	= "log_page_size",
     74};
     75
     76enum {
     77	CQ_PID,
     78	CQ_NUM_CQES,
     79	CQ_LOG_PG_SZ,
     80};
     81
     82static char *cq_fields[] = {
     83	[CQ_PID]	= "pid",
     84	[CQ_NUM_CQES]	= "num_cqes",
     85	[CQ_LOG_PG_SZ]	= "log_page_size",
     86};
     87
     88struct dentry *mlx5_debugfs_root;
     89EXPORT_SYMBOL(mlx5_debugfs_root);
     90
     91void mlx5_register_debugfs(void)
     92{
     93	mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL);
     94}
     95
     96void mlx5_unregister_debugfs(void)
     97{
     98	debugfs_remove(mlx5_debugfs_root);
     99}
    100
    101struct dentry *mlx5_debugfs_get_dev_root(struct mlx5_core_dev *dev)
    102{
    103	return dev->priv.dbg.dbg_root;
    104}
    105EXPORT_SYMBOL(mlx5_debugfs_get_dev_root);
    106
    107void mlx5_qp_debugfs_init(struct mlx5_core_dev *dev)
    108{
    109	dev->priv.dbg.qp_debugfs = debugfs_create_dir("QPs", dev->priv.dbg.dbg_root);
    110}
    111EXPORT_SYMBOL(mlx5_qp_debugfs_init);
    112
    113void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev)
    114{
    115	debugfs_remove_recursive(dev->priv.dbg.qp_debugfs);
    116}
    117EXPORT_SYMBOL(mlx5_qp_debugfs_cleanup);
    118
    119void mlx5_eq_debugfs_init(struct mlx5_core_dev *dev)
    120{
    121	dev->priv.dbg.eq_debugfs = debugfs_create_dir("EQs", dev->priv.dbg.dbg_root);
    122}
    123
    124void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev)
    125{
    126	debugfs_remove_recursive(dev->priv.dbg.eq_debugfs);
    127}
    128
    129static ssize_t average_read(struct file *filp, char __user *buf, size_t count,
    130			    loff_t *pos)
    131{
    132	struct mlx5_cmd_stats *stats;
    133	u64 field = 0;
    134	int ret;
    135	char tbuf[22];
    136
    137	stats = filp->private_data;
    138	spin_lock_irq(&stats->lock);
    139	if (stats->n)
    140		field = div64_u64(stats->sum, stats->n);
    141	spin_unlock_irq(&stats->lock);
    142	ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field);
    143	return simple_read_from_buffer(buf, count, pos, tbuf, ret);
    144}
    145
    146static ssize_t average_write(struct file *filp, const char __user *buf,
    147			     size_t count, loff_t *pos)
    148{
    149	struct mlx5_cmd_stats *stats;
    150
    151	stats = filp->private_data;
    152	spin_lock_irq(&stats->lock);
    153	stats->sum = 0;
    154	stats->n = 0;
    155	spin_unlock_irq(&stats->lock);
    156
    157	*pos += count;
    158
    159	return count;
    160}
    161
    162static const struct file_operations stats_fops = {
    163	.owner	= THIS_MODULE,
    164	.open	= simple_open,
    165	.read	= average_read,
    166	.write	= average_write,
    167};
    168
    169void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
    170{
    171	struct mlx5_cmd_stats *stats;
    172	struct dentry **cmd;
    173	const char *namep;
    174	int i;
    175
    176	cmd = &dev->priv.dbg.cmdif_debugfs;
    177	*cmd = debugfs_create_dir("commands", dev->priv.dbg.dbg_root);
    178
    179	for (i = 0; i < MLX5_CMD_OP_MAX; i++) {
    180		stats = &dev->cmd.stats[i];
    181		namep = mlx5_command_str(i);
    182		if (strcmp(namep, "unknown command opcode")) {
    183			stats->root = debugfs_create_dir(namep, *cmd);
    184
    185			debugfs_create_file("average", 0400, stats->root, stats,
    186					    &stats_fops);
    187			debugfs_create_u64("n", 0400, stats->root, &stats->n);
    188			debugfs_create_u64("failed", 0400, stats->root, &stats->failed);
    189			debugfs_create_u64("failed_mbox_status", 0400, stats->root,
    190					   &stats->failed_mbox_status);
    191			debugfs_create_u32("last_failed_errno", 0400, stats->root,
    192					   &stats->last_failed_errno);
    193			debugfs_create_u8("last_failed_mbox_status", 0400, stats->root,
    194					  &stats->last_failed_mbox_status);
    195			debugfs_create_x32("last_failed_syndrome", 0400, stats->root,
    196					   &stats->last_failed_syndrome);
    197		}
    198	}
    199}
    200
    201void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)
    202{
    203	debugfs_remove_recursive(dev->priv.dbg.cmdif_debugfs);
    204}
    205
    206void mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)
    207{
    208	dev->priv.dbg.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg.dbg_root);
    209}
    210
    211void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)
    212{
    213	debugfs_remove_recursive(dev->priv.dbg.cq_debugfs);
    214}
    215
    216void mlx5_pages_debugfs_init(struct mlx5_core_dev *dev)
    217{
    218	struct dentry *pages;
    219
    220	dev->priv.dbg.pages_debugfs = debugfs_create_dir("pages", dev->priv.dbg.dbg_root);
    221	pages = dev->priv.dbg.pages_debugfs;
    222
    223	debugfs_create_u32("fw_pages_total", 0400, pages, &dev->priv.fw_pages);
    224	debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.vfs_pages);
    225	debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.host_pf_pages);
    226	debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed);
    227	debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped);
    228	debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages,
    229			   &dev->priv.reclaim_pages_discard);
    230}
    231
    232void mlx5_pages_debugfs_cleanup(struct mlx5_core_dev *dev)
    233{
    234	debugfs_remove_recursive(dev->priv.dbg.pages_debugfs);
    235}
    236
    237static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
    238			 int index, int *is_str)
    239{
    240	int outlen = MLX5_ST_SZ_BYTES(query_qp_out);
    241	u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {};
    242	u64 param = 0;
    243	u32 *out;
    244	int state;
    245	u32 *qpc;
    246	int err;
    247
    248	out = kzalloc(outlen, GFP_KERNEL);
    249	if (!out)
    250		return 0;
    251
    252	MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP);
    253	MLX5_SET(query_qp_in, in, qpn, qp->qpn);
    254	err = mlx5_cmd_exec_inout(dev, query_qp, in, out);
    255	if (err)
    256		goto out;
    257
    258	*is_str = 0;
    259
    260	qpc = MLX5_ADDR_OF(query_qp_out, out, qpc);
    261	switch (index) {
    262	case QP_PID:
    263		param = qp->pid;
    264		break;
    265	case QP_STATE:
    266		state = MLX5_GET(qpc, qpc, state);
    267		param = (unsigned long)mlx5_qp_state_str(state);
    268		*is_str = 1;
    269		break;
    270	case QP_XPORT:
    271		param = (unsigned long)mlx5_qp_type_str(MLX5_GET(qpc, qpc, st));
    272		*is_str = 1;
    273		break;
    274	case QP_MTU:
    275		switch (MLX5_GET(qpc, qpc, mtu)) {
    276		case IB_MTU_256:
    277			param = 256;
    278			break;
    279		case IB_MTU_512:
    280			param = 512;
    281			break;
    282		case IB_MTU_1024:
    283			param = 1024;
    284			break;
    285		case IB_MTU_2048:
    286			param = 2048;
    287			break;
    288		case IB_MTU_4096:
    289			param = 4096;
    290			break;
    291		default:
    292			param = 0;
    293		}
    294		break;
    295	case QP_N_RECV:
    296		param = 1 << MLX5_GET(qpc, qpc, log_rq_size);
    297		break;
    298	case QP_RECV_SZ:
    299		param = 1 << (MLX5_GET(qpc, qpc, log_rq_stride) + 4);
    300		break;
    301	case QP_N_SEND:
    302		if (!MLX5_GET(qpc, qpc, no_sq))
    303			param = 1 << MLX5_GET(qpc, qpc, log_sq_size);
    304		break;
    305	case QP_LOG_PG_SZ:
    306		param = MLX5_GET(qpc, qpc, log_page_size) + 12;
    307		break;
    308	case QP_RQPN:
    309		param = MLX5_GET(qpc, qpc, remote_qpn);
    310		break;
    311	}
    312out:
    313	kfree(out);
    314	return param;
    315}
    316
    317static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
    318			 int index)
    319{
    320	int outlen = MLX5_ST_SZ_BYTES(query_eq_out);
    321	u32 in[MLX5_ST_SZ_DW(query_eq_in)] = {};
    322	u64 param = 0;
    323	void *ctx;
    324	u32 *out;
    325	int err;
    326
    327	out = kzalloc(outlen, GFP_KERNEL);
    328	if (!out)
    329		return param;
    330
    331	MLX5_SET(query_eq_in, in, opcode, MLX5_CMD_OP_QUERY_EQ);
    332	MLX5_SET(query_eq_in, in, eq_number, eq->eqn);
    333	err = mlx5_cmd_exec_inout(dev, query_eq, in, out);
    334	if (err) {
    335		mlx5_core_warn(dev, "failed to query eq\n");
    336		goto out;
    337	}
    338	ctx = MLX5_ADDR_OF(query_eq_out, out, eq_context_entry);
    339
    340	switch (index) {
    341	case EQ_NUM_EQES:
    342		param = 1 << MLX5_GET(eqc, ctx, log_eq_size);
    343		break;
    344	case EQ_INTR:
    345		param = MLX5_GET(eqc, ctx, intr);
    346		break;
    347	case EQ_LOG_PG_SZ:
    348		param = MLX5_GET(eqc, ctx, log_page_size) + 12;
    349		break;
    350	}
    351
    352out:
    353	kfree(out);
    354	return param;
    355}
    356
    357static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
    358			 int index)
    359{
    360	int outlen = MLX5_ST_SZ_BYTES(query_cq_out);
    361	u64 param = 0;
    362	void *ctx;
    363	u32 *out;
    364	int err;
    365
    366	out = kvzalloc(outlen, GFP_KERNEL);
    367	if (!out)
    368		return param;
    369
    370	err = mlx5_core_query_cq(dev, cq, out);
    371	if (err) {
    372		mlx5_core_warn(dev, "failed to query cq\n");
    373		goto out;
    374	}
    375	ctx = MLX5_ADDR_OF(query_cq_out, out, cq_context);
    376
    377	switch (index) {
    378	case CQ_PID:
    379		param = cq->pid;
    380		break;
    381	case CQ_NUM_CQES:
    382		param = 1 << MLX5_GET(cqc, ctx, log_cq_size);
    383		break;
    384	case CQ_LOG_PG_SZ:
    385		param = MLX5_GET(cqc, ctx, log_page_size);
    386		break;
    387	}
    388
    389out:
    390	kvfree(out);
    391	return param;
    392}
    393
    394static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,
    395			loff_t *pos)
    396{
    397	struct mlx5_field_desc *desc;
    398	struct mlx5_rsc_debug *d;
    399	char tbuf[18];
    400	int is_str = 0;
    401	u64 field;
    402	int ret;
    403
    404	desc = filp->private_data;
    405	d = (void *)(desc - desc->i) - sizeof(*d);
    406	switch (d->type) {
    407	case MLX5_DBG_RSC_QP:
    408		field = qp_read_field(d->dev, d->object, desc->i, &is_str);
    409		break;
    410
    411	case MLX5_DBG_RSC_EQ:
    412		field = eq_read_field(d->dev, d->object, desc->i);
    413		break;
    414
    415	case MLX5_DBG_RSC_CQ:
    416		field = cq_read_field(d->dev, d->object, desc->i);
    417		break;
    418
    419	default:
    420		mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type);
    421		return -EINVAL;
    422	}
    423
    424	if (is_str)
    425		ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field);
    426	else
    427		ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);
    428
    429	return simple_read_from_buffer(buf, count, pos, tbuf, ret);
    430}
    431
    432static const struct file_operations fops = {
    433	.owner	= THIS_MODULE,
    434	.open	= simple_open,
    435	.read	= dbg_read,
    436};
    437
    438static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type,
    439			struct dentry *root, struct mlx5_rsc_debug **dbg,
    440			int rsn, char **field, int nfile, void *data)
    441{
    442	struct mlx5_rsc_debug *d;
    443	char resn[32];
    444	int i;
    445
    446	d = kzalloc(struct_size(d, fields, nfile), GFP_KERNEL);
    447	if (!d)
    448		return -ENOMEM;
    449
    450	d->dev = dev;
    451	d->object = data;
    452	d->type = type;
    453	sprintf(resn, "0x%x", rsn);
    454	d->root = debugfs_create_dir(resn,  root);
    455
    456	for (i = 0; i < nfile; i++) {
    457		d->fields[i].i = i;
    458		debugfs_create_file(field[i], 0400, d->root, &d->fields[i],
    459				    &fops);
    460	}
    461	*dbg = d;
    462
    463	return 0;
    464}
    465
    466static void rem_res_tree(struct mlx5_rsc_debug *d)
    467{
    468	debugfs_remove_recursive(d->root);
    469	kfree(d);
    470}
    471
    472int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
    473{
    474	int err;
    475
    476	if (!mlx5_debugfs_root)
    477		return 0;
    478
    479	err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.dbg.qp_debugfs,
    480			   &qp->dbg, qp->qpn, qp_fields,
    481			   ARRAY_SIZE(qp_fields), qp);
    482	if (err)
    483		qp->dbg = NULL;
    484
    485	return err;
    486}
    487EXPORT_SYMBOL(mlx5_debug_qp_add);
    488
    489void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
    490{
    491	if (!mlx5_debugfs_root)
    492		return;
    493
    494	if (qp->dbg)
    495		rem_res_tree(qp->dbg);
    496}
    497EXPORT_SYMBOL(mlx5_debug_qp_remove);
    498
    499int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
    500{
    501	int err;
    502
    503	if (!mlx5_debugfs_root)
    504		return 0;
    505
    506	err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.dbg.eq_debugfs,
    507			   &eq->dbg, eq->eqn, eq_fields,
    508			   ARRAY_SIZE(eq_fields), eq);
    509	if (err)
    510		eq->dbg = NULL;
    511
    512	return err;
    513}
    514
    515void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
    516{
    517	if (!mlx5_debugfs_root)
    518		return;
    519
    520	if (eq->dbg)
    521		rem_res_tree(eq->dbg);
    522}
    523
    524int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
    525{
    526	int err;
    527
    528	if (!mlx5_debugfs_root)
    529		return 0;
    530
    531	err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.dbg.cq_debugfs,
    532			   &cq->dbg, cq->cqn, cq_fields,
    533			   ARRAY_SIZE(cq_fields), cq);
    534	if (err)
    535		cq->dbg = NULL;
    536
    537	return err;
    538}
    539
    540void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
    541{
    542	if (!mlx5_debugfs_root)
    543		return;
    544
    545	if (cq->dbg) {
    546		rem_res_tree(cq->dbg);
    547		cq->dbg = NULL;
    548	}
    549}