sysfs.c 39.6 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 136 137 138 139
	return port_attr->store(p->ibdev, p->port_num, port_attr, buf, count);
}

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);
140

141
static const struct sysfs_ops port_sysfs_ops = {
142 143
	.show	= port_attr_show,
	.store	= port_attr_store
L
Linus Torvalds 已提交
144 145
};

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
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);
}

170 171
static ssize_t hw_stat_port_show(struct ib_device *ibdev, u32 port_num,
				 struct ib_port_attribute *attr, char *buf)
172 173 174
{
	struct hw_stats_port_attribute *stat_attr =
		container_of(attr, struct hw_stats_port_attribute, attr);
175
	struct ib_port *port = ibdev->port_data[port_num].sysfs;
176

177
	return stat_attr->show(ibdev, port->hw_stats_data->stats,
178 179 180 181
			       stat_attr - port->hw_stats_data->attrs,
			       port->port_num, buf);
}

182 183 184
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)
185 186 187
{
	struct hw_stats_port_attribute *stat_attr =
		container_of(attr, struct hw_stats_port_attribute, attr);
188
	struct ib_port *port = ibdev->port_data[port_num].sysfs;
189

190
	return stat_attr->store(ibdev, port->hw_stats_data->stats,
191 192 193 194
				stat_attr - port->hw_stats_data->attrs,
				port->port_num, buf, count);
}

M
Matan Barak 已提交
195 196 197
static ssize_t gid_attr_show(struct kobject *kobj,
			     struct attribute *attr, char *buf)
{
198 199
	struct ib_port_attribute *port_attr =
		container_of(attr, struct ib_port_attribute, attr);
M
Matan Barak 已提交
200 201 202 203 204 205
	struct ib_port *p = container_of(kobj, struct gid_attr_group,
					 kobj)->port;

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

206
	return port_attr->show(p->ibdev, p->port_num, port_attr, buf);
M
Matan Barak 已提交
207 208 209 210 211 212
}

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

213 214
static ssize_t state_show(struct ib_device *ibdev, u32 port_num,
			  struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
215 216 217 218 219 220 221 222 223 224 225 226 227
{
	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"
	};

228
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
229 230 231
	if (ret)
		return ret;

232 233 234 235 236
	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 已提交
237 238
}

