diff options
-rw-r--r-- | drivers/infiniband/hw/mlx4/Makefile | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/alias_GUID.c | 6 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/mad.c | 9 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/mcg.c | 67 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/mlx4_ib.h | 43 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/sysfs.c | 794 |
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 @@ | |||
1 | obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o | 1 | obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o |
2 | 2 | ||
3 | mlx4_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 | 3 | mlx4_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 | ||
116 | static ib_sa_comp_mask get_aguid_comp_mask_from_ix(int index) | 116 | ib_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 | |||
1999 | sysfs_err: | ||
1992 | mlx4_ib_destroy_alias_guid_service(dev); | 2000 | mlx4_ib_destroy_alias_guid_service(dev); |
1993 | 2001 | ||
1994 | paravirt_err: | 2002 | paravirt_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 | ||
803 | static ssize_t sysfs_show_group(struct device *dev, | ||
804 | struct device_attribute *attr, char *buf); | ||
805 | |||
799 | static struct mcast_group *acquire_group(struct mlx4_ib_demux_ctx *ctx, | 806 | static 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 | |||
847 | found: | 861 | found: |
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 | ||
986 | static 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 | |||
972 | int mlx4_ib_mcg_port_init(struct mlx4_ib_demux_ctx *ctx) | 1038 | int 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 | ||
430 | struct 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 | |||
440 | struct mlx4_ib_iov_sysfs_attr_ar { | ||
441 | struct mlx4_ib_iov_sysfs_attr dentries[3 * NUM_ALIAS_GUID_PER_PORT + 1]; | ||
442 | }; | ||
443 | |||
444 | struct 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 | |||
430 | struct mlx4_ib_dev { | 459 | struct 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 | ||
716 | int add_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, | ||
717 | struct attribute *attr); | ||
718 | void del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, | ||
719 | struct attribute *attr); | ||
720 | ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index); | ||
721 | |||
722 | int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *device) ; | ||
723 | |||
724 | void 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 | */ | ||
46 | static 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 | */ | ||
72 | static 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 | |||
131 | static 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 | |||
158 | static 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) \ | ||
178 | do { \ | ||
179 | sysfs_remove_file((_dentry)->kobj, &(_dentry)->dentry.attr); \ | ||
180 | } while (0); | ||
181 | |||
182 | static 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 | |||
220 | int 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 | |||
233 | void 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 | |||
241 | static 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 | |||
341 | err_mcgs: | ||
342 | kobject_put(port->cur_port); | ||
343 | |||
344 | err_pkeys_parent: | ||
345 | kobject_put(port->pkeys_parent); | ||
346 | |||
347 | err_pkeys: | ||
348 | kobject_put(port->cur_port); | ||
349 | |||
350 | err_gids_parent: | ||
351 | kobject_put(port->gids_parent); | ||
352 | |||
353 | err_gids: | ||
354 | kobject_put(port->cur_port); | ||
355 | |||
356 | err_admin_alias_parent: | ||
357 | kobject_put(port->admin_alias_parent); | ||
358 | |||
359 | err_admin_guids: | ||
360 | kobject_put(port->cur_port); | ||
361 | kobject_put(port->cur_port); /* once more for create_and_add buff */ | ||
362 | |||
363 | kobj_create_err: | ||
364 | kobject_put(device->ports_parent); | ||
365 | kfree(port->dentr_ar); | ||
366 | |||
367 | err: | ||
368 | pr_err("add_port_entries FAILED: for port:%d, error: %d\n", | ||
369 | port_num, ret); | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | static 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 | |||
387 | struct 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 | |||
397 | static 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 | |||
412 | struct 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 | |||
419 | static 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 | |||
431 | static 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 | |||
444 | static const struct sysfs_ops port_sysfs_ops = { | ||
445 | .show = port_attr_show, | ||
446 | .store = port_attr_store, | ||
447 | }; | ||
448 | |||
449 | static struct kobj_type port_type = { | ||
450 | .release = mlx4_port_release, | ||
451 | .sysfs_ops = &port_sysfs_ops, | ||
452 | }; | ||
453 | |||
454 | struct port_table_attribute { | ||
455 | struct port_attribute attr; | ||
456 | char name[8]; | ||
457 | int index; | ||
458 | }; | ||
459 | |||
460 | static 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 | |||
477 | static 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 | |||
509 | static 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 | |||
515 | static struct attribute ** | ||
516 | alloc_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 | |||
554 | err: | ||
555 | while (--i >= 0) | ||
556 | kfree(tab_attr[i]); | ||
557 | kfree(tab_attr); | ||
558 | return NULL; | ||
559 | } | ||
560 | |||
561 | static 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 | |||
604 | err_free_gid: | ||
605 | kfree(p->gid_group.attrs[0]); | ||
606 | kfree(p->gid_group.attrs); | ||
607 | |||
608 | err_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 | |||
613 | err_alloc: | ||
614 | kobject_put(dev->dev_ports_parent[slave]); | ||
615 | kfree(p); | ||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | static 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 | |||
655 | err_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 | |||
667 | err_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 | |||
672 | fail_dev: | ||
673 | kobject_put(dev->iov_parent); | ||
674 | return err; | ||
675 | } | ||
676 | |||
677 | static 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 | |||
690 | static 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 | |||
717 | int 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 | |||
751 | err_add_entries: | ||
752 | kobject_put(dev->ports_parent); | ||
753 | |||
754 | err_ports: | ||
755 | kobject_put(dev->iov_parent); | ||
756 | err: | ||
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 | |||
762 | static 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 | |||
786 | void 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 | } | ||