sysfs.c 39.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3 4
 * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "core_priv.h"

37
#include <linux/slab.h>
38
#include <linux/stat.h>
39
#include <linux/string.h>
M
Matan Barak 已提交
40
#include <linux/netdevice.h>
41
#include <linux/ethtool.h>
42

43
#include <rdma/ib_mad.h>
44
#include <rdma/ib_pma.h>
45
#include <rdma/ib_cache.h>
46
#include <rdma/rdma_counter.h>
47
#include <rdma/ib_sysfs.h>
L
Linus Torvalds 已提交
48 49

struct port_table_attribute {
50
	struct ib_port_attribute attr;
51 52
	char			name[8];
	int			index;
53
	__be16			attr_id;
L
Linus Torvalds 已提交
54 55
};

56 57 58 59 60 61 62 63 64 65 66 67 68
struct gid_attr_group {
	struct ib_port *port;
	struct kobject kobj;
	struct attribute_group groups[2];
	const struct attribute_group *groups_list[3];
	struct port_table_attribute attrs_list[];
};

struct ib_port {
	struct kobject kobj;
	struct ib_device *ibdev;
	struct gid_attr_group *gid_attr_group;
	struct hw_stats_port_data *hw_stats_data;
69 70 71

	struct attribute_group groups[3];
	const struct attribute_group *groups_list[5];
72
	u32 port_num;
73
	struct port_table_attribute attrs_list[];
74 75
};

76 77 78 79 80 81 82 83 84 85
struct hw_stats_device_attribute {
	struct device_attribute attr;
	ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
			unsigned int index, unsigned int port_num, char *buf);
	ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
			 unsigned int index, unsigned int port_num,
			 const char *buf, size_t count);
};

struct hw_stats_port_attribute {
86
	struct ib_port_attribute attr;
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
			unsigned int index, unsigned int port_num, char *buf);
	ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
			 unsigned int index, unsigned int port_num,
			 const char *buf, size_t count);
};

struct hw_stats_device_data {
	struct attribute_group group;
	struct rdma_hw_stats *stats;
	struct hw_stats_device_attribute attrs[];
};

struct hw_stats_port_data {
	struct rdma_hw_stats *stats;
	struct hw_stats_port_attribute attrs[];
103 104
};

L
Linus Torvalds 已提交
105 106 107
static ssize_t port_attr_show(struct kobject *kobj,
			      struct attribute *attr, char *buf)
{
108 109
	struct ib_port_attribute *port_attr =
		container_of(attr, struct ib_port_attribute, attr);
L
Linus Torvalds 已提交
110 111 112
	struct ib_port *p = container_of(kobj, struct ib_port, kobj);

	if (!port_attr->show)
113
		return -EIO;
L
Linus Torvalds 已提交
114

115
	return port_attr->show(p->ibdev, p->port_num, port_attr, buf);
L
Linus Torvalds 已提交
116 117
}

118 119 120 121
static ssize_t port_attr_store(struct kobject *kobj,
			       struct attribute *attr,
			       const char *buf, size_t count)
{
122 123
	struct ib_port_attribute *port_attr =
		container_of(attr, struct ib_port_attribute, attr);
124 125 126 127
	struct ib_port *p = container_of(kobj, struct ib_port, kobj);

	if (!port_attr->store)
		return -EIO;
128 129 130 131 132 133 134 135
	return port_attr->store(p->ibdev, p->port_num, port_attr, buf, count);
}

int ib_port_sysfs_create_groups(struct ib_device *ibdev, u32 port_num,
				const struct attribute_group **groups)
{
	return sysfs_create_groups(&ibdev->port_data[port_num].sysfs->kobj,
				   groups);
136
}
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
EXPORT_SYMBOL_GPL(ib_port_sysfs_create_groups);

void ib_port_sysfs_remove_groups(struct ib_device *ibdev, u32 port_num,
				 const struct attribute_group **groups)
{
	return sysfs_remove_groups(&ibdev->port_data[port_num].sysfs->kobj,
				   groups);
}
EXPORT_SYMBOL_GPL(ib_port_sysfs_remove_groups);

struct ib_device *ib_port_sysfs_get_ibdev_kobj(struct kobject *kobj,
					       u32 *port_num)
{
	struct ib_port *port = container_of(kobj, struct ib_port, kobj);

	*port_num = port->port_num;
	return port->ibdev;
}
EXPORT_SYMBOL(ib_port_sysfs_get_ibdev_kobj);
156

157
static const struct sysfs_ops port_sysfs_ops = {
158 159
	.show	= port_attr_show,
	.store	= port_attr_store
L
Linus Torvalds 已提交
160 161
};

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
static ssize_t hw_stat_device_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct hw_stats_device_attribute *stat_attr =
		container_of(attr, struct hw_stats_device_attribute, attr);
	struct ib_device *ibdev = container_of(dev, struct ib_device, dev);

	return stat_attr->show(ibdev, ibdev->hw_stats_data->stats,
			       stat_attr - ibdev->hw_stats_data->attrs, 0, buf);
}

static ssize_t hw_stat_device_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	struct hw_stats_device_attribute *stat_attr =
		container_of(attr, struct hw_stats_device_attribute, attr);
	struct ib_device *ibdev = container_of(dev, struct ib_device, dev);

	return stat_attr->store(ibdev, ibdev->hw_stats_data->stats,
				stat_attr - ibdev->hw_stats_data->attrs, 0, buf,
				count);
}

186 187
static ssize_t hw_stat_port_show(struct ib_device *ibdev, u32 port_num,
				 struct ib_port_attribute *attr, char *buf)
188 189 190
{
	struct hw_stats_port_attribute *stat_attr =
		container_of(attr, struct hw_stats_port_attribute, attr);
191
	struct ib_port *port = ibdev->port_data[port_num].sysfs;
192

193
	return stat_attr->show(ibdev, port->hw_stats_data->stats,
194 195 196 197
			       stat_attr - port->hw_stats_data->attrs,
			       port->port_num, buf);
}

198 199 200
static ssize_t hw_stat_port_store(struct ib_device *ibdev, u32 port_num,
				  struct ib_port_attribute *attr,
				  const char *buf, size_t count)
201 202 203
{
	struct hw_stats_port_attribute *stat_attr =
		container_of(attr, struct hw_stats_port_attribute, attr);
204
	struct ib_port *port = ibdev->port_data[port_num].sysfs;
205

206
	return stat_attr->store(ibdev, port->hw_stats_data->stats,
207 208 209 210
				stat_attr - port->hw_stats_data->attrs,
				port->port_num, buf, count);
}

M
Matan Barak 已提交
211 212 213
static ssize_t gid_attr_show(struct kobject *kobj,
			     struct attribute *attr, char *buf)
{
214 215
	struct ib_port_attribute *port_attr =
		container_of(attr, struct ib_port_attribute, attr);
M
Matan Barak 已提交
216 217 218 219 220 221
	struct ib_port *p = container_of(kobj, struct gid_attr_group,
					 kobj)->port;

	if (!port_attr->show)
		return -EIO;

222
	return port_attr->show(p->ibdev, p->port_num, port_attr, buf);
M
Matan Barak 已提交
223 224 225 226 227 228
}

static const struct sysfs_ops gid_attr_sysfs_ops = {
	.show = gid_attr_show
};

