|
@@ -37,12 +37,22 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/stat.h>
|
|
|
#include <linux/string.h>
|
|
|
+#include <linux/netdevice.h>
|
|
|
|
|
|
#include <rdma/ib_mad.h>
|
|
|
|
|
|
+struct ib_port;
|
|
|
+
|
|
|
+struct gid_attr_group {
|
|
|
+ struct ib_port *port;
|
|
|
+ struct kobject kobj;
|
|
|
+ struct attribute_group ndev;
|
|
|
+ struct attribute_group type;
|
|
|
+};
|
|
|
struct ib_port {
|
|
|
struct kobject kobj;
|
|
|
struct ib_device *ibdev;
|
|
|
+ struct gid_attr_group *gid_attr_group;
|
|
|
struct attribute_group gid_group;
|
|
|
struct attribute_group pkey_group;
|
|
|
u8 port_num;
|
|
@@ -84,6 +94,24 @@ static const struct sysfs_ops port_sysfs_ops = {
|
|
|
.show = port_attr_show
|
|
|
};
|
|
|
|
|
|
+static ssize_t gid_attr_show(struct kobject *kobj,
|
|
|
+ struct attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct port_attribute *port_attr =
|
|
|
+ container_of(attr, struct port_attribute, attr);
|
|
|
+ struct ib_port *p = container_of(kobj, struct gid_attr_group,
|
|
|
+ kobj)->port;
|
|
|
+
|
|
|
+ if (!port_attr->show)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return port_attr->show(p, port_attr, buf);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct sysfs_ops gid_attr_sysfs_ops = {
|
|
|
+ .show = gid_attr_show
|
|
|
+};
|
|
|
+
|
|
|
static ssize_t state_show(struct ib_port *p, struct port_attribute *unused,
|
|
|
char *buf)
|
|
|
{
|
|
@@ -281,6 +309,46 @@ static struct attribute *port_default_attrs[] = {
|
|
|
NULL
|
|
|
};
|
|
|
|
|
|
+static size_t print_ndev(struct ib_gid_attr *gid_attr, char *buf)
|
|
|
+{
|
|
|
+ if (!gid_attr->ndev)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return sprintf(buf, "%s\n", gid_attr->ndev->name);
|
|
|
+}
|
|
|
+
|
|
|
+static size_t print_gid_type(struct ib_gid_attr *gid_attr, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%s\n", ib_cache_gid_type_str(gid_attr->gid_type));
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t _show_port_gid_attr(struct ib_port *p,
|
|
|
+ struct port_attribute *attr,
|
|
|
+ char *buf,
|
|
|
+ size_t (*print)(struct ib_gid_attr *gid_attr,
|
|
|
+ char *buf))
|
|
|
+{
|
|
|
+ struct port_table_attribute *tab_attr =
|
|
|
+ container_of(attr, struct port_table_attribute, attr);
|
|
|
+ union ib_gid gid;
|
|
|
+ struct ib_gid_attr gid_attr = {};
|
|
|
+ ssize_t ret;
|
|
|
+ va_list args;
|
|
|
+
|
|
|
+ ret = ib_query_gid(p->ibdev, p->port_num, tab_attr->index, &gid,
|
|
|
+ &gid_attr);
|
|
|
+ if (ret)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ ret = print(&gid_attr, buf);
|
|
|
+
|
|
|
+err:
|
|
|
+ if (gid_attr.ndev)
|
|
|
+ dev_put(gid_attr.ndev);
|
|
|
+ va_end(args);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
|
|
|
char *buf)
|
|
|
{
|
|
@@ -296,6 +364,19 @@ static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
|
|
|
return sprintf(buf, "%pI6\n", gid.raw);
|
|
|
}
|
|
|
|
|
|
+static ssize_t show_port_gid_attr_ndev(struct ib_port *p,
|
|
|
+ struct port_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return _show_port_gid_attr(p, attr, buf, print_ndev);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t show_port_gid_attr_gid_type(struct ib_port *p,
|
|
|
+ struct port_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ return _show_port_gid_attr(p, attr, buf, print_gid_type);
|
|
|
+}
|
|
|
+
|
|
|
static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr,
|
|
|
char *buf)
|
|
|
{
|
|
@@ -451,12 +532,41 @@ static void ib_port_release(struct kobject *kobj)
|
|
|
kfree(p);
|
|
|
}
|
|
|
|
|
|
+static void ib_port_gid_attr_release(struct kobject *kobj)
|
|
|
+{
|
|
|
+ struct gid_attr_group *g = container_of(kobj, struct gid_attr_group,
|
|
|
+ kobj);
|
|
|
+ struct attribute *a;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (g->ndev.attrs) {
|
|
|
+ for (i = 0; (a = g->ndev.attrs[i]); ++i)
|
|
|
+ kfree(a);
|
|
|
+
|
|
|
+ kfree(g->ndev.attrs);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (g->type.attrs) {
|
|
|
+ for (i = 0; (a = g->type.attrs[i]); ++i)
|
|
|
+ kfree(a);
|
|
|
+
|
|
|
+ kfree(g->type.attrs);
|
|
|
+ }
|
|
|
+
|
|
|
+ kfree(g);
|
|
|
+}
|
|
|
+
|
|
|
static struct kobj_type port_type = {
|
|
|
.release = ib_port_release,
|
|
|
.sysfs_ops = &port_sysfs_ops,
|
|
|
.default_attrs = port_default_attrs
|
|
|
};
|
|
|
|
|
|
+static struct kobj_type gid_attr_type = {
|
|
|
+ .sysfs_ops = &gid_attr_sysfs_ops,
|
|
|
+ .release = ib_port_gid_attr_release
|
|
|
+};
|
|
|
+
|
|
|
static struct attribute **
|
|
|
alloc_group_attrs(ssize_t (*show)(struct ib_port *,
|
|
|
struct port_attribute *, char *buf),
|
|
@@ -528,9 +638,23 @@ static int add_port(struct ib_device *device, int port_num,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ p->gid_attr_group = kzalloc(sizeof(*p->gid_attr_group), GFP_KERNEL);
|
|
|
+ if (!p->gid_attr_group) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err_put;
|
|
|
+ }
|
|
|
+
|
|
|
+ p->gid_attr_group->port = p;
|
|
|
+ ret = kobject_init_and_add(&p->gid_attr_group->kobj, &gid_attr_type,
|
|
|
+ &p->kobj, "gid_attrs");
|
|
|
+ if (ret) {
|
|
|
+ kfree(p->gid_attr_group);
|
|
|
+ goto err_put;
|
|
|
+ }
|
|
|
+
|
|
|
ret = sysfs_create_group(&p->kobj, &pma_group);
|
|
|
if (ret)
|
|
|
- goto err_put;
|
|
|
+ goto err_put_gid_attrs;
|
|
|
|
|
|
p->gid_group.name = "gids";
|
|
|
p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len);
|
|
@@ -543,12 +667,38 @@ static int add_port(struct ib_device *device, int port_num,
|
|
|
if (ret)
|
|
|
goto err_free_gid;
|
|
|
|
|
|
+ p->gid_attr_group->ndev.name = "ndevs";
|
|
|
+ p->gid_attr_group->ndev.attrs = alloc_group_attrs(show_port_gid_attr_ndev,
|
|
|
+ attr.gid_tbl_len);
|
|
|
+ if (!p->gid_attr_group->ndev.attrs) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err_remove_gid;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = sysfs_create_group(&p->gid_attr_group->kobj,
|
|
|
+ &p->gid_attr_group->ndev);
|
|
|
+ if (ret)
|
|
|
+ goto err_free_gid_ndev;
|
|
|
+
|
|
|
+ p->gid_attr_group->type.name = "types";
|
|
|
+ p->gid_attr_group->type.attrs = alloc_group_attrs(show_port_gid_attr_gid_type,
|
|
|
+ attr.gid_tbl_len);
|
|
|
+ if (!p->gid_attr_group->type.attrs) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err_remove_gid_ndev;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = sysfs_create_group(&p->gid_attr_group->kobj,
|
|
|
+ &p->gid_attr_group->type);
|
|
|
+ if (ret)
|
|
|
+ goto err_free_gid_type;
|
|
|
+
|
|
|
p->pkey_group.name = "pkeys";
|
|
|
p->pkey_group.attrs = alloc_group_attrs(show_port_pkey,
|
|
|
attr.pkey_tbl_len);
|
|
|
if (!p->pkey_group.attrs) {
|
|
|
ret = -ENOMEM;
|
|
|
- goto err_remove_gid;
|
|
|
+ goto err_remove_gid_type;
|
|
|
}
|
|
|
|
|
|
ret = sysfs_create_group(&p->kobj, &p->pkey_group);
|
|
@@ -576,6 +726,28 @@ err_free_pkey:
|
|
|
kfree(p->pkey_group.attrs);
|
|
|
p->pkey_group.attrs = NULL;
|
|
|
|
|
|
+err_remove_gid_type:
|
|
|
+ sysfs_remove_group(&p->gid_attr_group->kobj,
|
|
|
+ &p->gid_attr_group->type);
|
|
|
+
|
|
|
+err_free_gid_type:
|
|
|
+ for (i = 0; i < attr.gid_tbl_len; ++i)
|
|
|
+ kfree(p->gid_attr_group->type.attrs[i]);
|
|
|
+
|
|
|
+ kfree(p->gid_attr_group->type.attrs);
|
|
|
+ p->gid_attr_group->type.attrs = NULL;
|
|
|
+
|
|
|
+err_remove_gid_ndev:
|
|
|
+ sysfs_remove_group(&p->gid_attr_group->kobj,
|
|
|
+ &p->gid_attr_group->ndev);
|
|
|
+
|
|
|
+err_free_gid_ndev:
|
|
|
+ for (i = 0; i < attr.gid_tbl_len; ++i)
|
|
|
+ kfree(p->gid_attr_group->ndev.attrs[i]);
|
|
|
+
|
|
|
+ kfree(p->gid_attr_group->ndev.attrs);
|
|
|
+ p->gid_attr_group->ndev.attrs = NULL;
|
|
|
+
|
|
|
err_remove_gid:
|
|
|
sysfs_remove_group(&p->kobj, &p->gid_group);
|
|
|
|
|
@@ -589,6 +761,9 @@ err_free_gid:
|
|
|
err_remove_pma:
|
|
|
sysfs_remove_group(&p->kobj, &pma_group);
|
|
|
|
|
|
+err_put_gid_attrs:
|
|
|
+ kobject_put(&p->gid_attr_group->kobj);
|
|
|
+
|
|
|
err_put:
|
|
|
kobject_put(&p->kobj);
|
|
|
return ret;
|
|
@@ -797,6 +972,11 @@ static void free_port_list_attributes(struct ib_device *device)
|
|
|
sysfs_remove_group(p, &pma_group);
|
|
|
sysfs_remove_group(p, &port->pkey_group);
|
|
|
sysfs_remove_group(p, &port->gid_group);
|
|
|
+ sysfs_remove_group(&port->gid_attr_group->kobj,
|
|
|
+ &port->gid_attr_group->ndev);
|
|
|
+ sysfs_remove_group(&port->gid_attr_group->kobj,
|
|
|
+ &port->gid_attr_group->type);
|
|
|
+ kobject_put(&port->gid_attr_group->kobj);
|
|
|
kobject_put(p);
|
|
|
}
|
|
|
|