239 240
static ssize_t lid_show(struct ib_device *ibdev, u32 port_num,
			struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
241 242 243 244
{
	struct ib_port_attr attr;
	ssize_t ret;

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

249
	return sysfs_emit(buf, "0x%x\n", attr.lid);
L
Linus Torvalds 已提交
250 251
}

252 253
static ssize_t lid_mask_count_show(struct ib_device *ibdev, u32 port_num,
				   struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
254 255 256 257
{
	struct ib_port_attr attr;
	ssize_t ret;

258
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
259 260 261
	if (ret)
		return ret;

262
	return sysfs_emit(buf, "%u\n", attr.lmc);
L
Linus Torvalds 已提交
263 264
}

265 266
static ssize_t sm_lid_show(struct ib_device *ibdev, u32 port_num,
			   struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
267 268 269 270
{
	struct ib_port_attr attr;
	ssize_t ret;

271
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
272 273 274
	if (ret)
		return ret;

275
	return sysfs_emit(buf, "0x%x\n", attr.sm_lid);
L
Linus Torvalds 已提交
276 277
}

278 279
static ssize_t sm_sl_show(struct ib_device *ibdev, u32 port_num,
			  struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
280 281 282 283
{
	struct ib_port_attr attr;
	ssize_t ret;

284
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
285 286 287
	if (ret)
		return ret;

288
	return sysfs_emit(buf, "%u\n", attr.sm_sl);
L
Linus Torvalds 已提交
289 290
}

291 292
static ssize_t cap_mask_show(struct ib_device *ibdev, u32 port_num,
			     struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
293 294 295 296
{
	struct ib_port_attr attr;
	ssize_t ret;

297
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
298 299 300
	if (ret)
		return ret;

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

304 305
static ssize_t rate_show(struct ib_device *ibdev, u32 port_num,
			 struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
306 307 308
{
	struct ib_port_attr attr;
	char *speed = "";
309
	int rate;		/* in deci-Gb/sec */
L
Linus Torvalds 已提交
310 311
	ssize_t ret;

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

	switch (attr.active_speed) {
317
	case IB_SPEED_DDR:
318
		speed = " DDR";
R
Roland Dreier 已提交
319
		rate = 50;
320
		break;
321
	case IB_SPEED_QDR:
322
		speed = " QDR";
R
Roland Dreier 已提交
323
		rate = 100;
324
		break;
325
	case IB_SPEED_FDR10:
326
		speed = " FDR10";
R
Roland Dreier 已提交
327
		rate = 100;
328
		break;
329
	case IB_SPEED_FDR:
330
		speed = " FDR";
R
Roland Dreier 已提交
331
		rate = 140;
332
		break;
333
	case IB_SPEED_EDR:
334
		speed = " EDR";
R
Roland Dreier 已提交
335
		rate = 250;
336
		break;
N
Noa Osherovich 已提交
337 338 339 340
	case IB_SPEED_HDR:
		speed = " HDR";
		rate = 500;
		break;
341 342 343 344
	case IB_SPEED_NDR:
		speed = " NDR";
		rate = 1000;
		break;
345 346
	case IB_SPEED_SDR:
	default:		/* default to SDR for invalid rates */
347
		speed = " SDR";
348 349
		rate = 25;
		break;
L
Linus Torvalds 已提交
350 351
	}

352
	rate *= ib_width_enum_to_int(attr.active_width);
L
Linus Torvalds 已提交
353 354 355
	if (rate < 0)
		return -EINVAL;

356 357 358
	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 已提交
359 360
}

361 362
static const char *phys_state_to_str(enum ib_port_phys_state phys_state)
{
363
	static const char *phys_state_str[] = {
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
		"<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>";
}

379 380
static ssize_t phys_state_show(struct ib_device *ibdev, u32 port_num,
			       struct ib_port_attribute *unused, char *buf)
L
Linus Torvalds 已提交
381 382 383 384 385
{
	struct ib_port_attr attr;

	ssize_t ret;

386
	ret = ib_query_port(ibdev, port_num, &attr);
L
Linus Torvalds 已提交
387 388 389
	if (ret)
		return ret;

390
	return sysfs_emit(buf, "%u: %s\n", attr.phys_state,
391
			  phys_state_to_str(attr.phys_state));
L
Linus Torvalds 已提交
392 393
}

394 395
static ssize_t link_layer_show(struct ib_device *ibdev, u32 port_num,
			       struct ib_port_attribute *unused, char *buf)
396
{
397 398
	const char *output;

399
	switch (rdma_port_get_link_layer(ibdev, port_num)) {
400
	case IB_LINK_LAYER_INFINIBAND:
401 402
		output = "InfiniBand";
		break;
403
	case IB_LINK_LAYER_ETHERNET:
404 405
		output = "Ethernet";
		break;
406
	default:
407 408
		output = "Unknown";
		break;
409
	}
410 411

	return sysfs_emit(buf, "%s\n", output);
412 413
}

414 415 416 417 418 419 420 421 422
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 已提交
423 424

static struct attribute *port_default_attrs[] = {
425 426 427 428 429 430 431 432 433
	&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 已提交
434 435 436
	NULL
};

437
static ssize_t print_ndev(const struct ib_gid_attr *gid_attr, char *buf)
M
Matan Barak 已提交
438
{
439
	struct net_device *ndev;
440
	int ret = -EINVAL;
441 442 443 444

	rcu_read_lock();
	ndev = rcu_dereference(gid_attr->ndev);
	if (ndev)
445
		ret = sysfs_emit(buf, "%s\n", ndev->name);
446 447
	rcu_read_unlock();
	return ret;
M
Matan Barak 已提交
448 449
}

450
static ssize_t print_gid_type(const struct ib_gid_attr *gid_attr, char *buf)
M
Matan Barak 已提交
451
{
452 453
	return sysfs_emit(buf, "%s\n",
			  ib_cache_gid_type_str(gid_attr->gid_type));
M
Matan Barak 已提交
454 455
}

456
static ssize_t _show_port_gid_attr(
457 458
	struct ib_device *ibdev, u32 port_num, struct ib_port_attribute *attr,
	char *buf,
459
	ssize_t (*print)(const struct ib_gid_attr *gid_attr, char *buf))
M
Matan Barak 已提交
460 461 462
{
	struct port_table_attribute *tab_attr =
		container_of(attr, struct port_table_attribute, attr);
463
	const struct ib_gid_attr *gid_attr;
M
Matan Barak 已提交
464 465
	ssize_t ret;

466
	gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);
467
	if (IS_ERR(gid_attr))
468 469
		/* -EINVAL is returned for user space compatibility reasons. */
		return -EINVAL;
M
Matan Barak 已提交
470

471 472
	ret = print(gid_attr, buf);
	rdma_put_gid_attr(gid_attr);
M
Matan Barak 已提交
473 474 475
	return ret;
}

476 477
static ssize_t show_port_gid(struct ib_device *ibdev, u32 port_num,
			     struct ib_port_attribute *attr, char *buf)
L
Linus Torvalds 已提交
478 479 480
{
	struct port_table_attribute *tab_attr =
		container_of(attr, struct port_table_attribute, attr);
481
	const struct ib_gid_attr *gid_attr;
482
	int len;
L
Linus Torvalds 已提交
483

484
	gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);
485 486 487 488 489 490 491 492 493 494 495 496
	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.
		 */
497
		return sysfs_emit(buf, "%pI6\n", zgid.raw);
498 499
	}

500
	len = sysfs_emit(buf, "%pI6\n", gid_attr->gid.raw);
501
	rdma_put_gid_attr(gid_attr);
502
	return len;
L
Linus Torvalds 已提交
503 504
}

505 506 507
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 已提交
508
{
509
	return _show_port_gid_attr(ibdev, port_num, attr, buf, print_ndev);
M
Matan Barak 已提交
510 511
}

512 513 514
static ssize_t show_port_gid_attr_gid_type(struct ib_device *ibdev,
					   u32 port_num,
					   struct ib_port_attribute *attr,
M
Matan Barak 已提交
515 516
					   char *buf)
{
517
	return _show_port_gid_attr(ibdev, port_num, attr, buf, print_gid_type);
M
Matan Barak 已提交
518 519
}

520 521
static ssize_t show_port_pkey(struct ib_device *ibdev, u32 port_num,
			      struct ib_port_attribute *attr, char *buf)
L
Linus Torvalds 已提交
522 523 524 525
{
	struct port_table_attribute *tab_attr =
		container_of(attr, struct port_table_attribute, attr);
	u16 pkey;
526
	int ret;
L
Linus Torvalds 已提交
527

528
	ret = ib_query_pkey(ibdev, port_num, tab_attr->index, &pkey);
L
Linus Torvalds 已提交
529 530 531
	if (ret)
		return ret;

532
	return sysfs_emit(buf, "0x%04x\n", pkey);
L
Linus Torvalds 已提交
533 534 535 536 537
}

#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),	\
538
	.index = (_offset) | ((_width) << 16) | ((_counter) << 24),	\
539
	.attr_id = IB_PMA_PORT_COUNTERS,				\
L
Linus Torvalds 已提交
540 541
}

542 543 544 545
#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),				\
546
	.attr_id = IB_PMA_PORT_COUNTERS_EXT,				\
547 548
}

549 550 551 552
/*
 * Get a Perfmgmt MAD block of data.
 * Returns error code or the number of bytes retrieved.
 */
553
static int get_perf_mad(struct ib_device *dev, int port_num, __be16 attr,
554
		void *data, int offset, size_t size)
L
Linus Torvalds 已提交
555
{
556 557
	struct ib_mad *in_mad;
	struct ib_mad *out_mad;
558 559
	size_t mad_size = sizeof(*out_mad);
	u16 out_mad_pkey_index = 0;
L
Linus Torvalds 已提交
560 561
	ssize_t ret;

K
Kamal Heib 已提交
562
	if (!dev->ops.process_mad)
563
		return -ENOSYS;
L
Linus Torvalds 已提交
564

565 566
	in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
	out_mad = kzalloc(sizeof(*out_mad), GFP_KERNEL);
L
Linus Torvalds 已提交
567 568 569 570 571 572 573 574 575
	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;
576
	in_mad->mad_hdr.attr_id       = attr;
L
Linus Torvalds 已提交
577

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

581 582
	if ((dev->ops.process_mad(dev, IB_MAD_IGNORE_MKEY, port_num, NULL, NULL,
				  in_mad, out_mad, &mad_size,
K
Kamal Heib 已提交
583
				  &out_mad_pkey_index) &
L
Linus Torvalds 已提交
584 585 586 587 588
	     (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) !=
	    (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) {
		ret = -EINVAL;
		goto out;
	}
589 590 591 592 593 594 595 596
	memcpy(data, out_mad->data + offset, size);
	ret = size;
out:
	kfree(in_mad);
	kfree(out_mad);
	return ret;
}

597 598
static ssize_t show_pma_counter(struct ib_device *ibdev, u32 port_num,
				struct ib_port_attribute *attr, char *buf)
599 600 601 602 603
{
	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;
604
	int ret;
605
	u8 data[8];
606
	int len;
607

608
	ret = get_perf_mad(ibdev, port_num, tab_attr->attr_id, &data,
609 610
			40 + offset / 8, sizeof(data));
	if (ret < 0)
611
		return ret;
L
Linus Torvalds 已提交
612 613 614

	switch (width) {
	case 4:
615
		len = sysfs_emit(buf, "%d\n",
616
				 (*data >> (4 - (offset % 8))) & 0xf);
L
Linus Torvalds 已提交
617 618
		break;
	case 8:
619
		len = sysfs_emit(buf, "%u\n", *data);
L
Linus Torvalds 已提交
620 621
		break;
	case 16:
622
		len = sysfs_emit(buf, "%u\n", be16_to_cpup((__be16 *)data));
L
Linus Torvalds 已提交
623 624
		break;
	case 32:
625
		len = sysfs_emit(buf, "%u\n", be32_to_cpup((__be32 *)data));
L
Linus Torvalds 已提交
626
		break;
627
	case 64:
628
		len = sysfs_emit(buf, "%llu\n", be64_to_cpup((__be64 *)data));
629
		break;
L
Linus Torvalds 已提交
630
	default:
631 632
		len = 0;
		break;
L
Linus Torvalds 已提交
633 634
	}

635
	return len;
L
Linus Torvalds 已提交
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
}

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);
654
static PORT_PMA_ATTR(port_xmit_wait		    ,  0, 32, 320);
L
Linus Torvalds 已提交
655

656 657 658 659 660 661 662 663 664 665 666 667
/*
 * 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 已提交
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
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,
685
	&port_pma_attr_port_xmit_wait.attr.attr,
L
Linus Torvalds 已提交
686 687 688
	NULL
};

689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
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,
705
	&port_pma_attr_port_xmit_wait.attr.attr,
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
	&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,
731
	&port_pma_attr_port_xmit_wait.attr.attr,
732 733 734
	NULL
};

735
static const struct attribute_group pma_group = {
L
Linus Torvalds 已提交
736 737 738 739
	.name  = "counters",
	.attrs  = pma_attrs
};

740
static const struct attribute_group pma_group_ext = {
741 742 743 744
	.name  = "counters",
	.attrs  = pma_attrs_ext
};

745
static const struct attribute_group pma_group_noietf = {
746 747 748 749
	.name  = "counters",
	.attrs  = pma_attrs_noietf
};

L
Linus Torvalds 已提交
750 751
static void ib_port_release(struct kobject *kobj)
{
752
	struct ib_port *port = container_of(kobj, struct ib_port, kobj);
L
Linus Torvalds 已提交
753 754
	int i;

755 756 757
	for (i = 0; i != ARRAY_SIZE(port->groups); i++)
		kfree(port->groups[i].attrs);
	if (port->hw_stats_data)
758
		rdma_free_hw_stats_struct(port->hw_stats_data->stats);
759 760
	kfree(port->hw_stats_data);
	kfree(port);
L
Linus Torvalds 已提交
761 762
}

M
Matan Barak 已提交
763 764
static void ib_port_gid_attr_release(struct kobject *kobj)
{
765 766
	struct gid_attr_group *gid_attr_group =
		container_of(kobj, struct gid_attr_group, kobj);
M
Matan Barak 已提交
767 768
	int i;

769 770 771
	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 已提交
772 773
}

L
Linus Torvalds 已提交
774 775 776 777 778 779
static struct kobj_type port_type = {
	.release       = ib_port_release,
	.sysfs_ops     = &port_sysfs_ops,
	.default_attrs = port_default_attrs
};

M
Matan Barak 已提交
780 781 782 783 784
static struct kobj_type gid_attr_type = {
	.sysfs_ops      = &gid_attr_sysfs_ops,
	.release        = ib_port_gid_attr_release
};

785 786 787 788
/*
 * Figure out which counter table to use depending on
 * the device capabilities.
 */
789 790
static const struct attribute_group *get_counter_table(struct ib_device *dev,
						       int port_num)
791 792 793
{
	struct ib_class_port_info cpi;

794
	if (get_perf_mad(dev, port_num, IB_PMA_CLASS_PORT_INFO,
795
				&cpi, 40, sizeof(cpi)) >= 0) {
796
		if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH)
797 798 799
			/* We have extended counters */
			return &pma_group_ext;

800
		if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH_NOIETF)
801 802 803 804 805 806 807 808
			/* But not the IETF ones */
			return &pma_group_noietf;
	}

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

809
static int update_hw_stats(struct ib_device *dev, struct rdma_hw_stats *stats,
810
			   u32 port_num, int index)
811 812 813 814 815
{
	int ret;

	if (time_is_after_eq_jiffies(stats->timestamp + stats->lifespan))
		return 0;
K
Kamal Heib 已提交
816
	ret = dev->ops.get_hw_stats(dev, stats, port_num, index);
817 818 819 820 821 822 823 824
	if (ret < 0)
		return ret;
	if (ret == stats->num_counters)
		stats->timestamp = jiffies;

	return 0;
}

825 826
static int print_hw_stat(struct ib_device *dev, int port_num,
			 struct rdma_hw_stats *stats, int index, char *buf)
827
{
828 829
	u64 v = rdma_counter_get_hwstat_value(dev, port_num, index);

830
	return sysfs_emit(buf, "%llu\n", stats->value[index] + v);
831 832
}

833 834 835
static ssize_t show_hw_stats(struct ib_device *ibdev,
			     struct rdma_hw_stats *stats, unsigned int index,
			     unsigned int port_num, char *buf)
836 837 838
{
	int ret;

839
	mutex_lock(&stats->lock);
840
	ret = update_hw_stats(ibdev, stats, port_num, index);
841
	if (ret)
842
		goto unlock;
843
	ret = print_hw_stat(ibdev, port_num, stats, index, buf);
844 845 846 847
unlock:
	mutex_unlock(&stats->lock);

	return ret;
848 849
}

850 851 852
static ssize_t show_stats_lifespan(struct ib_device *ibdev,
				   struct rdma_hw_stats *stats,
				   unsigned int index, unsigned int port_num,
853 854 855 856
				   char *buf)
{
	int msecs;

857 858 859 860
	mutex_lock(&stats->lock);
	msecs = jiffies_to_msecs(stats->lifespan);
	mutex_unlock(&stats->lock);

861
	return sysfs_emit(buf, "%d\n", msecs);
862 863
}

864 865 866 867
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)
868 869 870 871 872 873 874 875 876 877 878
{
	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);
879 880 881 882 883

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

884 885 886
	return count;
}

887 888
static struct hw_stats_device_data *
alloc_hw_stats_device(struct ib_device *ibdev)
889
{
890 891 892 893 894 895 896 897
	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);
898
	if (!stats->descs || stats->num_counters <= 0)
899 900 901 902 903 904 905 906 907 908 909 910 911 912
		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;
913

914 915 916 917
	mutex_init(&stats->lock);
	data->group.name = "hw_counters";
	data->stats = stats;
	return data;
918

919 920 921
err_free_data:
	kfree(data);
err_free_stats:
922
	rdma_free_hw_stats_struct(stats);
923
	return ERR_PTR(-ENOMEM);
924 925
}