229 230
static ssize_t state_show(struct ib_device *ibdev, u32 port_num,
			  struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
231 232 233 234 235 236 237 238 239 240 241 242 243
{
	struct ib_port_attr attr;
	ssize_t ret;

	static const char *state_name[] = {
		[IB_PORT_NOP]		= "NOP",
		[IB_PORT_DOWN]		= "DOWN",
		[IB_PORT_INIT]		= "INIT",
		[IB_PORT_ARMED]		= "ARMED",
		[IB_PORT_ACTIVE]	= "ACTIVE",
		[IB_PORT_ACTIVE_DEFER]	= "ACTIVE_DEFER"
	};

244
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
245 246 247
	if (ret)
		return ret;

248 249 250 251 252
	return sysfs_emit(buf, "%d: %s\n", attr.state,
			  attr.state >= 0 &&
					  attr.state < ARRAY_SIZE(state_name) ?
				  state_name[attr.state] :
				  "UNKNOWN");
L
Linus Torvalds 已提交
253 254
}

255 256
static ssize_t lid_show(struct ib_device *ibdev, u32 port_num,
			struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
257 258 259 260
{
	struct ib_port_attr attr;
	ssize_t ret;

261
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
262 263 264
	if (ret)
		return ret;

265
	return sysfs_emit(buf, "0x%x\n", attr.lid);
L
Linus Torvalds 已提交
266 267
}

268 269
static ssize_t lid_mask_count_show(struct ib_device *ibdev, u32 port_num,
				   struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
270 271 272 273
{
	struct ib_port_attr attr;
	ssize_t ret;

274
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
275 276 277
	if (ret)
		return ret;

278
	return sysfs_emit(buf, "%d\n", attr.lmc);
L
Linus Torvalds 已提交
279 280
}

281 282
static ssize_t sm_lid_show(struct ib_device *ibdev, u32 port_num,
			   struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
283 284 285 286
{
	struct ib_port_attr attr;
	ssize_t ret;

287
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
288 289 290
	if (ret)
		return ret;

291
	return sysfs_emit(buf, "0x%x\n", attr.sm_lid);
L
Linus Torvalds 已提交
292 293
}

294 295
static ssize_t sm_sl_show(struct ib_device *ibdev, u32 port_num,
			  struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
296 297 298 299
{
	struct ib_port_attr attr;
	ssize_t ret;

300
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
301 302 303
	if (ret)
		return ret;

304
	return sysfs_emit(buf, "%d\n", attr.sm_sl);
L
Linus Torvalds 已提交
305 306
}

307 308
static ssize_t cap_mask_show(struct ib_device *ibdev, u32 port_num,
			     struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
309 310 311 312
{
	struct ib_port_attr attr;
	ssize_t ret;

313
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
314 315 316
	if (ret)
		return ret;

317
	return sysfs_emit(buf, "0x%08x\n", attr.port_cap_flags);
L
Linus Torvalds 已提交
318 319
}

320 321
static ssize_t rate_show(struct ib_device *ibdev, u32 port_num,
			 struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
322 323 324
{
	struct ib_port_attr attr;
	char *speed = "";
325
	int rate;		/* in deci-Gb/sec */
L
Linus Torvalds 已提交
326 327
	ssize_t ret;

328
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
329 330 331 332
	if (ret)
		return ret;

	switch (attr.active_speed) {
333
	case IB_SPEED_DDR:
334
		speed = " DDR";
R
Roland Dreier 已提交
335
		rate = 50;
336
		break;
337
	case IB_SPEED_QDR:
338
		speed = " QDR";
R
Roland Dreier 已提交
339
		rate = 100;
340
		break;
341
	case IB_SPEED_FDR10:
342
		speed = " FDR10";
R
Roland Dreier 已提交
343
		rate = 100;
344
		break;
345
	case IB_SPEED_FDR:
346
		speed = " FDR";
R
Roland Dreier 已提交
347
		rate = 140;
348
		break;
349
	case IB_SPEED_EDR:
350
		speed = " EDR";
R
Roland Dreier 已提交
351
		rate = 250;
352
		break;
N
Noa Osherovich 已提交
353 354 355 356
	case IB_SPEED_HDR:
		speed = " HDR";
		rate = 500;
		break;
357 358 359 360
	case IB_SPEED_NDR:
		speed = " NDR";
		rate = 1000;
		break;
361 362
	case IB_SPEED_SDR:
	default:		/* default to SDR for invalid rates */
363
		speed = " SDR";
364 365
		rate = 25;
		break;
L
Linus Torvalds 已提交
366 367
	}

368
	rate *= ib_width_enum_to_int(attr.active_width);
L
Linus Torvalds 已提交
369 370 371
	if (rate < 0)
		return -EINVAL;

372 373 374
	return sysfs_emit(buf, "%d%s Gb/sec (%dX%s)\n", rate / 10,
			  rate % 10 ? ".5" : "",
			  ib_width_enum_to_int(attr.active_width), speed);
L
Linus Torvalds 已提交
375 376
}

377 378
static const char *phys_state_to_str(enum ib_port_phys_state phys_state)
{
379
	static const char *phys_state_str[] = {
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
		"<unknown>",
		"Sleep",
		"Polling",
		"Disabled",
		"PortConfigurationTraining",
		"LinkUp",
		"LinkErrorRecovery",
		"Phy Test",
	};

	if (phys_state < ARRAY_SIZE(phys_state_str))
		return phys_state_str[phys_state];
	return "<unknown>";
}

395 396
static ssize_t phys_state_show(struct ib_device *ibdev, u32 port_num,
			       struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
397 398 399 400 401
{
	struct ib_port_attr attr;

	ssize_t ret;

402
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
403 404 405
	if (ret)
		return ret;

406 407
	return sysfs_emit(buf, "%d: %s\n", attr.phys_state,
			  phys_state_to_str(attr.phys_state));
L
Linus Torvalds 已提交
408 409
}

410 411
static ssize_t link_layer_show(struct ib_device *ibdev, u32 port_num,
			       struct ib_port_attribute *unused, char *buf)
412
{
413 414
	const char *output;

415
	switch (rdma_port_get_link_layer(ibdev, port_num)) {
416
	case IB_LINK_LAYER_INFINIBAND:
417 418
		output = "InfiniBand";
		break;
419
	case IB_LINK_LAYER_ETHERNET:
420 421
		output = "Ethernet";
		break;
422
	default:
423 424
		output = "Unknown";
		break;
425
	}
426 427

	return sysfs_emit(buf, "%s\n", output);
428 429
}

430 431 432 433 434 435 436 437 438
static IB_PORT_ATTR_RO(state);
static IB_PORT_ATTR_RO(lid);
static IB_PORT_ATTR_RO(lid_mask_count);
static IB_PORT_ATTR_RO(sm_lid);
static IB_PORT_ATTR_RO(sm_sl);
static IB_PORT_ATTR_RO(cap_mask);
static IB_PORT_ATTR_RO(rate);
static IB_PORT_ATTR_RO(phys_state);
static IB_PORT_ATTR_RO(link_layer);
L
Linus Torvalds 已提交
439 440

static struct attribute *port_default_attrs[] = {
441 442 443 444 445 446 447 448 449
	&ib_port_attr_state.attr,
	&ib_port_attr_lid.attr,
	&ib_port_attr_lid_mask_count.attr,
	&ib_port_attr_sm_lid.attr,
	&ib_port_attr_sm_sl.attr,
	&ib_port_attr_cap_mask.attr,
	&ib_port_attr_rate.attr,
	&ib_port_attr_phys_state.attr,
	&ib_port_attr_link_layer.attr,
L
Linus Torvalds 已提交
450 451 452
	NULL
};

453
static ssize_t print_ndev(const struct ib_gid_attr *gid_attr, char *buf)
M
Matan Barak 已提交
454
{
455
	struct net_device *ndev;
456
	int ret = -EINVAL;
457 458 459 460

	rcu_read_lock();
	ndev = rcu_dereference(gid_attr->ndev);
	if (ndev)
461
		ret = sysfs_emit(buf, "%s\n", ndev->name);
462 463
	rcu_read_unlock();
	return ret;
M
Matan Barak 已提交
464 465
}

466
static ssize_t print_gid_type(const struct ib_gid_attr *gid_attr, char *buf)
M
Matan Barak 已提交
467
{
468 469
	return sysfs_emit(buf, "%s\n",
			  ib_cache_gid_type_str(gid_attr->gid_type));
M
Matan Barak 已提交
470 471
}

472
static ssize_t _show_port_gid_attr(
473 474
	struct ib_device *ibdev, u32 port_num, struct ib_port_attribute *attr,
	char *buf,
475
	ssize_t (*print)(const struct ib_gid_attr *gid_attr, char *buf))
M
Matan Barak 已提交
476 477 478
{
	struct port_table_attribute *tab_attr =
		container_of(attr, struct port_table_attribute, attr);
479
	const struct ib_gid_attr *gid_attr;
M
Matan Barak 已提交
480 481
	ssize_t ret;

482
	gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);
483
	if (IS_ERR(gid_attr))
484 485
		/* -EINVAL is returned for user space compatibility reasons. */
		return -EINVAL;
M
Matan Barak 已提交
486

487 488
	ret = print(gid_attr, buf);
	rdma_put_gid_attr(gid_attr);
M
Matan Barak 已提交
489 490 491
	return ret;
}

492 493
static ssize_t show_port_gid(struct ib_device *ibdev, u32 port_num,
			     struct ib_port_attribute *attr, char *buf)
L
Linus Torvalds 已提交
494 495 496
{
	struct port_table_attribute *tab_attr =
		container_of(attr, struct port_table_attribute, attr);
497
	const struct ib_gid_attr *gid_attr;
498
	int len;
L
Linus Torvalds 已提交
499

500
	gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);
501 502 503 504 505 506 507 508 509 510 511 512
	if (IS_ERR(gid_attr)) {
		const union ib_gid zgid = {};

		/* If reading GID fails, it is likely due to GID entry being
		 * empty (invalid) or reserved GID in the table.  User space
		 * expects to read GID table entries as long as it given index
		 * is within GID table size.  Administrative/debugging tool
		 * fails to query rest of the GID entries if it hits error
		 * while querying a GID of the given index.  To avoid user
		 * space throwing such error on fail to read gid, return zero
		 * GID as before. This maintains backward compatibility.
		 */
513
		return sysfs_emit(buf, "%pI6\n", zgid.raw);
514 515
	}

516
	len = sysfs_emit(buf, "%pI6\n", gid_attr->gid.raw);
517
	rdma_put_gid_attr(gid_attr);
518
	return len;
L
Linus Torvalds 已提交
519 520
}

521 522 523
static ssize_t show_port_gid_attr_ndev(struct ib_device *ibdev, u32 port_num,
				       struct ib_port_attribute *attr,
				       char *buf)
M
Matan Barak 已提交
524
{
525
	return _show_port_gid_attr(ibdev, port_num, attr, buf, print_ndev);
M
Matan Barak 已提交
526 527
}

528 529 530
static ssize_t show_port_gid_attr_gid_type(struct ib_device *ibdev,
					   u32 port_num,
					   struct ib_port_attribute *attr,
M
Matan Barak 已提交
531 532
					   char *buf)
{
533
	return _show_port_gid_attr(ibdev, port_num, attr, buf, print_gid_type);
M
Matan Barak 已提交
534 535
}

536 537
static ssize_t show_port_pkey(struct ib_device *ibdev, u32 port_num,
			      struct ib_port_attribute *attr, char *buf)
L
Linus Torvalds 已提交
538 539 540 541
{
	struct port_table_attribute *tab_attr =
		container_of(attr, struct port_table_attribute, attr);
	u16 pkey;
542
	int ret;
L
Linus Torvalds 已提交
543

544
	ret = ib_query_pkey(ibdev, port_num, tab_attr->index, &pkey);
L
Linus Torvalds 已提交
545 546 547
	if (ret)
		return ret;

548
	return sysfs_emit(buf, "0x%04x\n", pkey);
L
Linus Torvalds 已提交
549 550 551 552 553
}

#define PORT_PMA_ATTR(_name, _counter, _width, _offset)			\
struct port_table_attribute port_pma_attr_##_name = {			\
	.attr  = __ATTR(_name, S_IRUGO, show_pma_counter, NULL),	\
554
	.index = (_offset) | ((_width) << 16) | ((_counter) << 24),	\
555
	.attr_id = IB_PMA_PORT_COUNTERS,				\
L
Linus Torvalds 已提交
556 557
}

558 559 560 561
#define PORT_PMA_ATTR_EXT(_name, _width, _offset)			\
struct port_table_attribute port_pma_attr_ext_##_name = {		\
	.attr  = __ATTR(_name, S_IRUGO, show_pma_counter, NULL),	\
	.index = (_offset) | ((_width) << 16),				\
562
	.attr_id = IB_PMA_PORT_COUNTERS_EXT,				\
563 564
}

565 566 567 568
/*
 * Get a Perfmgmt MAD block of data.
 * Returns error code or the number of bytes retrieved.
 */
569
static int get_perf_mad(struct ib_device *dev, int port_num, __be16 attr,
570
		void *data, int offset, size_t size)
L
Linus Torvalds 已提交
571
{
572 573
	struct ib_mad *in_mad;
	struct ib_mad *out_mad;
574 575
	size_t mad_size = sizeof(*out_mad);
	u16 out_mad_pkey_index = 0;
L
Linus Torvalds 已提交
576 577
	ssize_t ret;

K
Kamal Heib 已提交
578
	if (!dev->ops.process_mad)
579
		return -ENOSYS;
L
Linus Torvalds 已提交
580

581 582
	in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
	out_mad = kzalloc(sizeof(*out_mad), GFP_KERNEL);
L
Linus Torvalds 已提交
583 584 585 586 587 588 589 590 591
	if (!in_mad || !out_mad) {
		ret = -ENOMEM;
		goto out;
	}

	in_mad->mad_hdr.base_version  = 1;
	in_mad->mad_hdr.mgmt_class    = IB_MGMT_CLASS_PERF_MGMT;
	in_mad->mad_hdr.class_version = 1;
	in_mad->mad_hdr.method        = IB_MGMT_METHOD_GET;
592
	in_mad->mad_hdr.attr_id       = attr;
L
Linus Torvalds 已提交
593

594 595
	if (attr != IB_PMA_CLASS_PORT_INFO)
		in_mad->data[41] = port_num;	/* PortSelect field */
L
Linus Torvalds 已提交
596

597 598
	if ((dev->ops.process_mad(dev, IB_MAD_IGNORE_MKEY, port_num, NULL, NULL,
				  in_mad, out_mad, &mad_size,
K
Kamal Heib 已提交
599
				  &out_mad_pkey_index) &
L
Linus Torvalds 已提交
600 601 602 603 604
	     (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) !=
	    (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) {
		ret = -EINVAL;
		goto out;
	}
605 606 607 608 609 610 611 612
	memcpy(data, out_mad->data + offset, size);
	ret = size;
out:
	kfree(in_mad);
	kfree(out_mad);
	return ret;
}

613 614
static ssize_t show_pma_counter(struct ib_device *ibdev, u32 port_num,
				struct ib_port_attribute *attr, char *buf)
615 616 617 618 619
{
	struct port_table_attribute *tab_attr =
		container_of(attr, struct port_table_attribute, attr);
	int offset = tab_attr->index & 0xffff;
	int width  = (tab_attr->index >> 16) & 0xff;
620
	int ret;
621
	u8 data[8];
622
	int len;
623

624
	ret = get_perf_mad(ibdev, port_num, tab_attr->attr_id, &data,
625 626
			40 + offset / 8, sizeof(data));
	if (ret < 0)
627
		return ret;
L
Linus Torvalds 已提交
628 629 630

	switch (width) {
	case 4:
631 632
		len = sysfs_emit(buf, "%u\n",
				 (*data >> (4 - (offset % 8))) & 0xf);
L
Linus Torvalds 已提交
633 634
		break;
	case 8:
635
		len = sysfs_emit(buf, "%u\n", *data);
L
Linus Torvalds 已提交
636 637
		break;
	case 16:
638
		len = sysfs_emit(buf, "%u\n", be16_to_cpup((__be16 *)data));
L
Linus Torvalds 已提交
639 640
		break;
	case 32:
641
		len = sysfs_emit(buf, "%u\n", be32_to_cpup((__be32 *)data));
L
Linus Torvalds 已提交
642
		break;
643
	case 64:
644
		len = sysfs_emit(buf, "%llu\n", be64_to_cpup((__be64 *)data));
645
		break;
L
Linus Torvalds 已提交
646
	default:
647 648
		len = 0;
		break;
L
Linus Torvalds 已提交
649 650
	}

651
	return len;
L
Linus Torvalds 已提交
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
}

static PORT_PMA_ATTR(symbol_error		    ,  0, 16,  32);
static PORT_PMA_ATTR(link_error_recovery	    ,  1,  8,  48);
static PORT_PMA_ATTR(link_downed		    ,  2,  8,  56);
static PORT_PMA_ATTR(port_rcv_errors		    ,  3, 16,  64);
static PORT_PMA_ATTR(port_rcv_remote_physical_errors,  4, 16,  80);
static PORT_PMA_ATTR(port_rcv_switch_relay_errors   ,  5, 16,  96);
static PORT_PMA_ATTR(port_xmit_discards		    ,  6, 16, 112);
static PORT_PMA_ATTR(port_xmit_constraint_errors    ,  7,  8, 128);
static PORT_PMA_ATTR(port_rcv_constraint_errors	    ,  8,  8, 136);
static PORT_PMA_ATTR(local_link_integrity_errors    ,  9,  4, 152);
static PORT_PMA_ATTR(excessive_buffer_overrun_errors, 10,  4, 156);
static PORT_PMA_ATTR(VL15_dropped		    , 11, 16, 176);
static PORT_PMA_ATTR(port_xmit_data		    , 12, 32, 192);
static PORT_PMA_ATTR(port_rcv_data		    , 13, 32, 224);
static PORT_PMA_ATTR(port_xmit_packets		    , 14, 32, 256);
static PORT_PMA_ATTR(port_rcv_packets		    , 15, 32, 288);
670
static PORT_PMA_ATTR(port_xmit_wait		    ,  0, 32, 320);
L
Linus Torvalds 已提交
671

672 673 674 675 676 677 678 679 680 681 682 683
/*
 * Counters added by extended set
 */
static PORT_PMA_ATTR_EXT(port_xmit_data		    , 64,  64);
static PORT_PMA_ATTR_EXT(port_rcv_data		    , 64, 128);
static PORT_PMA_ATTR_EXT(port_xmit_packets	    , 64, 192);
static PORT_PMA_ATTR_EXT(port_rcv_packets	    , 64, 256);
static PORT_PMA_ATTR_EXT(unicast_xmit_packets	    , 64, 320);
static PORT_PMA_ATTR_EXT(unicast_rcv_packets	    , 64, 384);
static PORT_PMA_ATTR_EXT(multicast_xmit_packets	    , 64, 448);
static PORT_PMA_ATTR_EXT(multicast_rcv_packets	    , 64, 512);

L
Linus Torvalds 已提交
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
static struct attribute *pma_attrs[] = {
	&port_pma_attr_symbol_error.attr.attr,
	&port_pma_attr_link_error_recovery.attr.attr,
	&port_pma_attr_link_downed.attr.attr,
	&port_pma_attr_port_rcv_errors.attr.attr,
	&port_pma_attr_port_rcv_remote_physical_errors.attr.attr,
	&port_pma_attr_port_rcv_switch_relay_errors.attr.attr,
	&port_pma_attr_port_xmit_discards.attr.attr,
	&port_pma_attr_port_xmit_constraint_errors.attr.attr,
	&port_pma_attr_port_rcv_constraint_errors.attr.attr,
	&port_pma_attr_local_link_integrity_errors.attr.attr,
	&port_pma_attr_excessive_buffer_overrun_errors.attr.attr,
	&port_pma_attr_VL15_dropped.attr.attr,
	&port_pma_attr_port_xmit_data.attr.attr,
	&port_pma_attr_port_rcv_data.attr.attr,
	&port_pma_attr_port_xmit_packets.attr.attr,
	&port_pma_attr_port_rcv_packets.attr.attr,
701
	&port_pma_attr_port_xmit_wait.attr.attr,
L
Linus Torvalds 已提交
702 703 704
	NULL
};

705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
static struct attribute *pma_attrs_ext[] = {
	&port_pma_attr_symbol_error.attr.attr,
	&port_pma_attr_link_error_recovery.attr.attr,
	&port_pma_attr_link_downed.attr.attr,
	&port_pma_attr_port_rcv_errors.attr.attr,
	&port_pma_attr_port_rcv_remote_physical_errors.attr.attr,
	&port_pma_attr_port_rcv_switch_relay_errors.attr.attr,
	&port_pma_attr_port_xmit_discards.attr.attr,
	&port_pma_attr_port_xmit_constraint_errors.attr.attr,
	&port_pma_attr_port_rcv_constraint_errors.attr.attr,
	&port_pma_attr_local_link_integrity_errors.attr.attr,
	&port_pma_attr_excessive_buffer_overrun_errors.attr.attr,
	&port_pma_attr_VL15_dropped.attr.attr,
	&port_pma_attr_ext_port_xmit_data.attr.attr,
	&port_pma_attr_ext_port_rcv_data.attr.attr,
	&port_pma_attr_ext_port_xmit_packets.attr.attr,
721
	&port_pma_attr_port_xmit_wait.attr.attr,
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
	&port_pma_attr_ext_port_rcv_packets.attr.attr,
	&port_pma_attr_ext_unicast_rcv_packets.attr.attr,
	&port_pma_attr_ext_unicast_xmit_packets.attr.attr,
	&port_pma_attr_ext_multicast_rcv_packets.attr.attr,
	&port_pma_attr_ext_multicast_xmit_packets.attr.attr,
	NULL
};

static struct attribute *pma_attrs_noietf[] = {
	&port_pma_attr_symbol_error.attr.attr,
	&port_pma_attr_link_error_recovery.attr.attr,
	&port_pma_attr_link_downed.attr.attr,
	&port_pma_attr_port_rcv_errors.attr.attr,
	&port_pma_attr_port_rcv_remote_physical_errors.attr.attr,
	&port_pma_attr_port_rcv_switch_relay_errors.attr.attr,
	&port_pma_attr_port_xmit_discards.attr.attr,
	&port_pma_attr_port_xmit_constraint_errors.attr.attr,
	&port_pma_attr_port_rcv_constraint_errors.attr.attr,
	&port_pma_attr_local_link_integrity_errors.attr.attr,
	&port_pma_attr_excessive_buffer_overrun_errors.attr.attr,
	&port_pma_attr_VL15_dropped.attr.attr,
	&port_pma_attr_ext_port_xmit_data.attr.attr,
	&port_pma_attr_ext_port_rcv_data.attr.attr,
	&port_pma_attr_ext_port_xmit_packets.attr.attr,
	&port_pma_attr_ext_port_rcv_packets.attr.attr,
747
	&port_pma_attr_port_xmit_wait.attr.attr,
748 749 750
	NULL
};

751
static const struct attribute_group pma_group = {
L
Linus Torvalds 已提交
752 753 754 755
	.name  = "counters",
	.attrs  = pma_attrs
};

756
static const struct attribute_group pma_group_ext = {
757 758 759 760
	.name  = "counters",
	.attrs  = pma_attrs_ext
};

761
static const struct attribute_group pma_group_noietf = {
762 763 764 765
	.name  = "counters",
	.attrs  = pma_attrs_noietf
};

L
Linus Torvalds 已提交
766 767
static void ib_port_release(struct kobject *kobj)
{
768
	struct ib_port *port = container_of(kobj, struct ib_port, kobj);
L
Linus Torvalds 已提交
769 770
	int i;

771 772 773 774 775 776
	for (i = 0; i != ARRAY_SIZE(port->groups); i++)
		kfree(port->groups[i].attrs);
	if (port->hw_stats_data)
		kfree(port->hw_stats_data->stats);
	kfree(port->hw_stats_data);
	kfree(port);
L
Linus Torvalds 已提交
777 778
}

M
Matan Barak 已提交
779 780
static void ib_port_gid_attr_release(struct kobject *kobj)
{
781 782
	struct gid_attr_group *gid_attr_group =
		container_of(kobj, struct gid_attr_group, kobj);
M
Matan Barak 已提交
783 784
	int i;

785 786 787
	for (i = 0; i != ARRAY_SIZE(gid_attr_group->groups); i++)
		kfree(gid_attr_group->groups[i].attrs);
	kfree(gid_attr_group);
M
Matan Barak 已提交
788 789
}

L
Linus Torvalds 已提交
790 791 792 793 794 795
static struct kobj_type port_type = {
	.release       = ib_port_release,
	.sysfs_ops     = &port_sysfs_ops,
	.default_attrs = port_default_attrs
};

M
Matan Barak 已提交
796 797 798 799 800
static struct kobj_type gid_attr_type = {
	.sysfs_ops      = &gid_attr_sysfs_ops,
	.release        = ib_port_gid_attr_release
};

801 802 803 804
/*
 * Figure out which counter table to use depending on
 * the device capabilities.
 */
805 806
static const struct attribute_group *get_counter_table(struct ib_device *dev,
						       int port_num)
807 808 809
{
	struct ib_class_port_info cpi;

810
	if (get_perf_mad(dev, port_num, IB_PMA_CLASS_PORT_INFO,
811
				&cpi, 40, sizeof(cpi)) >= 0) {
812
		if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH)
813 814 815
			/* We have extended counters */
			return &pma_group_ext;

816
		if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH_NOIETF)
817 818 819 820 821 822 823 824
			/* But not the IETF ones */
			return &pma_group_noietf;
	}

	/* Fall back to normal counters */
	return &pma_group;
}

825
static int update_hw_stats(struct ib_device *dev, struct rdma_hw_stats *stats,
826
			   u32 port_num, int index)
827 828 829 830 831
{
	int ret;

	if (time_is_after_eq_jiffies(stats->timestamp + stats->lifespan))
		return 0;
K
Kamal Heib 已提交
832
	ret = dev->ops.get_hw_stats(dev, stats, port_num, index);
833 834 835 836 837 838 839 840
	if (ret < 0)
		return ret;
	if (ret == stats->num_counters)
		stats->timestamp = jiffies;

	return 0;
}

841 842
static int print_hw_stat(struct ib_device *dev, int port_num,
			 struct rdma_hw_stats *stats, int index, char *buf)
843
{
844 845
	u64 v = rdma_counter_get_hwstat_value(dev, port_num, index);

846
	return sysfs_emit(buf, "%llu\n", stats->value[index] + v);
847 848
}

849 850 851
static ssize_t show_hw_stats(struct ib_device *ibdev,
			     struct rdma_hw_stats *stats, unsigned int index,
			     unsigned int port_num, char *buf)
852 853 854
{
	int ret;

855
	mutex_lock(&stats->lock);
856
	ret = update_hw_stats(ibdev, stats, port_num, index);
857
	if (ret)
858
		goto unlock;
859
	ret = print_hw_stat(ibdev, port_num, stats, index, buf);
860 861 862 863
unlock:
	mutex_unlock(&stats->lock);

	return ret;
864 865
}

866 867 868
static ssize_t show_stats_lifespan(struct ib_device *ibdev,
				   struct rdma_hw_stats *stats,
				   unsigned int index, unsigned int port_num,
869 870 871 872
				   char *buf)
{
	int msecs;

873 874 875 876
	mutex_lock(&stats->lock);
	msecs = jiffies_to_msecs(stats->lifespan);
	mutex_unlock(&stats->lock);

877
	return sysfs_emit(buf, "%d\n", msecs);
878 879
}

880 881 882 883
static ssize_t set_stats_lifespan(struct ib_device *ibdev,
				   struct rdma_hw_stats *stats,
				   unsigned int index, unsigned int port_num,
				   const char *buf, size_t count)
884 885 886 887 888 889 890 891 892 893 894
{
	int msecs;
	int jiffies;
	int ret;

	ret = kstrtoint(buf, 10, &msecs);
	if (ret)
		return ret;
	if (msecs < 0 || msecs > 10000)
		return -EINVAL;
	jiffies = msecs_to_jiffies(msecs);
895 896 897 898 899

	mutex_lock(&stats->lock);
	stats->lifespan = jiffies;
	mutex_unlock(&stats->lock);

900 901 902
	return count;
}

903 904
static struct hw_stats_device_data *
alloc_hw_stats_device(struct ib_device *ibdev)
905
{
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
	struct hw_stats_device_data *data;
	struct rdma_hw_stats *stats;

	if (!ibdev->ops.alloc_hw_device_stats)
		return ERR_PTR(-EOPNOTSUPP);
	stats = ibdev->ops.alloc_hw_device_stats(ibdev);
	if (!stats)
		return ERR_PTR(-ENOMEM);
	if (!stats->names || stats->num_counters <= 0)
		goto err_free_stats;

	/*
	 * Two extra attribue elements here, one for the lifespan entry and
	 * one to NULL terminate the list for the sysfs core code
	 */
	data = kzalloc(struct_size(data, attrs, stats->num_counters + 1),
		       GFP_KERNEL);
	if (!data)
		goto err_free_stats;
	data->group.attrs = kcalloc(stats->num_counters + 2,
				    sizeof(*data->group.attrs), GFP_KERNEL);
	if (!data->group.attrs)
		goto err_free_data;
929

930 931 932 933
	mutex_init(&stats->lock);
	data->group.name = "hw_counters";
	data->stats = stats;
	return data;
934

935 936 937 938 939
err_free_data:
	kfree(data);
err_free_stats:
	kfree(stats);
	return ERR_PTR(-ENOMEM);
940 941
}

942
void ib_device_release_hw_stats(struct hw_stats_device_data *data)
943
{
944 945 946 947
	kfree(data->group.attrs);
	kfree(data->stats);
	kfree(data);
}
948

949
int ib_setup_device_attrs(struct ib_device *ibdev)
950 951 952 953
{
	struct hw_stats_device_attribute *attr;
	struct hw_stats_device_data *data;
	int i, ret;
954

955
	data = alloc_hw_stats_device(ibdev);
956 957 958
	if (IS_ERR(data)) {
		if (PTR_ERR(data) == -EOPNOTSUPP)
			return 0;
959
		return PTR_ERR(data);
960 961
	}
	ibdev->hw_stats_data = data;
962

963 964 965 966
	ret = ibdev->ops.get_hw_stats(ibdev, data->stats, 0,
				      data->stats->num_counters);
	if (ret != data->stats->num_counters) {
		if (WARN_ON(ret >= 0))
967 968
			return -EINVAL;
		return ret;
969
	}
970

971
	data->stats->timestamp = jiffies;
972

973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
	for (i = 0; i < data->stats->num_counters; i++) {
		attr = &data->attrs[i];
		sysfs_attr_init(&attr->attr.attr);
		attr->attr.attr.name = data->stats->names[i];
		attr->attr.attr.mode = 0444;
		attr->attr.show = hw_stat_device_show;
		attr->show = show_hw_stats;
		data->group.attrs[i] = &attr->attr.attr;
	}

	attr = &data->attrs[i];
	sysfs_attr_init(&attr->attr.attr);
	attr->attr.attr.name = "lifespan";
	attr->attr.attr.mode = 0644;
	attr->attr.show = hw_stat_device_show;
	attr->show = show_stats_lifespan;
	attr->attr.store = hw_stat_device_store;
	attr->store = set_stats_lifespan;
	data->group.attrs[i] = &attr->attr.attr;
992 993 994 995 996 997 998
	for (i = 0; i != ARRAY_SIZE(ibdev->groups); i++)
		if (!ibdev->groups[i]) {
			ibdev->groups[i] = &data->group;
			return 0;
		}
	WARN(true, "struct ib_device->groups is too small");
	return -EINVAL;
999 1000
}

1001 1002
static struct hw_stats_port_data *
alloc_hw_stats_port(struct ib_port *port, struct attribute_group *group)
1003
{
1004 1005
	struct ib_device *ibdev = port->ibdev;
	struct hw_stats_port_data *data;
1006 1007
	struct rdma_hw_stats *stats;

1008 1009 1010
	if (!ibdev->ops.alloc_hw_port_stats)
		return ERR_PTR(-EOPNOTSUPP);
	stats = ibdev->ops.alloc_hw_port_stats(port->ibdev, port->port_num);
1011
	if (!stats)
1012
		return ERR_PTR(-ENOMEM);
1013
	if (!stats->names || stats->num_counters <= 0)
1014
		goto err_free_stats;
1015

1016 1017 1018 1019
	/*
	 * Two extra attribue elements here, one for the lifespan entry and
	 * one to NULL terminate the list for the sysfs core code
	 */
1020
	data = kzalloc(struct_size(data, attrs, stats->num_counters + 1),
1021
		       GFP_KERNEL);
1022
	if (!data)
1023
		goto err_free_stats;
1024 1025 1026
	group->attrs = kcalloc(stats->num_counters + 2,
				    sizeof(*group->attrs), GFP_KERNEL);
	if (!group->attrs)
1027
		goto err_free_data;
1028

1029
	mutex_init(&stats->lock);
1030
	group->name = "hw_counters";
1031 1032
	data->stats = stats;
	return data;
1033

1034 1035 1036 1037 1038 1039
err_free_data:
	kfree(data);
err_free_stats:
	kfree(stats);
	return ERR_PTR(-ENOMEM);
}
1040

1041 1042
static int setup_hw_port_stats(struct ib_port *port,
			       struct attribute_group *group)
1043 1044 1045 1046
{
	struct hw_stats_port_attribute *attr;
	struct hw_stats_port_data *data;
	int i, ret;
1047

1048
	data = alloc_hw_stats_port(port, group);
1049 1050 1051 1052 1053 1054 1055 1056
	if (IS_ERR(data))
		return PTR_ERR(data);

	ret = port->ibdev->ops.get_hw_stats(port->ibdev, data->stats,
					    port->port_num,
					    data->stats->num_counters);
	if (ret != data->stats->num_counters) {
		if (WARN_ON(ret >= 0))
1057 1058
			return -EINVAL;
		return ret;
1059
	}
1060

1061 1062 1063 1064 1065 1066 1067 1068 1069
	data->stats->timestamp = jiffies;

	for (i = 0; i < data->stats->num_counters; i++) {
		attr = &data->attrs[i];
		sysfs_attr_init(&attr->attr.attr);
		attr->attr.attr.name = data->stats->names[i];
		attr->attr.attr.mode = 0444;
		attr->attr.show = hw_stat_port_show;
		attr->show = show_hw_stats;
1070
		group->attrs[i] = &attr->attr.attr;
1071 1072
	}

1073 1074 1075 1076 1077 1078 1079 1080
	attr = &data->attrs[i];
	sysfs_attr_init(&attr->attr.attr);
	attr->attr.attr.name = "lifespan";
	attr->attr.attr.mode = 0644;
	attr->attr.show = hw_stat_port_show;
	attr->show = show_stats_lifespan;
	attr->attr.store = hw_stat_port_store;
	attr->store = set_stats_lifespan;
1081
	group->attrs[i] = &attr->attr.attr;
1082 1083 1084

	port->hw_stats_data = data;
	return 0;
1085 1086
}

1087 1088 1089
struct rdma_hw_stats *ib_get_hw_stats_port(struct ib_device *ibdev,
					   u32 port_num)
{
1090 1091
	if (!ibdev->port_data || !rdma_is_port_valid(ibdev, port_num) ||
	    !ibdev->port_data[port_num].sysfs->hw_stats_data)
1092
		return NULL;
1093
	return ibdev->port_data[port_num].sysfs->hw_stats_data->stats;
1094 1095
}

1096 1097 1098 1099 1100
static int
alloc_port_table_group(const char *name, struct attribute_group *group,
		       struct port_table_attribute *attrs, size_t num,
		       ssize_t (*show)(struct ib_device *ibdev, u32 port_num,
				       struct ib_port_attribute *, char *buf))
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
{
	struct attribute **attr_list;
	int i;

	attr_list = kcalloc(num + 1, sizeof(*attr_list), GFP_KERNEL);
	if (!attr_list)
		return -ENOMEM;

	for (i = 0; i < num; i++) {
		struct port_table_attribute *element = &attrs[i];

		if (snprintf(element->name, sizeof(element->name), "%d", i) >=
		    sizeof(element->name))
			goto err;

		sysfs_attr_init(&element->attr.attr);
		element->attr.attr.name = element->name;
		element->attr.attr.mode = 0444;
		element->attr.show = show;
		element->index = i;

		attr_list[i] = &element->attr.attr;
	}
	group->name = name;
	group->attrs = attr_list;
	return 0;
err:
	kfree(attr_list);
	return -EINVAL;
}

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
/*
 * Create the sysfs:
 *  ibp0s9/ports/XX/gid_attrs/{ndevs,types}/YYY
 * YYY is the gid table index in decimal
 */
static int setup_gid_attrs(struct ib_port *port,
			   const struct ib_port_attr *attr)
{
	struct gid_attr_group *gid_attr_group;
	int ret;

1143 1144 1145
	gid_attr_group = kzalloc(struct_size(gid_attr_group, attrs_list,
					     attr->gid_tbl_len * 2),
				 GFP_KERNEL);
1146 1147 1148
	if (!gid_attr_group)
		return -ENOMEM;
	gid_attr_group->port = port;
1149
	kobject_init(&gid_attr_group->kobj, &gid_attr_type);
1150

1151 1152 1153 1154
	ret = alloc_port_table_group("ndevs", &gid_attr_group->groups[0],
				     gid_attr_group->attrs_list,
				     attr->gid_tbl_len,
				     show_port_gid_attr_ndev);
1155
	if (ret)
1156 1157
		goto err_put;
	gid_attr_group->groups_list[0] = &gid_attr_group->groups[0];
1158

1159 1160 1161 1162
	ret = alloc_port_table_group(
		"types", &gid_attr_group->groups[1],
		gid_attr_group->attrs_list + attr->gid_tbl_len,
		attr->gid_tbl_len, show_port_gid_attr_gid_type);
1163
	if (ret)
1164 1165
		goto err_put;
	gid_attr_group->groups_list[1] = &gid_attr_group->groups[1];
1166

1167 1168 1169 1170 1171 1172 1173
	ret = kobject_add(&gid_attr_group->kobj, &port->kobj, "gid_attrs");
	if (ret)
		goto err_put;
	ret = sysfs_create_groups(&gid_attr_group->kobj,
				  gid_attr_group->groups_list);
	if (ret)
		goto err_del;
1174 1175 1176
	port->gid_attr_group = gid_attr_group;
	return 0;

1177 1178 1179
err_del:
	kobject_del(&gid_attr_group->kobj);
err_put:
1180 1181 1182 1183 1184 1185 1186 1187
	kobject_put(&gid_attr_group->kobj);
	return ret;
}

static void destroy_gid_attrs(struct ib_port *port)
{
	struct gid_attr_group *gid_attr_group = port->gid_attr_group;

1188 1189 1190 1191
	if (!gid_attr_group)
		return;
	sysfs_remove_groups(&gid_attr_group->kobj, gid_attr_group->groups_list);
	kobject_del(&gid_attr_group->kobj);
1192 1193 1194
	kobject_put(&gid_attr_group->kobj);
}

1195 1196 1197 1198 1199 1200
/*
 * Create the sysfs:
 *  ibp0s9/ports/XX/{gids,pkeys,counters}/YYY
 */
static struct ib_port *setup_port(struct ib_core_device *coredev, int port_num,
				  const struct ib_port_attr *attr)
L
Linus Torvalds 已提交
1201
{
1202
	struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);
1203
	bool is_full_dev = &device->coredev == coredev;
1204
	const struct attribute_group **cur_group;
L
Linus Torvalds 已提交
1205 1206 1207
	struct ib_port *p;
	int ret;

1208 1209 1210
	p = kzalloc(struct_size(p, attrs_list,
				attr->gid_tbl_len + attr->pkey_tbl_len),
		    GFP_KERNEL);
L
Linus Torvalds 已提交
1211
	if (!p)
1212 1213 1214 1215
		return ERR_PTR(-ENOMEM);
	p->ibdev = device;
	p->port_num = port_num;
	kobject_init(&p->kobj, &port_type);
L
Linus Torvalds 已提交
1216

1217 1218 1219
	cur_group = p->groups_list;
	ret = alloc_port_table_group("gids", &p->groups[0], p->attrs_list,
				     attr->gid_tbl_len, show_port_gid);
1220
	if (ret)
1221
		goto err_put;
1222
	*cur_group++ = &p->groups[0];
L
Linus Torvalds 已提交
1223

1224 1225 1226 1227
	if (attr->pkey_tbl_len) {
		ret = alloc_port_table_group("pkeys", &p->groups[1],
					     p->attrs_list + attr->gid_tbl_len,
					     attr->pkey_tbl_len, show_port_pkey);
1228
		if (ret)
1229
			goto err_put;
1230
		*cur_group++ = &p->groups[1];
1231
	}
L
Linus Torvalds 已提交
1232

1233 1234 1235 1236 1237 1238
	/*
	 * If port == 0, it means hw_counters are per device and not per
	 * port, so holder should be device. Therefore skip per port
	 * counter initialization.
	 */
	if (port_num && is_full_dev) {
1239
		ret = setup_hw_port_stats(p, &p->groups[2]);
1240
		if (ret && ret != -EOPNOTSUPP)
1241 1242 1243
			goto err_put;
		if (!ret)
			*cur_group++ = &p->groups[2];
1244
	}
L
Linus Torvalds 已提交
1245

1246 1247 1248 1249 1250 1251 1252 1253 1254
	if (device->ops.process_mad && is_full_dev)
		*cur_group++ = get_counter_table(device, port_num);

	ret = kobject_add(&p->kobj, coredev->ports_kobj, "%d", port_num);
	if (ret)
		goto err_put;
	ret = sysfs_create_groups(&p->kobj, p->groups_list);
	if (ret)
		goto err_del;
1255

1256
	list_add_tail(&p->kobj.entry, &coredev->port_list);
1257 1258
	if (device->port_data && is_full_dev)
		device->port_data[port_num].sysfs = p;
L
Linus Torvalds 已提交
1259

1260
	return p;
L
Linus Torvalds 已提交
1261

1262 1263
err_del:
	kobject_del(&p->kobj);
L
Linus Torvalds 已提交
1264
err_put:
1265
	kobject_put(&p->kobj);
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
	return ERR_PTR(ret);
}

static void destroy_port(struct ib_port *port)
{
	if (port->ibdev->port_data &&
	    port->ibdev->port_data[port->port_num].sysfs == port)
		port->ibdev->port_data[port->port_num].sysfs = NULL;
	list_del(&port->kobj.entry);
	sysfs_remove_groups(&port->kobj, port->groups_list);
	kobject_del(&port->kobj);
	kobject_put(&port->kobj);
L
Linus Torvalds 已提交
1278 1279
}

1280
static const char *node_type_string(int node_type)
L
Linus Torvalds 已提交
1281
{
1282
	switch (node_type) {
1283
	case RDMA_NODE_IB_CA:
1284 1285 1286 1287 1288
		return "CA";
	case RDMA_NODE_IB_SWITCH:
		return "switch";
	case RDMA_NODE_IB_ROUTER:
		return "router";
1289
	case RDMA_NODE_RNIC:
1290
		return "RNIC";
1291
	case RDMA_NODE_USNIC:
1292
		return "usNIC";
1293
	case RDMA_NODE_USNIC_UDP:
1294
		return "usNIC UDP";
1295
	case RDMA_NODE_UNSPECIFIED:
1296
		return "unspecified";
L
Linus Torvalds 已提交
1297
	}
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
	return "<unknown>";
}

static ssize_t node_type_show(struct device *device,
			      struct device_attribute *attr, char *buf)
{
	struct ib_device *dev = rdma_device_to_ibdev(device);

	return sysfs_emit(buf, "%d: %s\n", dev->node_type,
			  node_type_string(dev->node_type));
L
Linus Torvalds 已提交
1308
}
1309
static DEVICE_ATTR_RO(node_type);
L
Linus Torvalds 已提交
1310

1311
static ssize_t sys_image_guid_show(struct device *device,
1312
				   struct device_attribute *dev_attr, char *buf)
L
Linus Torvalds 已提交
1313
{
1314
	struct ib_device *dev = rdma_device_to_ibdev(device);
1315
	__be16 *guid = (__be16 *)&dev->attrs.sys_image_guid;
L
Linus Torvalds 已提交
1316

1317 1318 1319 1320 1321
	return sysfs_emit(buf, "%04x:%04x:%04x:%04x\n",
			  be16_to_cpu(guid[0]),
			  be16_to_cpu(guid[1]),
			  be16_to_cpu(guid[2]),
			  be16_to_cpu(guid[3]));
L
Linus Torvalds 已提交
1322
}
1323
static DEVICE_ATTR_RO(sys_image_guid);
L
Linus Torvalds 已提交
1324

1325
static ssize_t node_guid_show(struct device *device,
1326
			      struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
1327
{
1328
	struct ib_device *dev = rdma_device_to_ibdev(device);
1329
	__be16 *node_guid = (__be16 *)&dev->node_guid;
L
Linus Torvalds 已提交
1330

1331
	return sysfs_emit(buf, "%04x:%04x:%04x:%04x\n",
1332 1333 1334 1335
			  be16_to_cpu(node_guid[0]),
			  be16_to_cpu(node_guid[1]),
			  be16_to_cpu(node_guid[2]),
			  be16_to_cpu(node_guid[3]));
L
Linus Torvalds 已提交
1336
}
1337
static DEVICE_ATTR_RO(node_guid);
L
Linus Torvalds 已提交
1338

1339
static ssize_t node_desc_show(struct device *device,
1340
			      struct device_attribute *attr, char *buf)
1341
{
1342
	struct ib_device *dev = rdma_device_to_ibdev(device);
1343

1344
	return sysfs_emit(buf, "%.64s\n", dev->node_desc);
1345 1346
}

1347 1348 1349
static ssize_t node_desc_store(struct device *device,
			       struct device_attribute *attr,
			       const char *buf, size_t count)
1350
{
1351
	struct ib_device *dev = rdma_device_to_ibdev(device);
1352 1353 1354
	struct ib_device_modify desc = {};
	int ret;

K
Kamal Heib 已提交
1355
	if (!dev->ops.modify_device)
1356
		return -EOPNOTSUPP;
1357

1358
	memcpy(desc.node_desc, buf, min_t(int, count, IB_DEVICE_NODE_DESC_MAX));
1359 1360 1361 1362 1363 1364
	ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
	if (ret)
		return ret;

	return count;
}
1365
static DEVICE_ATTR_RW(node_desc);
1366

1367
static ssize_t fw_ver_show(struct device *device, struct device_attribute *attr,
1368 1369
			   char *buf)
{
1370
	struct ib_device *dev = rdma_device_to_ibdev(device);
1371 1372 1373
	char version[IB_FW_VERSION_NAME_MAX] = {};

	ib_get_device_fw_str(dev, version);
1374

1375
	return sysfs_emit(buf, "%s\n", version);
1376
}
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
static DEVICE_ATTR_RO(fw_ver);

static struct attribute *ib_dev_attrs[] = {
	&dev_attr_node_type.attr,
	&dev_attr_node_guid.attr,
	&dev_attr_sys_image_guid.attr,
	&dev_attr_fw_ver.attr,
	&dev_attr_node_desc.attr,
	NULL,
};
1387

1388
const struct attribute_group ib_dev_attr_group = {
1389
	.attrs = ib_dev_attrs,
L
Linus Torvalds 已提交
1390 1391
};

1392
void ib_free_port_attrs(struct ib_core_device *coredev)
1393 1394 1395
{
	struct kobject *p, *t;

1396
	list_for_each_entry_safe(p, t, &coredev->port_list, entry) {
1397
		struct ib_port *port = container_of(p, struct ib_port, kobj);
1398

1399
		destroy_gid_attrs(port);
1400
		destroy_port(port);
1401 1402
	}

1403
	kobject_put(coredev->ports_kobj);
1404 1405
}

1406
int ib_setup_port_attrs(struct ib_core_device *coredev)
L
Linus Torvalds 已提交
1407
{
1408
	struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);
1409 1410
	bool is_full_dev = &device->coredev == coredev;
	u32 port_num;
L
Linus Torvalds 已提交
1411 1412
	int ret;

1413 1414 1415
	coredev->ports_kobj = kobject_create_and_add("ports",
						     &coredev->dev.kobj);
	if (!coredev->ports_kobj)
1416
		return -ENOMEM;
L
Linus Torvalds 已提交
1417

1418 1419 1420 1421 1422
	rdma_for_each_port (device, port_num) {
		struct ib_port_attr attr;
		struct ib_port *port;

		ret = ib_query_port(device, port_num, &attr);
L
Linus Torvalds 已提交
1423 1424 1425
		if (ret)
			goto err_put;

1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
		port = setup_port(coredev, port_num, &attr);
		if (IS_ERR(port)) {
			ret = PTR_ERR(port);
			goto err_put;
		}

		ret = setup_gid_attrs(port, &attr);
		if (ret)
			goto err_put;

		if (device->ops.init_port && is_full_dev) {
			ret = device->ops.init_port(device, port_num,
						    &port->kobj);
			if (ret)
				goto err_put;
		}
	}
L
Linus Torvalds 已提交
1443 1444 1445
	return 0;

err_put:
1446
	ib_free_port_attrs(coredev);
L
Linus Torvalds 已提交
1447 1448 1449
	return ret;
}

1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
/**
 * ib_port_register_module_stat - add module counters under relevant port
 *  of IB device.
 *
 * @device: IB device to add counters
 * @port_num: valid port number
 * @kobj: pointer to the kobject to initialize
 * @ktype: pointer to the ktype for this kobject.
 * @name: the name of the kobject
 */
1460
int ib_port_register_module_stat(struct ib_device *device, u32 port_num,
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
				 struct kobject *kobj, struct kobj_type *ktype,
				 const char *name)
{
	struct kobject *p, *t;
	int ret;

	list_for_each_entry_safe(p, t, &device->coredev.port_list, entry) {
		struct ib_port *port = container_of(p, struct ib_port, kobj);

		if (port->port_num != port_num)
			continue;

		ret = kobject_init_and_add(kobj, ktype, &port->kobj, "%s",
					   name);
1475 1476
		if (ret) {
			kobject_put(kobj);
1477
			return ret;
1478
		}
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
	}

	return 0;
}
EXPORT_SYMBOL(ib_port_register_module_stat);

/**
 * ib_port_unregister_module_stat - release module counters
 * @kobj: pointer to the kobject to release
 */
void ib_port_unregister_module_stat(struct kobject *kobj)
{
	kobject_put(kobj);
}
EXPORT_SYMBOL(ib_port_unregister_module_stat);