[ofa-general] [PATCH] mlx4: make firmware diagnostic counters available via sysfs

Jack Morgenstein jackm at dev.mellanox.co.il
Wed Apr 2 06:15:44 PDT 2008


mlx4: make firmware diagnostic counters available via sysfs.

Developed by: Gabi Liron of Mellanox.

Signed-off-by: Jack Morgenstein <jackm at dev.mellanox.co.il>

---
Roland,
Please queue this up for kernel 2.6.26.

Thanks!
Jack

Index: infiniband/drivers/net/mlx4/fw.c
===================================================================
--- infiniband.orig/drivers/net/mlx4/fw.c	2008-02-05 09:32:14.000000000 +0200
+++ infiniband/drivers/net/mlx4/fw.c	2008-04-02 16:06:05.000000000 +0300
@@ -827,3 +827,40 @@ int mlx4_NOP(struct mlx4_dev *dev)
 	/* Input modifier of 0x1f means "finish as soon as possible." */
 	return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100);
 }
+
+int mlx4_query_diag_counters(struct mlx4_dev *dev, int array_length,
+			     int in_modifier, unsigned int in_offset[],
+			     u32 counter_out[])
+{
+	struct mlx4_cmd_mailbox *mailbox;
+	u32 *outbox;
+	u32 op_modifer = (u32)in_modifier;
+	int ret;
+	int i;
+
+	mailbox = mlx4_alloc_cmd_mailbox(dev);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	outbox = mailbox->buf;
+
+	ret = mlx4_cmd_box(dev, 0, mailbox->dma, 0, op_modifer,
+			   MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A);
+	if (ret)
+		goto out;
+
+	for(i=0; i<array_length; i++) {
+		if (in_offset[i] > MLX4_MAILBOX_SIZE) {
+			ret = -1;
+			goto out;
+		}
+
+		MLX4_GET(counter_out[i], outbox,   in_offset[i]);
+	}
+	ret = 0;
+
+out:
+	mlx4_free_cmd_mailbox(dev, mailbox);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mlx4_query_diag_counters);
+
Index: infiniband/include/linux/mlx4/device.h
===================================================================
--- infiniband.orig/include/linux/mlx4/device.h	2008-02-10 16:33:29.000000000 +0200
+++ infiniband/include/linux/mlx4/device.h	2008-04-02 16:06:05.000000000 +0300
@@ -368,5 +368,8 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev
 		    u32 *lkey, u32 *rkey);
 int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
 int mlx4_SYNC_TPT(struct mlx4_dev *dev);
+int mlx4_query_diag_counters(struct mlx4_dev *melx4_dev, int array_length,
+			     int in_modifier, unsigned int in_offset[],
+			     u32 counter_out[]);
 
 #endif /* MLX4_DEVICE_H */
Index: infiniband/drivers/infiniband/hw/mlx4/main.c
===================================================================
--- infiniband.orig/drivers/infiniband/hw/mlx4/main.c	2008-02-27 16:21:35.000000000 +0200
+++ infiniband/drivers/infiniband/hw/mlx4/main.c	2008-04-02 16:06:05.000000000 +0300
@@ -515,6 +515,155 @@ static struct class_device_attribute *ml
 	&class_device_attr_board_id
 };
 
