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