| 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| 2 | /* |
| 3 | * Copyright(c) 2015-2017 Intel Corporation. |
| 4 | */ |
| 5 | |
| 6 | #include <linux/ctype.h> |
| 7 | #include <rdma/ib_sysfs.h> |
| 8 | |
| 9 | #include "hfi.h" |
| 10 | #include "mad.h" |
| 11 | #include "trace.h" |
| 12 | |
| 13 | static struct hfi1_pportdata *hfi1_get_pportdata_kobj(struct kobject *kobj) |
| 14 | { |
| 15 | u32 port_num; |
| 16 | struct ib_device *ibdev = ib_port_sysfs_get_ibdev_kobj(kobj, port_num: &port_num); |
| 17 | struct hfi1_devdata *dd = dd_from_ibdev(ibdev); |
| 18 | |
| 19 | return &dd->pport[port_num - 1]; |
| 20 | } |
| 21 | |
| 22 | /* |
| 23 | * Start of per-port congestion control structures and support code |
| 24 | */ |
| 25 | |
| 26 | /* |
| 27 | * Congestion control table size followed by table entries |
| 28 | */ |
| 29 | static ssize_t cc_table_bin_read(struct file *filp, struct kobject *kobj, |
| 30 | const struct bin_attribute *bin_attr, |
| 31 | char *buf, loff_t pos, size_t count) |
| 32 | { |
| 33 | int ret; |
| 34 | struct hfi1_pportdata *ppd = hfi1_get_pportdata_kobj(kobj); |
| 35 | struct cc_state *cc_state; |
| 36 | |
| 37 | ret = ppd->total_cct_entry * sizeof(struct ib_cc_table_entry_shadow) |
| 38 | + sizeof(__be16); |
| 39 | |
| 40 | if (pos > ret) |
| 41 | return -EINVAL; |
| 42 | |
| 43 | if (count > ret - pos) |
| 44 | count = ret - pos; |
| 45 | |
| 46 | if (!count) |
| 47 | return count; |
| 48 | |
| 49 | rcu_read_lock(); |
| 50 | cc_state = get_cc_state(ppd); |
| 51 | if (!cc_state) { |
| 52 | rcu_read_unlock(); |
| 53 | return -EINVAL; |
| 54 | } |
| 55 | memcpy(buf, (void *)&cc_state->cct + pos, count); |
| 56 | rcu_read_unlock(); |
| 57 | |
| 58 | return count; |
| 59 | } |
| 60 | static const BIN_ATTR_RO(cc_table_bin, PAGE_SIZE); |
| 61 | |
| 62 | /* |
| 63 | * Congestion settings: port control, control map and an array of 16 |
| 64 | * entries for the congestion entries - increase, timer, event log |
| 65 | * trigger threshold and the minimum injection rate delay. |
| 66 | */ |
| 67 | static ssize_t cc_setting_bin_read(struct file *filp, struct kobject *kobj, |
| 68 | const struct bin_attribute *bin_attr, |
| 69 | char *buf, loff_t pos, size_t count) |
| 70 | { |
| 71 | struct hfi1_pportdata *ppd = hfi1_get_pportdata_kobj(kobj); |
| 72 | int ret; |
| 73 | struct cc_state *cc_state; |
| 74 | |
| 75 | ret = sizeof(struct opa_congestion_setting_attr_shadow); |
| 76 | |
| 77 | if (pos > ret) |
| 78 | return -EINVAL; |
| 79 | if (count > ret - pos) |
| 80 | count = ret - pos; |
| 81 | |
| 82 | if (!count) |
| 83 | return count; |
| 84 | |
| 85 | rcu_read_lock(); |
| 86 | cc_state = get_cc_state(ppd); |
| 87 | if (!cc_state) { |
| 88 | rcu_read_unlock(); |
| 89 | return -EINVAL; |
| 90 | } |
| 91 | memcpy(buf, (void *)&cc_state->cong_setting + pos, count); |
| 92 | rcu_read_unlock(); |
| 93 | |
| 94 | return count; |
| 95 | } |
| 96 | static const BIN_ATTR_RO(cc_setting_bin, PAGE_SIZE); |
| 97 | |
| 98 | static const struct bin_attribute *const port_cc_bin_attributes[] = { |
| 99 | &bin_attr_cc_setting_bin, |
| 100 | &bin_attr_cc_table_bin, |
| 101 | NULL |
| 102 | }; |
| 103 | |
| 104 | static ssize_t cc_prescan_show(struct ib_device *ibdev, u32 port_num, |
| 105 | struct ib_port_attribute *attr, char *buf) |
| 106 | { |
| 107 | struct hfi1_devdata *dd = dd_from_ibdev(ibdev); |
| 108 | struct hfi1_pportdata *ppd = &dd->pport[port_num - 1]; |
| 109 | |
| 110 | return sysfs_emit(buf, fmt: "%s\n" , ppd->cc_prescan ? "on" : "off" ); |
| 111 | } |
| 112 | |
| 113 | static ssize_t cc_prescan_store(struct ib_device *ibdev, u32 port_num, |
| 114 | struct ib_port_attribute *attr, const char *buf, |
| 115 | size_t count) |
| 116 | { |
| 117 | struct hfi1_devdata *dd = dd_from_ibdev(ibdev); |
| 118 | struct hfi1_pportdata *ppd = &dd->pport[port_num - 1]; |
| 119 | |
| 120 | if (!memcmp(p: buf, q: "on" , size: 2)) |
| 121 | ppd->cc_prescan = true; |
| 122 | else if (!memcmp(p: buf, q: "off" , size: 3)) |
| 123 | ppd->cc_prescan = false; |
| 124 | |
| 125 | return count; |
| 126 | } |
| 127 | static IB_PORT_ATTR_ADMIN_RW(cc_prescan); |
| 128 | |
| 129 | static struct attribute *port_cc_attributes[] = { |
| 130 | &ib_port_attr_cc_prescan.attr, |
| 131 | NULL |
| 132 | }; |
| 133 | |
| 134 | static const struct attribute_group port_cc_group = { |
| 135 | .name = "CCMgtA" , |
| 136 | .attrs = port_cc_attributes, |
| 137 | .bin_attrs = port_cc_bin_attributes, |
| 138 | }; |
| 139 | |
| 140 | /* Start sc2vl */ |
| 141 | struct hfi1_sc2vl_attr { |
| 142 | struct ib_port_attribute attr; |
| 143 | int sc; |
| 144 | }; |
| 145 | |
| 146 | static ssize_t sc2vl_attr_show(struct ib_device *ibdev, u32 port_num, |
| 147 | struct ib_port_attribute *attr, char *buf) |
| 148 | { |
| 149 | struct hfi1_sc2vl_attr *sattr = |
| 150 | container_of(attr, struct hfi1_sc2vl_attr, attr); |
| 151 | struct hfi1_devdata *dd = dd_from_ibdev(ibdev); |
| 152 | |
| 153 | return sysfs_emit(buf, fmt: "%u\n" , *((u8 *)dd->sc2vl + sattr->sc)); |
| 154 | } |
| 155 | |
| 156 | #define HFI1_SC2VL_ATTR(N) \ |
| 157 | static struct hfi1_sc2vl_attr hfi1_sc2vl_attr_##N = { \ |
| 158 | .attr = __ATTR(N, 0444, sc2vl_attr_show, NULL), \ |
| 159 | .sc = N, \ |
| 160 | } |
| 161 | |
| 162 | HFI1_SC2VL_ATTR(0); |
| 163 | HFI1_SC2VL_ATTR(1); |
| 164 | HFI1_SC2VL_ATTR(2); |
| 165 | HFI1_SC2VL_ATTR(3); |
| 166 | HFI1_SC2VL_ATTR(4); |
| 167 | HFI1_SC2VL_ATTR(5); |
| 168 | HFI1_SC2VL_ATTR(6); |
| 169 | HFI1_SC2VL_ATTR(7); |
| 170 | HFI1_SC2VL_ATTR(8); |
| 171 | HFI1_SC2VL_ATTR(9); |
| 172 | HFI1_SC2VL_ATTR(10); |
| 173 | HFI1_SC2VL_ATTR(11); |
| 174 | HFI1_SC2VL_ATTR(12); |
| 175 | HFI1_SC2VL_ATTR(13); |
| 176 | HFI1_SC2VL_ATTR(14); |
| 177 | HFI1_SC2VL_ATTR(15); |
| 178 | HFI1_SC2VL_ATTR(16); |
| 179 | HFI1_SC2VL_ATTR(17); |
| 180 | HFI1_SC2VL_ATTR(18); |
| 181 | HFI1_SC2VL_ATTR(19); |
| 182 | HFI1_SC2VL_ATTR(20); |
| 183 | HFI1_SC2VL_ATTR(21); |
| 184 | HFI1_SC2VL_ATTR(22); |
| 185 | HFI1_SC2VL_ATTR(23); |
| 186 | HFI1_SC2VL_ATTR(24); |
| 187 | HFI1_SC2VL_ATTR(25); |
| 188 | HFI1_SC2VL_ATTR(26); |
| 189 | HFI1_SC2VL_ATTR(27); |
| 190 | HFI1_SC2VL_ATTR(28); |
| 191 | HFI1_SC2VL_ATTR(29); |
| 192 | HFI1_SC2VL_ATTR(30); |
| 193 | HFI1_SC2VL_ATTR(31); |
| 194 | |
| 195 | static struct attribute *port_sc2vl_attributes[] = { |
| 196 | &hfi1_sc2vl_attr_0.attr.attr, |
| 197 | &hfi1_sc2vl_attr_1.attr.attr, |
| 198 | &hfi1_sc2vl_attr_2.attr.attr, |
| 199 | &hfi1_sc2vl_attr_3.attr.attr, |
| 200 | &hfi1_sc2vl_attr_4.attr.attr, |
| 201 | &hfi1_sc2vl_attr_5.attr.attr, |
| 202 | &hfi1_sc2vl_attr_6.attr.attr, |
| 203 | &hfi1_sc2vl_attr_7.attr.attr, |
| 204 | &hfi1_sc2vl_attr_8.attr.attr, |
| 205 | &hfi1_sc2vl_attr_9.attr.attr, |
| 206 | &hfi1_sc2vl_attr_10.attr.attr, |
| 207 | &hfi1_sc2vl_attr_11.attr.attr, |
| 208 | &hfi1_sc2vl_attr_12.attr.attr, |
| 209 | &hfi1_sc2vl_attr_13.attr.attr, |
| 210 | &hfi1_sc2vl_attr_14.attr.attr, |
| 211 | &hfi1_sc2vl_attr_15.attr.attr, |
| 212 | &hfi1_sc2vl_attr_16.attr.attr, |
| 213 | &hfi1_sc2vl_attr_17.attr.attr, |
| 214 | &hfi1_sc2vl_attr_18.attr.attr, |
| 215 | &hfi1_sc2vl_attr_19.attr.attr, |
| 216 | &hfi1_sc2vl_attr_20.attr.attr, |
| 217 | &hfi1_sc2vl_attr_21.attr.attr, |
| 218 | &hfi1_sc2vl_attr_22.attr.attr, |
| 219 | &hfi1_sc2vl_attr_23.attr.attr, |
| 220 | &hfi1_sc2vl_attr_24.attr.attr, |
| 221 | &hfi1_sc2vl_attr_25.attr.attr, |
| 222 | &hfi1_sc2vl_attr_26.attr.attr, |
| 223 | &hfi1_sc2vl_attr_27.attr.attr, |
| 224 | &hfi1_sc2vl_attr_28.attr.attr, |
| 225 | &hfi1_sc2vl_attr_29.attr.attr, |
| 226 | &hfi1_sc2vl_attr_30.attr.attr, |
| 227 | &hfi1_sc2vl_attr_31.attr.attr, |
| 228 | NULL |
| 229 | }; |
| 230 | |
| 231 | static const struct attribute_group port_sc2vl_group = { |
| 232 | .name = "sc2vl" , |
| 233 | .attrs = port_sc2vl_attributes, |
| 234 | }; |
| 235 | /* End sc2vl */ |
| 236 | |
| 237 | /* Start sl2sc */ |
| 238 | struct hfi1_sl2sc_attr { |
| 239 | struct ib_port_attribute attr; |
| 240 | int sl; |
| 241 | }; |
| 242 | |
| 243 | static ssize_t sl2sc_attr_show(struct ib_device *ibdev, u32 port_num, |
| 244 | struct ib_port_attribute *attr, char *buf) |
| 245 | { |
| 246 | struct hfi1_sl2sc_attr *sattr = |
| 247 | container_of(attr, struct hfi1_sl2sc_attr, attr); |
| 248 | struct hfi1_devdata *dd = dd_from_ibdev(ibdev); |
| 249 | struct hfi1_ibport *ibp = &dd->pport[port_num - 1].ibport_data; |
| 250 | |
| 251 | return sysfs_emit(buf, fmt: "%u\n" , ibp->sl_to_sc[sattr->sl]); |
| 252 | } |
| 253 | |
| 254 | #define HFI1_SL2SC_ATTR(N) \ |
| 255 | static struct hfi1_sl2sc_attr hfi1_sl2sc_attr_##N = { \ |
| 256 | .attr = __ATTR(N, 0444, sl2sc_attr_show, NULL), .sl = N \ |
| 257 | } |
| 258 | |
| 259 | HFI1_SL2SC_ATTR(0); |
| 260 | HFI1_SL2SC_ATTR(1); |
| 261 | HFI1_SL2SC_ATTR(2); |
| 262 | HFI1_SL2SC_ATTR(3); |
| 263 | HFI1_SL2SC_ATTR(4); |
| 264 | HFI1_SL2SC_ATTR(5); |
| 265 | HFI1_SL2SC_ATTR(6); |
| 266 | HFI1_SL2SC_ATTR(7); |
| 267 | HFI1_SL2SC_ATTR(8); |
| 268 | HFI1_SL2SC_ATTR(9); |
| 269 | HFI1_SL2SC_ATTR(10); |
| 270 | HFI1_SL2SC_ATTR(11); |
| 271 | HFI1_SL2SC_ATTR(12); |
| 272 | HFI1_SL2SC_ATTR(13); |
| 273 | HFI1_SL2SC_ATTR(14); |
| 274 | HFI1_SL2SC_ATTR(15); |
| 275 | HFI1_SL2SC_ATTR(16); |
| 276 | HFI1_SL2SC_ATTR(17); |
| 277 | HFI1_SL2SC_ATTR(18); |
| 278 | HFI1_SL2SC_ATTR(19); |
| 279 | HFI1_SL2SC_ATTR(20); |
| 280 | HFI1_SL2SC_ATTR(21); |
| 281 | HFI1_SL2SC_ATTR(22); |
| 282 | HFI1_SL2SC_ATTR(23); |
| 283 | HFI1_SL2SC_ATTR(24); |
| 284 | HFI1_SL2SC_ATTR(25); |
| 285 | HFI1_SL2SC_ATTR(26); |
| 286 | HFI1_SL2SC_ATTR(27); |
| 287 | HFI1_SL2SC_ATTR(28); |
| 288 | HFI1_SL2SC_ATTR(29); |
| 289 | HFI1_SL2SC_ATTR(30); |
| 290 | HFI1_SL2SC_ATTR(31); |
| 291 | |
| 292 | static struct attribute *port_sl2sc_attributes[] = { |
| 293 | &hfi1_sl2sc_attr_0.attr.attr, |
| 294 | &hfi1_sl2sc_attr_1.attr.attr, |
| 295 | &hfi1_sl2sc_attr_2.attr.attr, |
| 296 | &hfi1_sl2sc_attr_3.attr.attr, |
| 297 | &hfi1_sl2sc_attr_4.attr.attr, |
| 298 | &hfi1_sl2sc_attr_5.attr.attr, |
| 299 | &hfi1_sl2sc_attr_6.attr.attr, |
| 300 | &hfi1_sl2sc_attr_7.attr.attr, |
| 301 | &hfi1_sl2sc_attr_8.attr.attr, |
| 302 | &hfi1_sl2sc_attr_9.attr.attr, |
| 303 | &hfi1_sl2sc_attr_10.attr.attr, |
| 304 | &hfi1_sl2sc_attr_11.attr.attr, |
| 305 | &hfi1_sl2sc_attr_12.attr.attr, |
| 306 | &hfi1_sl2sc_attr_13.attr.attr, |
| 307 | &hfi1_sl2sc_attr_14.attr.attr, |
| 308 | &hfi1_sl2sc_attr_15.attr.attr, |
| 309 | &hfi1_sl2sc_attr_16.attr.attr, |
| 310 | &hfi1_sl2sc_attr_17.attr.attr, |
| 311 | &hfi1_sl2sc_attr_18.attr.attr, |
| 312 | &hfi1_sl2sc_attr_19.attr.attr, |
| 313 | &hfi1_sl2sc_attr_20.attr.attr, |
| 314 | &hfi1_sl2sc_attr_21.attr.attr, |
| 315 | &hfi1_sl2sc_attr_22.attr.attr, |
| 316 | &hfi1_sl2sc_attr_23.attr.attr, |
| 317 | &hfi1_sl2sc_attr_24.attr.attr, |
| 318 | &hfi1_sl2sc_attr_25.attr.attr, |
| 319 | &hfi1_sl2sc_attr_26.attr.attr, |
| 320 | &hfi1_sl2sc_attr_27.attr.attr, |
| 321 | &hfi1_sl2sc_attr_28.attr.attr, |
| 322 | &hfi1_sl2sc_attr_29.attr.attr, |
| 323 | &hfi1_sl2sc_attr_30.attr.attr, |
| 324 | &hfi1_sl2sc_attr_31.attr.attr, |
| 325 | NULL |
| 326 | }; |
| 327 | |
| 328 | static const struct attribute_group port_sl2sc_group = { |
| 329 | .name = "sl2sc" , |
| 330 | .attrs = port_sl2sc_attributes, |
| 331 | }; |
| 332 | |
| 333 | /* End sl2sc */ |
| 334 | |
| 335 | /* Start vl2mtu */ |
| 336 | |
| 337 | struct hfi1_vl2mtu_attr { |
| 338 | struct ib_port_attribute attr; |
| 339 | int vl; |
| 340 | }; |
| 341 | |
| 342 | static ssize_t vl2mtu_attr_show(struct ib_device *ibdev, u32 port_num, |
| 343 | struct ib_port_attribute *attr, char *buf) |
| 344 | { |
| 345 | struct hfi1_vl2mtu_attr *vlattr = |
| 346 | container_of(attr, struct hfi1_vl2mtu_attr, attr); |
| 347 | struct hfi1_devdata *dd = dd_from_ibdev(ibdev); |
| 348 | |
| 349 | return sysfs_emit(buf, fmt: "%u\n" , dd->vld[vlattr->vl].mtu); |
| 350 | } |
| 351 | |
| 352 | #define HFI1_VL2MTU_ATTR(N) \ |
| 353 | static struct hfi1_vl2mtu_attr hfi1_vl2mtu_attr_##N = { \ |
| 354 | .attr = __ATTR(N, 0444, vl2mtu_attr_show, NULL), \ |
| 355 | .vl = N, \ |
| 356 | } |
| 357 | |
| 358 | HFI1_VL2MTU_ATTR(0); |
| 359 | HFI1_VL2MTU_ATTR(1); |
| 360 | HFI1_VL2MTU_ATTR(2); |
| 361 | HFI1_VL2MTU_ATTR(3); |
| 362 | HFI1_VL2MTU_ATTR(4); |
| 363 | HFI1_VL2MTU_ATTR(5); |
| 364 | HFI1_VL2MTU_ATTR(6); |
| 365 | HFI1_VL2MTU_ATTR(7); |
| 366 | HFI1_VL2MTU_ATTR(8); |
| 367 | HFI1_VL2MTU_ATTR(9); |
| 368 | HFI1_VL2MTU_ATTR(10); |
| 369 | HFI1_VL2MTU_ATTR(11); |
| 370 | HFI1_VL2MTU_ATTR(12); |
| 371 | HFI1_VL2MTU_ATTR(13); |
| 372 | HFI1_VL2MTU_ATTR(14); |
| 373 | HFI1_VL2MTU_ATTR(15); |
| 374 | |
| 375 | static struct attribute *port_vl2mtu_attributes[] = { |
| 376 | &hfi1_vl2mtu_attr_0.attr.attr, |
| 377 | &hfi1_vl2mtu_attr_1.attr.attr, |
| 378 | &hfi1_vl2mtu_attr_2.attr.attr, |
| 379 | &hfi1_vl2mtu_attr_3.attr.attr, |
| 380 | &hfi1_vl2mtu_attr_4.attr.attr, |
| 381 | &hfi1_vl2mtu_attr_5.attr.attr, |
| 382 | &hfi1_vl2mtu_attr_6.attr.attr, |
| 383 | &hfi1_vl2mtu_attr_7.attr.attr, |
| 384 | &hfi1_vl2mtu_attr_8.attr.attr, |
| 385 | &hfi1_vl2mtu_attr_9.attr.attr, |
| 386 | &hfi1_vl2mtu_attr_10.attr.attr, |
| 387 | &hfi1_vl2mtu_attr_11.attr.attr, |
| 388 | &hfi1_vl2mtu_attr_12.attr.attr, |
| 389 | &hfi1_vl2mtu_attr_13.attr.attr, |
| 390 | &hfi1_vl2mtu_attr_14.attr.attr, |
| 391 | &hfi1_vl2mtu_attr_15.attr.attr, |
| 392 | NULL |
| 393 | }; |
| 394 | |
| 395 | static const struct attribute_group port_vl2mtu_group = { |
| 396 | .name = "vl2mtu" , |
| 397 | .attrs = port_vl2mtu_attributes, |
| 398 | }; |
| 399 | |
| 400 | /* end of per-port file structures and support code */ |
| 401 | |
| 402 | /* |
| 403 | * Start of per-unit (or driver, in some cases, but replicated |
| 404 | * per unit) functions (these get a device *) |
| 405 | */ |
| 406 | static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, |
| 407 | char *buf) |
| 408 | { |
| 409 | struct hfi1_ibdev *dev = |
| 410 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 411 | |
| 412 | return sysfs_emit(buf, fmt: "%x\n" , dd_from_dev(dev)->minrev); |
| 413 | } |
| 414 | static DEVICE_ATTR_RO(hw_rev); |
| 415 | |
| 416 | static ssize_t board_id_show(struct device *device, |
| 417 | struct device_attribute *attr, char *buf) |
| 418 | { |
| 419 | struct hfi1_ibdev *dev = |
| 420 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 421 | struct hfi1_devdata *dd = dd_from_dev(dev); |
| 422 | |
| 423 | if (!dd->boardname) |
| 424 | return -EINVAL; |
| 425 | |
| 426 | return sysfs_emit(buf, fmt: "%s\n" , dd->boardname); |
| 427 | } |
| 428 | static DEVICE_ATTR_RO(board_id); |
| 429 | |
| 430 | static ssize_t boardversion_show(struct device *device, |
| 431 | struct device_attribute *attr, char *buf) |
| 432 | { |
| 433 | struct hfi1_ibdev *dev = |
| 434 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 435 | struct hfi1_devdata *dd = dd_from_dev(dev); |
| 436 | |
| 437 | /* The string printed here is already newline-terminated. */ |
| 438 | return sysfs_emit(buf, fmt: "%s" , dd->boardversion); |
| 439 | } |
| 440 | static DEVICE_ATTR_RO(boardversion); |
| 441 | |
| 442 | static ssize_t nctxts_show(struct device *device, |
| 443 | struct device_attribute *attr, char *buf) |
| 444 | { |
| 445 | struct hfi1_ibdev *dev = |
| 446 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 447 | struct hfi1_devdata *dd = dd_from_dev(dev); |
| 448 | |
| 449 | /* |
| 450 | * Return the smaller of send and receive contexts. |
| 451 | * Normally, user level applications would require both a send |
| 452 | * and a receive context, so returning the smaller of the two counts |
| 453 | * give a more accurate picture of total contexts available. |
| 454 | */ |
| 455 | return sysfs_emit(buf, fmt: "%u\n" , |
| 456 | min(dd->num_user_contexts, |
| 457 | (u32)dd->sc_sizes[SC_USER].count)); |
| 458 | } |
| 459 | static DEVICE_ATTR_RO(nctxts); |
| 460 | |
| 461 | static ssize_t nfreectxts_show(struct device *device, |
| 462 | struct device_attribute *attr, char *buf) |
| 463 | { |
| 464 | struct hfi1_ibdev *dev = |
| 465 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 466 | struct hfi1_devdata *dd = dd_from_dev(dev); |
| 467 | |
| 468 | /* Return the number of free user ports (contexts) available. */ |
| 469 | return sysfs_emit(buf, fmt: "%u\n" , dd->freectxts); |
| 470 | } |
| 471 | static DEVICE_ATTR_RO(nfreectxts); |
| 472 | |
| 473 | static ssize_t serial_show(struct device *device, |
| 474 | struct device_attribute *attr, char *buf) |
| 475 | { |
| 476 | struct hfi1_ibdev *dev = |
| 477 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 478 | struct hfi1_devdata *dd = dd_from_dev(dev); |
| 479 | |
| 480 | /* dd->serial is already newline terminated in chip.c */ |
| 481 | return sysfs_emit(buf, fmt: "%s" , dd->serial); |
| 482 | } |
| 483 | static DEVICE_ATTR_RO(serial); |
| 484 | |
| 485 | static ssize_t chip_reset_store(struct device *device, |
| 486 | struct device_attribute *attr, const char *buf, |
| 487 | size_t count) |
| 488 | { |
| 489 | struct hfi1_ibdev *dev = |
| 490 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 491 | struct hfi1_devdata *dd = dd_from_dev(dev); |
| 492 | int ret; |
| 493 | |
| 494 | if (count < 5 || memcmp(p: buf, q: "reset" , size: 5) || !dd->diag_client) { |
| 495 | ret = -EINVAL; |
| 496 | goto bail; |
| 497 | } |
| 498 | |
| 499 | ret = hfi1_reset_device(dd->unit); |
| 500 | bail: |
| 501 | return ret < 0 ? ret : count; |
| 502 | } |
| 503 | static DEVICE_ATTR_WO(chip_reset); |
| 504 | |
| 505 | /* |
| 506 | * Convert the reported temperature from an integer (reported in |
| 507 | * units of 0.25C) to a floating point number. |
| 508 | */ |
| 509 | #define temp_d(t) ((t) >> 2) |
| 510 | #define temp_f(t) (((t)&0x3) * 25u) |
| 511 | |
| 512 | /* |
| 513 | * Dump tempsense values, in decimal, to ease shell-scripts. |
| 514 | */ |
| 515 | static ssize_t tempsense_show(struct device *device, |
| 516 | struct device_attribute *attr, char *buf) |
| 517 | { |
| 518 | struct hfi1_ibdev *dev = |
| 519 | rdma_device_to_drv_device(device, struct hfi1_ibdev, rdi.ibdev); |
| 520 | struct hfi1_devdata *dd = dd_from_dev(dev); |
| 521 | struct hfi1_temp temp; |
| 522 | int ret; |
| 523 | |
| 524 | ret = hfi1_tempsense_rd(dd, temp: &temp); |
| 525 | if (ret) |
| 526 | return ret; |
| 527 | |
| 528 | return sysfs_emit(buf, fmt: "%u.%02u %u.%02u %u.%02u %u.%02u %u %u %u\n" , |
| 529 | temp_d(temp.curr), temp_f(temp.curr), |
| 530 | temp_d(temp.lo_lim), temp_f(temp.lo_lim), |
| 531 | temp_d(temp.hi_lim), temp_f(temp.hi_lim), |
| 532 | temp_d(temp.crit_lim), temp_f(temp.crit_lim), |
| 533 | temp.triggers & 0x1, |
| 534 | temp.triggers & 0x2, |
| 535 | temp.triggers & 0x4); |
| 536 | } |
| 537 | static DEVICE_ATTR_RO(tempsense); |
| 538 | |
| 539 | /* |
| 540 | * end of per-unit (or driver, in some cases, but replicated |
| 541 | * per unit) functions |
| 542 | */ |
| 543 | |
| 544 | /* start of per-unit file structures and support code */ |
| 545 | static struct attribute *hfi1_attributes[] = { |
| 546 | &dev_attr_hw_rev.attr, |
| 547 | &dev_attr_board_id.attr, |
| 548 | &dev_attr_nctxts.attr, |
| 549 | &dev_attr_nfreectxts.attr, |
| 550 | &dev_attr_serial.attr, |
| 551 | &dev_attr_boardversion.attr, |
| 552 | &dev_attr_tempsense.attr, |
| 553 | &dev_attr_chip_reset.attr, |
| 554 | NULL, |
| 555 | }; |
| 556 | |
| 557 | const struct attribute_group ib_hfi1_attr_group = { |
| 558 | .attrs = hfi1_attributes, |
| 559 | }; |
| 560 | |
| 561 | const struct attribute_group *hfi1_attr_port_groups[] = { |
| 562 | &port_cc_group, |
| 563 | &port_sc2vl_group, |
| 564 | &port_sl2sc_group, |
| 565 | &port_vl2mtu_group, |
| 566 | NULL, |
| 567 | }; |
| 568 | |
| 569 | struct sde_attribute { |
| 570 | struct attribute attr; |
| 571 | ssize_t (*show)(struct sdma_engine *sde, char *buf); |
| 572 | ssize_t (*store)(struct sdma_engine *sde, const char *buf, size_t cnt); |
| 573 | }; |
| 574 | |
| 575 | static ssize_t sde_show(struct kobject *kobj, struct attribute *attr, char *buf) |
| 576 | { |
| 577 | struct sde_attribute *sde_attr = |
| 578 | container_of(attr, struct sde_attribute, attr); |
| 579 | struct sdma_engine *sde = |
| 580 | container_of(kobj, struct sdma_engine, kobj); |
| 581 | |
| 582 | if (!sde_attr->show) |
| 583 | return -EINVAL; |
| 584 | |
| 585 | return sde_attr->show(sde, buf); |
| 586 | } |
| 587 | |
| 588 | static ssize_t sde_store(struct kobject *kobj, struct attribute *attr, |
| 589 | const char *buf, size_t count) |
| 590 | { |
| 591 | struct sde_attribute *sde_attr = |
| 592 | container_of(attr, struct sde_attribute, attr); |
| 593 | struct sdma_engine *sde = |
| 594 | container_of(kobj, struct sdma_engine, kobj); |
| 595 | |
| 596 | if (!capable(CAP_SYS_ADMIN)) |
| 597 | return -EPERM; |
| 598 | |
| 599 | if (!sde_attr->store) |
| 600 | return -EINVAL; |
| 601 | |
| 602 | return sde_attr->store(sde, buf, count); |
| 603 | } |
| 604 | |
| 605 | static const struct sysfs_ops sde_sysfs_ops = { |
| 606 | .show = sde_show, |
| 607 | .store = sde_store, |
| 608 | }; |
| 609 | |
| 610 | static struct kobj_type sde_ktype = { |
| 611 | .sysfs_ops = &sde_sysfs_ops, |
| 612 | }; |
| 613 | |
| 614 | #define SDE_ATTR(_name, _mode, _show, _store) \ |
| 615 | struct sde_attribute sde_attr_##_name = \ |
| 616 | __ATTR(_name, _mode, _show, _store) |
| 617 | |
| 618 | static ssize_t sde_show_cpu_to_sde_map(struct sdma_engine *sde, char *buf) |
| 619 | { |
| 620 | return sdma_get_cpu_to_sde_map(sde, buf); |
| 621 | } |
| 622 | |
| 623 | static ssize_t sde_store_cpu_to_sde_map(struct sdma_engine *sde, |
| 624 | const char *buf, size_t count) |
| 625 | { |
| 626 | return sdma_set_cpu_to_sde_map(sde, buf, count); |
| 627 | } |
| 628 | |
| 629 | static ssize_t sde_show_vl(struct sdma_engine *sde, char *buf) |
| 630 | { |
| 631 | int vl; |
| 632 | |
| 633 | vl = sdma_engine_get_vl(sde); |
| 634 | if (vl < 0) |
| 635 | return vl; |
| 636 | |
| 637 | return sysfs_emit(buf, fmt: "%d\n" , vl); |
| 638 | } |
| 639 | |
| 640 | static SDE_ATTR(cpu_list, S_IWUSR | S_IRUGO, |
| 641 | sde_show_cpu_to_sde_map, |
| 642 | sde_store_cpu_to_sde_map); |
| 643 | static SDE_ATTR(vl, S_IRUGO, sde_show_vl, NULL); |
| 644 | |
| 645 | static struct sde_attribute *sde_attribs[] = { |
| 646 | &sde_attr_cpu_list, |
| 647 | &sde_attr_vl |
| 648 | }; |
| 649 | |
| 650 | /* |
| 651 | * Register and create our files in /sys/class/infiniband. |
| 652 | */ |
| 653 | int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd) |
| 654 | { |
| 655 | struct ib_device *dev = &dd->verbs_dev.rdi.ibdev; |
| 656 | struct device *class_dev = &dev->dev; |
| 657 | int i, j, ret; |
| 658 | |
| 659 | for (i = 0; i < dd->num_sdma; i++) { |
| 660 | ret = kobject_init_and_add(kobj: &dd->per_sdma[i].kobj, |
| 661 | ktype: &sde_ktype, parent: &class_dev->kobj, |
| 662 | fmt: "sdma%d" , i); |
| 663 | if (ret) |
| 664 | goto bail; |
| 665 | |
| 666 | for (j = 0; j < ARRAY_SIZE(sde_attribs); j++) { |
| 667 | ret = sysfs_create_file(kobj: &dd->per_sdma[i].kobj, |
| 668 | attr: &sde_attribs[j]->attr); |
| 669 | if (ret) |
| 670 | goto bail; |
| 671 | } |
| 672 | } |
| 673 | |
| 674 | return 0; |
| 675 | bail: |
| 676 | /* |
| 677 | * The function kobject_put() will call kobject_del() if the kobject |
| 678 | * has been added successfully. The sysfs files created under the |
| 679 | * kobject directory will also be removed during the process. |
| 680 | */ |
| 681 | for (; i >= 0; i--) |
| 682 | kobject_put(kobj: &dd->per_sdma[i].kobj); |
| 683 | |
| 684 | return ret; |
| 685 | } |
| 686 | |
| 687 | /* |
| 688 | * Unregister and remove our files in /sys/class/infiniband. |
| 689 | */ |
| 690 | void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd) |
| 691 | { |
| 692 | int i; |
| 693 | |
| 694 | /* Unwind operations in hfi1_verbs_register_sysfs() */ |
| 695 | for (i = 0; i < dd->num_sdma; i++) |
| 696 | kobject_put(kobj: &dd->per_sdma[i].kobj); |
| 697 | } |
| 698 | |