xref: /OK3568_Linux_fs/kernel/drivers/infiniband/hw/mlx4/sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2012 Mellanox Technologies.  All rights reserved.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This software is available to you under a choice of one of two
5*4882a593Smuzhiyun  * licenses.  You may choose to be licensed under the terms of the GNU
6*4882a593Smuzhiyun  * General Public License (GPL) Version 2, available from the file
7*4882a593Smuzhiyun  * COPYING in the main directory of this source tree, or the
8*4882a593Smuzhiyun  * OpenIB.org BSD license below:
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *     Redistribution and use in source and binary forms, with or
11*4882a593Smuzhiyun  *     without modification, are permitted provided that the following
12*4882a593Smuzhiyun  *     conditions are met:
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *      - Redistributions of source code must retain the above
15*4882a593Smuzhiyun  *        copyright notice, this list of conditions and the following
16*4882a593Smuzhiyun  *        disclaimer.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  *      - Redistributions in binary form must reproduce the above
19*4882a593Smuzhiyun  *        copyright notice, this list of conditions and the following
20*4882a593Smuzhiyun  *        disclaimer in the documentation and/or other materials
21*4882a593Smuzhiyun  *        provided with the distribution.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*4882a593Smuzhiyun  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*4882a593Smuzhiyun  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26*4882a593Smuzhiyun  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27*4882a593Smuzhiyun  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28*4882a593Smuzhiyun  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29*4882a593Smuzhiyun  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30*4882a593Smuzhiyun  * SOFTWARE.
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /*#include "core_priv.h"*/
34*4882a593Smuzhiyun #include "mlx4_ib.h"
35*4882a593Smuzhiyun #include <linux/slab.h>
36*4882a593Smuzhiyun #include <linux/string.h>
37*4882a593Smuzhiyun #include <linux/stat.h>
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <rdma/ib_mad.h>
40*4882a593Smuzhiyun /*show_admin_alias_guid returns the administratively assigned value of that GUID.
41*4882a593Smuzhiyun  * Values returned in buf parameter string:
42*4882a593Smuzhiyun  *	0			- requests opensm to assign a value.
43*4882a593Smuzhiyun  *	ffffffffffffffff	- delete this entry.
44*4882a593Smuzhiyun  *	other			- value assigned by administrator.
45*4882a593Smuzhiyun  */
show_admin_alias_guid(struct device * dev,struct device_attribute * attr,char * buf)46*4882a593Smuzhiyun static ssize_t show_admin_alias_guid(struct device *dev,
47*4882a593Smuzhiyun 			      struct device_attribute *attr, char *buf)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
50*4882a593Smuzhiyun 		container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
51*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
52*4882a593Smuzhiyun 	struct mlx4_ib_dev *mdev = port->dev;
53*4882a593Smuzhiyun 	__be64 sysadmin_ag_val;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	sysadmin_ag_val = mlx4_get_admin_guid(mdev->dev,
56*4882a593Smuzhiyun 					      mlx4_ib_iov_dentry->entry_num,
57*4882a593Smuzhiyun 					      port->num);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	return sprintf(buf, "%llx\n", be64_to_cpu(sysadmin_ag_val));
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* store_admin_alias_guid stores the (new) administratively assigned value of that GUID.
63*4882a593Smuzhiyun  * Values in buf parameter string:
64*4882a593Smuzhiyun  *	0			- requests opensm to assign a value.
65*4882a593Smuzhiyun  *	0xffffffffffffffff	- delete this entry.
66*4882a593Smuzhiyun  *	other			- guid value assigned by the administrator.
67*4882a593Smuzhiyun  */
store_admin_alias_guid(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)68*4882a593Smuzhiyun static ssize_t store_admin_alias_guid(struct device *dev,
69*4882a593Smuzhiyun 				      struct device_attribute *attr,
70*4882a593Smuzhiyun 				      const char *buf, size_t count)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	int record_num;/*0-15*/
73*4882a593Smuzhiyun 	int guid_index_in_rec; /*0 - 7*/
74*4882a593Smuzhiyun 	struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
75*4882a593Smuzhiyun 		container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
76*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
77*4882a593Smuzhiyun 	struct mlx4_ib_dev *mdev = port->dev;
78*4882a593Smuzhiyun 	u64 sysadmin_ag_val;
79*4882a593Smuzhiyun 	unsigned long flags;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	record_num = mlx4_ib_iov_dentry->entry_num / 8;
82*4882a593Smuzhiyun 	guid_index_in_rec = mlx4_ib_iov_dentry->entry_num % 8;
83*4882a593Smuzhiyun 	if (0 == record_num && 0 == guid_index_in_rec) {
84*4882a593Smuzhiyun 		pr_err("GUID 0 block 0 is RO\n");
85*4882a593Smuzhiyun 		return count;
86*4882a593Smuzhiyun 	}
87*4882a593Smuzhiyun 	spin_lock_irqsave(&mdev->sriov.alias_guid.ag_work_lock, flags);
88*4882a593Smuzhiyun 	sscanf(buf, "%llx", &sysadmin_ag_val);
89*4882a593Smuzhiyun 	*(__be64 *)&mdev->sriov.alias_guid.ports_guid[port->num - 1].
90*4882a593Smuzhiyun 		all_rec_per_port[record_num].
91*4882a593Smuzhiyun 		all_recs[GUID_REC_SIZE * guid_index_in_rec] =
92*4882a593Smuzhiyun 			cpu_to_be64(sysadmin_ag_val);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* Change the state to be pending for update */
95*4882a593Smuzhiyun 	mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].status
96*4882a593Smuzhiyun 		= MLX4_GUID_INFO_STATUS_IDLE ;
97*4882a593Smuzhiyun 	mlx4_set_admin_guid(mdev->dev, cpu_to_be64(sysadmin_ag_val),
98*4882a593Smuzhiyun 			    mlx4_ib_iov_dentry->entry_num,
99*4882a593Smuzhiyun 			    port->num);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	/* set the record index */
102*4882a593Smuzhiyun 	mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].guid_indexes
103*4882a593Smuzhiyun 		|= mlx4_ib_get_aguid_comp_mask_from_ix(guid_index_in_rec);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	spin_unlock_irqrestore(&mdev->sriov.alias_guid.ag_work_lock, flags);
106*4882a593Smuzhiyun 	mlx4_ib_init_alias_guid_work(mdev, port->num - 1);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return count;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
show_port_gid(struct device * dev,struct device_attribute * attr,char * buf)111*4882a593Smuzhiyun static ssize_t show_port_gid(struct device *dev,
112*4882a593Smuzhiyun 			     struct device_attribute *attr,
113*4882a593Smuzhiyun 			     char *buf)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
116*4882a593Smuzhiyun 		container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
117*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
118*4882a593Smuzhiyun 	struct mlx4_ib_dev *mdev = port->dev;
119*4882a593Smuzhiyun 	union ib_gid gid;
120*4882a593Smuzhiyun 	ssize_t ret;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	ret = __mlx4_ib_query_gid(&mdev->ib_dev, port->num,
123*4882a593Smuzhiyun 				  mlx4_ib_iov_dentry->entry_num, &gid, 1);
124*4882a593Smuzhiyun 	if (ret)
125*4882a593Smuzhiyun 		return ret;
126*4882a593Smuzhiyun 	ret = sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
127*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[0]),
128*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[1]),
129*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[2]),
130*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[3]),
131*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[4]),
132*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[5]),
133*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[6]),
134*4882a593Smuzhiyun 		      be16_to_cpu(((__be16 *) gid.raw)[7]));
135*4882a593Smuzhiyun 	return ret;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
show_phys_port_pkey(struct device * dev,struct device_attribute * attr,char * buf)138*4882a593Smuzhiyun static ssize_t show_phys_port_pkey(struct device *dev,
139*4882a593Smuzhiyun 				   struct device_attribute *attr,
140*4882a593Smuzhiyun 				   char *buf)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry =
143*4882a593Smuzhiyun 		container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry);
144*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx;
145*4882a593Smuzhiyun 	struct mlx4_ib_dev *mdev = port->dev;
146*4882a593Smuzhiyun 	u16 pkey;
147*4882a593Smuzhiyun 	ssize_t ret;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	ret = __mlx4_ib_query_pkey(&mdev->ib_dev, port->num,
150*4882a593Smuzhiyun 				   mlx4_ib_iov_dentry->entry_num, &pkey, 1);
151*4882a593Smuzhiyun 	if (ret)
152*4882a593Smuzhiyun 		return ret;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	return sprintf(buf, "0x%04x\n", pkey);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun #define DENTRY_REMOVE(_dentry)						\
158*4882a593Smuzhiyun do {									\
159*4882a593Smuzhiyun 	sysfs_remove_file((_dentry)->kobj, &(_dentry)->dentry.attr);	\
160*4882a593Smuzhiyun } while (0);
161*4882a593Smuzhiyun 
create_sysfs_entry(void * _ctx,struct mlx4_ib_iov_sysfs_attr * _dentry,char * _name,struct kobject * _kobj,ssize_t (* show)(struct device * dev,struct device_attribute * attr,char * buf),ssize_t (* store)(struct device * dev,struct device_attribute * attr,const char * buf,size_t count))162*4882a593Smuzhiyun static int create_sysfs_entry(void *_ctx, struct mlx4_ib_iov_sysfs_attr *_dentry,
163*4882a593Smuzhiyun 			      char *_name, struct kobject *_kobj,
164*4882a593Smuzhiyun 			      ssize_t (*show)(struct device *dev,
165*4882a593Smuzhiyun 					      struct device_attribute *attr,
166*4882a593Smuzhiyun 					      char *buf),
167*4882a593Smuzhiyun 			      ssize_t (*store)(struct device *dev,
168*4882a593Smuzhiyun 					       struct device_attribute *attr,
169*4882a593Smuzhiyun 					       const char *buf, size_t count)
170*4882a593Smuzhiyun 			      )
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	int ret = 0;
173*4882a593Smuzhiyun 	struct mlx4_ib_iov_sysfs_attr *vdentry = _dentry;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	vdentry->ctx = _ctx;
176*4882a593Smuzhiyun 	vdentry->dentry.show = show;
177*4882a593Smuzhiyun 	vdentry->dentry.store = store;
178*4882a593Smuzhiyun 	sysfs_attr_init(&vdentry->dentry.attr);
179*4882a593Smuzhiyun 	vdentry->dentry.attr.name = vdentry->name;
180*4882a593Smuzhiyun 	vdentry->dentry.attr.mode = 0;
181*4882a593Smuzhiyun 	vdentry->kobj = _kobj;
182*4882a593Smuzhiyun 	snprintf(vdentry->name, 15, "%s", _name);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (vdentry->dentry.store)
185*4882a593Smuzhiyun 		vdentry->dentry.attr.mode |= S_IWUSR;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (vdentry->dentry.show)
188*4882a593Smuzhiyun 		vdentry->dentry.attr.mode |= S_IRUGO;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	ret = sysfs_create_file(vdentry->kobj, &vdentry->dentry.attr);
191*4882a593Smuzhiyun 	if (ret) {
192*4882a593Smuzhiyun 		pr_err("failed to create %s\n", vdentry->dentry.attr.name);
193*4882a593Smuzhiyun 		vdentry->ctx = NULL;
194*4882a593Smuzhiyun 		return ret;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return ret;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
add_sysfs_port_mcg_attr(struct mlx4_ib_dev * device,int port_num,struct attribute * attr)200*4882a593Smuzhiyun int add_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num,
201*4882a593Smuzhiyun 		struct attribute *attr)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1];
204*4882a593Smuzhiyun 	int ret;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	ret = sysfs_create_file(port->mcgs_parent, attr);
207*4882a593Smuzhiyun 	if (ret)
208*4882a593Smuzhiyun 		pr_err("failed to create %s\n", attr->name);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	return ret;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
del_sysfs_port_mcg_attr(struct mlx4_ib_dev * device,int port_num,struct attribute * attr)213*4882a593Smuzhiyun void del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num,
214*4882a593Smuzhiyun 		struct attribute *attr)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1];
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	sysfs_remove_file(port->mcgs_parent, attr);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
add_port_entries(struct mlx4_ib_dev * device,int port_num)221*4882a593Smuzhiyun static int add_port_entries(struct mlx4_ib_dev *device, int port_num)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	int i;
224*4882a593Smuzhiyun 	char buff[11];
225*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *port = NULL;
226*4882a593Smuzhiyun 	int ret = 0 ;
227*4882a593Smuzhiyun 	struct ib_port_attr attr;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	memset(&attr, 0, sizeof(attr));
230*4882a593Smuzhiyun 	/* get the physical gid and pkey table sizes.*/
231*4882a593Smuzhiyun 	ret = __mlx4_ib_query_port(&device->ib_dev, port_num, &attr, 1);
232*4882a593Smuzhiyun 	if (ret)
233*4882a593Smuzhiyun 		goto err;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	port = &device->iov_ports[port_num - 1];
236*4882a593Smuzhiyun 	port->dev = device;
237*4882a593Smuzhiyun 	port->num = port_num;
238*4882a593Smuzhiyun 	/* Directory structure:
239*4882a593Smuzhiyun 	 * iov -
240*4882a593Smuzhiyun 	 *   port num -
241*4882a593Smuzhiyun 	 *	admin_guids
242*4882a593Smuzhiyun 	 *	gids (operational)
243*4882a593Smuzhiyun 	 *	mcg_table
244*4882a593Smuzhiyun 	 */
245*4882a593Smuzhiyun 	port->dentr_ar = kzalloc(sizeof (struct mlx4_ib_iov_sysfs_attr_ar),
246*4882a593Smuzhiyun 				 GFP_KERNEL);
247*4882a593Smuzhiyun 	if (!port->dentr_ar) {
248*4882a593Smuzhiyun 		ret = -ENOMEM;
249*4882a593Smuzhiyun 		goto err;
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 	sprintf(buff, "%d", port_num);
252*4882a593Smuzhiyun 	port->cur_port = kobject_create_and_add(buff,
253*4882a593Smuzhiyun 				 kobject_get(device->ports_parent));
254*4882a593Smuzhiyun 	if (!port->cur_port) {
255*4882a593Smuzhiyun 		ret = -ENOMEM;
256*4882a593Smuzhiyun 		goto kobj_create_err;
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 	/* admin GUIDs */
259*4882a593Smuzhiyun 	port->admin_alias_parent = kobject_create_and_add("admin_guids",
260*4882a593Smuzhiyun 						  kobject_get(port->cur_port));
261*4882a593Smuzhiyun 	if (!port->admin_alias_parent) {
262*4882a593Smuzhiyun 		ret = -ENOMEM;
263*4882a593Smuzhiyun 		goto err_admin_guids;
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 	for (i = 0 ; i < attr.gid_tbl_len; i++) {
266*4882a593Smuzhiyun 		sprintf(buff, "%d", i);
267*4882a593Smuzhiyun 		port->dentr_ar->dentries[i].entry_num = i;
268*4882a593Smuzhiyun 		ret = create_sysfs_entry(port, &port->dentr_ar->dentries[i],
269*4882a593Smuzhiyun 					  buff, port->admin_alias_parent,
270*4882a593Smuzhiyun 					  show_admin_alias_guid, store_admin_alias_guid);
271*4882a593Smuzhiyun 		if (ret)
272*4882a593Smuzhiyun 			goto err_admin_alias_parent;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	/* gids subdirectory (operational gids) */
276*4882a593Smuzhiyun 	port->gids_parent = kobject_create_and_add("gids",
277*4882a593Smuzhiyun 						  kobject_get(port->cur_port));
278*4882a593Smuzhiyun 	if (!port->gids_parent) {
279*4882a593Smuzhiyun 		ret = -ENOMEM;
280*4882a593Smuzhiyun 		goto err_gids;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	for (i = 0 ; i < attr.gid_tbl_len; i++) {
284*4882a593Smuzhiyun 		sprintf(buff, "%d", i);
285*4882a593Smuzhiyun 		port->dentr_ar->dentries[attr.gid_tbl_len + i].entry_num = i;
286*4882a593Smuzhiyun 		ret = create_sysfs_entry(port,
287*4882a593Smuzhiyun 					 &port->dentr_ar->dentries[attr.gid_tbl_len + i],
288*4882a593Smuzhiyun 					 buff,
289*4882a593Smuzhiyun 					 port->gids_parent, show_port_gid, NULL);
290*4882a593Smuzhiyun 		if (ret)
291*4882a593Smuzhiyun 			goto err_gids_parent;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* physical port pkey table */
295*4882a593Smuzhiyun 	port->pkeys_parent =
296*4882a593Smuzhiyun 		kobject_create_and_add("pkeys", kobject_get(port->cur_port));
297*4882a593Smuzhiyun 	if (!port->pkeys_parent) {
298*4882a593Smuzhiyun 		ret = -ENOMEM;
299*4882a593Smuzhiyun 		goto err_pkeys;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	for (i = 0 ; i < attr.pkey_tbl_len; i++) {
303*4882a593Smuzhiyun 		sprintf(buff, "%d", i);
304*4882a593Smuzhiyun 		port->dentr_ar->dentries[2 * attr.gid_tbl_len + i].entry_num = i;
305*4882a593Smuzhiyun 		ret = create_sysfs_entry(port,
306*4882a593Smuzhiyun 					 &port->dentr_ar->dentries[2 * attr.gid_tbl_len + i],
307*4882a593Smuzhiyun 					 buff, port->pkeys_parent,
308*4882a593Smuzhiyun 					 show_phys_port_pkey, NULL);
309*4882a593Smuzhiyun 		if (ret)
310*4882a593Smuzhiyun 			goto err_pkeys_parent;
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	/* MCGs table */
314*4882a593Smuzhiyun 	port->mcgs_parent =
315*4882a593Smuzhiyun 		kobject_create_and_add("mcgs", kobject_get(port->cur_port));
316*4882a593Smuzhiyun 	if (!port->mcgs_parent) {
317*4882a593Smuzhiyun 		ret = -ENOMEM;
318*4882a593Smuzhiyun 		goto err_mcgs;
319*4882a593Smuzhiyun 	}
320*4882a593Smuzhiyun 	return 0;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun err_mcgs:
323*4882a593Smuzhiyun 	kobject_put(port->cur_port);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun err_pkeys_parent:
326*4882a593Smuzhiyun 	kobject_put(port->pkeys_parent);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun err_pkeys:
329*4882a593Smuzhiyun 	kobject_put(port->cur_port);
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun err_gids_parent:
332*4882a593Smuzhiyun 	kobject_put(port->gids_parent);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun err_gids:
335*4882a593Smuzhiyun 	kobject_put(port->cur_port);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun err_admin_alias_parent:
338*4882a593Smuzhiyun 	kobject_put(port->admin_alias_parent);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun err_admin_guids:
341*4882a593Smuzhiyun 	kobject_put(port->cur_port);
342*4882a593Smuzhiyun 	kobject_put(port->cur_port); /* once more for create_and_add buff */
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun kobj_create_err:
345*4882a593Smuzhiyun 	kobject_put(device->ports_parent);
346*4882a593Smuzhiyun 	kfree(port->dentr_ar);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun err:
349*4882a593Smuzhiyun 	pr_err("add_port_entries FAILED: for port:%d, error: %d\n",
350*4882a593Smuzhiyun 	       port_num, ret);
351*4882a593Smuzhiyun 	return ret;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
get_name(struct mlx4_ib_dev * dev,char * name,int i,int max)354*4882a593Smuzhiyun static void get_name(struct mlx4_ib_dev *dev, char *name, int i, int max)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	/* pci_name format is: bus:dev:func -> xxxx:yy:zz.n
357*4882a593Smuzhiyun 	 * with no ARI only 3 last bits are used so when the fn is higher than 8
358*4882a593Smuzhiyun 	 * need to add it to the dev num, so count in the last number will be
359*4882a593Smuzhiyun 	 * modulo 8 */
360*4882a593Smuzhiyun 	snprintf(name, max, "%.8s%.2d.%d", pci_name(dev->dev->persist->pdev),
361*4882a593Smuzhiyun 		 i / 8, i % 8);
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun struct mlx4_port {
365*4882a593Smuzhiyun 	struct kobject         kobj;
366*4882a593Smuzhiyun 	struct mlx4_ib_dev    *dev;
367*4882a593Smuzhiyun 	struct attribute_group pkey_group;
368*4882a593Smuzhiyun 	struct attribute_group gid_group;
369*4882a593Smuzhiyun 	struct device_attribute	enable_smi_admin;
370*4882a593Smuzhiyun 	struct device_attribute	smi_enabled;
371*4882a593Smuzhiyun 	int		       slave;
372*4882a593Smuzhiyun 	u8                     port_num;
373*4882a593Smuzhiyun };
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 
mlx4_port_release(struct kobject * kobj)376*4882a593Smuzhiyun static void mlx4_port_release(struct kobject *kobj)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj);
379*4882a593Smuzhiyun 	struct attribute *a;
380*4882a593Smuzhiyun 	int i;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	for (i = 0; (a = p->pkey_group.attrs[i]); ++i)
383*4882a593Smuzhiyun 		kfree(a);
384*4882a593Smuzhiyun 	kfree(p->pkey_group.attrs);
385*4882a593Smuzhiyun 	for (i = 0; (a = p->gid_group.attrs[i]); ++i)
386*4882a593Smuzhiyun 		kfree(a);
387*4882a593Smuzhiyun 	kfree(p->gid_group.attrs);
388*4882a593Smuzhiyun 	kfree(p);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun struct port_attribute {
392*4882a593Smuzhiyun 	struct attribute attr;
393*4882a593Smuzhiyun 	ssize_t (*show)(struct mlx4_port *, struct port_attribute *, char *buf);
394*4882a593Smuzhiyun 	ssize_t (*store)(struct mlx4_port *, struct port_attribute *,
395*4882a593Smuzhiyun 			 const char *buf, size_t count);
396*4882a593Smuzhiyun };
397*4882a593Smuzhiyun 
port_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)398*4882a593Smuzhiyun static ssize_t port_attr_show(struct kobject *kobj,
399*4882a593Smuzhiyun 			      struct attribute *attr, char *buf)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun 	struct port_attribute *port_attr =
402*4882a593Smuzhiyun 		container_of(attr, struct port_attribute, attr);
403*4882a593Smuzhiyun 	struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	if (!port_attr->show)
406*4882a593Smuzhiyun 		return -EIO;
407*4882a593Smuzhiyun 	return port_attr->show(p, port_attr, buf);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
port_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t size)410*4882a593Smuzhiyun static ssize_t port_attr_store(struct kobject *kobj,
411*4882a593Smuzhiyun 			       struct attribute *attr,
412*4882a593Smuzhiyun 			       const char *buf, size_t size)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	struct port_attribute *port_attr =
415*4882a593Smuzhiyun 		container_of(attr, struct port_attribute, attr);
416*4882a593Smuzhiyun 	struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	if (!port_attr->store)
419*4882a593Smuzhiyun 		return -EIO;
420*4882a593Smuzhiyun 	return port_attr->store(p, port_attr, buf, size);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun static const struct sysfs_ops port_sysfs_ops = {
424*4882a593Smuzhiyun 	.show = port_attr_show,
425*4882a593Smuzhiyun 	.store = port_attr_store,
426*4882a593Smuzhiyun };
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static struct kobj_type port_type = {
429*4882a593Smuzhiyun 	.release    = mlx4_port_release,
430*4882a593Smuzhiyun 	.sysfs_ops  = &port_sysfs_ops,
431*4882a593Smuzhiyun };
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun struct port_table_attribute {
434*4882a593Smuzhiyun 	struct port_attribute	attr;
435*4882a593Smuzhiyun 	char			name[8];
436*4882a593Smuzhiyun 	int			index;
437*4882a593Smuzhiyun };
438*4882a593Smuzhiyun 
show_port_pkey(struct mlx4_port * p,struct port_attribute * attr,char * buf)439*4882a593Smuzhiyun static ssize_t show_port_pkey(struct mlx4_port *p, struct port_attribute *attr,
440*4882a593Smuzhiyun 			      char *buf)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun 	struct port_table_attribute *tab_attr =
443*4882a593Smuzhiyun 		container_of(attr, struct port_table_attribute, attr);
444*4882a593Smuzhiyun 	ssize_t ret = -ENODEV;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if (p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1][tab_attr->index] >=
447*4882a593Smuzhiyun 	    (p->dev->dev->caps.pkey_table_len[p->port_num]))
448*4882a593Smuzhiyun 		ret = sprintf(buf, "none\n");
449*4882a593Smuzhiyun 	else
450*4882a593Smuzhiyun 		ret = sprintf(buf, "%d\n",
451*4882a593Smuzhiyun 			      p->dev->pkeys.virt2phys_pkey[p->slave]
452*4882a593Smuzhiyun 			      [p->port_num - 1][tab_attr->index]);
453*4882a593Smuzhiyun 	return ret;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun 
store_port_pkey(struct mlx4_port * p,struct port_attribute * attr,const char * buf,size_t count)456*4882a593Smuzhiyun static ssize_t store_port_pkey(struct mlx4_port *p, struct port_attribute *attr,
457*4882a593Smuzhiyun 			       const char *buf, size_t count)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun 	struct port_table_attribute *tab_attr =
460*4882a593Smuzhiyun 		container_of(attr, struct port_table_attribute, attr);
461*4882a593Smuzhiyun 	int idx;
462*4882a593Smuzhiyun 	int err;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	/* do not allow remapping Dom0 virtual pkey table */
465*4882a593Smuzhiyun 	if (p->slave == mlx4_master_func_num(p->dev->dev))
466*4882a593Smuzhiyun 		return -EINVAL;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	if (!strncasecmp(buf, "no", 2))
469*4882a593Smuzhiyun 		idx = p->dev->dev->phys_caps.pkey_phys_table_len[p->port_num] - 1;
470*4882a593Smuzhiyun 	else if (sscanf(buf, "%i", &idx) != 1 ||
471*4882a593Smuzhiyun 		 idx >= p->dev->dev->caps.pkey_table_len[p->port_num] ||
472*4882a593Smuzhiyun 		 idx < 0)
473*4882a593Smuzhiyun 		return -EINVAL;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1]
476*4882a593Smuzhiyun 				    [tab_attr->index] = idx;
477*4882a593Smuzhiyun 	mlx4_sync_pkey_table(p->dev->dev, p->slave, p->port_num,
478*4882a593Smuzhiyun 			     tab_attr->index, idx);
479*4882a593Smuzhiyun 	err = mlx4_gen_pkey_eqe(p->dev->dev, p->slave, p->port_num);
480*4882a593Smuzhiyun 	if (err) {
481*4882a593Smuzhiyun 		pr_err("mlx4_gen_pkey_eqe failed for slave %d,"
482*4882a593Smuzhiyun 		       " port %d, index %d\n", p->slave, p->port_num, idx);
483*4882a593Smuzhiyun 		return err;
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 	return count;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
show_port_gid_idx(struct mlx4_port * p,struct port_attribute * attr,char * buf)488*4882a593Smuzhiyun static ssize_t show_port_gid_idx(struct mlx4_port *p,
489*4882a593Smuzhiyun 				 struct port_attribute *attr, char *buf)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	return sprintf(buf, "%d\n", p->slave);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun static struct attribute **
alloc_group_attrs(ssize_t (* show)(struct mlx4_port *,struct port_attribute *,char * buf),ssize_t (* store)(struct mlx4_port *,struct port_attribute *,const char * buf,size_t count),int len)495*4882a593Smuzhiyun alloc_group_attrs(ssize_t (*show)(struct mlx4_port *,
496*4882a593Smuzhiyun 				  struct port_attribute *, char *buf),
497*4882a593Smuzhiyun 		  ssize_t (*store)(struct mlx4_port *, struct port_attribute *,
498*4882a593Smuzhiyun 				   const char *buf, size_t count),
499*4882a593Smuzhiyun 		  int len)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	struct attribute **tab_attr;
502*4882a593Smuzhiyun 	struct port_table_attribute *element;
503*4882a593Smuzhiyun 	int i;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	tab_attr = kcalloc(1 + len, sizeof (struct attribute *), GFP_KERNEL);
506*4882a593Smuzhiyun 	if (!tab_attr)
507*4882a593Smuzhiyun 		return NULL;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
510*4882a593Smuzhiyun 		element = kzalloc(sizeof (struct port_table_attribute),
511*4882a593Smuzhiyun 				  GFP_KERNEL);
512*4882a593Smuzhiyun 		if (!element)
513*4882a593Smuzhiyun 			goto err;
514*4882a593Smuzhiyun 		if (snprintf(element->name, sizeof (element->name),
515*4882a593Smuzhiyun 			     "%d", i) >= sizeof (element->name)) {
516*4882a593Smuzhiyun 			kfree(element);
517*4882a593Smuzhiyun 			goto err;
518*4882a593Smuzhiyun 		}
519*4882a593Smuzhiyun 		sysfs_attr_init(&element->attr.attr);
520*4882a593Smuzhiyun 		element->attr.attr.name  = element->name;
521*4882a593Smuzhiyun 		if (store) {
522*4882a593Smuzhiyun 			element->attr.attr.mode  = S_IWUSR | S_IRUGO;
523*4882a593Smuzhiyun 			element->attr.store	 = store;
524*4882a593Smuzhiyun 		} else
525*4882a593Smuzhiyun 			element->attr.attr.mode  = S_IRUGO;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 		element->attr.show       = show;
528*4882a593Smuzhiyun 		element->index		 = i;
529*4882a593Smuzhiyun 		tab_attr[i] = &element->attr.attr;
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 	return tab_attr;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun err:
534*4882a593Smuzhiyun 	while (--i >= 0)
535*4882a593Smuzhiyun 		kfree(tab_attr[i]);
536*4882a593Smuzhiyun 	kfree(tab_attr);
537*4882a593Smuzhiyun 	return NULL;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
sysfs_show_smi_enabled(struct device * dev,struct device_attribute * attr,char * buf)540*4882a593Smuzhiyun static ssize_t sysfs_show_smi_enabled(struct device *dev,
541*4882a593Smuzhiyun 				      struct device_attribute *attr, char *buf)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	struct mlx4_port *p =
544*4882a593Smuzhiyun 		container_of(attr, struct mlx4_port, smi_enabled);
545*4882a593Smuzhiyun 	ssize_t len = 0;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	if (mlx4_vf_smi_enabled(p->dev->dev, p->slave, p->port_num))
548*4882a593Smuzhiyun 		len = sprintf(buf, "%d\n", 1);
549*4882a593Smuzhiyun 	else
550*4882a593Smuzhiyun 		len = sprintf(buf, "%d\n", 0);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	return len;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
sysfs_show_enable_smi_admin(struct device * dev,struct device_attribute * attr,char * buf)555*4882a593Smuzhiyun static ssize_t sysfs_show_enable_smi_admin(struct device *dev,
556*4882a593Smuzhiyun 					   struct device_attribute *attr,
557*4882a593Smuzhiyun 					   char *buf)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	struct mlx4_port *p =
560*4882a593Smuzhiyun 		container_of(attr, struct mlx4_port, enable_smi_admin);
561*4882a593Smuzhiyun 	ssize_t len = 0;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	if (mlx4_vf_get_enable_smi_admin(p->dev->dev, p->slave, p->port_num))
564*4882a593Smuzhiyun 		len = sprintf(buf, "%d\n", 1);
565*4882a593Smuzhiyun 	else
566*4882a593Smuzhiyun 		len = sprintf(buf, "%d\n", 0);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	return len;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
sysfs_store_enable_smi_admin(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)571*4882a593Smuzhiyun static ssize_t sysfs_store_enable_smi_admin(struct device *dev,
572*4882a593Smuzhiyun 					    struct device_attribute *attr,
573*4882a593Smuzhiyun 					    const char *buf, size_t count)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	struct mlx4_port *p =
576*4882a593Smuzhiyun 		container_of(attr, struct mlx4_port, enable_smi_admin);
577*4882a593Smuzhiyun 	int enable;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	if (sscanf(buf, "%i", &enable) != 1 ||
580*4882a593Smuzhiyun 	    enable < 0 || enable > 1)
581*4882a593Smuzhiyun 		return -EINVAL;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	if (mlx4_vf_set_enable_smi_admin(p->dev->dev, p->slave, p->port_num, enable))
584*4882a593Smuzhiyun 		return -EINVAL;
585*4882a593Smuzhiyun 	return count;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
add_vf_smi_entries(struct mlx4_port * p)588*4882a593Smuzhiyun static int add_vf_smi_entries(struct mlx4_port *p)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	int is_eth = rdma_port_get_link_layer(&p->dev->ib_dev, p->port_num) ==
591*4882a593Smuzhiyun 			IB_LINK_LAYER_ETHERNET;
592*4882a593Smuzhiyun 	int ret;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	/* do not display entries if eth transport, or if master */
595*4882a593Smuzhiyun 	if (is_eth || p->slave == mlx4_master_func_num(p->dev->dev))
596*4882a593Smuzhiyun 		return 0;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	sysfs_attr_init(&p->smi_enabled.attr);
599*4882a593Smuzhiyun 	p->smi_enabled.show = sysfs_show_smi_enabled;
600*4882a593Smuzhiyun 	p->smi_enabled.store = NULL;
601*4882a593Smuzhiyun 	p->smi_enabled.attr.name = "smi_enabled";
602*4882a593Smuzhiyun 	p->smi_enabled.attr.mode = 0444;
603*4882a593Smuzhiyun 	ret = sysfs_create_file(&p->kobj, &p->smi_enabled.attr);
604*4882a593Smuzhiyun 	if (ret) {
605*4882a593Smuzhiyun 		pr_err("failed to create smi_enabled\n");
606*4882a593Smuzhiyun 		return ret;
607*4882a593Smuzhiyun 	}
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	sysfs_attr_init(&p->enable_smi_admin.attr);
610*4882a593Smuzhiyun 	p->enable_smi_admin.show = sysfs_show_enable_smi_admin;
611*4882a593Smuzhiyun 	p->enable_smi_admin.store = sysfs_store_enable_smi_admin;
612*4882a593Smuzhiyun 	p->enable_smi_admin.attr.name = "enable_smi_admin";
613*4882a593Smuzhiyun 	p->enable_smi_admin.attr.mode = 0644;
614*4882a593Smuzhiyun 	ret = sysfs_create_file(&p->kobj, &p->enable_smi_admin.attr);
615*4882a593Smuzhiyun 	if (ret) {
616*4882a593Smuzhiyun 		pr_err("failed to create enable_smi_admin\n");
617*4882a593Smuzhiyun 		sysfs_remove_file(&p->kobj, &p->smi_enabled.attr);
618*4882a593Smuzhiyun 		return ret;
619*4882a593Smuzhiyun 	}
620*4882a593Smuzhiyun 	return 0;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun 
remove_vf_smi_entries(struct mlx4_port * p)623*4882a593Smuzhiyun static void remove_vf_smi_entries(struct mlx4_port *p)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	int is_eth = rdma_port_get_link_layer(&p->dev->ib_dev, p->port_num) ==
626*4882a593Smuzhiyun 			IB_LINK_LAYER_ETHERNET;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	if (is_eth || p->slave == mlx4_master_func_num(p->dev->dev))
629*4882a593Smuzhiyun 		return;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	sysfs_remove_file(&p->kobj, &p->smi_enabled.attr);
632*4882a593Smuzhiyun 	sysfs_remove_file(&p->kobj, &p->enable_smi_admin.attr);
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
add_port(struct mlx4_ib_dev * dev,int port_num,int slave)635*4882a593Smuzhiyun static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun 	struct mlx4_port *p;
638*4882a593Smuzhiyun 	int i;
639*4882a593Smuzhiyun 	int ret;
640*4882a593Smuzhiyun 	int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port_num) ==
641*4882a593Smuzhiyun 			IB_LINK_LAYER_ETHERNET;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	p = kzalloc(sizeof *p, GFP_KERNEL);
644*4882a593Smuzhiyun 	if (!p)
645*4882a593Smuzhiyun 		return -ENOMEM;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	p->dev = dev;
648*4882a593Smuzhiyun 	p->port_num = port_num;
649*4882a593Smuzhiyun 	p->slave = slave;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	ret = kobject_init_and_add(&p->kobj, &port_type,
652*4882a593Smuzhiyun 				   kobject_get(dev->dev_ports_parent[slave]),
653*4882a593Smuzhiyun 				   "%d", port_num);
654*4882a593Smuzhiyun 	if (ret)
655*4882a593Smuzhiyun 		goto err_alloc;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	p->pkey_group.name  = "pkey_idx";
658*4882a593Smuzhiyun 	p->pkey_group.attrs =
659*4882a593Smuzhiyun 		alloc_group_attrs(show_port_pkey,
660*4882a593Smuzhiyun 				  is_eth ? NULL : store_port_pkey,
661*4882a593Smuzhiyun 				  dev->dev->caps.pkey_table_len[port_num]);
662*4882a593Smuzhiyun 	if (!p->pkey_group.attrs) {
663*4882a593Smuzhiyun 		ret = -ENOMEM;
664*4882a593Smuzhiyun 		goto err_alloc;
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	ret = sysfs_create_group(&p->kobj, &p->pkey_group);
668*4882a593Smuzhiyun 	if (ret)
669*4882a593Smuzhiyun 		goto err_free_pkey;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	p->gid_group.name  = "gid_idx";
672*4882a593Smuzhiyun 	p->gid_group.attrs = alloc_group_attrs(show_port_gid_idx, NULL, 1);
673*4882a593Smuzhiyun 	if (!p->gid_group.attrs) {
674*4882a593Smuzhiyun 		ret = -ENOMEM;
675*4882a593Smuzhiyun 		goto err_free_pkey;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	ret = sysfs_create_group(&p->kobj, &p->gid_group);
679*4882a593Smuzhiyun 	if (ret)
680*4882a593Smuzhiyun 		goto err_free_gid;
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	ret = add_vf_smi_entries(p);
683*4882a593Smuzhiyun 	if (ret)
684*4882a593Smuzhiyun 		goto err_free_gid;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	list_add_tail(&p->kobj.entry, &dev->pkeys.pkey_port_list[slave]);
687*4882a593Smuzhiyun 	return 0;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun err_free_gid:
690*4882a593Smuzhiyun 	kfree(p->gid_group.attrs[0]);
691*4882a593Smuzhiyun 	kfree(p->gid_group.attrs);
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun err_free_pkey:
694*4882a593Smuzhiyun 	for (i = 0; i < dev->dev->caps.pkey_table_len[port_num]; ++i)
695*4882a593Smuzhiyun 		kfree(p->pkey_group.attrs[i]);
696*4882a593Smuzhiyun 	kfree(p->pkey_group.attrs);
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun err_alloc:
699*4882a593Smuzhiyun 	kobject_put(dev->dev_ports_parent[slave]);
700*4882a593Smuzhiyun 	kfree(p);
701*4882a593Smuzhiyun 	return ret;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
register_one_pkey_tree(struct mlx4_ib_dev * dev,int slave)704*4882a593Smuzhiyun static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	char name[32];
707*4882a593Smuzhiyun 	int err;
708*4882a593Smuzhiyun 	int port;
709*4882a593Smuzhiyun 	struct kobject *p, *t;
710*4882a593Smuzhiyun 	struct mlx4_port *mport;
711*4882a593Smuzhiyun 	struct mlx4_active_ports actv_ports;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	get_name(dev, name, slave, sizeof name);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	dev->pkeys.device_parent[slave] =
716*4882a593Smuzhiyun 		kobject_create_and_add(name, kobject_get(dev->iov_parent));
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	if (!dev->pkeys.device_parent[slave]) {
719*4882a593Smuzhiyun 		err = -ENOMEM;
720*4882a593Smuzhiyun 		goto fail_dev;
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	INIT_LIST_HEAD(&dev->pkeys.pkey_port_list[slave]);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	dev->dev_ports_parent[slave] =
726*4882a593Smuzhiyun 		kobject_create_and_add("ports",
727*4882a593Smuzhiyun 				       kobject_get(dev->pkeys.device_parent[slave]));
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	if (!dev->dev_ports_parent[slave]) {
730*4882a593Smuzhiyun 		err = -ENOMEM;
731*4882a593Smuzhiyun 		goto err_ports;
732*4882a593Smuzhiyun 	}
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	actv_ports = mlx4_get_active_ports(dev->dev, slave);
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	for (port = 1; port <= dev->dev->caps.num_ports; ++port) {
737*4882a593Smuzhiyun 		if (!test_bit(port - 1, actv_ports.ports))
738*4882a593Smuzhiyun 			continue;
739*4882a593Smuzhiyun 		err = add_port(dev, port, slave);
740*4882a593Smuzhiyun 		if (err)
741*4882a593Smuzhiyun 			goto err_add;
742*4882a593Smuzhiyun 	}
743*4882a593Smuzhiyun 	return 0;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun err_add:
746*4882a593Smuzhiyun 	list_for_each_entry_safe(p, t,
747*4882a593Smuzhiyun 				 &dev->pkeys.pkey_port_list[slave],
748*4882a593Smuzhiyun 				 entry) {
749*4882a593Smuzhiyun 		list_del(&p->entry);
750*4882a593Smuzhiyun 		mport = container_of(p, struct mlx4_port, kobj);
751*4882a593Smuzhiyun 		sysfs_remove_group(p, &mport->pkey_group);
752*4882a593Smuzhiyun 		sysfs_remove_group(p, &mport->gid_group);
753*4882a593Smuzhiyun 		remove_vf_smi_entries(mport);
754*4882a593Smuzhiyun 		kobject_put(p);
755*4882a593Smuzhiyun 	}
756*4882a593Smuzhiyun 	kobject_put(dev->dev_ports_parent[slave]);
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun err_ports:
759*4882a593Smuzhiyun 	kobject_put(dev->pkeys.device_parent[slave]);
760*4882a593Smuzhiyun 	/* extra put for the device_parent create_and_add */
761*4882a593Smuzhiyun 	kobject_put(dev->pkeys.device_parent[slave]);
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun fail_dev:
764*4882a593Smuzhiyun 	kobject_put(dev->iov_parent);
765*4882a593Smuzhiyun 	return err;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun 
register_pkey_tree(struct mlx4_ib_dev * device)768*4882a593Smuzhiyun static int register_pkey_tree(struct mlx4_ib_dev *device)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun 	int i;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	if (!mlx4_is_master(device->dev))
773*4882a593Smuzhiyun 		return 0;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	for (i = 0; i <= device->dev->persist->num_vfs; ++i)
776*4882a593Smuzhiyun 		register_one_pkey_tree(device, i);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	return 0;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun 
unregister_pkey_tree(struct mlx4_ib_dev * device)781*4882a593Smuzhiyun static void unregister_pkey_tree(struct mlx4_ib_dev *device)
782*4882a593Smuzhiyun {
783*4882a593Smuzhiyun 	int slave;
784*4882a593Smuzhiyun 	struct kobject *p, *t;
785*4882a593Smuzhiyun 	struct mlx4_port *port;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	if (!mlx4_is_master(device->dev))
788*4882a593Smuzhiyun 		return;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) {
791*4882a593Smuzhiyun 		list_for_each_entry_safe(p, t,
792*4882a593Smuzhiyun 					 &device->pkeys.pkey_port_list[slave],
793*4882a593Smuzhiyun 					 entry) {
794*4882a593Smuzhiyun 			list_del(&p->entry);
795*4882a593Smuzhiyun 			port = container_of(p, struct mlx4_port, kobj);
796*4882a593Smuzhiyun 			sysfs_remove_group(p, &port->pkey_group);
797*4882a593Smuzhiyun 			sysfs_remove_group(p, &port->gid_group);
798*4882a593Smuzhiyun 			remove_vf_smi_entries(port);
799*4882a593Smuzhiyun 			kobject_put(p);
800*4882a593Smuzhiyun 			kobject_put(device->dev_ports_parent[slave]);
801*4882a593Smuzhiyun 		}
802*4882a593Smuzhiyun 		kobject_put(device->dev_ports_parent[slave]);
803*4882a593Smuzhiyun 		kobject_put(device->pkeys.device_parent[slave]);
804*4882a593Smuzhiyun 		kobject_put(device->pkeys.device_parent[slave]);
805*4882a593Smuzhiyun 		kobject_put(device->iov_parent);
806*4882a593Smuzhiyun 	}
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun 
mlx4_ib_device_register_sysfs(struct mlx4_ib_dev * dev)809*4882a593Smuzhiyun int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *dev)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun 	int i;
812*4882a593Smuzhiyun 	int ret = 0;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	if (!mlx4_is_master(dev->dev))
815*4882a593Smuzhiyun 		return 0;
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	dev->iov_parent = kobject_create_and_add("iov", &dev->ib_dev.dev.kobj);
818*4882a593Smuzhiyun 	if (!dev->iov_parent) {
819*4882a593Smuzhiyun 		ret = -ENOMEM;
820*4882a593Smuzhiyun 		goto err;
821*4882a593Smuzhiyun 	}
822*4882a593Smuzhiyun 	dev->ports_parent =
823*4882a593Smuzhiyun 		kobject_create_and_add("ports",
824*4882a593Smuzhiyun 				       kobject_get(dev->iov_parent));
825*4882a593Smuzhiyun 	if (!dev->ports_parent) {
826*4882a593Smuzhiyun 		ret = -ENOMEM;
827*4882a593Smuzhiyun 		goto err_ports;
828*4882a593Smuzhiyun 	}
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	for (i = 1; i <= dev->ib_dev.phys_port_cnt; ++i) {
831*4882a593Smuzhiyun 		ret = add_port_entries(dev, i);
832*4882a593Smuzhiyun 		if (ret)
833*4882a593Smuzhiyun 			goto err_add_entries;
834*4882a593Smuzhiyun 	}
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	ret = register_pkey_tree(dev);
837*4882a593Smuzhiyun 	if (ret)
838*4882a593Smuzhiyun 		goto err_add_entries;
839*4882a593Smuzhiyun 	return 0;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun err_add_entries:
842*4882a593Smuzhiyun 	kobject_put(dev->ports_parent);
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun err_ports:
845*4882a593Smuzhiyun 	kobject_put(dev->iov_parent);
846*4882a593Smuzhiyun err:
847*4882a593Smuzhiyun 	pr_err("mlx4_ib_device_register_sysfs error (%d)\n", ret);
848*4882a593Smuzhiyun 	return ret;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun 
unregister_alias_guid_tree(struct mlx4_ib_dev * device)851*4882a593Smuzhiyun static void unregister_alias_guid_tree(struct mlx4_ib_dev *device)
852*4882a593Smuzhiyun {
853*4882a593Smuzhiyun 	struct mlx4_ib_iov_port *p;
854*4882a593Smuzhiyun 	int i;
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	if (!mlx4_is_master(device->dev))
857*4882a593Smuzhiyun 		return;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	for (i = 0; i < device->dev->caps.num_ports; i++) {
860*4882a593Smuzhiyun 		p = &device->iov_ports[i];
861*4882a593Smuzhiyun 		kobject_put(p->admin_alias_parent);
862*4882a593Smuzhiyun 		kobject_put(p->gids_parent);
863*4882a593Smuzhiyun 		kobject_put(p->pkeys_parent);
864*4882a593Smuzhiyun 		kobject_put(p->mcgs_parent);
865*4882a593Smuzhiyun 		kobject_put(p->cur_port);
866*4882a593Smuzhiyun 		kobject_put(p->cur_port);
867*4882a593Smuzhiyun 		kobject_put(p->cur_port);
868*4882a593Smuzhiyun 		kobject_put(p->cur_port);
869*4882a593Smuzhiyun 		kobject_put(p->cur_port);
870*4882a593Smuzhiyun 		kobject_put(p->dev->ports_parent);
871*4882a593Smuzhiyun 		kfree(p->dentr_ar);
872*4882a593Smuzhiyun 	}
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun 
mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev * device)875*4882a593Smuzhiyun void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device)
876*4882a593Smuzhiyun {
877*4882a593Smuzhiyun 	unregister_alias_guid_tree(device);
878*4882a593Smuzhiyun 	unregister_pkey_tree(device);
879*4882a593Smuzhiyun 	kobject_put(device->ports_parent);
880*4882a593Smuzhiyun 	kobject_put(device->iov_parent);
881*4882a593Smuzhiyun 	kobject_put(device->iov_parent);
882*4882a593Smuzhiyun }
883