162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/init.h> 3562306a36Sopenharmony_ci#include <linux/errno.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 3862306a36Sopenharmony_ci#include <rdma/ib_addr.h> 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include "usnic_common_util.h" 4162306a36Sopenharmony_ci#include "usnic_ib.h" 4262306a36Sopenharmony_ci#include "usnic_ib_qp_grp.h" 4362306a36Sopenharmony_ci#include "usnic_vnic.h" 4462306a36Sopenharmony_ci#include "usnic_ib_verbs.h" 4562306a36Sopenharmony_ci#include "usnic_ib_sysfs.h" 4662306a36Sopenharmony_ci#include "usnic_log.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic ssize_t board_id_show(struct device *device, 4962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev = 5262306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); 5362306a36Sopenharmony_ci unsigned short subsystem_device_id; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci mutex_lock(&us_ibdev->usdev_lock); 5662306a36Sopenharmony_ci subsystem_device_id = us_ibdev->pdev->subsystem_device; 5762306a36Sopenharmony_ci mutex_unlock(&us_ibdev->usdev_lock); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", subsystem_device_id); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(board_id); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * Report the configuration for this PF 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic ssize_t 6762306a36Sopenharmony_ciconfig_show(struct device *device, struct device_attribute *attr, char *buf) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev = 7062306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); 7162306a36Sopenharmony_ci enum usnic_vnic_res_type res_type; 7262306a36Sopenharmony_ci int len; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci mutex_lock(&us_ibdev->usdev_lock); 7562306a36Sopenharmony_ci if (kref_read(&us_ibdev->vf_cnt) > 0) { 7662306a36Sopenharmony_ci char *busname; 7762306a36Sopenharmony_ci char *sep = ""; 7862306a36Sopenharmony_ci /* 7962306a36Sopenharmony_ci * bus name seems to come with annoying prefix. 8062306a36Sopenharmony_ci * Remove it if it is predictable 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci busname = us_ibdev->pdev->bus->name; 8362306a36Sopenharmony_ci if (strncmp(busname, "PCI Bus ", 8) == 0) 8462306a36Sopenharmony_ci busname += 8; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci len = sysfs_emit(buf, "%s: %s:%d.%d, %s, %pM, %u VFs\n", 8762306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev), 8862306a36Sopenharmony_ci busname, 8962306a36Sopenharmony_ci PCI_SLOT(us_ibdev->pdev->devfn), 9062306a36Sopenharmony_ci PCI_FUNC(us_ibdev->pdev->devfn), 9162306a36Sopenharmony_ci netdev_name(us_ibdev->netdev), 9262306a36Sopenharmony_ci us_ibdev->ufdev->mac, 9362306a36Sopenharmony_ci kref_read(&us_ibdev->vf_cnt)); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, " Per VF:"); 9662306a36Sopenharmony_ci for (res_type = USNIC_VNIC_RES_TYPE_EOL; 9762306a36Sopenharmony_ci res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) { 9862306a36Sopenharmony_ci if (us_ibdev->vf_res_cnt[res_type] == 0) 9962306a36Sopenharmony_ci continue; 10062306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, "%s %d %s", 10162306a36Sopenharmony_ci sep, 10262306a36Sopenharmony_ci us_ibdev->vf_res_cnt[res_type], 10362306a36Sopenharmony_ci usnic_vnic_res_type_to_str(res_type)); 10462306a36Sopenharmony_ci sep = ","; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, "\n"); 10762306a36Sopenharmony_ci } else { 10862306a36Sopenharmony_ci len = sysfs_emit(buf, "%s: no VFs\n", 10962306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci mutex_unlock(&us_ibdev->usdev_lock); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return len; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(config); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic ssize_t 11962306a36Sopenharmony_ciiface_show(struct device *device, struct device_attribute *attr, char *buf) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev = 12262306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", netdev_name(us_ibdev->netdev)); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(iface); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic ssize_t 12962306a36Sopenharmony_cimax_vf_show(struct device *device, struct device_attribute *attr, char *buf) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev = 13262306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", kref_read(&us_ibdev->vf_cnt)); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(max_vf); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic ssize_t 13962306a36Sopenharmony_ciqp_per_vf_show(struct device *device, struct device_attribute *attr, char *buf) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev = 14262306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); 14362306a36Sopenharmony_ci int qp_per_vf; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ], 14662306a36Sopenharmony_ci us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", qp_per_vf); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(qp_per_vf); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic ssize_t 15362306a36Sopenharmony_cicq_per_vf_show(struct device *device, struct device_attribute *attr, char *buf) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev = 15662306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct usnic_ib_dev, ib_dev); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", 15962306a36Sopenharmony_ci us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cq_per_vf); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic struct attribute *usnic_class_attributes[] = { 16462306a36Sopenharmony_ci &dev_attr_board_id.attr, 16562306a36Sopenharmony_ci &dev_attr_config.attr, 16662306a36Sopenharmony_ci &dev_attr_iface.attr, 16762306a36Sopenharmony_ci &dev_attr_max_vf.attr, 16862306a36Sopenharmony_ci &dev_attr_qp_per_vf.attr, 16962306a36Sopenharmony_ci &dev_attr_cq_per_vf.attr, 17062306a36Sopenharmony_ci NULL 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciconst struct attribute_group usnic_attr_group = { 17462306a36Sopenharmony_ci .attrs = usnic_class_attributes, 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistruct qpn_attribute { 17862306a36Sopenharmony_ci struct attribute attr; 17962306a36Sopenharmony_ci ssize_t (*show)(struct usnic_ib_qp_grp *, char *buf); 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * Definitions for supporting QPN entries in sysfs 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistatic ssize_t 18662306a36Sopenharmony_ciusnic_ib_qpn_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct usnic_ib_qp_grp *qp_grp; 18962306a36Sopenharmony_ci struct qpn_attribute *qpn_attr; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci qp_grp = container_of(kobj, struct usnic_ib_qp_grp, kobj); 19262306a36Sopenharmony_ci qpn_attr = container_of(attr, struct qpn_attribute, attr); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return qpn_attr->show(qp_grp, buf); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic const struct sysfs_ops usnic_ib_qpn_sysfs_ops = { 19862306a36Sopenharmony_ci .show = usnic_ib_qpn_attr_show 19962306a36Sopenharmony_ci}; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#define QPN_ATTR_RO(NAME) \ 20262306a36Sopenharmony_cistruct qpn_attribute qpn_attr_##NAME = __ATTR_RO(NAME) 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic ssize_t context_show(struct usnic_ib_qp_grp *qp_grp, char *buf) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci return sysfs_emit(buf, "0x%p\n", qp_grp->ctx); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic ssize_t summary_show(struct usnic_ib_qp_grp *qp_grp, char *buf) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int i, j; 21262306a36Sopenharmony_ci struct usnic_vnic_res_chunk *res_chunk; 21362306a36Sopenharmony_ci struct usnic_vnic_res *vnic_res; 21462306a36Sopenharmony_ci int len; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci len = sysfs_emit(buf, "QPN: %d State: (%s) PID: %u VF Idx: %hu", 21762306a36Sopenharmony_ci qp_grp->ibqp.qp_num, 21862306a36Sopenharmony_ci usnic_ib_qp_grp_state_to_string(qp_grp->state), 21962306a36Sopenharmony_ci qp_grp->owner_pid, 22062306a36Sopenharmony_ci usnic_vnic_get_index(qp_grp->vf->vnic)); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci for (i = 0; qp_grp->res_chunk_list[i]; i++) { 22362306a36Sopenharmony_ci res_chunk = qp_grp->res_chunk_list[i]; 22462306a36Sopenharmony_ci for (j = 0; j < res_chunk->cnt; j++) { 22562306a36Sopenharmony_ci vnic_res = res_chunk->res[j]; 22662306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, " %s[%d]", 22762306a36Sopenharmony_ci usnic_vnic_res_type_to_str(vnic_res->type), 22862306a36Sopenharmony_ci vnic_res->vnic_idx); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, "\n"); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return len; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic QPN_ATTR_RO(context); 23862306a36Sopenharmony_cistatic QPN_ATTR_RO(summary); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic struct attribute *usnic_ib_qpn_default_attrs[] = { 24162306a36Sopenharmony_ci &qpn_attr_context.attr, 24262306a36Sopenharmony_ci &qpn_attr_summary.attr, 24362306a36Sopenharmony_ci NULL 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ciATTRIBUTE_GROUPS(usnic_ib_qpn_default); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic struct kobj_type usnic_ib_qpn_type = { 24862306a36Sopenharmony_ci .sysfs_ops = &usnic_ib_qpn_sysfs_ops, 24962306a36Sopenharmony_ci .default_groups = usnic_ib_qpn_default_groups, 25062306a36Sopenharmony_ci}; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciint usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci /* create kernel object for looking at individual QPs */ 25562306a36Sopenharmony_ci kobject_get(&us_ibdev->ib_dev.dev.kobj); 25662306a36Sopenharmony_ci us_ibdev->qpn_kobj = kobject_create_and_add("qpn", 25762306a36Sopenharmony_ci &us_ibdev->ib_dev.dev.kobj); 25862306a36Sopenharmony_ci if (us_ibdev->qpn_kobj == NULL) { 25962306a36Sopenharmony_ci kobject_put(&us_ibdev->ib_dev.dev.kobj); 26062306a36Sopenharmony_ci return -ENOMEM; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_civoid usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci kobject_put(us_ibdev->qpn_kobj); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_civoid usnic_ib_sysfs_qpn_add(struct usnic_ib_qp_grp *qp_grp) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev; 27462306a36Sopenharmony_ci int err; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci us_ibdev = qp_grp->vf->pf; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci err = kobject_init_and_add(&qp_grp->kobj, &usnic_ib_qpn_type, 27962306a36Sopenharmony_ci kobject_get(us_ibdev->qpn_kobj), 28062306a36Sopenharmony_ci "%d", qp_grp->grp_id); 28162306a36Sopenharmony_ci if (err) { 28262306a36Sopenharmony_ci kobject_put(us_ibdev->qpn_kobj); 28362306a36Sopenharmony_ci return; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_civoid usnic_ib_sysfs_qpn_remove(struct usnic_ib_qp_grp *qp_grp) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci us_ibdev = qp_grp->vf->pf; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci kobject_put(&qp_grp->kobj); 29462306a36Sopenharmony_ci kobject_put(us_ibdev->qpn_kobj); 29562306a36Sopenharmony_ci} 296