926
void ib_device_release_hw_stats(struct hw_stats_device_data *data)
927
{
928
	kfree(data->group.attrs);
929
	rdma_free_hw_stats_struct(data->stats);
930 931
	kfree(data);
}
932

933
int ib_setup_device_attrs(struct ib_device *ibdev)
934 935 936
{
	struct hw_stats_device_attribute *attr;
	struct hw_stats_device_data *data;
937 938
	bool opstat_skipped = false;
	int i, ret, pos = 0;
939

940
	data = alloc_hw_stats_device(ibdev);
941 942 943
	if (IS_ERR(data)) {
		if (PTR_ERR(data) == -EOPNOTSUPP)
			return 0;
944
		return PTR_ERR(data);
945 946
	}
	ibdev->hw_stats_data = data;
947

948 949 950 951
	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))
952 953
			return -EINVAL;
		return ret;
954
	}
955

956
	data->stats->timestamp = jiffies;
957

958
	for (i = 0; i < data->stats->num_counters; i++) {
959 960 961 962 963 964 965
		if (data->stats->descs[i].flags & IB_STAT_FLAG_OPTIONAL) {
			opstat_skipped = true;
			continue;
		}

		WARN_ON(opstat_skipped);
		attr = &data->attrs[pos];
966
		sysfs_attr_init(&attr->attr.attr);
967
		attr->attr.attr.name = data->stats->descs[i].name;
968 969 970
		attr->attr.attr.mode = 0444;
		attr->attr.show = hw_stat_device_show;
		attr->show = show_hw_stats;
971 972
		data->group.attrs[pos] = &attr->attr.attr;
		pos++;
973 974
	}