+/*
+ * create 2 functions (show, store) and a class_device_attribute struct
+ * pointing to the functions for _name
+ */
+#define CLASS_DEVICE_DIAG_CLR_RPRT_ATTR(_name, _offset, _in_mod)		\
+static ssize_t store_rprt_##_name(struct class_device *cdev, 			\
+				  const char *buf, size_t length) {		\
+	return store_diag_rprt(cdev, buf, length, _offset, _in_mod);		\
+}										\
+static ssize_t show_rprt_##_name(struct class_device *cdev, char *buf) {	\
+	return show_diag_rprt(cdev, buf, _offset, _in_mod);			\
+}										\
+static CLASS_DEVICE_ATTR(_name, S_IRUGO | S_IWUGO, 				\
+	show_rprt_##_name, store_rprt_##_name);
+
+/*
+ * create show function and a class_device_attribute struct pointing to
+ * the function for _name
+ */
+#define CLASS_DEVICE_DIAG_RPRT_ATTR(_name, _offset, _in_mod)			\
+static ssize_t show_rprt_##_name(struct class_device *cdev, char *buf){		\
+	return show_diag_rprt(cdev, buf, _offset, _in_mod);			\
+}										\
+static CLASS_DEVICE_ATTR(_name, S_IRUGO, show_rprt_##_name, NULL);
+
+static ssize_t show_diag_rprt(struct class_device *cdev, char *buf,
+                              int offset, int in_mod)
+{
+	size_t ret = -1;
+	u32 counter_offset = offset;
+	u32 diag_counter = 0;
+	struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev,
+					       ib_dev.class_dev);
+	/* clear counters file, can't read it */
+	if(offset < 0)
+		return sprintf(buf,"This file is write only\n");
+
+	ret = mlx4_query_diag_counters(dev->dev, 1, in_mod, &counter_offset,
+			 	       &diag_counter);
+	if (ret < 0)
+	{
+		sprintf(buf,"Operation failed\n");
+		return ret;
+	}
+
+	return sprintf(buf,"%d\n", diag_counter);
+}
+
+/* the store function is used for counter clear */
+static ssize_t store_diag_rprt(struct class_device *cdev,
+			       const char *buf, size_t length,
+			       int offset, int in_mod)
+{
+	size_t ret = -1;
+	u32 counter_offset = 0;
+	u32 diag_counter;
+	struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev,
+					       ib_dev.class_dev);
+
+	ret = mlx4_query_diag_counters(dev->dev, 1, in_mod, &counter_offset,
+				       &diag_counter);
+	if (ret)
+		return ret;
+
+	return length;
+}
+
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_lle		  , 0x00, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_lle		  , 0x04, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_lqpoe	  , 0x08, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_lqpoe 	  , 0x0C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_leeoe	  , 0x10, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_leeoe	  , 0x14, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_lpe		  , 0x18, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_lpe		  , 0x1C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_wrfe		  , 0x20, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_wrfe		  , 0x24, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_mwbe		  , 0x2C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_bre		  , 0x34, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_lae		  , 0x38, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_rire		  , 0x44, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_rire		  , 0x48, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_rae		  , 0x4C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_rae		  , 0x50, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_roe		  , 0x54, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_tree		  , 0x5C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_rree		  , 0x64, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_rnr		  , 0x68, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_rnr		  , 0x6C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_rabrte	  , 0x7C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_ieecne	  , 0x84, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_ieecse	  , 0x8C, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_oos		  , 0x100, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_oos		  , 0x104, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_mce		  , 0x108, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_rsync	  , 0x110, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(sq_num_rsync	  , 0x114, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_udsdprd	  , 0x118, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(rq_num_ucsdprd	  , 0x120, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(num_cqovf	  	  , 0x1A0, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(num_eqovf		  , 0x1A4, 2);
+CLASS_DEVICE_DIAG_RPRT_ATTR(num_baddb		  , 0x1A8, 2);
+CLASS_DEVICE_DIAG_CLR_RPRT_ATTR(clear_diag	  , -1   , 3);
+
+static struct attribute *diag_rprt_attrs[] = {
+	&class_device_attr_rq_num_lle.attr,
+	&class_device_attr_sq_num_lle.attr,
+	&class_device_attr_rq_num_lqpoe.attr,
+	&class_device_attr_sq_num_lqpoe.attr,
+	&class_device_attr_rq_num_leeoe.attr,
+	&class_device_attr_sq_num_leeoe.attr,
+	&class_device_attr_rq_num_lpe.attr,
+	&class_device_attr_sq_num_lpe.attr,
+	&class_device_attr_rq_num_wrfe.attr,
+	&class_device_attr_sq_num_wrfe.attr,
+	&class_device_attr_sq_num_mwbe.attr,
+	&class_device_attr_sq_num_bre.attr,
+	&class_device_attr_rq_num_lae.attr,
+	&class_device_attr_sq_num_rire.attr,
+	&class_device_attr_rq_num_rire.attr,
+	&class_device_attr_sq_num_rae.attr,
+	&class_device_attr_rq_num_rae.attr,
+	&class_device_attr_sq_num_roe.attr,
+	&class_device_attr_sq_num_tree.attr,
+	&class_device_attr_sq_num_rree.attr,
+	&class_device_attr_rq_num_rnr.attr,
+	&class_device_attr_sq_num_rnr.attr,
+	&class_device_attr_sq_num_rabrte.attr,
+	&class_device_attr_sq_num_ieecne.attr,
+	&class_device_attr_sq_num_ieecse.attr,
+	&class_device_attr_rq_num_oos.attr,
+	&class_device_attr_sq_num_oos.attr,
+	&class_device_attr_rq_num_mce.attr,
+	&class_device_attr_rq_num_rsync.attr,
+	&class_device_attr_sq_num_rsync.attr,
+	&class_device_attr_rq_num_udsdprd.attr,
+	&class_device_attr_rq_num_ucsdprd.attr,
+	&class_device_attr_num_cqovf.attr,
+	&class_device_attr_num_eqovf.attr,
+	&class_device_attr_num_baddb.attr,
+	&class_device_attr_clear_diag.attr,
+	NULL
+};
+
+static struct attribute_group diag_counters_group = {
+	.name  = "diag_counters",
+	.attrs  = diag_rprt_attrs
+};
+
 static void *mlx4_ib_add(struct mlx4_dev *dev)
 {
 	static int mlx4_ib_version_printed;
@@ -638,8 +787,14 @@ static void *mlx4_ib_add(struct mlx4_dev
 			goto err_reg;
 	}
 
+	if(sysfs_create_group(&ibdev->ib_dev.class_dev.kobj, &diag_counters_group))
+		goto err_diag;
+
 	return ibdev;
 
+err_diag:
+	ib_unregister_device(&ibdev->ib_dev);
+
 err_reg:
 	ib_unregister_device(&ibdev->ib_dev);
 
@@ -663,6 +818,8 @@ static void mlx4_ib_remove(struct mlx4_d
 	struct mlx4_ib_dev *ibdev = ibdev_ptr;
 	int p;
 
+	sysfs_remove_group(&ibdev->ib_dev.class_dev.kobj, &diag_counters_group);
+
 	for (p = 1; p <= dev->caps.num_ports; ++p)
 		mlx4_CLOSE_PORT(dev, p);
 



More information about the general mailing list