brintos

brintos / linux-shallow public Read only

0
0
Text · 14.2 KiB · 36806e8 Raw
616 lines · c
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 two5 * licenses.  You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 *     Redistribution and use in source and binary forms, with or11 *     without modification, are permitted provided that the following12 *     conditions are met:13 *14 *      - Redistributions of source code must retain the above15 *        copyright notice, this list of conditions and the following16 *        disclaimer.17 *18 *      - Redistributions in binary form must reproduce the above19 *        copyright notice, this list of conditions and the following20 *        disclaimer in the documentation and/or other materials21 *        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 OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * 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 reset_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	stats->failed = 0;156	stats->failed_mbox_status = 0;157	stats->last_failed_errno = 0;158	stats->last_failed_mbox_status = 0;159	stats->last_failed_syndrome = 0;160	spin_unlock_irq(&stats->lock);161 162	*pos += count;163 164	return count;165}166 167static const struct file_operations reset_fops = {168	.owner	= THIS_MODULE,169	.open	= simple_open,170	.write	= reset_write,171};172 173static const struct file_operations average_fops = {174	.owner	= THIS_MODULE,175	.open	= simple_open,176	.read	= average_read,177};178 179static ssize_t slots_read(struct file *filp, char __user *buf, size_t count,180			  loff_t *pos)181{182	struct mlx5_cmd *cmd;183	char tbuf[6];184	int weight;185	int field;186	int ret;187 188	cmd = filp->private_data;189	weight = bitmap_weight(&cmd->vars.bitmask, cmd->vars.max_reg_cmds);190	field = cmd->vars.max_reg_cmds - weight;191	ret = snprintf(tbuf, sizeof(tbuf), "%d\n", field);192	return simple_read_from_buffer(buf, count, pos, tbuf, ret);193}194 195static const struct file_operations slots_fops = {196	.owner	= THIS_MODULE,197	.open	= simple_open,198	.read	= slots_read,199};200 201static struct mlx5_cmd_stats *202mlx5_cmdif_alloc_stats(struct xarray *stats_xa, int opcode)203{204	struct mlx5_cmd_stats *stats = kzalloc(sizeof(*stats), GFP_KERNEL);205	int err;206 207	if (!stats)208		return NULL;209 210	err = xa_insert(stats_xa, opcode, stats, GFP_KERNEL);211	if (err) {212		kfree(stats);213		return NULL;214	}215	spin_lock_init(&stats->lock);216	return stats;217}218 219void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)220{221	struct mlx5_cmd_stats *stats;222	struct dentry **cmd;223	const char *namep;224	int i;225 226	cmd = &dev->priv.dbg.cmdif_debugfs;227	*cmd = debugfs_create_dir("commands", dev->priv.dbg.dbg_root);228 229	debugfs_create_file("slots_inuse", 0400, *cmd, &dev->cmd, &slots_fops);230 231	xa_init(&dev->cmd.stats);232 233	for (i = 0; i < MLX5_CMD_OP_MAX; i++) {234		namep = mlx5_command_str(i);235		if (strcmp(namep, "unknown command opcode")) {236			stats = mlx5_cmdif_alloc_stats(&dev->cmd.stats, i);237			if (!stats)238				continue;239			stats->root = debugfs_create_dir(namep, *cmd);240 241			debugfs_create_file("reset", 0200, stats->root, stats,242					    &reset_fops);243			debugfs_create_file("average", 0400, stats->root, stats,244					    &average_fops);245			debugfs_create_u64("n", 0400, stats->root, &stats->n);246			debugfs_create_u64("failed", 0400, stats->root, &stats->failed);247			debugfs_create_u64("failed_mbox_status", 0400, stats->root,248					   &stats->failed_mbox_status);249			debugfs_create_u32("last_failed_errno", 0400, stats->root,250					   &stats->last_failed_errno);251			debugfs_create_u8("last_failed_mbox_status", 0400, stats->root,252					  &stats->last_failed_mbox_status);253			debugfs_create_x32("last_failed_syndrome", 0400, stats->root,254					   &stats->last_failed_syndrome);255		}256	}257}258 259void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)260{261	struct mlx5_cmd_stats *stats;262	unsigned long i;263 264	debugfs_remove_recursive(dev->priv.dbg.cmdif_debugfs);265	xa_for_each(&dev->cmd.stats, i, stats)266		kfree(stats);267	xa_destroy(&dev->cmd.stats);268}269 270void mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)271{272	dev->priv.dbg.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg.dbg_root);273}274 275void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)276{277	debugfs_remove_recursive(dev->priv.dbg.cq_debugfs);278}279 280void mlx5_pages_debugfs_init(struct mlx5_core_dev *dev)281{282	struct dentry *pages;283 284	dev->priv.dbg.pages_debugfs = debugfs_create_dir("pages", dev->priv.dbg.dbg_root);285	pages = dev->priv.dbg.pages_debugfs;286 287	debugfs_create_u32("fw_pages_total", 0400, pages, &dev->priv.fw_pages);288	debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.page_counters[MLX5_VF]);289	debugfs_create_u32("fw_pages_ec_vfs", 0400, pages, &dev->priv.page_counters[MLX5_EC_VF]);290	debugfs_create_u32("fw_pages_sfs", 0400, pages, &dev->priv.page_counters[MLX5_SF]);291	debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.page_counters[MLX5_HOST_PF]);292	debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed);293	debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped);294	debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages,295			   &dev->priv.reclaim_pages_discard);296}297 298void mlx5_pages_debugfs_cleanup(struct mlx5_core_dev *dev)299{300	debugfs_remove_recursive(dev->priv.dbg.pages_debugfs);301}302 303static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,304			 int index, int *is_str)305{306	int outlen = MLX5_ST_SZ_BYTES(query_qp_out);307	u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {};308	u64 param = 0;309	u32 *out;310	int state;311	u32 *qpc;312	int err;313 314	out = kzalloc(outlen, GFP_KERNEL);315	if (!out)316		return 0;317 318	MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP);319	MLX5_SET(query_qp_in, in, qpn, qp->qpn);320	err = mlx5_cmd_exec_inout(dev, query_qp, in, out);321	if (err)322		goto out;323 324	*is_str = 0;325 326	qpc = MLX5_ADDR_OF(query_qp_out, out, qpc);327	switch (index) {328	case QP_PID:329		param = qp->pid;330		break;331	case QP_STATE:332		state = MLX5_GET(qpc, qpc, state);333		param = (unsigned long)mlx5_qp_state_str(state);334		*is_str = 1;335		break;336	case QP_XPORT:337		param = (unsigned long)mlx5_qp_type_str(MLX5_GET(qpc, qpc, st));338		*is_str = 1;339		break;340	case QP_MTU:341		switch (MLX5_GET(qpc, qpc, mtu)) {342		case IB_MTU_256:343			param = 256;344			break;345		case IB_MTU_512:346			param = 512;347			break;348		case IB_MTU_1024:349			param = 1024;350			break;351		case IB_MTU_2048:352			param = 2048;353			break;354		case IB_MTU_4096:355			param = 4096;356			break;357		default:358			param = 0;359		}360		break;361	case QP_N_RECV:362		param = 1 << MLX5_GET(qpc, qpc, log_rq_size);363		break;364	case QP_RECV_SZ:365		param = 1 << (MLX5_GET(qpc, qpc, log_rq_stride) + 4);366		break;367	case QP_N_SEND:368		if (!MLX5_GET(qpc, qpc, no_sq))369			param = 1 << MLX5_GET(qpc, qpc, log_sq_size);370		break;371	case QP_LOG_PG_SZ:372		param = MLX5_GET(qpc, qpc, log_page_size) + 12;373		break;374	case QP_RQPN:375		param = MLX5_GET(qpc, qpc, remote_qpn);376		break;377	}378out:379	kfree(out);380	return param;381}382 383static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq,384			 int index)385{386	int outlen = MLX5_ST_SZ_BYTES(query_eq_out);387	u32 in[MLX5_ST_SZ_DW(query_eq_in)] = {};388	u64 param = 0;389	void *ctx;390	u32 *out;391	int err;392 393	out = kzalloc(outlen, GFP_KERNEL);394	if (!out)395		return param;396 397	MLX5_SET(query_eq_in, in, opcode, MLX5_CMD_OP_QUERY_EQ);398	MLX5_SET(query_eq_in, in, eq_number, eq->eqn);399	err = mlx5_cmd_exec_inout(dev, query_eq, in, out);400	if (err) {401		mlx5_core_warn(dev, "failed to query eq\n");402		goto out;403	}404	ctx = MLX5_ADDR_OF(query_eq_out, out, eq_context_entry);405 406	switch (index) {407	case EQ_NUM_EQES:408		param = 1 << MLX5_GET(eqc, ctx, log_eq_size);409		break;410	case EQ_INTR:411		param = MLX5_GET(eqc, ctx, intr);412		break;413	case EQ_LOG_PG_SZ:414		param = MLX5_GET(eqc, ctx, log_page_size) + 12;415		break;416	}417 418out:419	kfree(out);420	return param;421}422 423static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,424			 int index)425{426	int outlen = MLX5_ST_SZ_BYTES(query_cq_out);427	u64 param = 0;428	void *ctx;429	u32 *out;430	int err;431 432	out = kvzalloc(outlen, GFP_KERNEL);433	if (!out)434		return param;435 436	err = mlx5_core_query_cq(dev, cq, out);437	if (err) {438		mlx5_core_warn(dev, "failed to query cq\n");439		goto out;440	}441	ctx = MLX5_ADDR_OF(query_cq_out, out, cq_context);442 443	switch (index) {444	case CQ_PID:445		param = cq->pid;446		break;447	case CQ_NUM_CQES:448		param = 1 << MLX5_GET(cqc, ctx, log_cq_size);449		break;450	case CQ_LOG_PG_SZ:451		param = MLX5_GET(cqc, ctx, log_page_size);452		break;453	}454 455out:456	kvfree(out);457	return param;458}459 460static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,461			loff_t *pos)462{463	struct mlx5_field_desc *desc;464	struct mlx5_rsc_debug *d;465	char tbuf[18];466	int is_str = 0;467	u64 field;468	int ret;469 470	desc = filp->private_data;471	d = (void *)(desc - desc->i) - sizeof(*d);472	switch (d->type) {473	case MLX5_DBG_RSC_QP:474		field = qp_read_field(d->dev, d->object, desc->i, &is_str);475		break;476 477	case MLX5_DBG_RSC_EQ:478		field = eq_read_field(d->dev, d->object, desc->i);479		break;480 481	case MLX5_DBG_RSC_CQ:482		field = cq_read_field(d->dev, d->object, desc->i);483		break;484 485	default:486		mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type);487		return -EINVAL;488	}489 490	if (is_str)491		ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field);492	else493		ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);494 495	return simple_read_from_buffer(buf, count, pos, tbuf, ret);496}497 498static const struct file_operations fops = {499	.owner	= THIS_MODULE,500	.open	= simple_open,501	.read	= dbg_read,502};503 504static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type,505			struct dentry *root, struct mlx5_rsc_debug **dbg,506			int rsn, char **field, int nfile, void *data)507{508	struct mlx5_rsc_debug *d;509	char resn[32];510	int i;511 512	d = kzalloc(struct_size(d, fields, nfile), GFP_KERNEL);513	if (!d)514		return -ENOMEM;515 516	d->dev = dev;517	d->object = data;518	d->type = type;519	sprintf(resn, "0x%x", rsn);520	d->root = debugfs_create_dir(resn,  root);521 522	for (i = 0; i < nfile; i++) {523		d->fields[i].i = i;524		debugfs_create_file(field[i], 0400, d->root, &d->fields[i],525				    &fops);526	}527	*dbg = d;528 529	return 0;530}531 532static void rem_res_tree(struct mlx5_rsc_debug *d)533{534	debugfs_remove_recursive(d->root);535	kfree(d);536}537 538int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)539{540	int err;541 542	if (!mlx5_debugfs_root)543		return 0;544 545	err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.dbg.qp_debugfs,546			   &qp->dbg, qp->qpn, qp_fields,547			   ARRAY_SIZE(qp_fields), qp);548	if (err)549		qp->dbg = NULL;550 551	return err;552}553EXPORT_SYMBOL(mlx5_debug_qp_add);554 555void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)556{557	if (!mlx5_debugfs_root || !qp->dbg)558		return;559 560	rem_res_tree(qp->dbg);561	qp->dbg = NULL;562}563EXPORT_SYMBOL(mlx5_debug_qp_remove);564 565int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq)566{567	int err;568 569	if (!mlx5_debugfs_root)570		return 0;571 572	err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.dbg.eq_debugfs,573			   &eq->dbg, eq->eqn, eq_fields,574			   ARRAY_SIZE(eq_fields), eq);575	if (err)576		eq->dbg = NULL;577 578	return err;579}580 581void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq)582{583	if (!mlx5_debugfs_root)584		return;585 586	if (eq->dbg)587		rem_res_tree(eq->dbg);588}589 590int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)591{592	int err;593 594	if (!mlx5_debugfs_root)595		return 0;596 597	err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.dbg.cq_debugfs,598			   &cq->dbg, cq->cqn, cq_fields,599			   ARRAY_SIZE(cq_fields), cq);600	if (err)601		cq->dbg = NULL;602 603	return err;604}605 606void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)607{608	if (!mlx5_debugfs_root)609		return;610 611	if (cq->dbg) {612		rem_res_tree(cq->dbg);613		cq->dbg = NULL;614	}615}616