975
	attr = &data->attrs[pos];
976 977 978 979 980 981 982
	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;
983
	data->group.attrs[pos] = &attr->attr.attr;
984 985 986 987 988 989 990
	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;
991 992
}

993 994
static struct hw_stats_port_data *
alloc_hw_stats_port(struct ib_port *port, struct attribute_group *group)
995
{
996 997
	struct ib_device *ibdev = port->ibdev;
	struct hw_stats_port_data *data;
998 999
	struct rdma_hw_stats *stats;

1000 1001 1002
	if (!ibdev->ops.alloc_hw_port_stats)
		return ERR_PTR(-EOPNOTSUPP);
	stats = ibdev->ops.alloc_hw_port_stats(port->ibdev, port->port_num);
1003
	if (!stats)
1004
		return ERR_PTR(-ENOMEM);
1005
	if (!stats->descs || stats->num_counters <= 0)
1006
		goto err_free_stats;
1007

1008 1009 1010 1011
	/*
	 * Two extra attribue elements here, one for the lifespan entry and
	 * one to NULL terminate the list for the sysfs core code
	 */
1012
	data = kzalloc(struct_size(data, attrs, stats->num_counters + 1),
1013
		       GFP_KERNEL);
1014
	if (!data)
1015
		goto err_free_stats;
1016 1017 1018
	group->attrs = kcalloc(stats->num_counters + 2,
				    sizeof(*group->attrs), GFP_KERNEL);
	if (!group->attrs)
1019
		goto err_free_data;
1020

1021
	mutex_init(&stats->lock);
1022
	group->name = "hw_counters";
1023 1024
	data->stats = stats;
	return data;
1025

1026 1027 1028
err_free_data:
	kfree(data);
err_free_stats:
1029
	rdma_free_hw_stats_struct(stats);
1030 1031
	return ERR_PTR(-ENOMEM);
}
1032

