linux/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
<<
>>
Prefs
   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
  49static ssize_t board_id_show(struct device *device,
  50                             struct device_attribute *attr, char *buf)
  51{
  52        struct usnic_ib_dev *us_ibdev =
  53                rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev);
  54        unsigned short subsystem_device_id;
  55
  56        mutex_lock(&us_ibdev->usdev_lock);
  57        subsystem_device_id = us_ibdev->pdev->subsystem_device;
  58        mutex_unlock(&us_ibdev->usdev_lock);
  59
  60        return sysfs_emit(buf, "%u\n", subsystem_device_id);
  61}
  62static DEVICE_ATTR_RO(board_id);
  63
  64/*
  65 * Report the configuration for this PF
  66 */
  67static ssize_t
  68config_show(struct device *device, struct device_attribute *attr, char *buf)
  69{
  70        struct usnic_ib_dev *us_ibdev =
  71                rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev);
  72        enum usnic_vnic_res_type res_type;
  73        int len;
  74
  75        mutex_lock(&us_ibdev->usdev_lock);
  76        if (kref_read(&us_ibdev->vf_cnt) > 0) {
  77                char *busname;
  78                char *sep = "";
  79                /*
  80                 * bus name seems to come with annoying prefix.
  81                 * Remove it if it is predictable
  82                 */
  83                busname = us_ibdev->pdev->bus->name;
  84                if (strncmp(busname, "PCI Bus ", 8) == 0)
  85                        busname += 8;
  86
  87                len = sysfs_emit(buf, "%s: %s:%d.%d, %s, %pM, %u VFs\n",
  88                                 dev_name(&us_ibdev->ib_dev.dev),
  89                                 busname,
  90                                 PCI_SLOT(us_ibdev->pdev->devfn),
  91                                 PCI_FUNC(us_ibdev->pdev->devfn),
  92                                 netdev_name(us_ibdev->netdev),
  93                                 us_ibdev->ufdev->mac,
  94                                 kref_read(&us_ibdev->vf_cnt));
  95
  96                len += sysfs_emit_at(buf, len, " Per VF:");
  97                for (res_type = USNIC_VNIC_RES_TYPE_EOL;
  98                     res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) {
  99                        if (us_ibdev->vf_res_cnt[res_type] == 0)
 100                                continue;
 101                        len += sysfs_emit_at(buf, len, "%s %d %s",
 102                                             sep,
 103                                             us_ibdev->vf_res_cnt[res_type],
 104                                             usnic_vnic_res_type_to_str(res_type));
 105                        sep = ",";
 106                }
 107                len += sysfs_emit_at(buf, len, "\n");
 108        } else {
 109                len = sysfs_emit(buf, "%s: no VFs\n",
 110                                 dev_name(&us_ibdev->ib_dev.dev));
 111        }
 112
 113        mutex_unlock(&us_ibdev->usdev_lock);
 114
 115        return len;
 116}
 117static DEVICE_ATTR_RO(config);
 118
 119static ssize_t
 120iface_show(struct device *device, struct device_attribute *attr, char *buf)
 121{
 122        struct usnic_ib_dev *us_ibdev =
 123                rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev);
 124
 125        return sysfs_emit(buf, "%s\n", netdev_name(us_ibdev->netdev));
 126}
 127static DEVICE_ATTR_RO(iface);
 128
 129static ssize_t
 130max_vf_show(struct device *device, struct device_attribute *attr, char *buf)
 131{
 132        struct usnic_ib_dev *us_ibdev =
 133                rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev);
 134
 135        return sysfs_emit(buf, "%u\n", kref_read(&us_ibdev->vf_cnt));
 136}
 137static DEVICE_ATTR_RO(max_vf);
 138
 139static ssize_t
 140qp_per_vf_show(struct device *device, struct device_attribute *attr, char *buf)
 141{
 142        struct usnic_ib_dev *us_ibdev =
 143                rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev);
 144        int qp_per_vf;
 145
 146        qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ],
 147                        us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]);
 148
 149        return sysfs_emit(buf, "%d\n", qp_per_vf);
 150}
 151static DEVICE_ATTR_RO(qp_per_vf);
 152
 153static ssize_t
 154cq_per_vf_show(struct device *device, struct device_attribute *attr, char *buf)
 155{
 156        struct usnic_ib_dev *us_ibdev =
 157                rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev);
 158
 159        return sysfs_emit(buf, "%d\n",
 160                          us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]);
 161}
 162static DEVICE_ATTR_RO(cq_per_vf);
 163
 164static struct attribute *usnic_class_attributes[] = {
 165        &dev_attr_board_id.attr,
 166        &dev_attr_config.attr,
 167        &dev_attr_iface.attr,
 168        &dev_attr_max_vf.attr,
 169        &dev_attr_qp_per_vf.attr,
 170        &dev_attr_cq_per_vf.attr,
 171        NULL
 172};
 173
 174const struct attribute_group usnic_attr_group = {
 175        .attrs = usnic_class_attributes,
 176};
 177
 178struct qpn_attribute {
 179        struct attribute attr;
 180        ssize_t (*show)(struct usnic_ib_qp_grp *, char *buf);
 181};
 182
 183/*
 184 * Definitions for supporting QPN entries in sysfs
 185 */
 186static ssize_t
 187usnic_ib_qpn_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
 188{
 189        struct usnic_ib_qp_grp *qp_grp;
 190        struct qpn_attribute *qpn_attr;
 191
 192        qp_grp = container_of(kobj, struct usnic_ib_qp_grp, kobj);
 193        qpn_attr = container_of(attr, struct qpn_attribute, attr);
 194
 195        return qpn_attr->show(qp_grp, buf);
 196}
 197
 198static const struct sysfs_ops usnic_ib_qpn_sysfs_ops = {
 199        .show = usnic_ib_qpn_attr_show
 200};
 201
 202#define QPN_ATTR_RO(NAME) \
 203struct qpn_attribute qpn_attr_##NAME = __ATTR_RO(NAME)
 204
 205static ssize_t context_show(struct usnic_ib_qp_grp *qp_grp, char *buf)
 206{
 207        return sysfs_emit(buf, "0x%p\n", qp_grp->ctx);
 208}
 209
 210static ssize_t summary_show(struct usnic_ib_qp_grp *qp_grp, char *buf)
 211{
 212        int i, j;
 213        struct usnic_vnic_res_chunk *res_chunk;
 214        struct usnic_vnic_res *vnic_res;
 215        int len;
 216
 217        len = sysfs_emit(buf, "QPN: %d State: (%s) PID: %u VF Idx: %hu",
 218                         qp_grp->ibqp.qp_num,
 219                         usnic_ib_qp_grp_state_to_string(qp_grp->state),
 220                         qp_grp->owner_pid,
 221                         usnic_vnic_get_index(qp_grp->vf->vnic));
 222
 223        for (i = 0; qp_grp->res_chunk_list[i]; i++) {
 224                res_chunk = qp_grp->res_chunk_list[i];
 225                for (j = 0; j < res_chunk->cnt; j++) {
 226                        vnic_res = res_chunk->res[j];
 227                        len += sysfs_emit_at(buf, len, " %s[%d]",
 228                                usnic_vnic_res_type_to_str(vnic_res->type),
 229                                vnic_res->vnic_idx);
 230                }
 231        }
 232
 233        len += sysfs_emit_at(buf, len, "\n");
 234
 235        return len;
 236}
 237
 238static QPN_ATTR_RO(context);
 239static QPN_ATTR_RO(summary);
 240
 241static struct attribute *usnic_ib_qpn_default_attrs[] = {
 242        &qpn_attr_context.attr,
 243        &qpn_attr_summary.attr,
 244        NULL
 245};
 246
 247static struct kobj_type usnic_ib_qpn_type = {
 248        .sysfs_ops = &usnic_ib_qpn_sysfs_ops,
 249        .default_attrs = usnic_ib_qpn_default_attrs
 250};
 251
 252int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev)
 253{
 254        /* create kernel object for looking at individual QPs */
 255        kobject_get(&us_ibdev->ib_dev.dev.kobj);
 256        us_ibdev->qpn_kobj = kobject_create_and_add("qpn",
 257                        &us_ibdev->ib_dev.dev.kobj);
 258        if (us_ibdev->qpn_kobj == NULL) {
 259                kobject_put(&us_ibdev->ib_dev.dev.kobj);
 260                return -ENOMEM;
 261        }
 262
 263        return 0;
 264}
 265
 266void usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev)
 267{
 268        kobject_put(us_ibdev->qpn_kobj);
 269}
 270
 271void usnic_ib_sysfs_qpn_add(struct usnic_ib_qp_grp *qp_grp)
 272{
 273        struct usnic_ib_dev *us_ibdev;
 274        int err;
 275
 276        us_ibdev = qp_grp->vf->pf;
 277
 278        err = kobject_init_and_add(&qp_grp->kobj, &usnic_ib_qpn_type,
 279                        kobject_get(us_ibdev->qpn_kobj),
 280                        "%d", qp_grp->grp_id);
 281        if (err) {
 282                kobject_put(us_ibdev->qpn_kobj);
 283                return;
 284        }
 285}
 286
 287void usnic_ib_sysfs_qpn_remove(struct usnic_ib_qp_grp *qp_grp)
 288{
 289        struct usnic_ib_dev *us_ibdev;
 290
 291        us_ibdev = qp_grp->vf->pf;
 292
 293        kobject_put(&qp_grp->kobj);
 294        kobject_put(us_ibdev->qpn_kobj);
 295}
 296