| /* | |
| * Copyright (c) 2004 Topspin Communications. All rights reserved. | |
| * | |
| * This software is available to you under a choice of one of two | |
| * licenses. You may choose to be licensed under the terms of the GNU | |
| * General Public License (GPL) Version 2, available from the file | |
| * COPYING in the main directory of this source tree, or the | |
| * OpenIB.org BSD license below: | |
| * | |
| * Redistribution and use in source and binary forms, with or | |
| * without modification, are permitted provided that the following | |
| * conditions are met: | |
| * | |
| * - Redistributions of source code must retain the above | |
| * copyright notice, this list of conditions and the following | |
| * disclaimer. | |
| * | |
| * - Redistributions in binary form must reproduce the above | |
| * copyright notice, this list of conditions and the following | |
| * disclaimer in the documentation and/or other materials | |
| * provided with the distribution. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| * SOFTWARE. | |
| */ | |
| #include <linux/err.h> | |
| #include <linux/seq_file.h> | |
| #include <linux/slab.h> | |
| struct file_operations; | |
| #include <linux/debugfs.h> | |
| #include <linux/export.h> | |
| #include "ipoib.h" | |
| static struct dentry *ipoib_root; | |
| static void format_gid(union ib_gid *gid, char *buf) | |
| { | |
| int i, n; | |
| for (n = 0, i = 0; i < 8; ++i) { | |
| n += sprintf(buf + n, "%x", | |
| be16_to_cpu(((__be16 *) gid->raw)[i])); | |
| if (i < 7) | |
| buf[n++] = ':'; | |
| } | |
| } | |
| static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos) | |
| { | |
| struct ipoib_mcast_iter *iter; | |
| loff_t n = *pos; | |
| iter = ipoib_mcast_iter_init(file->private); | |
| if (!iter) | |
| return NULL; | |
| while (n--) { | |
| if (ipoib_mcast_iter_next(iter)) { | |
| kfree(iter); | |
| return NULL; | |
| } | |
| } | |
| return iter; | |
| } | |
| static void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr, | |
| loff_t *pos) | |
| { | |
| struct ipoib_mcast_iter *iter = iter_ptr; | |
| (*pos)++; | |
| if (ipoib_mcast_iter_next(iter)) { | |
| kfree(iter); | |
| return NULL; | |
| } | |
| return iter; | |
| } | |
| static void ipoib_mcg_seq_stop(struct seq_file *file, void *iter_ptr) | |
| { | |
| /* nothing for now */ | |
| } | |
| static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr) | |
| { | |
| struct ipoib_mcast_iter *iter = iter_ptr; | |
| char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; | |
| union ib_gid mgid; | |
| unsigned long created; | |
| unsigned int queuelen, complete, send_only; | |
| if (!iter) | |
| return 0; | |
| ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen, | |
| &complete, &send_only); | |
| format_gid(&mgid, gid_buf); | |
| seq_printf(file, | |
| "GID: %s\n" | |
| " created: %10ld\n" | |
| " queuelen: %9d\n" | |
| " complete: %9s\n" | |
| " send_only: %8s\n" | |
| "\n", | |
| gid_buf, created, queuelen, | |
| complete ? "yes" : "no", | |
| send_only ? "yes" : "no"); | |
| return 0; | |
| } | |
| static const struct seq_operations ipoib_mcg_sops = { | |
| .start = ipoib_mcg_seq_start, | |
| .next = ipoib_mcg_seq_next, | |
| .stop = ipoib_mcg_seq_stop, | |
| .show = ipoib_mcg_seq_show, | |
| }; | |
| DEFINE_SEQ_ATTRIBUTE(ipoib_mcg); | |
| static void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos) | |
| { | |
| struct ipoib_path_iter *iter; | |
| loff_t n = *pos; | |
| iter = ipoib_path_iter_init(file->private); | |
| if (!iter) | |
| return NULL; | |
| while (n--) { | |
| if (ipoib_path_iter_next(iter)) { | |
| kfree(iter); | |
| return NULL; | |
| } | |
| } | |
| return iter; | |
| } | |
| static void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr, | |
| loff_t *pos) | |
| { | |
| struct ipoib_path_iter *iter = iter_ptr; | |
| (*pos)++; | |
| if (ipoib_path_iter_next(iter)) { | |
| kfree(iter); | |
| return NULL; | |
| } | |
| return iter; | |
| } | |
| static void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr) | |
| { | |
| /* nothing for now */ | |
| } | |
| static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr) | |
| { | |
| struct ipoib_path_iter *iter = iter_ptr; | |
| char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; | |
| struct ipoib_path path; | |
| int rate; | |
| if (!iter) | |
| return 0; | |
| ipoib_path_iter_read(iter, &path); | |
| format_gid(&path.pathrec.dgid, gid_buf); | |
| seq_printf(file, | |
| "GID: %s\n" | |
| " complete: %6s\n", | |
| gid_buf, sa_path_get_dlid(&path.pathrec) ? "yes" : "no"); | |
| if (sa_path_get_dlid(&path.pathrec)) { | |
| rate = ib_rate_to_mbps(path.pathrec.rate); | |
| seq_printf(file, | |
| " DLID: 0x%04x\n" | |
| " SL: %12d\n" | |
| " rate: %8d.%d Gb/sec\n", | |
| be32_to_cpu(sa_path_get_dlid(&path.pathrec)), | |
| path.pathrec.sl, | |
| rate / 1000, rate % 1000); | |
| } | |
| seq_putc(file, '\n'); | |
| return 0; | |
| } | |
| static const struct seq_operations ipoib_path_sops = { | |
| .start = ipoib_path_seq_start, | |
| .next = ipoib_path_seq_next, | |
| .stop = ipoib_path_seq_stop, | |
| .show = ipoib_path_seq_show, | |
| }; | |
| DEFINE_SEQ_ATTRIBUTE(ipoib_path); | |
| void ipoib_create_debug_files(struct net_device *dev) | |
| { | |
| struct ipoib_dev_priv *priv = ipoib_priv(dev); | |
| char name[IFNAMSIZ + sizeof("_path")]; | |
| snprintf(name, sizeof(name), "%s_mcg", dev->name); | |
| priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, | |
| ipoib_root, dev, &ipoib_mcg_fops); | |
| snprintf(name, sizeof(name), "%s_path", dev->name); | |
| priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, | |
| ipoib_root, dev, &ipoib_path_fops); | |
| } | |
| void ipoib_delete_debug_files(struct net_device *dev) | |
| { | |
| struct ipoib_dev_priv *priv = ipoib_priv(dev); | |
| debugfs_remove(priv->mcg_dentry); | |
| debugfs_remove(priv->path_dentry); | |
| priv->mcg_dentry = priv->path_dentry = NULL; | |
| } | |
| void ipoib_register_debugfs(void) | |
| { | |
| ipoib_root = debugfs_create_dir("ipoib", NULL); | |
| } | |
| void ipoib_unregister_debugfs(void) | |
| { | |
| debugfs_remove(ipoib_root); | |
| } |