1033 1034
static int setup_hw_port_stats(struct ib_port *port,
			       struct attribute_group *group)
1035 1036 1037
{
	struct hw_stats_port_attribute *attr;
	struct hw_stats_port_data *data;
1038 1039
	bool opstat_skipped = false;
	int i, ret, pos = 0;
1040

1041
	data = alloc_hw_stats_port(port, group);
1042 1043 1044 1045 1046 1047 1048 1049
	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))
1050 1051
			return -EINVAL;
		return ret;
1052
	}
1053

1054 1055 1056
	data->stats->timestamp = jiffies;

	for (i = 0; i < data->stats->num_counters; i++) {
1057 1058 1059 1060 1061 1062 1063
		if (data->stats->descs[i].flags & IB_STAT_FLAG_OPTIONAL) {
			opstat_skipped = true;
			continue;
		}

		WARN_ON(opstat_skipped);
		attr = &data->attrs[pos];
1064
		sysfs_attr_init(&attr->attr.attr);
1065
		attr->attr.attr.name = data->stats->descs[i].name;
1066 1067 1068
		attr->attr.attr.mode = 0444;
		attr->attr.show = hw_stat_port_show;
		attr->show = show_hw_stats;
1069 1070
		group->attrs[pos] = &attr->attr.attr;
		pos++;
1071 1072
	}

