1485 lines · c
1/*2 * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.3 * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved.4 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.5 *6 * This software is available to you under a choice of one of two7 * licenses. You may choose to be licensed under the terms of the GNU8 * General Public License (GPL) Version 2, available from the file9 * COPYING in the main directory of this source tree, or the10 * OpenIB.org BSD license below:11 *12 * Redistribution and use in source and binary forms, with or13 * without modification, are permitted provided that the following14 * conditions are met:15 *16 * - Redistributions of source code must retain the above17 * copyright notice, this list of conditions and the following18 * disclaimer.19 *20 * - Redistributions in binary form must reproduce the above21 * copyright notice, this list of conditions and the following22 * disclaimer in the documentation and/or other materials23 * provided with the distribution.24 *25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE32 * SOFTWARE.33 */34 35#include "core_priv.h"36 37#include <linux/slab.h>38#include <linux/stat.h>39#include <linux/string.h>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>48 49struct port_table_attribute {50 struct ib_port_attribute attr;51 char name[8];52 int index;53 __be16 attr_id;54};55 56struct gid_attr_group {57 struct ib_port *port;58 struct kobject kobj;59 struct attribute_group groups[2];60 const struct attribute_group *groups_list[3];61 struct port_table_attribute attrs_list[];62};63 64struct ib_port {65 struct kobject kobj;66 struct ib_device *ibdev;67 struct gid_attr_group *gid_attr_group;68 struct hw_stats_port_data *hw_stats_data;69 70 struct attribute_group groups[3];71 const struct attribute_group *groups_list[5];72 u32 port_num;73 struct port_table_attribute attrs_list[];74};75 76struct hw_stats_device_attribute {77 struct device_attribute attr;78 ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats,79 unsigned int index, unsigned int port_num, char *buf);80 ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats,81 unsigned int index, unsigned int port_num,82 const char *buf, size_t count);83};84 85struct hw_stats_port_attribute {86 struct ib_port_attribute attr;87 ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats,88 unsigned int index, unsigned int port_num, char *buf);89 ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats,90 unsigned int index, unsigned int port_num,91 const char *buf, size_t count);92};93 94struct hw_stats_device_data {95 struct attribute_group group;96 struct rdma_hw_stats *stats;97 struct hw_stats_device_attribute attrs[];98};99 100struct hw_stats_port_data {101 struct rdma_hw_stats *stats;102 struct hw_stats_port_attribute attrs[];103};104 105static ssize_t port_attr_show(struct kobject *kobj,106 struct attribute *attr, char *buf)107{108 struct ib_port_attribute *port_attr =109 container_of(attr, struct ib_port_attribute, attr);110 struct ib_port *p = container_of(kobj, struct ib_port, kobj);111 112 if (!port_attr->show)113 return -EIO;114 115 return port_attr->show(p->ibdev, p->port_num, port_attr, buf);116}117 118static ssize_t port_attr_store(struct kobject *kobj,119 struct attribute *attr,120 const char *buf, size_t count)121{122 struct ib_port_attribute *port_attr =123 container_of(attr, struct ib_port_attribute, attr);124 struct ib_port *p = container_of(kobj, struct ib_port, kobj);125 126 if (!port_attr->store)127 return -EIO;128 return port_attr->store(p->ibdev, p->port_num, port_attr, buf, count);129}130 131struct ib_device *ib_port_sysfs_get_ibdev_kobj(struct kobject *kobj,132 u32 *port_num)133{134 struct ib_port *port = container_of(kobj, struct ib_port, kobj);135 136 *port_num = port->port_num;137 return port->ibdev;138}139EXPORT_SYMBOL(ib_port_sysfs_get_ibdev_kobj);140 141static const struct sysfs_ops port_sysfs_ops = {142 .show = port_attr_show,143 .store = port_attr_store144};145 146static ssize_t hw_stat_device_show(struct device *dev,147 struct device_attribute *attr, char *buf)148{149 struct hw_stats_device_attribute *stat_attr =150 container_of(attr, struct hw_stats_device_attribute, attr);151 struct ib_device *ibdev = container_of(dev, struct ib_device, dev);152 153 return stat_attr->show(ibdev, ibdev->hw_stats_data->stats,154 stat_attr - ibdev->hw_stats_data->attrs, 0, buf);155}156 157static ssize_t hw_stat_device_store(struct device *dev,158 struct device_attribute *attr,159 const char *buf, size_t count)160{161 struct hw_stats_device_attribute *stat_attr =162 container_of(attr, struct hw_stats_device_attribute, attr);163 struct ib_device *ibdev = container_of(dev, struct ib_device, dev);164 165 return stat_attr->store(ibdev, ibdev->hw_stats_data->stats,166 stat_attr - ibdev->hw_stats_data->attrs, 0, buf,167 count);168}169 170static ssize_t hw_stat_port_show(struct ib_device *ibdev, u32 port_num,171 struct ib_port_attribute *attr, char *buf)172{173 struct hw_stats_port_attribute *stat_attr =174 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 stat_attr - port->hw_stats_data->attrs,179 port->port_num, buf);180}181 182static ssize_t hw_stat_port_store(struct ib_device *ibdev, u32 port_num,183 struct ib_port_attribute *attr,184 const char *buf, size_t count)185{186 struct hw_stats_port_attribute *stat_attr =187 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 stat_attr - port->hw_stats_data->attrs,192 port->port_num, buf, count);193}194 195static ssize_t gid_attr_show(struct kobject *kobj,196 struct attribute *attr, char *buf)197{198 struct ib_port_attribute *port_attr =199 container_of(attr, struct ib_port_attribute, attr);200 struct ib_port *p = container_of(kobj, struct gid_attr_group,201 kobj)->port;202 203 if (!port_attr->show)204 return -EIO;205 206 return port_attr->show(p->ibdev, p->port_num, port_attr, buf);207}208 209static const struct sysfs_ops gid_attr_sysfs_ops = {210 .show = gid_attr_show211};212 213static ssize_t state_show(struct ib_device *ibdev, u32 port_num,214 struct ib_port_attribute *unused, char *buf)215{216 struct ib_port_attr attr;217 ssize_t ret;218 219 static const char *state_name[] = {220 [IB_PORT_NOP] = "NOP",221 [IB_PORT_DOWN] = "DOWN",222 [IB_PORT_INIT] = "INIT",223 [IB_PORT_ARMED] = "ARMED",224 [IB_PORT_ACTIVE] = "ACTIVE",225 [IB_PORT_ACTIVE_DEFER] = "ACTIVE_DEFER"226 };227 228 ret = ib_query_port(ibdev, port_num, &attr);229 if (ret)230 return ret;231 232 return sysfs_emit(buf, "%d: %s\n", attr.state,233 attr.state >= 0 &&234 attr.state < ARRAY_SIZE(state_name) ?235 state_name[attr.state] :236 "UNKNOWN");237}238 239static ssize_t lid_show(struct ib_device *ibdev, u32 port_num,240 struct ib_port_attribute *unused, char *buf)241{242 struct ib_port_attr attr;243 ssize_t ret;244 245 ret = ib_query_port(ibdev, port_num, &attr);246 if (ret)247 return ret;248 249 return sysfs_emit(buf, "0x%x\n", attr.lid);250}251 252static ssize_t lid_mask_count_show(struct ib_device *ibdev, u32 port_num,253 struct ib_port_attribute *unused, char *buf)254{255 struct ib_port_attr attr;256 ssize_t ret;257 258 ret = ib_query_port(ibdev, port_num, &attr);259 if (ret)260 return ret;261 262 return sysfs_emit(buf, "%u\n", attr.lmc);263}264 265static ssize_t sm_lid_show(struct ib_device *ibdev, u32 port_num,266 struct ib_port_attribute *unused, char *buf)267{268 struct ib_port_attr attr;269 ssize_t ret;270 271 ret = ib_query_port(ibdev, port_num, &attr);272 if (ret)273 return ret;274 275 return sysfs_emit(buf, "0x%x\n", attr.sm_lid);276}277 278static ssize_t sm_sl_show(struct ib_device *ibdev, u32 port_num,279 struct ib_port_attribute *unused, char *buf)280{281 struct ib_port_attr attr;282 ssize_t ret;283 284 ret = ib_query_port(ibdev, port_num, &attr);285 if (ret)286 return ret;287 288 return sysfs_emit(buf, "%u\n", attr.sm_sl);289}290 291static ssize_t cap_mask_show(struct ib_device *ibdev, u32 port_num,292 struct ib_port_attribute *unused, char *buf)293{294 struct ib_port_attr attr;295 ssize_t ret;296 297 ret = ib_query_port(ibdev, port_num, &attr);298 if (ret)299 return ret;300 301 return sysfs_emit(buf, "0x%08x\n", attr.port_cap_flags);302}303 304static ssize_t rate_show(struct ib_device *ibdev, u32 port_num,305 struct ib_port_attribute *unused, char *buf)306{307 struct ib_port_attr attr;308 char *speed = "";309 int rate; /* in deci-Gb/sec */310 ssize_t ret;311 312 ret = ib_query_port(ibdev, port_num, &attr);313 if (ret)314 return ret;315 316 switch (attr.active_speed) {317 case IB_SPEED_DDR:318 speed = " DDR";319 rate = 50;320 break;321 case IB_SPEED_QDR:322 speed = " QDR";323 rate = 100;324 break;325 case IB_SPEED_FDR10:326 speed = " FDR10";327 rate = 100;328 break;329 case IB_SPEED_FDR:330 speed = " FDR";331 rate = 140;332 break;333 case IB_SPEED_EDR:334 speed = " EDR";335 rate = 250;336 break;337 case IB_SPEED_HDR:338 speed = " HDR";339 rate = 500;340 break;341 case IB_SPEED_NDR:342 speed = " NDR";343 rate = 1000;344 break;345 case IB_SPEED_XDR:346 speed = " XDR";347 rate = 2000;348 break;349 case IB_SPEED_SDR:350 default: /* default to SDR for invalid rates */351 speed = " SDR";352 rate = 25;353 break;354 }355 356 rate *= ib_width_enum_to_int(attr.active_width);357 if (rate < 0)358 return -EINVAL;359 360 return sysfs_emit(buf, "%d%s Gb/sec (%dX%s)\n", rate / 10,361 rate % 10 ? ".5" : "",362 ib_width_enum_to_int(attr.active_width), speed);363}364 365static const char *phys_state_to_str(enum ib_port_phys_state phys_state)366{367 static const char *phys_state_str[] = {368 "<unknown>",369 "Sleep",370 "Polling",371 "Disabled",372 "PortConfigurationTraining",373 "LinkUp",374 "LinkErrorRecovery",375 "Phy Test",376 };377 378 if (phys_state < ARRAY_SIZE(phys_state_str))379 return phys_state_str[phys_state];380 return "<unknown>";381}382 383static ssize_t phys_state_show(struct ib_device *ibdev, u32 port_num,384 struct ib_port_attribute *unused, char *buf)385{386 struct ib_port_attr attr;387 388 ssize_t ret;389 390 ret = ib_query_port(ibdev, port_num, &attr);391 if (ret)392 return ret;393 394 return sysfs_emit(buf, "%u: %s\n", attr.phys_state,395 phys_state_to_str(attr.phys_state));396}397 398static ssize_t link_layer_show(struct ib_device *ibdev, u32 port_num,399 struct ib_port_attribute *unused, char *buf)400{401 const char *output;402 403 switch (rdma_port_get_link_layer(ibdev, port_num)) {404 case IB_LINK_LAYER_INFINIBAND:405 output = "InfiniBand";406 break;407 case IB_LINK_LAYER_ETHERNET:408 output = "Ethernet";409 break;410 default:411 output = "Unknown";412 break;413 }414 415 return sysfs_emit(buf, "%s\n", output);416}417 418static IB_PORT_ATTR_RO(state);419static IB_PORT_ATTR_RO(lid);420static IB_PORT_ATTR_RO(lid_mask_count);421static IB_PORT_ATTR_RO(sm_lid);422static IB_PORT_ATTR_RO(sm_sl);423static IB_PORT_ATTR_RO(cap_mask);424static IB_PORT_ATTR_RO(rate);425static IB_PORT_ATTR_RO(phys_state);426static IB_PORT_ATTR_RO(link_layer);427 428static struct attribute *port_default_attrs[] = {429 &ib_port_attr_state.attr,430 &ib_port_attr_lid.attr,431 &ib_port_attr_lid_mask_count.attr,432 &ib_port_attr_sm_lid.attr,433 &ib_port_attr_sm_sl.attr,434 &ib_port_attr_cap_mask.attr,435 &ib_port_attr_rate.attr,436 &ib_port_attr_phys_state.attr,437 &ib_port_attr_link_layer.attr,438 NULL439};440ATTRIBUTE_GROUPS(port_default);441 442static ssize_t print_ndev(const struct ib_gid_attr *gid_attr, char *buf)443{444 struct net_device *ndev;445 int ret = -EINVAL;446 447 rcu_read_lock();448 ndev = rcu_dereference(gid_attr->ndev);449 if (ndev)450 ret = sysfs_emit(buf, "%s\n", ndev->name);451 rcu_read_unlock();452 return ret;453}454 455static ssize_t print_gid_type(const struct ib_gid_attr *gid_attr, char *buf)456{457 return sysfs_emit(buf, "%s\n",458 ib_cache_gid_type_str(gid_attr->gid_type));459}460 461static ssize_t _show_port_gid_attr(462 struct ib_device *ibdev, u32 port_num, struct ib_port_attribute *attr,463 char *buf,464 ssize_t (*print)(const struct ib_gid_attr *gid_attr, char *buf))465{466 struct port_table_attribute *tab_attr =467 container_of(attr, struct port_table_attribute, attr);468 const struct ib_gid_attr *gid_attr;469 ssize_t ret;470 471 gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);472 if (IS_ERR(gid_attr))473 /* -EINVAL is returned for user space compatibility reasons. */474 return -EINVAL;475 476 ret = print(gid_attr, buf);477 rdma_put_gid_attr(gid_attr);478 return ret;479}480 481static ssize_t show_port_gid(struct ib_device *ibdev, u32 port_num,482 struct ib_port_attribute *attr, char *buf)483{484 struct port_table_attribute *tab_attr =485 container_of(attr, struct port_table_attribute, attr);486 const struct ib_gid_attr *gid_attr;487 int len;488 489 gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);490 if (IS_ERR(gid_attr)) {491 const union ib_gid zgid = {};492 493 /* If reading GID fails, it is likely due to GID entry being494 * empty (invalid) or reserved GID in the table. User space495 * expects to read GID table entries as long as it given index496 * is within GID table size. Administrative/debugging tool497 * fails to query rest of the GID entries if it hits error498 * while querying a GID of the given index. To avoid user499 * space throwing such error on fail to read gid, return zero500 * GID as before. This maintains backward compatibility.501 */502 return sysfs_emit(buf, "%pI6\n", zgid.raw);503 }504 505 len = sysfs_emit(buf, "%pI6\n", gid_attr->gid.raw);506 rdma_put_gid_attr(gid_attr);507 return len;508}509 510static ssize_t show_port_gid_attr_ndev(struct ib_device *ibdev, u32 port_num,511 struct ib_port_attribute *attr,512 char *buf)513{514 return _show_port_gid_attr(ibdev, port_num, attr, buf, print_ndev);515}516 517static ssize_t show_port_gid_attr_gid_type(struct ib_device *ibdev,518 u32 port_num,519 struct ib_port_attribute *attr,520 char *buf)521{522 return _show_port_gid_attr(ibdev, port_num, attr, buf, print_gid_type);523}524 525static ssize_t show_port_pkey(struct ib_device *ibdev, u32 port_num,526 struct ib_port_attribute *attr, char *buf)527{528 struct port_table_attribute *tab_attr =529 container_of(attr, struct port_table_attribute, attr);530 u16 pkey;531 int ret;532 533 ret = ib_query_pkey(ibdev, port_num, tab_attr->index, &pkey);534 if (ret)535 return ret;536 537 return sysfs_emit(buf, "0x%04x\n", pkey);538}539 540#define PORT_PMA_ATTR(_name, _counter, _width, _offset) \541struct port_table_attribute port_pma_attr_##_name = { \542 .attr = __ATTR(_name, S_IRUGO, show_pma_counter, NULL), \543 .index = (_offset) | ((_width) << 16) | ((_counter) << 24), \544 .attr_id = IB_PMA_PORT_COUNTERS, \545}546 547#define PORT_PMA_ATTR_EXT(_name, _width, _offset) \548struct port_table_attribute port_pma_attr_ext_##_name = { \549 .attr = __ATTR(_name, S_IRUGO, show_pma_counter, NULL), \550 .index = (_offset) | ((_width) << 16), \551 .attr_id = IB_PMA_PORT_COUNTERS_EXT, \552}553 554/*555 * Get a Perfmgmt MAD block of data.556 * Returns error code or the number of bytes retrieved.557 */558static int get_perf_mad(struct ib_device *dev, int port_num, __be16 attr,559 void *data, int offset, size_t size)560{561 struct ib_mad *in_mad;562 struct ib_mad *out_mad;563 size_t mad_size = sizeof(*out_mad);564 u16 out_mad_pkey_index = 0;565 ssize_t ret;566 567 if (!dev->ops.process_mad)568 return -ENOSYS;569 570 in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);571 out_mad = kzalloc(sizeof(*out_mad), GFP_KERNEL);572 if (!in_mad || !out_mad) {573 ret = -ENOMEM;574 goto out;575 }576 577 in_mad->mad_hdr.base_version = 1;578 in_mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_PERF_MGMT;579 in_mad->mad_hdr.class_version = 1;580 in_mad->mad_hdr.method = IB_MGMT_METHOD_GET;581 in_mad->mad_hdr.attr_id = attr;582 583 if (attr != IB_PMA_CLASS_PORT_INFO)584 in_mad->data[41] = port_num; /* PortSelect field */585 586 if ((dev->ops.process_mad(dev, IB_MAD_IGNORE_MKEY, port_num, NULL, NULL,587 in_mad, out_mad, &mad_size,588 &out_mad_pkey_index) &589 (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) !=590 (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) {591 ret = -EINVAL;592 goto out;593 }594 memcpy(data, out_mad->data + offset, size);595 ret = size;596out:597 kfree(in_mad);598 kfree(out_mad);599 return ret;600}601 602static ssize_t show_pma_counter(struct ib_device *ibdev, u32 port_num,603 struct ib_port_attribute *attr, char *buf)604{605 struct port_table_attribute *tab_attr =606 container_of(attr, struct port_table_attribute, attr);607 int offset = tab_attr->index & 0xffff;608 int width = (tab_attr->index >> 16) & 0xff;609 int ret;610 u8 data[8];611 int len;612 613 ret = get_perf_mad(ibdev, port_num, tab_attr->attr_id, &data,614 40 + offset / 8, sizeof(data));615 if (ret < 0)616 return ret;617 618 switch (width) {619 case 4:620 len = sysfs_emit(buf, "%d\n",621 (*data >> (4 - (offset % 8))) & 0xf);622 break;623 case 8:624 len = sysfs_emit(buf, "%u\n", *data);625 break;626 case 16:627 len = sysfs_emit(buf, "%u\n", be16_to_cpup((__be16 *)data));628 break;629 case 32:630 len = sysfs_emit(buf, "%u\n", be32_to_cpup((__be32 *)data));631 break;632 case 64:633 len = sysfs_emit(buf, "%llu\n", be64_to_cpup((__be64 *)data));634 break;635 default:636 len = 0;637 break;638 }639 640 return len;641}642 643static PORT_PMA_ATTR(symbol_error , 0, 16, 32);644static PORT_PMA_ATTR(link_error_recovery , 1, 8, 48);645static PORT_PMA_ATTR(link_downed , 2, 8, 56);646static PORT_PMA_ATTR(port_rcv_errors , 3, 16, 64);647static PORT_PMA_ATTR(port_rcv_remote_physical_errors, 4, 16, 80);648static PORT_PMA_ATTR(port_rcv_switch_relay_errors , 5, 16, 96);649static PORT_PMA_ATTR(port_xmit_discards , 6, 16, 112);650static PORT_PMA_ATTR(port_xmit_constraint_errors , 7, 8, 128);651static PORT_PMA_ATTR(port_rcv_constraint_errors , 8, 8, 136);652static PORT_PMA_ATTR(local_link_integrity_errors , 9, 4, 152);653static PORT_PMA_ATTR(excessive_buffer_overrun_errors, 10, 4, 156);654static PORT_PMA_ATTR(VL15_dropped , 11, 16, 176);655static PORT_PMA_ATTR(port_xmit_data , 12, 32, 192);656static PORT_PMA_ATTR(port_rcv_data , 13, 32, 224);657static PORT_PMA_ATTR(port_xmit_packets , 14, 32, 256);658static PORT_PMA_ATTR(port_rcv_packets , 15, 32, 288);659static PORT_PMA_ATTR(port_xmit_wait , 0, 32, 320);660 661/*662 * Counters added by extended set663 */664static PORT_PMA_ATTR_EXT(port_xmit_data , 64, 64);665static PORT_PMA_ATTR_EXT(port_rcv_data , 64, 128);666static PORT_PMA_ATTR_EXT(port_xmit_packets , 64, 192);667static PORT_PMA_ATTR_EXT(port_rcv_packets , 64, 256);668static PORT_PMA_ATTR_EXT(unicast_xmit_packets , 64, 320);669static PORT_PMA_ATTR_EXT(unicast_rcv_packets , 64, 384);670static PORT_PMA_ATTR_EXT(multicast_xmit_packets , 64, 448);671static PORT_PMA_ATTR_EXT(multicast_rcv_packets , 64, 512);672 673static struct attribute *pma_attrs[] = {674 &port_pma_attr_symbol_error.attr.attr,675 &port_pma_attr_link_error_recovery.attr.attr,676 &port_pma_attr_link_downed.attr.attr,677 &port_pma_attr_port_rcv_errors.attr.attr,678 &port_pma_attr_port_rcv_remote_physical_errors.attr.attr,679 &port_pma_attr_port_rcv_switch_relay_errors.attr.attr,680 &port_pma_attr_port_xmit_discards.attr.attr,681 &port_pma_attr_port_xmit_constraint_errors.attr.attr,682 &port_pma_attr_port_rcv_constraint_errors.attr.attr,683 &port_pma_attr_local_link_integrity_errors.attr.attr,684 &port_pma_attr_excessive_buffer_overrun_errors.attr.attr,685 &port_pma_attr_VL15_dropped.attr.attr,686 &port_pma_attr_port_xmit_data.attr.attr,687 &port_pma_attr_port_rcv_data.attr.attr,688 &port_pma_attr_port_xmit_packets.attr.attr,689 &port_pma_attr_port_rcv_packets.attr.attr,690 &port_pma_attr_port_xmit_wait.attr.attr,691 NULL692};693 694static struct attribute *pma_attrs_ext[] = {695 &port_pma_attr_symbol_error.attr.attr,696 &port_pma_attr_link_error_recovery.attr.attr,697 &port_pma_attr_link_downed.attr.attr,698 &port_pma_attr_port_rcv_errors.attr.attr,699 &port_pma_attr_port_rcv_remote_physical_errors.attr.attr,700 &port_pma_attr_port_rcv_switch_relay_errors.attr.attr,701 &port_pma_attr_port_xmit_discards.attr.attr,702 &port_pma_attr_port_xmit_constraint_errors.attr.attr,703 &port_pma_attr_port_rcv_constraint_errors.attr.attr,704 &port_pma_attr_local_link_integrity_errors.attr.attr,705 &port_pma_attr_excessive_buffer_overrun_errors.attr.attr,706 &port_pma_attr_VL15_dropped.attr.attr,707 &port_pma_attr_ext_port_xmit_data.attr.attr,708 &port_pma_attr_ext_port_rcv_data.attr.attr,709 &port_pma_attr_ext_port_xmit_packets.attr.attr,710 &port_pma_attr_port_xmit_wait.attr.attr,711 &port_pma_attr_ext_port_rcv_packets.attr.attr,712 &port_pma_attr_ext_unicast_rcv_packets.attr.attr,713 &port_pma_attr_ext_unicast_xmit_packets.attr.attr,714 &port_pma_attr_ext_multicast_rcv_packets.attr.attr,715 &port_pma_attr_ext_multicast_xmit_packets.attr.attr,716 NULL717};718 719static struct attribute *pma_attrs_noietf[] = {720 &port_pma_attr_symbol_error.attr.attr,721 &port_pma_attr_link_error_recovery.attr.attr,722 &port_pma_attr_link_downed.attr.attr,723 &port_pma_attr_port_rcv_errors.attr.attr,724 &port_pma_attr_port_rcv_remote_physical_errors.attr.attr,725 &port_pma_attr_port_rcv_switch_relay_errors.attr.attr,726 &port_pma_attr_port_xmit_discards.attr.attr,727 &port_pma_attr_port_xmit_constraint_errors.attr.attr,728 &port_pma_attr_port_rcv_constraint_errors.attr.attr,729 &port_pma_attr_local_link_integrity_errors.attr.attr,730 &port_pma_attr_excessive_buffer_overrun_errors.attr.attr,731 &port_pma_attr_VL15_dropped.attr.attr,732 &port_pma_attr_ext_port_xmit_data.attr.attr,733 &port_pma_attr_ext_port_rcv_data.attr.attr,734 &port_pma_attr_ext_port_xmit_packets.attr.attr,735 &port_pma_attr_ext_port_rcv_packets.attr.attr,736 &port_pma_attr_port_xmit_wait.attr.attr,737 NULL738};739 740static const struct attribute_group pma_group = {741 .name = "counters",742 .attrs = pma_attrs743};744 745static const struct attribute_group pma_group_ext = {746 .name = "counters",747 .attrs = pma_attrs_ext748};749 750static const struct attribute_group pma_group_noietf = {751 .name = "counters",752 .attrs = pma_attrs_noietf753};754 755static void ib_port_release(struct kobject *kobj)756{757 struct ib_port *port = container_of(kobj, struct ib_port, kobj);758 int i;759 760 for (i = 0; i != ARRAY_SIZE(port->groups); i++)761 kfree(port->groups[i].attrs);762 if (port->hw_stats_data)763 rdma_free_hw_stats_struct(port->hw_stats_data->stats);764 kfree(port->hw_stats_data);765 kvfree(port);766}767 768static void ib_port_gid_attr_release(struct kobject *kobj)769{770 struct gid_attr_group *gid_attr_group =771 container_of(kobj, struct gid_attr_group, kobj);772 int i;773 774 for (i = 0; i != ARRAY_SIZE(gid_attr_group->groups); i++)775 kfree(gid_attr_group->groups[i].attrs);776 kfree(gid_attr_group);777}778 779static struct kobj_type port_type = {780 .release = ib_port_release,781 .sysfs_ops = &port_sysfs_ops,782 .default_groups = port_default_groups,783};784 785static struct kobj_type gid_attr_type = {786 .sysfs_ops = &gid_attr_sysfs_ops,787 .release = ib_port_gid_attr_release788};789 790/*791 * Figure out which counter table to use depending on792 * the device capabilities.793 */794static const struct attribute_group *get_counter_table(struct ib_device *dev,795 int port_num)796{797 struct ib_class_port_info cpi;798 799 if (get_perf_mad(dev, port_num, IB_PMA_CLASS_PORT_INFO,800 &cpi, 40, sizeof(cpi)) >= 0) {801 if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH)802 /* We have extended counters */803 return &pma_group_ext;804 805 if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH_NOIETF)806 /* But not the IETF ones */807 return &pma_group_noietf;808 }809 810 /* Fall back to normal counters */811 return &pma_group;812}813 814static int update_hw_stats(struct ib_device *dev, struct rdma_hw_stats *stats,815 u32 port_num, int index)816{817 int ret;818 819 if (time_is_after_eq_jiffies(stats->timestamp + stats->lifespan))820 return 0;821 ret = dev->ops.get_hw_stats(dev, stats, port_num, index);822 if (ret < 0)823 return ret;824 if (ret == stats->num_counters)825 stats->timestamp = jiffies;826 827 return 0;828}829 830static int print_hw_stat(struct ib_device *dev, int port_num,831 struct rdma_hw_stats *stats, int index, char *buf)832{833 u64 v = rdma_counter_get_hwstat_value(dev, port_num, index);834 835 return sysfs_emit(buf, "%llu\n", stats->value[index] + v);836}837 838static ssize_t show_hw_stats(struct ib_device *ibdev,839 struct rdma_hw_stats *stats, unsigned int index,840 unsigned int port_num, char *buf)841{842 int ret;843 844 mutex_lock(&stats->lock);845 ret = update_hw_stats(ibdev, stats, port_num, index);846 if (ret)847 goto unlock;848 ret = print_hw_stat(ibdev, port_num, stats, index, buf);849unlock:850 mutex_unlock(&stats->lock);851 852 return ret;853}854 855static ssize_t show_stats_lifespan(struct ib_device *ibdev,856 struct rdma_hw_stats *stats,857 unsigned int index, unsigned int port_num,858 char *buf)859{860 int msecs;861 862 mutex_lock(&stats->lock);863 msecs = jiffies_to_msecs(stats->lifespan);864 mutex_unlock(&stats->lock);865 866 return sysfs_emit(buf, "%d\n", msecs);867}868 869static ssize_t set_stats_lifespan(struct ib_device *ibdev,870 struct rdma_hw_stats *stats,871 unsigned int index, unsigned int port_num,872 const char *buf, size_t count)873{874 int msecs;875 int jiffies;876 int ret;877 878 ret = kstrtoint(buf, 10, &msecs);879 if (ret)880 return ret;881 if (msecs < 0 || msecs > 10000)882 return -EINVAL;883 jiffies = msecs_to_jiffies(msecs);884 885 mutex_lock(&stats->lock);886 stats->lifespan = jiffies;887 mutex_unlock(&stats->lock);888 889 return count;890}891 892static struct hw_stats_device_data *893alloc_hw_stats_device(struct ib_device *ibdev)894{895 struct hw_stats_device_data *data;896 struct rdma_hw_stats *stats;897 898 if (!ibdev->ops.alloc_hw_device_stats)899 return ERR_PTR(-EOPNOTSUPP);900 stats = ibdev->ops.alloc_hw_device_stats(ibdev);901 if (!stats)902 return ERR_PTR(-ENOMEM);903 if (!stats->descs || stats->num_counters <= 0)904 goto err_free_stats;905 906 /*907 * Two extra attribue elements here, one for the lifespan entry and908 * one to NULL terminate the list for the sysfs core code909 */910 data = kzalloc(struct_size(data, attrs, size_add(stats->num_counters, 1)),911 GFP_KERNEL);912 if (!data)913 goto err_free_stats;914 data->group.attrs = kcalloc(stats->num_counters + 2,915 sizeof(*data->group.attrs), GFP_KERNEL);916 if (!data->group.attrs)917 goto err_free_data;918 919 data->group.name = "hw_counters";920 data->stats = stats;921 return data;922 923err_free_data:924 kfree(data);925err_free_stats:926 rdma_free_hw_stats_struct(stats);927 return ERR_PTR(-ENOMEM);928}929 930void ib_device_release_hw_stats(struct hw_stats_device_data *data)931{932 kfree(data->group.attrs);933 rdma_free_hw_stats_struct(data->stats);934 kfree(data);935}936 937int ib_setup_device_attrs(struct ib_device *ibdev)938{939 struct hw_stats_device_attribute *attr;940 struct hw_stats_device_data *data;941 bool opstat_skipped = false;942 int i, ret, pos = 0;943 944 data = alloc_hw_stats_device(ibdev);945 if (IS_ERR(data)) {946 if (PTR_ERR(data) == -EOPNOTSUPP)947 return 0;948 return PTR_ERR(data);949 }950 ibdev->hw_stats_data = data;951 952 ret = ibdev->ops.get_hw_stats(ibdev, data->stats, 0,953 data->stats->num_counters);954 if (ret != data->stats->num_counters) {955 if (WARN_ON(ret >= 0))956 return -EINVAL;957 return ret;958 }959 960 data->stats->timestamp = jiffies;961 962 for (i = 0; i < data->stats->num_counters; i++) {963 if (data->stats->descs[i].flags & IB_STAT_FLAG_OPTIONAL) {964 opstat_skipped = true;965 continue;966 }967 968 WARN_ON(opstat_skipped);969 attr = &data->attrs[pos];970 sysfs_attr_init(&attr->attr.attr);971 attr->attr.attr.name = data->stats->descs[i].name;972 attr->attr.attr.mode = 0444;973 attr->attr.show = hw_stat_device_show;974 attr->show = show_hw_stats;975 data->group.attrs[pos] = &attr->attr.attr;976 pos++;977 }978 979 attr = &data->attrs[pos];980 sysfs_attr_init(&attr->attr.attr);981 attr->attr.attr.name = "lifespan";982 attr->attr.attr.mode = 0644;983 attr->attr.show = hw_stat_device_show;984 attr->show = show_stats_lifespan;985 attr->attr.store = hw_stat_device_store;986 attr->store = set_stats_lifespan;987 data->group.attrs[pos] = &attr->attr.attr;988 for (i = 0; i != ARRAY_SIZE(ibdev->groups); i++)989 if (!ibdev->groups[i]) {990 ibdev->groups[i] = &data->group;991 return 0;992 }993 WARN(true, "struct ib_device->groups is too small");994 return -EINVAL;995}996 997static struct hw_stats_port_data *998alloc_hw_stats_port(struct ib_port *port, struct attribute_group *group)999{1000 struct ib_device *ibdev = port->ibdev;1001 struct hw_stats_port_data *data;1002 struct rdma_hw_stats *stats;1003 1004 if (!ibdev->ops.alloc_hw_port_stats)1005 return ERR_PTR(-EOPNOTSUPP);1006 stats = ibdev->ops.alloc_hw_port_stats(port->ibdev, port->port_num);1007 if (!stats)1008 return ERR_PTR(-ENOMEM);1009 if (!stats->descs || stats->num_counters <= 0)1010 goto err_free_stats;1011 1012 /*1013 * Two extra attribue elements here, one for the lifespan entry and1014 * one to NULL terminate the list for the sysfs core code1015 */1016 data = kzalloc(struct_size(data, attrs, size_add(stats->num_counters, 1)),1017 GFP_KERNEL);1018 if (!data)1019 goto err_free_stats;1020 group->attrs = kcalloc(stats->num_counters + 2,1021 sizeof(*group->attrs), GFP_KERNEL);1022 if (!group->attrs)1023 goto err_free_data;1024 1025 group->name = "hw_counters";1026 data->stats = stats;1027 return data;1028 1029err_free_data:1030 kfree(data);1031err_free_stats:1032 rdma_free_hw_stats_struct(stats);1033 return ERR_PTR(-ENOMEM);1034}1035 1036static int setup_hw_port_stats(struct ib_port *port,1037 struct attribute_group *group)1038{1039 struct hw_stats_port_attribute *attr;1040 struct hw_stats_port_data *data;1041 bool opstat_skipped = false;1042 int i, ret, pos = 0;1043 1044 data = alloc_hw_stats_port(port, group);1045 if (IS_ERR(data))1046 return PTR_ERR(data);1047 1048 ret = port->ibdev->ops.get_hw_stats(port->ibdev, data->stats,1049 port->port_num,1050 data->stats->num_counters);1051 if (ret != data->stats->num_counters) {1052 if (WARN_ON(ret >= 0))1053 return -EINVAL;1054 return ret;1055 }1056 1057 data->stats->timestamp = jiffies;1058 1059 for (i = 0; i < data->stats->num_counters; i++) {1060 if (data->stats->descs[i].flags & IB_STAT_FLAG_OPTIONAL) {1061 opstat_skipped = true;1062 continue;1063 }1064 1065 WARN_ON(opstat_skipped);1066 attr = &data->attrs[pos];1067 sysfs_attr_init(&attr->attr.attr);1068 attr->attr.attr.name = data->stats->descs[i].name;1069 attr->attr.attr.mode = 0444;1070 attr->attr.show = hw_stat_port_show;1071 attr->show = show_hw_stats;1072 group->attrs[pos] = &attr->attr.attr;1073 pos++;1074 }1075 1076 attr = &data->attrs[pos];1077 sysfs_attr_init(&attr->attr.attr);1078 attr->attr.attr.name = "lifespan";1079 attr->attr.attr.mode = 0644;1080 attr->attr.show = hw_stat_port_show;1081 attr->show = show_stats_lifespan;1082 attr->attr.store = hw_stat_port_store;1083 attr->store = set_stats_lifespan;1084 group->attrs[pos] = &attr->attr.attr;1085 1086 port->hw_stats_data = data;1087 return 0;1088}1089 1090struct rdma_hw_stats *ib_get_hw_stats_port(struct ib_device *ibdev,1091 u32 port_num)1092{1093 if (!ibdev->port_data || !rdma_is_port_valid(ibdev, port_num) ||1094 !ibdev->port_data[port_num].sysfs->hw_stats_data)1095 return NULL;1096 return ibdev->port_data[port_num].sysfs->hw_stats_data->stats;1097}1098 1099static int1100alloc_port_table_group(const char *name, struct attribute_group *group,1101 struct port_table_attribute *attrs, size_t num,1102 ssize_t (*show)(struct ib_device *ibdev, u32 port_num,1103 struct ib_port_attribute *, char *buf))1104{1105 struct attribute **attr_list;1106 int i;1107 1108 attr_list = kcalloc(num + 1, sizeof(*attr_list), GFP_KERNEL);1109 if (!attr_list)1110 return -ENOMEM;1111 1112 for (i = 0; i < num; i++) {1113 struct port_table_attribute *element = &attrs[i];1114 1115 if (snprintf(element->name, sizeof(element->name), "%d", i) >=1116 sizeof(element->name))1117 goto err;1118 1119 sysfs_attr_init(&element->attr.attr);1120 element->attr.attr.name = element->name;1121 element->attr.attr.mode = 0444;1122 element->attr.show = show;1123 element->index = i;1124 1125 attr_list[i] = &element->attr.attr;1126 }1127 group->name = name;1128 group->attrs = attr_list;1129 return 0;1130err:1131 kfree(attr_list);1132 return -EINVAL;1133}1134 1135/*1136 * Create the sysfs:1137 * ibp0s9/ports/XX/gid_attrs/{ndevs,types}/YYY1138 * YYY is the gid table index in decimal1139 */1140static int setup_gid_attrs(struct ib_port *port,1141 const struct ib_port_attr *attr)1142{1143 struct gid_attr_group *gid_attr_group;1144 int ret;1145 1146 gid_attr_group = kzalloc(struct_size(gid_attr_group, attrs_list,1147 size_mul(attr->gid_tbl_len, 2)),1148 GFP_KERNEL);1149 if (!gid_attr_group)1150 return -ENOMEM;1151 gid_attr_group->port = port;1152 kobject_init(&gid_attr_group->kobj, &gid_attr_type);1153 1154 ret = alloc_port_table_group("ndevs", &gid_attr_group->groups[0],1155 gid_attr_group->attrs_list,1156 attr->gid_tbl_len,1157 show_port_gid_attr_ndev);1158 if (ret)1159 goto err_put;1160 gid_attr_group->groups_list[0] = &gid_attr_group->groups[0];1161 1162 ret = alloc_port_table_group(1163 "types", &gid_attr_group->groups[1],1164 gid_attr_group->attrs_list + attr->gid_tbl_len,1165 attr->gid_tbl_len, show_port_gid_attr_gid_type);1166 if (ret)1167 goto err_put;1168 gid_attr_group->groups_list[1] = &gid_attr_group->groups[1];1169 1170 ret = kobject_add(&gid_attr_group->kobj, &port->kobj, "gid_attrs");1171 if (ret)1172 goto err_put;1173 ret = sysfs_create_groups(&gid_attr_group->kobj,1174 gid_attr_group->groups_list);1175 if (ret)1176 goto err_del;1177 port->gid_attr_group = gid_attr_group;1178 return 0;1179 1180err_del:1181 kobject_del(&gid_attr_group->kobj);1182err_put:1183 kobject_put(&gid_attr_group->kobj);1184 return ret;1185}1186 1187static void destroy_gid_attrs(struct ib_port *port)1188{1189 struct gid_attr_group *gid_attr_group = port->gid_attr_group;1190 1191 if (!gid_attr_group)1192 return;1193 sysfs_remove_groups(&gid_attr_group->kobj, gid_attr_group->groups_list);1194 kobject_del(&gid_attr_group->kobj);1195 kobject_put(&gid_attr_group->kobj);1196}1197 1198/*1199 * Create the sysfs:1200 * ibp0s9/ports/XX/{gids,pkeys,counters}/YYY1201 */1202static struct ib_port *setup_port(struct ib_core_device *coredev, int port_num,1203 const struct ib_port_attr *attr)1204{1205 struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);1206 bool is_full_dev = &device->coredev == coredev;1207 const struct attribute_group **cur_group;1208 struct ib_port *p;1209 int ret;1210 1211 p = kvzalloc(struct_size(p, attrs_list,1212 size_add(attr->gid_tbl_len, attr->pkey_tbl_len)),1213 GFP_KERNEL);1214 if (!p)1215 return ERR_PTR(-ENOMEM);1216 p->ibdev = device;1217 p->port_num = port_num;1218 kobject_init(&p->kobj, &port_type);1219 1220 if (device->port_data && is_full_dev)1221 device->port_data[port_num].sysfs = p;1222 1223 cur_group = p->groups_list;1224 ret = alloc_port_table_group("gids", &p->groups[0], p->attrs_list,1225 attr->gid_tbl_len, show_port_gid);1226 if (ret)1227 goto err_put;1228 *cur_group++ = &p->groups[0];1229 1230 if (attr->pkey_tbl_len) {1231 ret = alloc_port_table_group("pkeys", &p->groups[1],1232 p->attrs_list + attr->gid_tbl_len,1233 attr->pkey_tbl_len, show_port_pkey);1234 if (ret)1235 goto err_put;1236 *cur_group++ = &p->groups[1];1237 }1238 1239 /*1240 * If port == 0, it means hw_counters are per device and not per1241 * port, so holder should be device. Therefore skip per port1242 * counter initialization.1243 */1244 if (port_num && is_full_dev) {1245 ret = setup_hw_port_stats(p, &p->groups[2]);1246 if (ret && ret != -EOPNOTSUPP)1247 goto err_put;1248 if (!ret)1249 *cur_group++ = &p->groups[2];1250 }1251 1252 if (device->ops.process_mad && is_full_dev)1253 *cur_group++ = get_counter_table(device, port_num);1254 1255 ret = kobject_add(&p->kobj, coredev->ports_kobj, "%d", port_num);1256 if (ret)1257 goto err_put;1258 ret = sysfs_create_groups(&p->kobj, p->groups_list);1259 if (ret)1260 goto err_del;1261 if (is_full_dev) {1262 ret = sysfs_create_groups(&p->kobj, device->ops.port_groups);1263 if (ret)1264 goto err_groups;1265 }1266 1267 list_add_tail(&p->kobj.entry, &coredev->port_list);1268 return p;1269 1270err_groups:1271 sysfs_remove_groups(&p->kobj, p->groups_list);1272err_del:1273 kobject_del(&p->kobj);1274err_put:1275 if (device->port_data && is_full_dev)1276 device->port_data[port_num].sysfs = NULL;1277 kobject_put(&p->kobj);1278 return ERR_PTR(ret);1279}1280 1281static void destroy_port(struct ib_core_device *coredev, struct ib_port *port)1282{1283 bool is_full_dev = &port->ibdev->coredev == coredev;1284 1285 list_del(&port->kobj.entry);1286 if (is_full_dev)1287 sysfs_remove_groups(&port->kobj, port->ibdev->ops.port_groups);1288 1289 sysfs_remove_groups(&port->kobj, port->groups_list);1290 kobject_del(&port->kobj);1291 1292 if (port->ibdev->port_data &&1293 port->ibdev->port_data[port->port_num].sysfs == port)1294 port->ibdev->port_data[port->port_num].sysfs = NULL;1295 1296 kobject_put(&port->kobj);1297}1298 1299static const char *node_type_string(int node_type)1300{1301 switch (node_type) {1302 case RDMA_NODE_IB_CA:1303 return "CA";1304 case RDMA_NODE_IB_SWITCH:1305 return "switch";1306 case RDMA_NODE_IB_ROUTER:1307 return "router";1308 case RDMA_NODE_RNIC:1309 return "RNIC";1310 case RDMA_NODE_USNIC:1311 return "usNIC";1312 case RDMA_NODE_USNIC_UDP:1313 return "usNIC UDP";1314 case RDMA_NODE_UNSPECIFIED:1315 return "unspecified";1316 }1317 return "<unknown>";1318}1319 1320static ssize_t node_type_show(struct device *device,1321 struct device_attribute *attr, char *buf)1322{1323 struct ib_device *dev = rdma_device_to_ibdev(device);1324 1325 return sysfs_emit(buf, "%u: %s\n", dev->node_type,1326 node_type_string(dev->node_type));1327}1328static DEVICE_ATTR_RO(node_type);1329 1330static ssize_t sys_image_guid_show(struct device *device,1331 struct device_attribute *dev_attr, char *buf)1332{1333 struct ib_device *dev = rdma_device_to_ibdev(device);1334 __be16 *guid = (__be16 *)&dev->attrs.sys_image_guid;1335 1336 return sysfs_emit(buf, "%04x:%04x:%04x:%04x\n",1337 be16_to_cpu(guid[0]),1338 be16_to_cpu(guid[1]),1339 be16_to_cpu(guid[2]),1340 be16_to_cpu(guid[3]));1341}1342static DEVICE_ATTR_RO(sys_image_guid);1343 1344static ssize_t node_guid_show(struct device *device,1345 struct device_attribute *attr, char *buf)1346{1347 struct ib_device *dev = rdma_device_to_ibdev(device);1348 __be16 *node_guid = (__be16 *)&dev->node_guid;1349 1350 return sysfs_emit(buf, "%04x:%04x:%04x:%04x\n",1351 be16_to_cpu(node_guid[0]),1352 be16_to_cpu(node_guid[1]),1353 be16_to_cpu(node_guid[2]),1354 be16_to_cpu(node_guid[3]));1355}1356static DEVICE_ATTR_RO(node_guid);1357 1358static ssize_t node_desc_show(struct device *device,1359 struct device_attribute *attr, char *buf)1360{1361 struct ib_device *dev = rdma_device_to_ibdev(device);1362 1363 return sysfs_emit(buf, "%.64s\n", dev->node_desc);1364}1365 1366static ssize_t node_desc_store(struct device *device,1367 struct device_attribute *attr,1368 const char *buf, size_t count)1369{1370 struct ib_device *dev = rdma_device_to_ibdev(device);1371 struct ib_device_modify desc = {};1372 int ret;1373 1374 if (!dev->ops.modify_device)1375 return -EOPNOTSUPP;1376 1377 memcpy(desc.node_desc, buf, min_t(int, count, IB_DEVICE_NODE_DESC_MAX));1378 ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);1379 if (ret)1380 return ret;1381 1382 return count;1383}1384static DEVICE_ATTR_RW(node_desc);1385 1386static ssize_t fw_ver_show(struct device *device, struct device_attribute *attr,1387 char *buf)1388{1389 struct ib_device *dev = rdma_device_to_ibdev(device);1390 char version[IB_FW_VERSION_NAME_MAX] = {};1391 1392 ib_get_device_fw_str(dev, version);1393 1394 return sysfs_emit(buf, "%s\n", version);1395}1396static DEVICE_ATTR_RO(fw_ver);1397 1398static struct attribute *ib_dev_attrs[] = {1399 &dev_attr_node_type.attr,1400 &dev_attr_node_guid.attr,1401 &dev_attr_sys_image_guid.attr,1402 &dev_attr_fw_ver.attr,1403 &dev_attr_node_desc.attr,1404 NULL,1405};1406 1407const struct attribute_group ib_dev_attr_group = {1408 .attrs = ib_dev_attrs,1409};1410 1411void ib_free_port_attrs(struct ib_core_device *coredev)1412{1413 struct kobject *p, *t;1414 1415 list_for_each_entry_safe(p, t, &coredev->port_list, entry) {1416 struct ib_port *port = container_of(p, struct ib_port, kobj);1417 1418 destroy_gid_attrs(port);1419 destroy_port(coredev, port);1420 }1421 1422 kobject_put(coredev->ports_kobj);1423}1424 1425int ib_setup_port_attrs(struct ib_core_device *coredev)1426{1427 struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);1428 u32 port_num;1429 int ret;1430 1431 coredev->ports_kobj = kobject_create_and_add("ports",1432 &coredev->dev.kobj);1433 if (!coredev->ports_kobj)1434 return -ENOMEM;1435 1436 rdma_for_each_port (device, port_num) {1437 struct ib_port_attr attr;1438 struct ib_port *port;1439 1440 ret = ib_query_port(device, port_num, &attr);1441 if (ret)1442 goto err_put;1443 1444 port = setup_port(coredev, port_num, &attr);1445 if (IS_ERR(port)) {1446 ret = PTR_ERR(port);1447 goto err_put;1448 }1449 1450 ret = setup_gid_attrs(port, &attr);1451 if (ret)1452 goto err_put;1453 }1454 return 0;1455 1456err_put:1457 ib_free_port_attrs(coredev);1458 return ret;1459}1460 1461/**1462 * ib_port_register_client_groups - Add an ib_client's attributes to the port1463 *1464 * @ibdev: IB device to add counters1465 * @port_num: valid port number1466 * @groups: Group list of attributes1467 *1468 * Do not use. Only for legacy sysfs compatibility.1469 */1470int ib_port_register_client_groups(struct ib_device *ibdev, u32 port_num,1471 const struct attribute_group **groups)1472{1473 return sysfs_create_groups(&ibdev->port_data[port_num].sysfs->kobj,1474 groups);1475}1476EXPORT_SYMBOL(ib_port_register_client_groups);1477 1478void ib_port_unregister_client_groups(struct ib_device *ibdev, u32 port_num,1479 const struct attribute_group **groups)1480{1481 return sysfs_remove_groups(&ibdev->port_data[port_num].sysfs->kobj,1482 groups);1483}1484EXPORT_SYMBOL(ib_port_unregister_client_groups);1485