aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorJack Morgenstein <jackm@dev.mellanox.co.il>2012-08-03 04:40:51 -0400
committerRoland Dreier <roland@purestorage.com>2012-09-30 23:33:39 -0400
commitc1e7e466120b80ce49e91af0c9da1ce6dee4844a (patch)
treefc67dbaf01fff7e0f411315ee3b5a6923cf22354 /drivers/infiniband
parent2a4fae148cf4b60e73faf0a427302697917409d9 (diff)
IB/mlx4: Add iov directory in sysfs under the ib device
This directory is added only for the master -- slaves do not have it. The sysfs iov directory is used to manage and examine the port P_Key and guid paravirtualization. Under iov/ports, the administrator may examine the gid and P_Key tables as they are present in the device (and as are seen in the "network view" presented to the SM). Under the iov/<pci slot number> directories, the admin may map the index numbers in the physical tables (as under iov/ports) to the paravirtualized index numbers that guests see. For example, if the administrator, for port 1 on guest 2 maps physical pkey index 10 to virtual index 1, then that guest, whenever it uses its pkey index 1, will actually be using the real pkey index 10. Based on patch from Erez Shitrit <erezsh@mellanox.com> Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/mlx4/Makefile2
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c6
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c9
-rw-r--r--drivers/infiniband/hw/mlx4/mcg.c67
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h43
-rw-r--r--drivers/infiniband/hw/mlx4/sysfs.c794
6 files changed, 917 insertions, 4 deletions
diff --git a/drivers/infiniband/hw/mlx4/Makefile b/drivers/infiniband/hw/mlx4/Makefile
index 31d4c8aac679..f4213b3a8fe1 100644
--- a/drivers/infiniband/hw/mlx4/Makefile
+++ b/drivers/infiniband/hw/mlx4/Makefile
@@ -1,3 +1,3 @@
1obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o 1obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o
2 2
3mlx4_ib-y := ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o mcg.o cm.o alias_GUID.o 3mlx4_ib-y := ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o mcg.o cm.o alias_GUID.o sysfs.o
diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c
index ef6d356927c3..0fcd5cd6f3ee 100644
--- a/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ b/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -113,7 +113,7 @@ static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index
113} 113}
114 114
115 115
116static ib_sa_comp_mask get_aguid_comp_mask_from_ix(int index) 116ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index)
117{ 117{
118 return IB_SA_COMP_MASK(4 + index); 118 return IB_SA_COMP_MASK(4 + index);
119} 119}
@@ -259,7 +259,7 @@ static void aliasguid_query_handler(int status,
259 /* Mark the record as not assigned, and let it 259 /* Mark the record as not assigned, and let it
260 * be sent again in the next work sched.*/ 260 * be sent again in the next work sched.*/
261 rec->status = MLX4_GUID_INFO_STATUS_IDLE; 261 rec->status = MLX4_GUID_INFO_STATUS_IDLE;
262 rec->guid_indexes |= get_aguid_comp_mask_from_ix(i); 262 rec->guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
263 } 263 }
264 } else { 264 } else {
265 /* properly assigned record. */ 265 /* properly assigned record. */
@@ -337,7 +337,7 @@ static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
337 MLX4_GUID_NONE_ASSIGN == dev->sriov.alias_guid. 337 MLX4_GUID_NONE_ASSIGN == dev->sriov.alias_guid.
338 ports_guid[port - 1].all_rec_per_port[index].ownership) 338 ports_guid[port - 1].all_rec_per_port[index].ownership)
339 continue; 339 continue;
340 comp_mask |= get_aguid_comp_mask_from_ix(i); 340 comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
341 } 341 }
342 dev->sriov.alias_guid.ports_guid[port - 1]. 342 dev->sriov.alias_guid.ports_guid[port - 1].
343 all_rec_per_port[index].guid_indexes = comp_mask; 343 all_rec_per_port[index].guid_indexes = comp_mask;
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 591c2891159b..b689dbd6d8f6 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -1963,6 +1963,11 @@ int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev)
1963 mlx4_ib_warn(&dev->ib_dev, "Failed init alias guid process.\n"); 1963 mlx4_ib_warn(&dev->ib_dev, "Failed init alias guid process.\n");
1964 goto paravirt_err; 1964 goto paravirt_err;
1965 } 1965 }
1966 err = mlx4_ib_device_register_sysfs(dev);
1967 if (err) {
1968 mlx4_ib_warn(&dev->ib_dev, "Failed to register sysfs\n");
1969 goto sysfs_err;
1970 }
1966 1971
1967 mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n", 1972 mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n",
1968 dev->dev->caps.sqp_demux); 1973 dev->dev->caps.sqp_demux);
@@ -1989,6 +1994,9 @@ demux_err:
1989 mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 1994 mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]);
1990 --i; 1995 --i;
1991 } 1996 }
1997 mlx4_ib_device_unregister_sysfs(dev);
1998
1999sysfs_err:
1992 mlx4_ib_destroy_alias_guid_service(dev); 2000 mlx4_ib_destroy_alias_guid_service(dev);
1993 2001
1994paravirt_err: 2002paravirt_err:
@@ -2019,5 +2027,6 @@ void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev)
2019 2027
2020 mlx4_ib_cm_paravirt_clean(dev, -1); 2028 mlx4_ib_cm_paravirt_clean(dev, -1);
2021 mlx4_ib_destroy_alias_guid_service(dev); 2029 mlx4_ib_destroy_alias_guid_service(dev);
2030 mlx4_ib_device_unregister_sysfs(dev);
2022 } 2031 }
2023} 2032}
diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c
index 1ee2e3a3347a..3c3b54c3fdd9 100644
--- a/drivers/infiniband/hw/mlx4/mcg.c
+++ b/drivers/infiniband/hw/mlx4/mcg.c
@@ -110,6 +110,7 @@ struct mcast_group {
110 __be64 last_req_tid; 110 __be64 last_req_tid;
111 111
112 char name[33]; /* MGID string */ 112 char name[33]; /* MGID string */
113 struct device_attribute dentry;
113 114
114 /* refcount is the reference count for the following: 115 /* refcount is the reference count for the following:
115 1. Each queued request 116 1. Each queued request
@@ -445,6 +446,8 @@ static int release_group(struct mcast_group *group, int from_timeout_handler)
445 } 446 }
446 447
447 nzgroup = memcmp(&group->rec.mgid, &mgid0, sizeof mgid0); 448 nzgroup = memcmp(&group->rec.mgid, &mgid0, sizeof mgid0);
449 if (nzgroup)
450 del_sysfs_port_mcg_attr(ctx->dev, ctx->port, &group->dentry.attr);
448 if (!list_empty(&group->pending_list)) 451 if (!list_empty(&group->pending_list))
449 mcg_warn_group(group, "releasing a group with non empty pending list\n"); 452 mcg_warn_group(group, "releasing a group with non empty pending list\n");
450 if (nzgroup) 453 if (nzgroup)
@@ -769,6 +772,7 @@ static struct mcast_group *search_relocate_mgid0_group(struct mlx4_ib_demux_ctx
769 } 772 }
770 773
771 atomic_inc(&group->refcount); 774 atomic_inc(&group->refcount);
775 add_sysfs_port_mcg_attr(ctx->dev, ctx->port, &group->dentry.attr);
772 mutex_unlock(&group->lock); 776 mutex_unlock(&group->lock);
773 mutex_unlock(&ctx->mcg_table_lock); 777 mutex_unlock(&ctx->mcg_table_lock);
774 return group; 778 return group;
@@ -796,6 +800,9 @@ static struct mcast_group *search_relocate_mgid0_group(struct mlx4_ib_demux_ctx
796 return NULL; 800 return NULL;
797} 801}
798 802
803static ssize_t sysfs_show_group(struct device *dev,
804 struct device_attribute *attr, char *buf);
805
799static struct mcast_group *acquire_group(struct mlx4_ib_demux_ctx *ctx, 806static struct mcast_group *acquire_group(struct mlx4_ib_demux_ctx *ctx,
800 union ib_gid *mgid, int create, 807 union ib_gid *mgid, int create,
801 gfp_t gfp_mask) 808 gfp_t gfp_mask)
@@ -830,6 +837,11 @@ static struct mcast_group *acquire_group(struct mlx4_ib_demux_ctx *ctx,
830 sprintf(group->name, "%016llx%016llx", 837 sprintf(group->name, "%016llx%016llx",
831 be64_to_cpu(group->rec.mgid.global.subnet_prefix), 838 be64_to_cpu(group->rec.mgid.global.subnet_prefix),
832 be64_to_cpu(group->rec.mgid.global.interface_id)); 839 be64_to_cpu(group->rec.mgid.global.interface_id));
840 sysfs_attr_init(&group->dentry.attr);
841 group->dentry.show = sysfs_show_group;
842 group->dentry.store = NULL;
843 group->dentry.attr.name = group->name;
844 group->dentry.attr.mode = 0400;
833 group->state = MCAST_IDLE; 845 group->state = MCAST_IDLE;
834 846
835 if (is_mgid0) { 847 if (is_mgid0) {
@@ -844,6 +856,8 @@ static struct mcast_group *acquire_group(struct mlx4_ib_demux_ctx *ctx,
844 return ERR_PTR(-EINVAL); 856 return ERR_PTR(-EINVAL);
845 } 857 }
846 858
859 add_sysfs_port_mcg_attr(ctx->dev, ctx->port, &group->dentry.attr);
860
847found: 861found:
848 atomic_inc(&group->refcount); 862 atomic_inc(&group->refcount);
849 return group; 863 return group;
@@ -969,6 +983,58 @@ int mlx4_ib_mcg_multiplex_handler(struct ib_device *ibdev, int port,
969 } 983 }
970} 984}
971 985
986static ssize_t sysfs_show_group(struct device *dev,
987 struct device_attribute *attr, char *buf)
988{
989 struct mcast_group *group =
990 container_of(attr, struct mcast_group, dentry);
991 struct mcast_req *req = NULL;
992 char pending_str[40];
993 char state_str[40];
994 ssize_t len = 0;
995 int f;
996
997 if (group->state == MCAST_IDLE)
998 sprintf(state_str, "%s", get_state_string(group->state));
999 else
1000 sprintf(state_str, "%s(TID=0x%llx)",
1001 get_state_string(group->state),
1002 be64_to_cpu(group->last_req_tid));
1003 if (list_empty(&group->pending_list)) {
1004 sprintf(pending_str, "No");
1005 } else {
1006 req = list_first_entry(&group->pending_list, struct mcast_req, group_list);
1007 sprintf(pending_str, "Yes(TID=0x%llx)",
1008 be64_to_cpu(req->sa_mad.mad_hdr.tid));
1009 }
1010 len += sprintf(buf + len, "%1d [%02d,%02d,%02d] %4d %4s %5s ",
1011 group->rec.scope_join_state & 0xf,
1012 group->members[2], group->members[1], group->members[0],
1013 atomic_read(&group->refcount),
1014 pending_str,
1015 state_str);
1016 for (f = 0; f < MAX_VFS; ++f)
1017 if (group->func[f].state == MCAST_MEMBER)
1018 len += sprintf(buf + len, "%d[%1x] ",
1019 f, group->func[f].join_state);
1020
1021 len += sprintf(buf + len, "\t\t(%4hx %4x %2x %2x %2x %2x %2x "
1022 "%4x %4x %2x %2x)\n",
1023 be16_to_cpu(group->rec.pkey),
1024 be32_to_cpu(group->rec.qkey),
1025 (group->rec.mtusel_mtu & 0xc0) >> 6,
1026 group->rec.mtusel_mtu & 0x3f,
1027 group->rec.tclass,
1028 (group->rec.ratesel_rate & 0xc0) >> 6,
1029 group->rec.ratesel_rate & 0x3f,
1030 (be32_to_cpu(group->rec.sl_flowlabel_hoplimit) & 0xf0000000) >> 28,
1031 (be32_to_cpu(group->rec.sl_flowlabel_hoplimit) & 0x0fffff00) >> 8,
1032 be32_to_cpu(group->rec.sl_flowlabel_hoplimit) & 0x000000ff,
1033 group->rec.proxy_join);
1034
1035 return len;
1036}
1037
972int mlx4_ib_mcg_port_init(struct mlx4_ib_demux_ctx *ctx) 1038int mlx4_ib_mcg_port_init(struct mlx4_ib_demux_ctx *ctx)
973{ 1039{
974 char name[20]; 1040 char name[20];
@@ -995,6 +1061,7 @@ static void force_clean_group(struct mcast_group *group)
995 list_del(&req->group_list); 1061 list_del(&req->group_list);
996 kfree(req); 1062 kfree(req);
997 } 1063 }
1064 del_sysfs_port_mcg_attr(group->demux->dev, group->demux->port, &group->dentry.attr);
998 rb_erase(&group->node, &group->demux->mcg_table); 1065 rb_erase(&group->node, &group->demux->mcg_table);
999 kfree(group); 1066 kfree(group);
1000} 1067}
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index f3f75f8229a7..e57a220a4d55 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -427,6 +427,35 @@ struct pkey_mgt {
427 struct kobject *device_parent[MLX4_MFUNC_MAX]; 427 struct kobject *device_parent[MLX4_MFUNC_MAX];
428}; 428};
429 429
430struct mlx4_ib_iov_sysfs_attr {
431 void *ctx;
432 struct kobject *kobj;
433 unsigned long data;
434 u32 entry_num;
435 char name[15];
436 struct device_attribute dentry;
437 struct device *dev;
438};
439
440struct mlx4_ib_iov_sysfs_attr_ar {
441 struct mlx4_ib_iov_sysfs_attr dentries[3 * NUM_ALIAS_GUID_PER_PORT + 1];
442};
443
444struct mlx4_ib_iov_port {
445 char name[100];
446 u8 num;
447 struct mlx4_ib_dev *dev;
448 struct list_head list;
449 struct mlx4_ib_iov_sysfs_attr_ar *dentr_ar;
450 struct ib_port_attr attr;
451 struct kobject *cur_port;
452 struct kobject *admin_alias_parent;
453 struct kobject *gids_parent;
454 struct kobject *pkeys_parent;
455 struct kobject *mcgs_parent;
456 struct mlx4_ib_iov_sysfs_attr mcg_dentry;
457};
458
430struct mlx4_ib_dev { 459struct mlx4_ib_dev {
431 struct ib_device ib_dev; 460 struct ib_device ib_dev;
432 struct mlx4_dev *dev; 461 struct mlx4_dev *dev;
@@ -448,6 +477,10 @@ struct mlx4_ib_dev {
448 int counters[MLX4_MAX_PORTS]; 477 int counters[MLX4_MAX_PORTS];
449 int *eq_table; 478 int *eq_table;
450 int eq_added; 479 int eq_added;
480 struct kobject *iov_parent;
481 struct kobject *ports_parent;
482 struct kobject *dev_ports_parent[MLX4_MFUNC_MAX];
483 struct mlx4_ib_iov_port iov_ports[MLX4_MAX_PORTS];
451 struct pkey_mgt pkeys; 484 struct pkey_mgt pkeys;
452}; 485};
453 486
@@ -680,4 +713,14 @@ void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev,
680 int block_num, u8 port_num, 713 int block_num, u8 port_num,
681 u8 *p_data); 714 u8 *p_data);
682 715
716int add_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num,
717 struct attribute *attr);
718void del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num,
719 struct attribute *attr);
720ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index);
721
722int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *device) ;
723
724void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device);
725
683#endif /* MLX4_IB_H */ 726#endif /* MLX4_IB_H */
diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c
new file mode 100644
index 000000000000..5b2a01dfb907
--- /dev/null
+++ b/drivers/infiniband/hw/mlx4/sysfs.c
@@ -0,0 +1,794 @@
1/*
2 * Copyright (c) 2012 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 "core_priv.h"*/
34#include "mlx4_ib.h"
35#include <linux/slab.h>
36#include <linux/string.h>
37#include <linux/stat.h>
38
39#include <rdma/ib_mad.h>
40/*show_admin_alias_guid returns the administratively assigned value of that GUID.
41 * Values returned in buf parameter string:
42 * 0 - requests opensm to assign a value.
43 * ffffffffffffffff - delete this entry.
44 * other - value assigned by administrator.
45 */
46static ssize_t show_admin_alias_guid(struct device *dev,
47 struct device_attribute *attr, char *buf)
48{
49 int record_num;/*0-15*/
50 int guid_index_in_rec; /*0 - 7*/
51 struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
52 container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
53 struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
54 struct mlx4_ib_dev *mdev = port->dev;
55
56 record_num = mlx4_ib_iov_dentry->entry_num / 8 ;
57 guid_index_in_rec = mlx4_ib_iov_dentry->entry_num % 8 ;
58
59 return sprintf(buf, "%llx\n",
60 be64_to_cpu(*(__be64 *)&mdev->sriov.alias_guid.
61 ports_guid[port->num - 1].
62 all_rec_per_port[record_num].
63 all_recs[8 * guid_index_in_rec]));
64}
65
66/* store_admin_alias_guid stores the (new) administratively assigned value of that GUID.
67 * Values in buf parameter string:
68 * 0 - requests opensm to assign a value.
69 * 0xffffffffffffffff - delete this entry.
70 * other - guid value assigned by the administrator.
71 */
72static ssize_t store_admin_alias_guid(struct device *dev,
73 struct device_attribute *attr,
74 const char *buf, size_t count)
75{
76 int record_num;/*0-15*/
77 int guid_index_in_rec; /*0 - 7*/
78 struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
79 container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
80 struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
81 struct mlx4_ib_dev *mdev = port->dev;
82 u64 sysadmin_ag_val;
83
84 record_num = mlx4_ib_iov_dentry->entry_num / 8;
85 guid_index_in_rec = mlx4_ib_iov_dentry->entry_num % 8;
86 if (0 == record_num && 0 == guid_index_in_rec) {
87 pr_err("GUID 0 block 0 is RO\n");
88 return count;
89 }
90 sscanf(buf, "%llx", &sysadmin_ag_val);
91 *(__be64 *)&mdev->sriov.alias_guid.ports_guid[port->num - 1].
92 all_rec_per_port[record_num].
93 all_recs[GUID_REC_SIZE * guid_index_in_rec] =
94 cpu_to_be64(sysadmin_ag_val);
95
96 /* Change the state to be pending for update */
97 mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].status
98 = MLX4_GUID_INFO_STATUS_IDLE ;
99
100 mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].method
101 = MLX4_GUID_INFO_RECORD_SET;
102
103 switch (sysadmin_ag_val) {
104 case MLX4_GUID_FOR_DELETE_VAL:
105 mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].method
106 = MLX4_GUID_INFO_RECORD_DELETE;
107 mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].ownership
108 = MLX4_GUID_SYSADMIN_ASSIGN;
109 break;
110 /* The sysadmin requests the SM to re-assign */
111 case MLX4_NOT_SET_GUID:
112 mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].ownership
113 = MLX4_GUID_DRIVER_ASSIGN;
114 break;
115 /* The sysadmin requests a specific value.*/
116 default:
117 mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].ownership
118 = MLX4_GUID_SYSADMIN_ASSIGN;
119 break;
120 }
121
122 /* set the record index */
123 mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].guid_indexes
124 = mlx4_ib_get_aguid_comp_mask_from_ix(guid_index_in_rec);
125
126 mlx4_ib_init_alias_guid_work(mdev, port->num - 1);
127
128 return count;
129}
130
131static ssize_t show_port_gid(struct device *dev,
132 struct device_attribute *attr,
133 char *buf)
134{
135 struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
136 container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
137 struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
138 struct mlx4_ib_dev *mdev = port->dev;
139 union ib_gid gid;
140 ssize_t ret;
141
142 ret = __mlx4_ib_query_gid(&mdev->ib_dev, port->num,
143 mlx4_ib_iov_dentry->entry_num, &gid, 1);
144 if (ret)
145 return ret;
146 ret = sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
147 be16_to_cpu(((__be16 *) gid.raw)[0]),
148 be16_to_cpu(((__be16 *) gid.raw)[1]),
149 be16_to_cpu(((__be16 *) gid.raw)[2]),
150 be16_to_cpu(((__be16 *) gid.raw)[3]),
151 be16_to_cpu(((__be16 *) gid.raw)[4]),
152 be16_to_cpu(((__be16 *) gid.raw)[5]),
153 be16_to_cpu(((__be16 *) gid.raw)[6]),
154 be16_to_cpu(((__be16 *) gid.raw)[7]));
155 return ret;
156}
157
158static ssize_t show_phys_port_pkey(struct device *dev,
159 struct device_attribute *attr,
160 char *buf)
161{
162 struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
163 container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
164 struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
165 struct mlx4_ib_dev *mdev = port->dev;
166 u16 pkey;
167 ssize_t ret;
168
169 ret = __mlx4_ib_query_pkey(&mdev->ib_dev, port->num,
170 mlx4_ib_iov_dentry->entry_num, &pkey, 1);
171 if (ret)
172 return ret;
173
174 return sprintf(buf, "0x%04x\n", pkey);
175}
176
177#define DENTRY_REMOVE(_dentry) \
178do { \
179 sysfs_remove_file((_dentry)->kobj, &(_dentry)->dentry.attr); \
180} while (0);
181
182static int create_sysfs_entry(void *_ctx, struct mlx4_ib_iov_sysfs_attr *_dentry,
183 char *_name, struct kobject *_kobj,
184 ssize_t (*show)(struct device *dev,
185 struct device_attribute *attr,
186 char *buf),
187 ssize_t (*store)(struct device *dev,
188 struct device_attribute *attr,
189 const char *buf, size_t count)
190 )
191{
192 int ret = 0;
193 struct mlx4_ib_iov_sysfs_attr *vdentry = _dentry;
194
195 vdentry->ctx = _ctx;
196 vdentry->dentry.show = show;
197 vdentry->dentry.store = store;
198 sysfs_attr_init(&vdentry->dentry.attr);
199 vdentry->dentry.attr.name = vdentry->name;
200 vdentry->dentry.attr.mode = 0;
201 vdentry->kobj = _kobj;
202 snprintf(vdentry->name, 15, "%s", _name);
203
204 if (vdentry->dentry.store)
205 vdentry->dentry.attr.mode |= S_IWUSR;
206
207 if (vdentry->dentry.show)
208 vdentry->dentry.attr.mode |= S_IRUGO;
209
210 ret = sysfs_create_file(vdentry->kobj, &vdentry->dentry.attr);
211 if (ret) {
212 pr_err("failed to create %s\n", vdentry->dentry.attr.name);
213 vdentry->ctx = NULL;
214 return ret;
215 }
216
217 return ret;
218}
219
220int add_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num,
221 struct attribute *attr)
222{
223 struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1];
224 int ret;
225
226 ret = sysfs_create_file(port->mcgs_parent, attr);
227 if (ret)
228 pr_err("failed to create %s\n", attr->name);
229
230 return ret;
231}
232
233void del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num,
234 struct attribute *attr)
235{
236 struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1];
237
238 sysfs_remove_file(port->mcgs_parent, attr);
239}
240
241static int add_port_entries(struct mlx4_ib_dev *device, int port_num)
242{
243 int i;
244 char buff[10];
245 struct mlx4_ib_iov_port *port = NULL;
246 int ret = 0 ;
247 struct ib_port_attr attr;
248
249 /* get the physical gid and pkey table sizes.*/
250 ret = __mlx4_ib_query_port(&device->ib_dev, port_num, &attr, 1);
251 if (ret)
252 goto err;
253
254 port = &device->iov_ports[port_num - 1];
255 port->dev = device;
256 port->num = port_num;
257 /* Directory structure:
258 * iov -
259 * port num -
260 * admin_guids
261 * gids (operational)
262 * mcg_table
263 */
264 port->dentr_ar = kzalloc(sizeof (struct mlx4_ib_iov_sysfs_attr_ar),
265 GFP_KERNEL);
266 if (!port->dentr_ar) {
267 ret = -ENOMEM;
268 goto err;
269 }
270 sprintf(buff, "%d", port_num);
271 port->cur_port = kobject_create_and_add(buff,
272 kobject_get(device->ports_parent));
273 if (!port->cur_port) {
274 ret = -ENOMEM;
275 goto kobj_create_err;
276 }
277 /* admin GUIDs */
278 port->admin_alias_parent = kobject_create_and_add("admin_guids",
279 kobject_get(port->cur_port));
280 if (!port->admin_alias_parent) {
281 ret = -ENOMEM;
282 goto err_admin_guids;
283 }
284 for (i = 0 ; i < attr.gid_tbl_len; i++) {
285 sprintf(buff, "%d", i);
286 port->dentr_ar->dentries[i].entry_num = i;
287 ret = create_sysfs_entry(port, &port->dentr_ar->dentries[i],
288 buff, port->admin_alias_parent,
289 show_admin_alias_guid, store_admin_alias_guid);
290 if (ret)
291 goto err_admin_alias_parent;
292 }
293
294 /* gids subdirectory (operational gids) */
295 port->gids_parent = kobject_create_and_add("gids",
296 kobject_get(port->cur_port));
297 if (!port->gids_parent) {
298 ret = -ENOMEM;
299 goto err_gids;
300 }
301
302 for (i = 0 ; i < attr.gid_tbl_len; i++) {
303 sprintf(buff, "%d", i);
304 port->dentr_ar->dentries[attr.gid_tbl_len + i].entry_num = i;
305 ret = create_sysfs_entry(port,
306 &port->dentr_ar->dentries[attr.gid_tbl_len + i],
307 buff,
308 port->gids_parent, show_port_gid, NULL);
309 if (ret)
310 goto err_gids_parent;
311 }
312
313 /* physical port pkey table */
314 port->pkeys_parent =
315 kobject_create_and_add("pkeys", kobject_get(port->cur_port));
316 if (!port->pkeys_parent) {
317 ret = -ENOMEM;
318 goto err_pkeys;
319 }
320
321 for (i = 0 ; i < attr.pkey_tbl_len; i++) {
322 sprintf(buff, "%d", i);
323 port->dentr_ar->dentries[2 * attr.gid_tbl_len + i].entry_num = i;
324 ret = create_sysfs_entry(port,
325 &port->dentr_ar->dentries[2 * attr.gid_tbl_len + i],
326 buff, port->pkeys_parent,
327 show_phys_port_pkey, NULL);
328 if (ret)
329 goto err_pkeys_parent;
330 }
331
332 /* MCGs table */
333 port->mcgs_parent =
334 kobject_create_and_add("mcgs", kobject_get(port->cur_port));
335 if (!port->mcgs_parent) {
336 ret = -ENOMEM;
337 goto err_mcgs;
338 }
339 return 0;
340
341err_mcgs:
342 kobject_put(port->cur_port);
343
344err_pkeys_parent:
345 kobject_put(port->pkeys_parent);
346
347err_pkeys:
348 kobject_put(port->cur_port);
349
350err_gids_parent:
351 kobject_put(port->gids_parent);
352
353err_gids:
354 kobject_put(port->cur_port);
355
356err_admin_alias_parent:
357 kobject_put(port->admin_alias_parent);
358
359err_admin_guids:
360 kobject_put(port->cur_port);
361 kobject_put(port->cur_port); /* once more for create_and_add buff */
362
363kobj_create_err:
364 kobject_put(device->ports_parent);
365 kfree(port->dentr_ar);
366
367err:
368 pr_err("add_port_entries FAILED: for port:%d, error: %d\n",
369 port_num, ret);
370 return ret;
371}
372
373static void get_name(struct mlx4_ib_dev *dev, char *name, int i, int max)
374{
375 char base_name[9];
376
377 /* pci_name format is: bus:dev:func -> xxxx:yy:zz.n */
378 strlcpy(name, pci_name(dev->dev->pdev), max);
379 strncpy(base_name, name, 8); /*till xxxx:yy:*/
380 base_name[8] = '\0';
381 /* with no ARI only 3 last bits are used so when the fn is higher than 8
382 * need to add it to the dev num, so count in the last number will be
383 * modulo 8 */
384 sprintf(name, "%s%.2d.%d", base_name, (i/8), (i%8));
385}
386
387struct mlx4_port {
388 struct kobject kobj;
389 struct mlx4_ib_dev *dev;
390 struct attribute_group pkey_group;
391 struct attribute_group gid_group;
392 u8 port_num;
393 int slave;
394};
395
396
397static void mlx4_port_release(struct kobject *kobj)
398{
399 struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj);
400 struct attribute *a;
401 int i;
402
403 for (i = 0; (a = p->pkey_group.attrs[i]); ++i)
404 kfree(a);
405 kfree(p->pkey_group.attrs);
406 for (i = 0; (a = p->gid_group.attrs[i]); ++i)
407 kfree(a);
408 kfree(p->gid_group.attrs);
409 kfree(p);
410}
411
412struct port_attribute {
413 struct attribute attr;
414 ssize_t (*show)(struct mlx4_port *, struct port_attribute *, char *buf);
415 ssize_t (*store)(struct mlx4_port *, struct port_attribute *,
416 const char *buf, size_t count);
417};
418
419static ssize_t port_attr_show(struct kobject *kobj,
420 struct attribute *attr, char *buf)
421{
422 struct port_attribute *port_attr =
423 container_of(attr, struct port_attribute, attr);
424 struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj);
425
426 if (!port_attr->show)
427 return -EIO;
428 return port_attr->show(p, port_attr, buf);
429}
430
431static ssize_t port_attr_store(struct kobject *kobj,
432 struct attribute *attr,
433 const char *buf, size_t size)
434{
435 struct port_attribute *port_attr =
436 container_of(attr, struct port_attribute, attr);
437 struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj);
438
439 if (!port_attr->store)
440 return -EIO;
441 return port_attr->store(p, port_attr, buf, size);
442}
443
444static const struct sysfs_ops port_sysfs_ops = {
445 .show = port_attr_show,
446 .store = port_attr_store,
447};
448
449static struct kobj_type port_type = {
450 .release = mlx4_port_release,
451 .sysfs_ops = &port_sysfs_ops,
452};
453
454struct port_table_attribute {
455 struct port_attribute attr;
456 char name[8];
457 int index;
458};
459
460static ssize_t show_port_pkey(struct mlx4_port *p, struct port_attribute *attr,
461 char *buf)
462{
463 struct port_table_attribute *tab_attr =
464 container_of(attr, struct port_table_attribute, attr);
465 ssize_t ret = -ENODEV;
466
467 if (p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1][tab_attr->index] >=
468 (p->dev->dev->caps.pkey_table_len[p->port_num]))
469 ret = sprintf(buf, "none\n");
470 else
471 ret = sprintf(buf, "%d\n",
472 p->dev->pkeys.virt2phys_pkey[p->slave]
473 [p->port_num - 1][tab_attr->index]);
474 return ret;
475}
476
477static ssize_t store_port_pkey(struct mlx4_port *p, struct port_attribute *attr,
478 const char *buf, size_t count)
479{
480 struct port_table_attribute *tab_attr =
481 container_of(attr, struct port_table_attribute, attr);
482 int idx;
483 int err;
484
485 /* do not allow remapping Dom0 virtual pkey table */
486 if (p->slave == mlx4_master_func_num(p->dev->dev))
487 return -EINVAL;
488
489 if (!strncasecmp(buf, "no", 2))
490 idx = p->dev->dev->phys_caps.pkey_phys_table_len[p->port_num] - 1;
491 else if (sscanf(buf, "%i", &idx) != 1 ||
492 idx >= p->dev->dev->caps.pkey_table_len[p->port_num] ||
493 idx < 0)
494 return -EINVAL;
495
496 p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1]
497 [tab_attr->index] = idx;
498 mlx4_sync_pkey_table(p->dev->dev, p->slave, p->port_num,
499 tab_attr->index, idx);
500 err = mlx4_gen_pkey_eqe(p->dev->dev, p->slave, p->port_num);
501 if (err) {
502 pr_err("mlx4_gen_pkey_eqe failed for slave %d,"
503 " port %d, index %d\n", p->slave, p->port_num, idx);
504 return err;
505 }
506 return count;
507}
508
509static ssize_t show_port_gid_idx(struct mlx4_port *p,
510 struct port_attribute *attr, char *buf)
511{
512 return sprintf(buf, "%d\n", p->slave);
513}
514
515static struct attribute **
516alloc_group_attrs(ssize_t (*show)(struct mlx4_port *,
517 struct port_attribute *, char *buf),
518 ssize_t (*store)(struct mlx4_port *, struct port_attribute *,
519 const char *buf, size_t count),
520 int len)
521{
522 struct attribute **tab_attr;
523 struct port_table_attribute *element;
524 int i;
525
526 tab_attr = kcalloc(1 + len, sizeof (struct attribute *), GFP_KERNEL);
527 if (!tab_attr)
528 return NULL;
529
530 for (i = 0; i < len; i++) {
531 element = kzalloc(sizeof (struct port_table_attribute),
532 GFP_KERNEL);
533 if (!element)
534 goto err;
535 if (snprintf(element->name, sizeof (element->name),
536 "%d", i) >= sizeof (element->name)) {
537 kfree(element);
538 goto err;
539 }
540 sysfs_attr_init(&element->attr.attr);
541 element->attr.attr.name = element->name;
542 if (store) {
543 element->attr.attr.mode = S_IWUSR | S_IRUGO;
544 element->attr.store = store;
545 } else
546 element->attr.attr.mode = S_IRUGO;
547
548 element->attr.show = show;
549 element->index = i;
550 tab_attr[i] = &element->attr.attr;
551 }
552 return tab_attr;
553
554err:
555 while (--i >= 0)
556 kfree(tab_attr[i]);
557 kfree(tab_attr);
558 return NULL;
559}
560
561static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave)
562{
563 struct mlx4_port *p;
564 int i;
565 int ret;
566
567 p = kzalloc(sizeof *p, GFP_KERNEL);
568 if (!p)
569 return -ENOMEM;
570
571 p->dev = dev;
572 p->port_num = port_num;
573 p->slave = slave;
574
575 ret = kobject_init_and_add(&p->kobj, &port_type,
576 kobject_get(dev->dev_ports_parent[slave]),
577 "%d", port_num);
578 if (ret)
579 goto err_alloc;
580
581 p->pkey_group.name = "pkey_idx";
582 p->pkey_group.attrs =
583 alloc_group_attrs(show_port_pkey, store_port_pkey,
584 dev->dev->caps.pkey_table_len[port_num]);
585 if (!p->pkey_group.attrs)
586 goto err_alloc;
587
588 ret = sysfs_create_group(&p->kobj, &p->pkey_group);
589 if (ret)
590 goto err_free_pkey;
591
592 p->gid_group.name = "gid_idx";
593 p->gid_group.attrs = alloc_group_attrs(show_port_gid_idx, NULL, 1);
594 if (!p->gid_group.attrs)
595 goto err_free_pkey;
596
597 ret = sysfs_create_group(&p->kobj, &p->gid_group);
598 if (ret)
599 goto err_free_gid;
600
601 list_add_tail(&p->kobj.entry, &dev->pkeys.pkey_port_list[slave]);
602 return 0;
603
604err_free_gid:
605 kfree(p->gid_group.attrs[0]);
606 kfree(p->gid_group.attrs);
607
608err_free_pkey:
609 for (i = 0; i < dev->dev->caps.pkey_table_len[port_num]; ++i)
610 kfree(p->pkey_group.attrs[i]);
611 kfree(p->pkey_group.attrs);
612
613err_alloc:
614 kobject_put(dev->dev_ports_parent[slave]);
615 kfree(p);
616 return ret;
617}
618
619static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave)
620{
621 char name[32];
622 int err;
623 int port;
624 struct kobject *p, *t;
625 struct mlx4_port *mport;
626
627 get_name(dev, name, slave, sizeof name);
628
629 dev->pkeys.device_parent[slave] =
630 kobject_create_and_add(name, kobject_get(dev->iov_parent));
631
632 if (!dev->pkeys.device_parent[slave]) {
633 err = -ENOMEM;
634 goto fail_dev;
635 }
636
637 INIT_LIST_HEAD(&dev->pkeys.pkey_port_list[slave]);
638
639 dev->dev_ports_parent[slave] =
640 kobject_create_and_add("ports",
641 kobject_get(dev->pkeys.device_parent[slave]));
642
643 if (!dev->dev_ports_parent[slave]) {
644 err = -ENOMEM;
645 goto err_ports;
646 }
647
648 for (port = 1; port <= dev->dev->caps.num_ports; ++port) {
649 err = add_port(dev, port, slave);
650 if (err)
651 goto err_add;
652 }
653 return 0;
654
655err_add:
656 list_for_each_entry_safe(p, t,
657 &dev->pkeys.pkey_port_list[slave],
658 entry) {
659 list_del(&p->entry);
660 mport = container_of(p, struct mlx4_port, kobj);
661 sysfs_remove_group(p, &mport->pkey_group);
662 sysfs_remove_group(p, &mport->gid_group);
663 kobject_put(p);
664 }
665 kobject_put(dev->dev_ports_parent[slave]);
666
667err_ports:
668 kobject_put(dev->pkeys.device_parent[slave]);
669 /* extra put for the device_parent create_and_add */
670 kobject_put(dev->pkeys.device_parent[slave]);
671
672fail_dev:
673 kobject_put(dev->iov_parent);
674 return err;
675}
676
677static int register_pkey_tree(struct mlx4_ib_dev *device)
678{
679 int i;
680
681 if (!mlx4_is_master(device->dev))
682 return 0;
683
684 for (i = 0; i <= device->dev->num_vfs; ++i)
685 register_one_pkey_tree(device, i);
686
687 return 0;
688}
689
690static void unregister_pkey_tree(struct mlx4_ib_dev *device)
691{
692 int slave;
693 struct kobject *p, *t;
694 struct mlx4_port *port;
695
696 if (!mlx4_is_master(device->dev))
697 return;
698
699 for (slave = device->dev->num_vfs; slave >= 0; --slave) {
700 list_for_each_entry_safe(p, t,
701 &device->pkeys.pkey_port_list[slave],
702 entry) {
703 list_del(&p->entry);
704 port = container_of(p, struct mlx4_port, kobj);
705 sysfs_remove_group(p, &port->pkey_group);
706 sysfs_remove_group(p, &port->gid_group);
707 kobject_put(p);
708 kobject_put(device->dev_ports_parent[slave]);
709 }
710 kobject_put(device->dev_ports_parent[slave]);
711 kobject_put(device->pkeys.device_parent[slave]);
712 kobject_put(device->pkeys.device_parent[slave]);
713 kobject_put(device->iov_parent);
714 }
715}
716
717int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *dev)
718{
719 int i;
720 int ret = 0;
721
722 if (!mlx4_is_master(dev->dev))
723 return 0;
724
725 dev->iov_parent =
726 kobject_create_and_add("iov",
727 kobject_get(dev->ib_dev.ports_parent->parent));
728 if (!dev->iov_parent) {
729 ret = -ENOMEM;
730 goto err;
731 }
732 dev->ports_parent =
733 kobject_create_and_add("ports",
734 kobject_get(dev->iov_parent));
735 if (!dev->iov_parent) {
736 ret = -ENOMEM;
737 goto err_ports;
738 }
739
740 for (i = 1; i <= dev->ib_dev.phys_port_cnt; ++i) {
741 ret = add_port_entries(dev, i);
742 if (ret)
743 goto err_add_entries;
744 }
745
746 ret = register_pkey_tree(dev);
747 if (ret)
748 goto err_add_entries;
749 return 0;
750
751err_add_entries:
752 kobject_put(dev->ports_parent);
753
754err_ports:
755 kobject_put(dev->iov_parent);
756err:
757 kobject_put(dev->ib_dev.ports_parent->parent);
758 pr_err("mlx4_ib_device_register_sysfs error (%d)\n", ret);
759 return ret;
760}
761
762static void unregister_alias_guid_tree(struct mlx4_ib_dev *device)
763{
764 struct mlx4_ib_iov_port *p;
765 int i;
766
767 if (!mlx4_is_master(device->dev))
768 return;
769
770 for (i = 0; i < device->dev->caps.num_ports; i++) {
771 p = &device->iov_ports[i];
772 kobject_put(p->admin_alias_parent);
773 kobject_put(p->gids_parent);
774 kobject_put(p->pkeys_parent);
775 kobject_put(p->mcgs_parent);
776 kobject_put(p->cur_port);
777 kobject_put(p->cur_port);
778 kobject_put(p->cur_port);
779 kobject_put(p->cur_port);
780 kobject_put(p->cur_port);
781 kobject_put(p->dev->ports_parent);
782 kfree(p->dentr_ar);
783 }
784}
785
786void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device)
787{
788 unregister_alias_guid_tree(device);
789 unregister_pkey_tree(device);
790 kobject_put(device->ports_parent);
791 kobject_put(device->iov_parent);
792 kobject_put(device->iov_parent);
793 kobject_put(device->ib_dev.ports_parent->parent);
794}