1073
	attr = &data->attrs[pos];
1074 1075 1076 1077 1078 1079 1080
	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[pos] = &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 1257 1258 1259
	if (is_full_dev) {
		ret = sysfs_create_groups(&p->kobj, device->ops.port_groups);
		if (ret)
			goto err_groups;
	}
1260

1261
	list_add_tail(&p->kobj.entry, &coredev->port_list);
1262 1263
	if (device->port_data && is_full_dev)
		device->port_data[port_num].sysfs = p;
L
Linus Torvalds 已提交
1264

1265
	return p;
L
Linus Torvalds 已提交
1266

1267 1268
err_groups:
	sysfs_remove_groups(&p->kobj, p->groups_list);
1269 1270
err_del:
	kobject_del(&p->kobj);
L
Linus Torvalds 已提交
1271
err_put:
1272
	kobject_put(&p->kobj);
1273 1274 1275
	return ERR_PTR(ret);
}

1276
static void destroy_port(struct ib_core_device *coredev, struct ib_port *port)
1277
{
1278 1279
	bool is_full_dev = &port->ibdev->coredev == coredev;

1280 1281 1282 1283
	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);
1284 1285
	if (is_full_dev)
		sysfs_remove_groups(&port->kobj, port->ibdev->ops.port_groups);
