usnic_ib_sysfs.c revision 60b215e8b267f911751a043de63181dab1b69706
1/* 2 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 3 * 4 * This program is free software; you may redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; version 2 of the License. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15 * SOFTWARE. 16 * 17 */ 18 19#include <linux/module.h> 20#include <linux/init.h> 21#include <linux/errno.h> 22 23#include <rdma/ib_user_verbs.h> 24#include <rdma/ib_addr.h> 25 26#include "usnic_common_util.h" 27#include "usnic_ib.h" 28#include "usnic_ib_qp_grp.h" 29#include "usnic_vnic.h" 30#include "usnic_ib_verbs.h" 31#include "usnic_log.h" 32 33#define UPDATE_PTR_LEFT(N, P, L) \ 34do { \ 35 L -= (N); \ 36 P += (N); \ 37} while (0) 38 39static ssize_t usnic_ib_show_fw_ver(struct device *device, 40 struct device_attribute *attr, 41 char *buf) 42{ 43 struct usnic_ib_dev *us_ibdev = 44 container_of(device, struct usnic_ib_dev, ib_dev.dev); 45 struct ethtool_drvinfo info; 46 47 mutex_lock(&us_ibdev->usdev_lock); 48 us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info); 49 mutex_unlock(&us_ibdev->usdev_lock); 50 51 return scnprintf(buf, PAGE_SIZE, "%s\n", info.fw_version); 52} 53 54static ssize_t usnic_ib_show_board(struct device *device, 55 struct device_attribute *attr, 56 char *buf) 57{ 58 struct usnic_ib_dev *us_ibdev = 59 container_of(device, struct usnic_ib_dev, ib_dev.dev); 60 unsigned short subsystem_device_id; 61 62 mutex_lock(&us_ibdev->usdev_lock); 63 subsystem_device_id = us_ibdev->pdev->subsystem_device; 64 mutex_unlock(&us_ibdev->usdev_lock); 65 66 return scnprintf(buf, PAGE_SIZE, "%hu\n", subsystem_device_id); 67} 68 69/* 70 * Report the configuration for this PF 71 */ 72static ssize_t 73usnic_ib_show_config(struct device *device, struct device_attribute *attr, 74 char *buf) 75{ 76 struct usnic_ib_dev *us_ibdev; 77 char *ptr; 78 unsigned left; 79 unsigned n; 80 enum usnic_vnic_res_type res_type; 81 82 us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); 83 84 /* Buffer space limit is 1 page */ 85 ptr = buf; 86 left = PAGE_SIZE; 87 88 mutex_lock(&us_ibdev->usdev_lock); 89 if (atomic_read(&us_ibdev->vf_cnt.refcount) > 0) { 90 char *busname; 91 92 /* 93 * bus name seems to come with annoying prefix. 94 * Remove it if it is predictable 95 */ 96 busname = us_ibdev->pdev->bus->name; 97 if (strncmp(busname, "PCI Bus ", 8) == 0) 98 busname += 8; 99 100 n = scnprintf(ptr, left, 101 "%s: %s:%d.%d, %s, %pM, %u VFs\n Per VF:", 102 us_ibdev->ib_dev.name, 103 busname, 104 PCI_SLOT(us_ibdev->pdev->devfn), 105 PCI_FUNC(us_ibdev->pdev->devfn), 106 netdev_name(us_ibdev->netdev), 107 us_ibdev->ufdev->mac, 108 atomic_read(&us_ibdev->vf_cnt.refcount)); 109 UPDATE_PTR_LEFT(n, ptr, left); 110 111 for (res_type = USNIC_VNIC_RES_TYPE_EOL; 112 res_type < USNIC_VNIC_RES_TYPE_MAX; 113 res_type++) { 114 if (us_ibdev->vf_res_cnt[res_type] == 0) 115 continue; 116 n = scnprintf(ptr, left, " %d %s%s", 117 us_ibdev->vf_res_cnt[res_type], 118 usnic_vnic_res_type_to_str(res_type), 119 (res_type < (USNIC_VNIC_RES_TYPE_MAX - 1)) ? 120 "," : ""); 121 UPDATE_PTR_LEFT(n, ptr, left); 122 } 123 n = scnprintf(ptr, left, "\n"); 124 UPDATE_PTR_LEFT(n, ptr, left); 125 } else { 126 n = scnprintf(ptr, left, "%s: no VFs\n", 127 us_ibdev->ib_dev.name); 128 UPDATE_PTR_LEFT(n, ptr, left); 129 } 130 mutex_unlock(&us_ibdev->usdev_lock); 131 132 return ptr - buf; 133} 134 135static ssize_t 136usnic_ib_show_iface(struct device *device, struct device_attribute *attr, 137 char *buf) 138{ 139 struct usnic_ib_dev *us_ibdev; 140 141 us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); 142 143 return scnprintf(buf, PAGE_SIZE, "%s\n", 144 netdev_name(us_ibdev->netdev)); 145} 146 147static ssize_t 148usnic_ib_show_max_vf(struct device *device, struct device_attribute *attr, 149 char *buf) 150{ 151 struct usnic_ib_dev *us_ibdev; 152 153 us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); 154 155 return scnprintf(buf, PAGE_SIZE, "%u\n", 156 atomic_read(&us_ibdev->vf_cnt.refcount)); 157} 158 159static ssize_t 160usnic_ib_show_qp_per_vf(struct device *device, struct device_attribute *attr, 161 char *buf) 162{ 163 struct usnic_ib_dev *us_ibdev; 164 int qp_per_vf; 165 166 us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); 167 qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ], 168 us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]); 169 170 return scnprintf(buf, PAGE_SIZE, 171 "%d\n", qp_per_vf); 172} 173 174static ssize_t 175usnic_ib_show_cq_per_vf(struct device *device, struct device_attribute *attr, 176 char *buf) 177{ 178 struct usnic_ib_dev *us_ibdev; 179 180 us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); 181 182 return scnprintf(buf, PAGE_SIZE, "%d\n", 183 us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]); 184} 185 186static DEVICE_ATTR(fw_ver, S_IRUGO, usnic_ib_show_fw_ver, NULL); 187static DEVICE_ATTR(board_id, S_IRUGO, usnic_ib_show_board, NULL); 188static DEVICE_ATTR(config, S_IRUGO, usnic_ib_show_config, NULL); 189static DEVICE_ATTR(iface, S_IRUGO, usnic_ib_show_iface, NULL); 190static DEVICE_ATTR(max_vf, S_IRUGO, usnic_ib_show_max_vf, NULL); 191static DEVICE_ATTR(qp_per_vf, S_IRUGO, usnic_ib_show_qp_per_vf, NULL); 192static DEVICE_ATTR(cq_per_vf, S_IRUGO, usnic_ib_show_cq_per_vf, NULL); 193 194static struct device_attribute *usnic_class_attributes[] = { 195 &dev_attr_fw_ver, 196 &dev_attr_board_id, 197 &dev_attr_config, 198 &dev_attr_iface, 199 &dev_attr_max_vf, 200 &dev_attr_qp_per_vf, 201 &dev_attr_cq_per_vf, 202}; 203 204struct qpn_attribute { 205 struct attribute attr; 206 ssize_t (*show)(struct usnic_ib_qp_grp *, char *buf); 207}; 208 209/* 210 * Definitions for supporting QPN entries in sysfs 211 */ 212static ssize_t 213usnic_ib_qpn_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) 214{ 215 struct usnic_ib_qp_grp *qp_grp; 216 struct qpn_attribute *qpn_attr; 217 218 qp_grp = container_of(kobj, struct usnic_ib_qp_grp, kobj); 219 qpn_attr = container_of(attr, struct qpn_attribute, attr); 220 221 return qpn_attr->show(qp_grp, buf); 222} 223 224static const struct sysfs_ops usnic_ib_qpn_sysfs_ops = { 225 .show = usnic_ib_qpn_attr_show 226}; 227 228#define QPN_ATTR_RO(NAME) \ 229struct qpn_attribute qpn_attr_##NAME = __ATTR_RO(NAME) 230 231static ssize_t context_show(struct usnic_ib_qp_grp *qp_grp, char *buf) 232{ 233 return scnprintf(buf, PAGE_SIZE, "0x%p\n", qp_grp->ctx); 234} 235 236static ssize_t summary_show(struct usnic_ib_qp_grp *qp_grp, char *buf) 237{ 238 int i, j, n; 239 int left; 240 char *ptr; 241 struct usnic_vnic_res_chunk *res_chunk; 242 struct usnic_vnic_res *vnic_res; 243 244 left = PAGE_SIZE; 245 ptr = buf; 246 247 n = scnprintf(ptr, left, 248 "QPN: %d State: (%s) PID: %u VF Idx: %hu ", 249 qp_grp->ibqp.qp_num, 250 usnic_ib_qp_grp_state_to_string(qp_grp->state), 251 qp_grp->owner_pid, 252 usnic_vnic_get_index(qp_grp->vf->vnic)); 253 UPDATE_PTR_LEFT(n, ptr, left); 254 255 for (i = 0; qp_grp->res_chunk_list[i]; i++) { 256 res_chunk = qp_grp->res_chunk_list[i]; 257 for (j = 0; j < res_chunk->cnt; j++) { 258 vnic_res = res_chunk->res[j]; 259 n = scnprintf(ptr, left, "%s[%d] ", 260 usnic_vnic_res_type_to_str(vnic_res->type), 261 vnic_res->vnic_idx); 262 UPDATE_PTR_LEFT(n, ptr, left); 263 } 264 } 265 266 n = scnprintf(ptr, left, "\n"); 267 UPDATE_PTR_LEFT(n, ptr, left); 268 269 return ptr - buf; 270} 271 272static QPN_ATTR_RO(context); 273static QPN_ATTR_RO(summary); 274 275static struct attribute *usnic_ib_qpn_default_attrs[] = { 276 &qpn_attr_context.attr, 277 &qpn_attr_summary.attr, 278 NULL 279}; 280 281static struct kobj_type usnic_ib_qpn_type = { 282 .sysfs_ops = &usnic_ib_qpn_sysfs_ops, 283 .default_attrs = usnic_ib_qpn_default_attrs 284}; 285 286int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev) 287{ 288 int i; 289 int err; 290 for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) { 291 err = device_create_file(&us_ibdev->ib_dev.dev, 292 usnic_class_attributes[i]); 293 if (err) { 294 usnic_err("Failed to create device file %d for %s eith err %d", 295 i, us_ibdev->ib_dev.name, err); 296 return -EINVAL; 297 } 298 } 299 300 /* create kernel object for looking at individual QPs */ 301 kobject_get(&us_ibdev->ib_dev.dev.kobj); 302 us_ibdev->qpn_kobj = kobject_create_and_add("qpn", 303 &us_ibdev->ib_dev.dev.kobj); 304 if (us_ibdev->qpn_kobj == NULL) { 305 kobject_put(&us_ibdev->ib_dev.dev.kobj); 306 return -ENOMEM; 307 } 308 309 return 0; 310} 311 312void usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev) 313{ 314 int i; 315 for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) { 316 device_remove_file(&us_ibdev->ib_dev.dev, 317 usnic_class_attributes[i]); 318 } 319 320 kobject_put(us_ibdev->qpn_kobj); 321} 322 323void usnic_ib_sysfs_qpn_add(struct usnic_ib_qp_grp *qp_grp) 324{ 325 struct usnic_ib_dev *us_ibdev; 326 int err; 327 328 us_ibdev = qp_grp->vf->pf; 329 330 err = kobject_init_and_add(&qp_grp->kobj, &usnic_ib_qpn_type, 331 kobject_get(us_ibdev->qpn_kobj), 332 "%d", qp_grp->grp_id); 333 if (err) { 334 kobject_put(us_ibdev->qpn_kobj); 335 return; 336 } 337} 338 339void usnic_ib_sysfs_qpn_remove(struct usnic_ib_qp_grp *qp_grp) 340{ 341 struct usnic_ib_dev *us_ibdev; 342 343 us_ibdev = qp_grp->vf->pf; 344 345 kobject_put(&qp_grp->kobj); 346 kobject_put(us_ibdev->qpn_kobj); 347} 348