1286 1287 1288
	sysfs_remove_groups(&port->kobj, port->groups_list);
	kobject_del(&port->kobj);
	kobject_put(&port->kobj);
L
Linus Torvalds 已提交
1289 1290
}

1291
static const char *node_type_string(int node_type)
L
Linus Torvalds 已提交
1292
{
1293
	switch (node_type) {
1294
	case RDMA_NODE_IB_CA:
1295 1296 1297 1298 1299
		return "CA";
	case RDMA_NODE_IB_SWITCH:
		return "switch";
	case RDMA_NODE_IB_ROUTER:
		return "router";
1300
	case RDMA_NODE_RNIC:
1301
		return "RNIC";
1302
	case RDMA_NODE_USNIC:
1303
		return "usNIC";
1304
	case RDMA_NODE_USNIC_UDP:
1305
		return "usNIC UDP";
1306
	case RDMA_NODE_UNSPECIFIED:
1307
		return "unspecified";
L
Linus Torvalds 已提交
1308
	}
1309 1310 1311 1312 1313 1314 1315 1316
	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);

1317
	return sysfs_emit(buf, "%u: %s\n", dev->node_type,
1318
			  node_type_string(dev->node_type));
L
Linus Torvalds 已提交
1319
}
1320
static DEVICE_ATTR_RO(node_type);
L
Linus Torvalds 已提交
1321

1322
static ssize_t sys_image_guid_show(struct device *device,
1323
				   struct device_attribute *dev_attr, char *buf)
L
Linus Torvalds 已提交
1324
{
1325
	struct ib_device *dev = rdma_device_to_ibdev(device);
1326
	__be16 *guid = (__be16 *)&dev->attrs.sys_image_guid;
L
Linus Torvalds 已提交
1327

1328 1329 1330 1331 1332
	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 已提交
1333
}
1334
static DEVICE_ATTR_RO(sys_image_guid);
L
Linus Torvalds 已提交
1335

1336
static ssize_t node_guid_show(struct device *device,
1337
			      struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
1338
{
1339
	struct ib_device *dev = rdma_device_to_ibdev(device);
1340
	__be16 *node_guid = (__be16 *)&dev->node_guid;
L
Linus Torvalds 已提交
1341

1342
	return sysfs_emit(buf, "%04x:%04x:%04x:%04x\n",
1343 1344 1345 1346
			  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 已提交
1347
}
1348
static DEVICE_ATTR_RO(node_guid);
L
Linus Torvalds 已提交
1349

1350
static ssize_t node_desc_show(struct device *device,
1351
			      struct device_attribute *attr, char *buf)
1352
{
1353
	struct ib_device *dev = rdma_device_to_ibdev(device);
1354

1355
	return sysfs_emit(buf, "%.64s\n", dev->node_desc);
1356 1357
}

1358 1359 1360
static ssize_t node_desc_store(struct device *device,
			       struct device_attribute *attr,
			       const char *buf, size_t count)
1361
{
1362
	struct ib_device *dev = rdma_device_to_ibdev(device);
1363 1364 1365
	struct ib_device_modify desc = {};
	int ret;

K
Kamal Heib 已提交
1366
	if (!dev->ops.modify_device)
1367
		return -EOPNOTSUPP;
1368

1369
	memcpy(desc.node_desc, buf, min_t(int, count, IB_DEVICE_NODE_DESC_MAX));
1370 1371 1372 1373 1374 1375
	ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
	if (ret)
		return ret;

	return count;
}
1376
static DEVICE_ATTR_RW(node_desc);
1377

1378
static ssize_t fw_ver_show(struct device *device, struct device_attribute *attr,
1379 1380
			   char *buf)
{
1381
	struct ib_device *dev = rdma_device_to_ibdev(device);
1382 1383 1384
	char version[IB_FW_VERSION_NAME_MAX] = {};

	ib_get_device_fw_str(dev, version);
1385

1386
	return sysfs_emit(buf, "%s\n", version);
1387
}
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
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,
};
1398

1399
const struct attribute_group ib_dev_attr_group = {
1400
	.attrs = ib_dev_attrs,
L
Linus Torvalds 已提交
1401 1402
};

1403
void ib_free_port_attrs(struct ib_core_device *coredev)
1404 1405 1406
{
	struct kobject *p, *t;

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

1410
		destroy_gid_attrs(port);
1411
		destroy_port(coredev, port);
1412 1413
	}

1414
	kobject_put(coredev->ports_kobj);
1415 1416
}

1417
int ib_setup_port_attrs(struct ib_core_device *coredev)
L
Linus Torvalds 已提交
1418
{
1419
	struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);
1420
	u32 port_num;
L
Linus Torvalds 已提交
1421 1422
	int ret;

1423 1424 1425
	coredev->ports_kobj = kobject_create_and_add("ports",
						     &coredev->dev.kobj);
	if (!coredev->ports_kobj)
1426
		return -ENOMEM;
L
Linus Torvalds 已提交
1427

1428 1429 1430 1431 1432
	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 已提交
1433 1434 1435
		if (ret)
			goto err_put;

1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
		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;
	}
L
Linus Torvalds 已提交
1446 1447 1448
	return 0;

err_put:
1449
	ib_free_port_attrs(coredev);
L
Linus Torvalds 已提交
1450 1451 1452
	return ret;
}

1453
/**
1454
 * ib_port_register_client_groups - Add an ib_client's attributes to the port
1455
 *
1456
 * @ibdev: IB device to add counters
1457
 * @port_num: valid port number
1458 1459 1460
 * @groups: Group list of attributes
 *
 * Do not use. Only for legacy sysfs compatibility.
1461
 */
1462 1463
int ib_port_register_client_groups(struct ib_device *ibdev, u32 port_num,
				   const struct attribute_group **groups)
1464
{
1465 1466
	return sysfs_create_groups(&ibdev->port_data[port_num].sysfs->kobj,
				   groups);
1467
}
1468
EXPORT_SYMBOL(ib_port_register_client_groups);
1469

1470 1471
void ib_port_unregister_client_groups(struct ib_device *ibdev, u32 port_num,
				      const struct attribute_group **groups)
1472
{
1473 1474
	return sysfs_remove_groups(&ibdev->port_data[port_num].sysfs->kobj,
				   groups);
1475
}
1476
EXPORT_SYMBOL(ib_port_unregister_client_groups);