18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2012 Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/*#include "core_priv.h"*/ 348c2ecf20Sopenharmony_ci#include "mlx4_ib.h" 358c2ecf20Sopenharmony_ci#include <linux/slab.h> 368c2ecf20Sopenharmony_ci#include <linux/string.h> 378c2ecf20Sopenharmony_ci#include <linux/stat.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <rdma/ib_mad.h> 408c2ecf20Sopenharmony_ci/*show_admin_alias_guid returns the administratively assigned value of that GUID. 418c2ecf20Sopenharmony_ci * Values returned in buf parameter string: 428c2ecf20Sopenharmony_ci * 0 - requests opensm to assign a value. 438c2ecf20Sopenharmony_ci * ffffffffffffffff - delete this entry. 448c2ecf20Sopenharmony_ci * other - value assigned by administrator. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic ssize_t show_admin_alias_guid(struct device *dev, 478c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = 508c2ecf20Sopenharmony_ci container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); 518c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; 528c2ecf20Sopenharmony_ci struct mlx4_ib_dev *mdev = port->dev; 538c2ecf20Sopenharmony_ci __be64 sysadmin_ag_val; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci sysadmin_ag_val = mlx4_get_admin_guid(mdev->dev, 568c2ecf20Sopenharmony_ci mlx4_ib_iov_dentry->entry_num, 578c2ecf20Sopenharmony_ci port->num); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return sprintf(buf, "%llx\n", be64_to_cpu(sysadmin_ag_val)); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* store_admin_alias_guid stores the (new) administratively assigned value of that GUID. 638c2ecf20Sopenharmony_ci * Values in buf parameter string: 648c2ecf20Sopenharmony_ci * 0 - requests opensm to assign a value. 658c2ecf20Sopenharmony_ci * 0xffffffffffffffff - delete this entry. 668c2ecf20Sopenharmony_ci * other - guid value assigned by the administrator. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_cistatic ssize_t store_admin_alias_guid(struct device *dev, 698c2ecf20Sopenharmony_ci struct device_attribute *attr, 708c2ecf20Sopenharmony_ci const char *buf, size_t count) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int record_num;/*0-15*/ 738c2ecf20Sopenharmony_ci int guid_index_in_rec; /*0 - 7*/ 748c2ecf20Sopenharmony_ci struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = 758c2ecf20Sopenharmony_ci container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); 768c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; 778c2ecf20Sopenharmony_ci struct mlx4_ib_dev *mdev = port->dev; 788c2ecf20Sopenharmony_ci u64 sysadmin_ag_val; 798c2ecf20Sopenharmony_ci unsigned long flags; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci record_num = mlx4_ib_iov_dentry->entry_num / 8; 828c2ecf20Sopenharmony_ci guid_index_in_rec = mlx4_ib_iov_dentry->entry_num % 8; 838c2ecf20Sopenharmony_ci if (0 == record_num && 0 == guid_index_in_rec) { 848c2ecf20Sopenharmony_ci pr_err("GUID 0 block 0 is RO\n"); 858c2ecf20Sopenharmony_ci return count; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci spin_lock_irqsave(&mdev->sriov.alias_guid.ag_work_lock, flags); 888c2ecf20Sopenharmony_ci sscanf(buf, "%llx", &sysadmin_ag_val); 898c2ecf20Sopenharmony_ci *(__be64 *)&mdev->sriov.alias_guid.ports_guid[port->num - 1]. 908c2ecf20Sopenharmony_ci all_rec_per_port[record_num]. 918c2ecf20Sopenharmony_ci all_recs[GUID_REC_SIZE * guid_index_in_rec] = 928c2ecf20Sopenharmony_ci cpu_to_be64(sysadmin_ag_val); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* Change the state to be pending for update */ 958c2ecf20Sopenharmony_ci mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].status 968c2ecf20Sopenharmony_ci = MLX4_GUID_INFO_STATUS_IDLE ; 978c2ecf20Sopenharmony_ci mlx4_set_admin_guid(mdev->dev, cpu_to_be64(sysadmin_ag_val), 988c2ecf20Sopenharmony_ci mlx4_ib_iov_dentry->entry_num, 998c2ecf20Sopenharmony_ci port->num); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* set the record index */ 1028c2ecf20Sopenharmony_ci mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].guid_indexes 1038c2ecf20Sopenharmony_ci |= mlx4_ib_get_aguid_comp_mask_from_ix(guid_index_in_rec); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mdev->sriov.alias_guid.ag_work_lock, flags); 1068c2ecf20Sopenharmony_ci mlx4_ib_init_alias_guid_work(mdev, port->num - 1); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return count; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic ssize_t show_port_gid(struct device *dev, 1128c2ecf20Sopenharmony_ci struct device_attribute *attr, 1138c2ecf20Sopenharmony_ci char *buf) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = 1168c2ecf20Sopenharmony_ci container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); 1178c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; 1188c2ecf20Sopenharmony_ci struct mlx4_ib_dev *mdev = port->dev; 1198c2ecf20Sopenharmony_ci union ib_gid gid; 1208c2ecf20Sopenharmony_ci ssize_t ret; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci ret = __mlx4_ib_query_gid(&mdev->ib_dev, port->num, 1238c2ecf20Sopenharmony_ci mlx4_ib_iov_dentry->entry_num, &gid, 1); 1248c2ecf20Sopenharmony_ci if (ret) 1258c2ecf20Sopenharmony_ci return ret; 1268c2ecf20Sopenharmony_ci ret = sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 1278c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[0]), 1288c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[1]), 1298c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[2]), 1308c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[3]), 1318c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[4]), 1328c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[5]), 1338c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[6]), 1348c2ecf20Sopenharmony_ci be16_to_cpu(((__be16 *) gid.raw)[7])); 1358c2ecf20Sopenharmony_ci return ret; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic ssize_t show_phys_port_pkey(struct device *dev, 1398c2ecf20Sopenharmony_ci struct device_attribute *attr, 1408c2ecf20Sopenharmony_ci char *buf) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = 1438c2ecf20Sopenharmony_ci container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); 1448c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; 1458c2ecf20Sopenharmony_ci struct mlx4_ib_dev *mdev = port->dev; 1468c2ecf20Sopenharmony_ci u16 pkey; 1478c2ecf20Sopenharmony_ci ssize_t ret; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ret = __mlx4_ib_query_pkey(&mdev->ib_dev, port->num, 1508c2ecf20Sopenharmony_ci mlx4_ib_iov_dentry->entry_num, &pkey, 1); 1518c2ecf20Sopenharmony_ci if (ret) 1528c2ecf20Sopenharmony_ci return ret; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return sprintf(buf, "0x%04x\n", pkey); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define DENTRY_REMOVE(_dentry) \ 1588c2ecf20Sopenharmony_cido { \ 1598c2ecf20Sopenharmony_ci sysfs_remove_file((_dentry)->kobj, &(_dentry)->dentry.attr); \ 1608c2ecf20Sopenharmony_ci} while (0); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int create_sysfs_entry(void *_ctx, struct mlx4_ib_iov_sysfs_attr *_dentry, 1638c2ecf20Sopenharmony_ci char *_name, struct kobject *_kobj, 1648c2ecf20Sopenharmony_ci ssize_t (*show)(struct device *dev, 1658c2ecf20Sopenharmony_ci struct device_attribute *attr, 1668c2ecf20Sopenharmony_ci char *buf), 1678c2ecf20Sopenharmony_ci ssize_t (*store)(struct device *dev, 1688c2ecf20Sopenharmony_ci struct device_attribute *attr, 1698c2ecf20Sopenharmony_ci const char *buf, size_t count) 1708c2ecf20Sopenharmony_ci ) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int ret = 0; 1738c2ecf20Sopenharmony_ci struct mlx4_ib_iov_sysfs_attr *vdentry = _dentry; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci vdentry->ctx = _ctx; 1768c2ecf20Sopenharmony_ci vdentry->dentry.show = show; 1778c2ecf20Sopenharmony_ci vdentry->dentry.store = store; 1788c2ecf20Sopenharmony_ci sysfs_attr_init(&vdentry->dentry.attr); 1798c2ecf20Sopenharmony_ci vdentry->dentry.attr.name = vdentry->name; 1808c2ecf20Sopenharmony_ci vdentry->dentry.attr.mode = 0; 1818c2ecf20Sopenharmony_ci vdentry->kobj = _kobj; 1828c2ecf20Sopenharmony_ci snprintf(vdentry->name, 15, "%s", _name); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (vdentry->dentry.store) 1858c2ecf20Sopenharmony_ci vdentry->dentry.attr.mode |= S_IWUSR; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (vdentry->dentry.show) 1888c2ecf20Sopenharmony_ci vdentry->dentry.attr.mode |= S_IRUGO; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = sysfs_create_file(vdentry->kobj, &vdentry->dentry.attr); 1918c2ecf20Sopenharmony_ci if (ret) { 1928c2ecf20Sopenharmony_ci pr_err("failed to create %s\n", vdentry->dentry.attr.name); 1938c2ecf20Sopenharmony_ci vdentry->ctx = NULL; 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ciint add_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, 2018c2ecf20Sopenharmony_ci struct attribute *attr) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1]; 2048c2ecf20Sopenharmony_ci int ret; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ret = sysfs_create_file(port->mcgs_parent, attr); 2078c2ecf20Sopenharmony_ci if (ret) 2088c2ecf20Sopenharmony_ci pr_err("failed to create %s\n", attr->name); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_civoid del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, 2148c2ecf20Sopenharmony_ci struct attribute *attr) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1]; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci sysfs_remove_file(port->mcgs_parent, attr); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int add_port_entries(struct mlx4_ib_dev *device, int port_num) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci int i; 2248c2ecf20Sopenharmony_ci char buff[12]; 2258c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *port = NULL; 2268c2ecf20Sopenharmony_ci int ret = 0 ; 2278c2ecf20Sopenharmony_ci struct ib_port_attr attr; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 2308c2ecf20Sopenharmony_ci /* get the physical gid and pkey table sizes.*/ 2318c2ecf20Sopenharmony_ci ret = __mlx4_ib_query_port(&device->ib_dev, port_num, &attr, 1); 2328c2ecf20Sopenharmony_ci if (ret) 2338c2ecf20Sopenharmony_ci goto err; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci port = &device->iov_ports[port_num - 1]; 2368c2ecf20Sopenharmony_ci port->dev = device; 2378c2ecf20Sopenharmony_ci port->num = port_num; 2388c2ecf20Sopenharmony_ci /* Directory structure: 2398c2ecf20Sopenharmony_ci * iov - 2408c2ecf20Sopenharmony_ci * port num - 2418c2ecf20Sopenharmony_ci * admin_guids 2428c2ecf20Sopenharmony_ci * gids (operational) 2438c2ecf20Sopenharmony_ci * mcg_table 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci port->dentr_ar = kzalloc(sizeof (struct mlx4_ib_iov_sysfs_attr_ar), 2468c2ecf20Sopenharmony_ci GFP_KERNEL); 2478c2ecf20Sopenharmony_ci if (!port->dentr_ar) { 2488c2ecf20Sopenharmony_ci ret = -ENOMEM; 2498c2ecf20Sopenharmony_ci goto err; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci sprintf(buff, "%d", port_num); 2528c2ecf20Sopenharmony_ci port->cur_port = kobject_create_and_add(buff, 2538c2ecf20Sopenharmony_ci kobject_get(device->ports_parent)); 2548c2ecf20Sopenharmony_ci if (!port->cur_port) { 2558c2ecf20Sopenharmony_ci ret = -ENOMEM; 2568c2ecf20Sopenharmony_ci goto kobj_create_err; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci /* admin GUIDs */ 2598c2ecf20Sopenharmony_ci port->admin_alias_parent = kobject_create_and_add("admin_guids", 2608c2ecf20Sopenharmony_ci kobject_get(port->cur_port)); 2618c2ecf20Sopenharmony_ci if (!port->admin_alias_parent) { 2628c2ecf20Sopenharmony_ci ret = -ENOMEM; 2638c2ecf20Sopenharmony_ci goto err_admin_guids; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci for (i = 0 ; i < attr.gid_tbl_len; i++) { 2668c2ecf20Sopenharmony_ci sprintf(buff, "%d", i); 2678c2ecf20Sopenharmony_ci port->dentr_ar->dentries[i].entry_num = i; 2688c2ecf20Sopenharmony_ci ret = create_sysfs_entry(port, &port->dentr_ar->dentries[i], 2698c2ecf20Sopenharmony_ci buff, port->admin_alias_parent, 2708c2ecf20Sopenharmony_ci show_admin_alias_guid, store_admin_alias_guid); 2718c2ecf20Sopenharmony_ci if (ret) 2728c2ecf20Sopenharmony_ci goto err_admin_alias_parent; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* gids subdirectory (operational gids) */ 2768c2ecf20Sopenharmony_ci port->gids_parent = kobject_create_and_add("gids", 2778c2ecf20Sopenharmony_ci kobject_get(port->cur_port)); 2788c2ecf20Sopenharmony_ci if (!port->gids_parent) { 2798c2ecf20Sopenharmony_ci ret = -ENOMEM; 2808c2ecf20Sopenharmony_ci goto err_gids; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci for (i = 0 ; i < attr.gid_tbl_len; i++) { 2848c2ecf20Sopenharmony_ci sprintf(buff, "%d", i); 2858c2ecf20Sopenharmony_ci port->dentr_ar->dentries[attr.gid_tbl_len + i].entry_num = i; 2868c2ecf20Sopenharmony_ci ret = create_sysfs_entry(port, 2878c2ecf20Sopenharmony_ci &port->dentr_ar->dentries[attr.gid_tbl_len + i], 2888c2ecf20Sopenharmony_ci buff, 2898c2ecf20Sopenharmony_ci port->gids_parent, show_port_gid, NULL); 2908c2ecf20Sopenharmony_ci if (ret) 2918c2ecf20Sopenharmony_ci goto err_gids_parent; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* physical port pkey table */ 2958c2ecf20Sopenharmony_ci port->pkeys_parent = 2968c2ecf20Sopenharmony_ci kobject_create_and_add("pkeys", kobject_get(port->cur_port)); 2978c2ecf20Sopenharmony_ci if (!port->pkeys_parent) { 2988c2ecf20Sopenharmony_ci ret = -ENOMEM; 2998c2ecf20Sopenharmony_ci goto err_pkeys; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci for (i = 0 ; i < attr.pkey_tbl_len; i++) { 3038c2ecf20Sopenharmony_ci sprintf(buff, "%d", i); 3048c2ecf20Sopenharmony_ci port->dentr_ar->dentries[2 * attr.gid_tbl_len + i].entry_num = i; 3058c2ecf20Sopenharmony_ci ret = create_sysfs_entry(port, 3068c2ecf20Sopenharmony_ci &port->dentr_ar->dentries[2 * attr.gid_tbl_len + i], 3078c2ecf20Sopenharmony_ci buff, port->pkeys_parent, 3088c2ecf20Sopenharmony_ci show_phys_port_pkey, NULL); 3098c2ecf20Sopenharmony_ci if (ret) 3108c2ecf20Sopenharmony_ci goto err_pkeys_parent; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* MCGs table */ 3148c2ecf20Sopenharmony_ci port->mcgs_parent = 3158c2ecf20Sopenharmony_ci kobject_create_and_add("mcgs", kobject_get(port->cur_port)); 3168c2ecf20Sopenharmony_ci if (!port->mcgs_parent) { 3178c2ecf20Sopenharmony_ci ret = -ENOMEM; 3188c2ecf20Sopenharmony_ci goto err_mcgs; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cierr_mcgs: 3238c2ecf20Sopenharmony_ci kobject_put(port->cur_port); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cierr_pkeys_parent: 3268c2ecf20Sopenharmony_ci kobject_put(port->pkeys_parent); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cierr_pkeys: 3298c2ecf20Sopenharmony_ci kobject_put(port->cur_port); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cierr_gids_parent: 3328c2ecf20Sopenharmony_ci kobject_put(port->gids_parent); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cierr_gids: 3358c2ecf20Sopenharmony_ci kobject_put(port->cur_port); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cierr_admin_alias_parent: 3388c2ecf20Sopenharmony_ci kobject_put(port->admin_alias_parent); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cierr_admin_guids: 3418c2ecf20Sopenharmony_ci kobject_put(port->cur_port); 3428c2ecf20Sopenharmony_ci kobject_put(port->cur_port); /* once more for create_and_add buff */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cikobj_create_err: 3458c2ecf20Sopenharmony_ci kobject_put(device->ports_parent); 3468c2ecf20Sopenharmony_ci kfree(port->dentr_ar); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cierr: 3498c2ecf20Sopenharmony_ci pr_err("add_port_entries FAILED: for port:%d, error: %d\n", 3508c2ecf20Sopenharmony_ci port_num, ret); 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void get_name(struct mlx4_ib_dev *dev, char *name, int i, int max) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci /* pci_name format is: bus:dev:func -> xxxx:yy:zz.n 3578c2ecf20Sopenharmony_ci * with no ARI only 3 last bits are used so when the fn is higher than 8 3588c2ecf20Sopenharmony_ci * need to add it to the dev num, so count in the last number will be 3598c2ecf20Sopenharmony_ci * modulo 8 */ 3608c2ecf20Sopenharmony_ci snprintf(name, max, "%.8s%.2d.%d", pci_name(dev->dev->persist->pdev), 3618c2ecf20Sopenharmony_ci i / 8, i % 8); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistruct mlx4_port { 3658c2ecf20Sopenharmony_ci struct kobject kobj; 3668c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev; 3678c2ecf20Sopenharmony_ci struct attribute_group pkey_group; 3688c2ecf20Sopenharmony_ci struct attribute_group gid_group; 3698c2ecf20Sopenharmony_ci struct device_attribute enable_smi_admin; 3708c2ecf20Sopenharmony_ci struct device_attribute smi_enabled; 3718c2ecf20Sopenharmony_ci int slave; 3728c2ecf20Sopenharmony_ci u8 port_num; 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void mlx4_port_release(struct kobject *kobj) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj); 3798c2ecf20Sopenharmony_ci struct attribute *a; 3808c2ecf20Sopenharmony_ci int i; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci for (i = 0; (a = p->pkey_group.attrs[i]); ++i) 3838c2ecf20Sopenharmony_ci kfree(a); 3848c2ecf20Sopenharmony_ci kfree(p->pkey_group.attrs); 3858c2ecf20Sopenharmony_ci for (i = 0; (a = p->gid_group.attrs[i]); ++i) 3868c2ecf20Sopenharmony_ci kfree(a); 3878c2ecf20Sopenharmony_ci kfree(p->gid_group.attrs); 3888c2ecf20Sopenharmony_ci kfree(p); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistruct port_attribute { 3928c2ecf20Sopenharmony_ci struct attribute attr; 3938c2ecf20Sopenharmony_ci ssize_t (*show)(struct mlx4_port *, struct port_attribute *, char *buf); 3948c2ecf20Sopenharmony_ci ssize_t (*store)(struct mlx4_port *, struct port_attribute *, 3958c2ecf20Sopenharmony_ci const char *buf, size_t count); 3968c2ecf20Sopenharmony_ci}; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic ssize_t port_attr_show(struct kobject *kobj, 3998c2ecf20Sopenharmony_ci struct attribute *attr, char *buf) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct port_attribute *port_attr = 4028c2ecf20Sopenharmony_ci container_of(attr, struct port_attribute, attr); 4038c2ecf20Sopenharmony_ci struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (!port_attr->show) 4068c2ecf20Sopenharmony_ci return -EIO; 4078c2ecf20Sopenharmony_ci return port_attr->show(p, port_attr, buf); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic ssize_t port_attr_store(struct kobject *kobj, 4118c2ecf20Sopenharmony_ci struct attribute *attr, 4128c2ecf20Sopenharmony_ci const char *buf, size_t size) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct port_attribute *port_attr = 4158c2ecf20Sopenharmony_ci container_of(attr, struct port_attribute, attr); 4168c2ecf20Sopenharmony_ci struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!port_attr->store) 4198c2ecf20Sopenharmony_ci return -EIO; 4208c2ecf20Sopenharmony_ci return port_attr->store(p, port_attr, buf, size); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic const struct sysfs_ops port_sysfs_ops = { 4248c2ecf20Sopenharmony_ci .show = port_attr_show, 4258c2ecf20Sopenharmony_ci .store = port_attr_store, 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic struct kobj_type port_type = { 4298c2ecf20Sopenharmony_ci .release = mlx4_port_release, 4308c2ecf20Sopenharmony_ci .sysfs_ops = &port_sysfs_ops, 4318c2ecf20Sopenharmony_ci}; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistruct port_table_attribute { 4348c2ecf20Sopenharmony_ci struct port_attribute attr; 4358c2ecf20Sopenharmony_ci char name[8]; 4368c2ecf20Sopenharmony_ci int index; 4378c2ecf20Sopenharmony_ci}; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic ssize_t show_port_pkey(struct mlx4_port *p, struct port_attribute *attr, 4408c2ecf20Sopenharmony_ci char *buf) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct port_table_attribute *tab_attr = 4438c2ecf20Sopenharmony_ci container_of(attr, struct port_table_attribute, attr); 4448c2ecf20Sopenharmony_ci ssize_t ret = -ENODEV; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1][tab_attr->index] >= 4478c2ecf20Sopenharmony_ci (p->dev->dev->caps.pkey_table_len[p->port_num])) 4488c2ecf20Sopenharmony_ci ret = sprintf(buf, "none\n"); 4498c2ecf20Sopenharmony_ci else 4508c2ecf20Sopenharmony_ci ret = sprintf(buf, "%d\n", 4518c2ecf20Sopenharmony_ci p->dev->pkeys.virt2phys_pkey[p->slave] 4528c2ecf20Sopenharmony_ci [p->port_num - 1][tab_attr->index]); 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic ssize_t store_port_pkey(struct mlx4_port *p, struct port_attribute *attr, 4578c2ecf20Sopenharmony_ci const char *buf, size_t count) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct port_table_attribute *tab_attr = 4608c2ecf20Sopenharmony_ci container_of(attr, struct port_table_attribute, attr); 4618c2ecf20Sopenharmony_ci int idx; 4628c2ecf20Sopenharmony_ci int err; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* do not allow remapping Dom0 virtual pkey table */ 4658c2ecf20Sopenharmony_ci if (p->slave == mlx4_master_func_num(p->dev->dev)) 4668c2ecf20Sopenharmony_ci return -EINVAL; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (!strncasecmp(buf, "no", 2)) 4698c2ecf20Sopenharmony_ci idx = p->dev->dev->phys_caps.pkey_phys_table_len[p->port_num] - 1; 4708c2ecf20Sopenharmony_ci else if (sscanf(buf, "%i", &idx) != 1 || 4718c2ecf20Sopenharmony_ci idx >= p->dev->dev->caps.pkey_table_len[p->port_num] || 4728c2ecf20Sopenharmony_ci idx < 0) 4738c2ecf20Sopenharmony_ci return -EINVAL; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1] 4768c2ecf20Sopenharmony_ci [tab_attr->index] = idx; 4778c2ecf20Sopenharmony_ci mlx4_sync_pkey_table(p->dev->dev, p->slave, p->port_num, 4788c2ecf20Sopenharmony_ci tab_attr->index, idx); 4798c2ecf20Sopenharmony_ci err = mlx4_gen_pkey_eqe(p->dev->dev, p->slave, p->port_num); 4808c2ecf20Sopenharmony_ci if (err) { 4818c2ecf20Sopenharmony_ci pr_err("mlx4_gen_pkey_eqe failed for slave %d," 4828c2ecf20Sopenharmony_ci " port %d, index %d\n", p->slave, p->port_num, idx); 4838c2ecf20Sopenharmony_ci return err; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci return count; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic ssize_t show_port_gid_idx(struct mlx4_port *p, 4898c2ecf20Sopenharmony_ci struct port_attribute *attr, char *buf) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->slave); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic struct attribute ** 4958c2ecf20Sopenharmony_cialloc_group_attrs(ssize_t (*show)(struct mlx4_port *, 4968c2ecf20Sopenharmony_ci struct port_attribute *, char *buf), 4978c2ecf20Sopenharmony_ci ssize_t (*store)(struct mlx4_port *, struct port_attribute *, 4988c2ecf20Sopenharmony_ci const char *buf, size_t count), 4998c2ecf20Sopenharmony_ci int len) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct attribute **tab_attr; 5028c2ecf20Sopenharmony_ci struct port_table_attribute *element; 5038c2ecf20Sopenharmony_ci int i; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci tab_attr = kcalloc(1 + len, sizeof (struct attribute *), GFP_KERNEL); 5068c2ecf20Sopenharmony_ci if (!tab_attr) 5078c2ecf20Sopenharmony_ci return NULL; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 5108c2ecf20Sopenharmony_ci element = kzalloc(sizeof (struct port_table_attribute), 5118c2ecf20Sopenharmony_ci GFP_KERNEL); 5128c2ecf20Sopenharmony_ci if (!element) 5138c2ecf20Sopenharmony_ci goto err; 5148c2ecf20Sopenharmony_ci if (snprintf(element->name, sizeof (element->name), 5158c2ecf20Sopenharmony_ci "%d", i) >= sizeof (element->name)) { 5168c2ecf20Sopenharmony_ci kfree(element); 5178c2ecf20Sopenharmony_ci goto err; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci sysfs_attr_init(&element->attr.attr); 5208c2ecf20Sopenharmony_ci element->attr.attr.name = element->name; 5218c2ecf20Sopenharmony_ci if (store) { 5228c2ecf20Sopenharmony_ci element->attr.attr.mode = S_IWUSR | S_IRUGO; 5238c2ecf20Sopenharmony_ci element->attr.store = store; 5248c2ecf20Sopenharmony_ci } else 5258c2ecf20Sopenharmony_ci element->attr.attr.mode = S_IRUGO; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci element->attr.show = show; 5288c2ecf20Sopenharmony_ci element->index = i; 5298c2ecf20Sopenharmony_ci tab_attr[i] = &element->attr.attr; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci return tab_attr; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cierr: 5348c2ecf20Sopenharmony_ci while (--i >= 0) 5358c2ecf20Sopenharmony_ci kfree(tab_attr[i]); 5368c2ecf20Sopenharmony_ci kfree(tab_attr); 5378c2ecf20Sopenharmony_ci return NULL; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic ssize_t sysfs_show_smi_enabled(struct device *dev, 5418c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct mlx4_port *p = 5448c2ecf20Sopenharmony_ci container_of(attr, struct mlx4_port, smi_enabled); 5458c2ecf20Sopenharmony_ci ssize_t len = 0; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (mlx4_vf_smi_enabled(p->dev->dev, p->slave, p->port_num)) 5488c2ecf20Sopenharmony_ci len = sprintf(buf, "%d\n", 1); 5498c2ecf20Sopenharmony_ci else 5508c2ecf20Sopenharmony_ci len = sprintf(buf, "%d\n", 0); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return len; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic ssize_t sysfs_show_enable_smi_admin(struct device *dev, 5568c2ecf20Sopenharmony_ci struct device_attribute *attr, 5578c2ecf20Sopenharmony_ci char *buf) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct mlx4_port *p = 5608c2ecf20Sopenharmony_ci container_of(attr, struct mlx4_port, enable_smi_admin); 5618c2ecf20Sopenharmony_ci ssize_t len = 0; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (mlx4_vf_get_enable_smi_admin(p->dev->dev, p->slave, p->port_num)) 5648c2ecf20Sopenharmony_ci len = sprintf(buf, "%d\n", 1); 5658c2ecf20Sopenharmony_ci else 5668c2ecf20Sopenharmony_ci len = sprintf(buf, "%d\n", 0); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return len; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic ssize_t sysfs_store_enable_smi_admin(struct device *dev, 5728c2ecf20Sopenharmony_ci struct device_attribute *attr, 5738c2ecf20Sopenharmony_ci const char *buf, size_t count) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct mlx4_port *p = 5768c2ecf20Sopenharmony_ci container_of(attr, struct mlx4_port, enable_smi_admin); 5778c2ecf20Sopenharmony_ci int enable; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (sscanf(buf, "%i", &enable) != 1 || 5808c2ecf20Sopenharmony_ci enable < 0 || enable > 1) 5818c2ecf20Sopenharmony_ci return -EINVAL; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (mlx4_vf_set_enable_smi_admin(p->dev->dev, p->slave, p->port_num, enable)) 5848c2ecf20Sopenharmony_ci return -EINVAL; 5858c2ecf20Sopenharmony_ci return count; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic int add_vf_smi_entries(struct mlx4_port *p) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci int is_eth = rdma_port_get_link_layer(&p->dev->ib_dev, p->port_num) == 5918c2ecf20Sopenharmony_ci IB_LINK_LAYER_ETHERNET; 5928c2ecf20Sopenharmony_ci int ret; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* do not display entries if eth transport, or if master */ 5958c2ecf20Sopenharmony_ci if (is_eth || p->slave == mlx4_master_func_num(p->dev->dev)) 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci sysfs_attr_init(&p->smi_enabled.attr); 5998c2ecf20Sopenharmony_ci p->smi_enabled.show = sysfs_show_smi_enabled; 6008c2ecf20Sopenharmony_ci p->smi_enabled.store = NULL; 6018c2ecf20Sopenharmony_ci p->smi_enabled.attr.name = "smi_enabled"; 6028c2ecf20Sopenharmony_ci p->smi_enabled.attr.mode = 0444; 6038c2ecf20Sopenharmony_ci ret = sysfs_create_file(&p->kobj, &p->smi_enabled.attr); 6048c2ecf20Sopenharmony_ci if (ret) { 6058c2ecf20Sopenharmony_ci pr_err("failed to create smi_enabled\n"); 6068c2ecf20Sopenharmony_ci return ret; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci sysfs_attr_init(&p->enable_smi_admin.attr); 6108c2ecf20Sopenharmony_ci p->enable_smi_admin.show = sysfs_show_enable_smi_admin; 6118c2ecf20Sopenharmony_ci p->enable_smi_admin.store = sysfs_store_enable_smi_admin; 6128c2ecf20Sopenharmony_ci p->enable_smi_admin.attr.name = "enable_smi_admin"; 6138c2ecf20Sopenharmony_ci p->enable_smi_admin.attr.mode = 0644; 6148c2ecf20Sopenharmony_ci ret = sysfs_create_file(&p->kobj, &p->enable_smi_admin.attr); 6158c2ecf20Sopenharmony_ci if (ret) { 6168c2ecf20Sopenharmony_ci pr_err("failed to create enable_smi_admin\n"); 6178c2ecf20Sopenharmony_ci sysfs_remove_file(&p->kobj, &p->smi_enabled.attr); 6188c2ecf20Sopenharmony_ci return ret; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci return 0; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic void remove_vf_smi_entries(struct mlx4_port *p) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci int is_eth = rdma_port_get_link_layer(&p->dev->ib_dev, p->port_num) == 6268c2ecf20Sopenharmony_ci IB_LINK_LAYER_ETHERNET; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (is_eth || p->slave == mlx4_master_func_num(p->dev->dev)) 6298c2ecf20Sopenharmony_ci return; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci sysfs_remove_file(&p->kobj, &p->smi_enabled.attr); 6328c2ecf20Sopenharmony_ci sysfs_remove_file(&p->kobj, &p->enable_smi_admin.attr); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int add_port(struct mlx4_ib_dev *dev, int port_num, int slave) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct mlx4_port *p; 6388c2ecf20Sopenharmony_ci int i; 6398c2ecf20Sopenharmony_ci int ret; 6408c2ecf20Sopenharmony_ci int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port_num) == 6418c2ecf20Sopenharmony_ci IB_LINK_LAYER_ETHERNET; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci p = kzalloc(sizeof *p, GFP_KERNEL); 6448c2ecf20Sopenharmony_ci if (!p) 6458c2ecf20Sopenharmony_ci return -ENOMEM; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci p->dev = dev; 6488c2ecf20Sopenharmony_ci p->port_num = port_num; 6498c2ecf20Sopenharmony_ci p->slave = slave; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci ret = kobject_init_and_add(&p->kobj, &port_type, 6528c2ecf20Sopenharmony_ci kobject_get(dev->dev_ports_parent[slave]), 6538c2ecf20Sopenharmony_ci "%d", port_num); 6548c2ecf20Sopenharmony_ci if (ret) 6558c2ecf20Sopenharmony_ci goto err_alloc; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci p->pkey_group.name = "pkey_idx"; 6588c2ecf20Sopenharmony_ci p->pkey_group.attrs = 6598c2ecf20Sopenharmony_ci alloc_group_attrs(show_port_pkey, 6608c2ecf20Sopenharmony_ci is_eth ? NULL : store_port_pkey, 6618c2ecf20Sopenharmony_ci dev->dev->caps.pkey_table_len[port_num]); 6628c2ecf20Sopenharmony_ci if (!p->pkey_group.attrs) { 6638c2ecf20Sopenharmony_ci ret = -ENOMEM; 6648c2ecf20Sopenharmony_ci goto err_alloc; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci ret = sysfs_create_group(&p->kobj, &p->pkey_group); 6688c2ecf20Sopenharmony_ci if (ret) 6698c2ecf20Sopenharmony_ci goto err_free_pkey; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci p->gid_group.name = "gid_idx"; 6728c2ecf20Sopenharmony_ci p->gid_group.attrs = alloc_group_attrs(show_port_gid_idx, NULL, 1); 6738c2ecf20Sopenharmony_ci if (!p->gid_group.attrs) { 6748c2ecf20Sopenharmony_ci ret = -ENOMEM; 6758c2ecf20Sopenharmony_ci goto err_free_pkey; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci ret = sysfs_create_group(&p->kobj, &p->gid_group); 6798c2ecf20Sopenharmony_ci if (ret) 6808c2ecf20Sopenharmony_ci goto err_free_gid; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci ret = add_vf_smi_entries(p); 6838c2ecf20Sopenharmony_ci if (ret) 6848c2ecf20Sopenharmony_ci goto err_free_gid; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci list_add_tail(&p->kobj.entry, &dev->pkeys.pkey_port_list[slave]); 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cierr_free_gid: 6908c2ecf20Sopenharmony_ci kfree(p->gid_group.attrs[0]); 6918c2ecf20Sopenharmony_ci kfree(p->gid_group.attrs); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cierr_free_pkey: 6948c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.pkey_table_len[port_num]; ++i) 6958c2ecf20Sopenharmony_ci kfree(p->pkey_group.attrs[i]); 6968c2ecf20Sopenharmony_ci kfree(p->pkey_group.attrs); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cierr_alloc: 6998c2ecf20Sopenharmony_ci kobject_put(dev->dev_ports_parent[slave]); 7008c2ecf20Sopenharmony_ci kfree(p); 7018c2ecf20Sopenharmony_ci return ret; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci char name[32]; 7078c2ecf20Sopenharmony_ci int err; 7088c2ecf20Sopenharmony_ci int port; 7098c2ecf20Sopenharmony_ci struct kobject *p, *t; 7108c2ecf20Sopenharmony_ci struct mlx4_port *mport; 7118c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci get_name(dev, name, slave, sizeof name); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci dev->pkeys.device_parent[slave] = 7168c2ecf20Sopenharmony_ci kobject_create_and_add(name, kobject_get(dev->iov_parent)); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (!dev->pkeys.device_parent[slave]) { 7198c2ecf20Sopenharmony_ci err = -ENOMEM; 7208c2ecf20Sopenharmony_ci goto fail_dev; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->pkeys.pkey_port_list[slave]); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci dev->dev_ports_parent[slave] = 7268c2ecf20Sopenharmony_ci kobject_create_and_add("ports", 7278c2ecf20Sopenharmony_ci kobject_get(dev->pkeys.device_parent[slave])); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (!dev->dev_ports_parent[slave]) { 7308c2ecf20Sopenharmony_ci err = -ENOMEM; 7318c2ecf20Sopenharmony_ci goto err_ports; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci actv_ports = mlx4_get_active_ports(dev->dev, slave); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci for (port = 1; port <= dev->dev->caps.num_ports; ++port) { 7378c2ecf20Sopenharmony_ci if (!test_bit(port - 1, actv_ports.ports)) 7388c2ecf20Sopenharmony_ci continue; 7398c2ecf20Sopenharmony_ci err = add_port(dev, port, slave); 7408c2ecf20Sopenharmony_ci if (err) 7418c2ecf20Sopenharmony_ci goto err_add; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci return 0; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cierr_add: 7468c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, t, 7478c2ecf20Sopenharmony_ci &dev->pkeys.pkey_port_list[slave], 7488c2ecf20Sopenharmony_ci entry) { 7498c2ecf20Sopenharmony_ci list_del(&p->entry); 7508c2ecf20Sopenharmony_ci mport = container_of(p, struct mlx4_port, kobj); 7518c2ecf20Sopenharmony_ci sysfs_remove_group(p, &mport->pkey_group); 7528c2ecf20Sopenharmony_ci sysfs_remove_group(p, &mport->gid_group); 7538c2ecf20Sopenharmony_ci remove_vf_smi_entries(mport); 7548c2ecf20Sopenharmony_ci kobject_put(p); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci kobject_put(dev->dev_ports_parent[slave]); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cierr_ports: 7598c2ecf20Sopenharmony_ci kobject_put(dev->pkeys.device_parent[slave]); 7608c2ecf20Sopenharmony_ci /* extra put for the device_parent create_and_add */ 7618c2ecf20Sopenharmony_ci kobject_put(dev->pkeys.device_parent[slave]); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cifail_dev: 7648c2ecf20Sopenharmony_ci kobject_put(dev->iov_parent); 7658c2ecf20Sopenharmony_ci return err; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic int register_pkey_tree(struct mlx4_ib_dev *device) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci int i; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (!mlx4_is_master(device->dev)) 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci for (i = 0; i <= device->dev->persist->num_vfs; ++i) 7768c2ecf20Sopenharmony_ci register_one_pkey_tree(device, i); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic void unregister_pkey_tree(struct mlx4_ib_dev *device) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci int slave; 7848c2ecf20Sopenharmony_ci struct kobject *p, *t; 7858c2ecf20Sopenharmony_ci struct mlx4_port *port; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (!mlx4_is_master(device->dev)) 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) { 7918c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, t, 7928c2ecf20Sopenharmony_ci &device->pkeys.pkey_port_list[slave], 7938c2ecf20Sopenharmony_ci entry) { 7948c2ecf20Sopenharmony_ci list_del(&p->entry); 7958c2ecf20Sopenharmony_ci port = container_of(p, struct mlx4_port, kobj); 7968c2ecf20Sopenharmony_ci sysfs_remove_group(p, &port->pkey_group); 7978c2ecf20Sopenharmony_ci sysfs_remove_group(p, &port->gid_group); 7988c2ecf20Sopenharmony_ci remove_vf_smi_entries(port); 7998c2ecf20Sopenharmony_ci kobject_put(p); 8008c2ecf20Sopenharmony_ci kobject_put(device->dev_ports_parent[slave]); 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci kobject_put(device->dev_ports_parent[slave]); 8038c2ecf20Sopenharmony_ci kobject_put(device->pkeys.device_parent[slave]); 8048c2ecf20Sopenharmony_ci kobject_put(device->pkeys.device_parent[slave]); 8058c2ecf20Sopenharmony_ci kobject_put(device->iov_parent); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ciint mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *dev) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci int i; 8128c2ecf20Sopenharmony_ci int ret = 0; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci dev->iov_parent = kobject_create_and_add("iov", &dev->ib_dev.dev.kobj); 8188c2ecf20Sopenharmony_ci if (!dev->iov_parent) { 8198c2ecf20Sopenharmony_ci ret = -ENOMEM; 8208c2ecf20Sopenharmony_ci goto err; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci dev->ports_parent = 8238c2ecf20Sopenharmony_ci kobject_create_and_add("ports", 8248c2ecf20Sopenharmony_ci kobject_get(dev->iov_parent)); 8258c2ecf20Sopenharmony_ci if (!dev->ports_parent) { 8268c2ecf20Sopenharmony_ci ret = -ENOMEM; 8278c2ecf20Sopenharmony_ci goto err_ports; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci for (i = 1; i <= dev->ib_dev.phys_port_cnt; ++i) { 8318c2ecf20Sopenharmony_ci ret = add_port_entries(dev, i); 8328c2ecf20Sopenharmony_ci if (ret) 8338c2ecf20Sopenharmony_ci goto err_add_entries; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci ret = register_pkey_tree(dev); 8378c2ecf20Sopenharmony_ci if (ret) 8388c2ecf20Sopenharmony_ci goto err_add_entries; 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cierr_add_entries: 8428c2ecf20Sopenharmony_ci kobject_put(dev->ports_parent); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cierr_ports: 8458c2ecf20Sopenharmony_ci kobject_put(dev->iov_parent); 8468c2ecf20Sopenharmony_cierr: 8478c2ecf20Sopenharmony_ci pr_err("mlx4_ib_device_register_sysfs error (%d)\n", ret); 8488c2ecf20Sopenharmony_ci return ret; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic void unregister_alias_guid_tree(struct mlx4_ib_dev *device) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci struct mlx4_ib_iov_port *p; 8548c2ecf20Sopenharmony_ci int i; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (!mlx4_is_master(device->dev)) 8578c2ecf20Sopenharmony_ci return; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci for (i = 0; i < device->dev->caps.num_ports; i++) { 8608c2ecf20Sopenharmony_ci p = &device->iov_ports[i]; 8618c2ecf20Sopenharmony_ci kobject_put(p->admin_alias_parent); 8628c2ecf20Sopenharmony_ci kobject_put(p->gids_parent); 8638c2ecf20Sopenharmony_ci kobject_put(p->pkeys_parent); 8648c2ecf20Sopenharmony_ci kobject_put(p->mcgs_parent); 8658c2ecf20Sopenharmony_ci kobject_put(p->cur_port); 8668c2ecf20Sopenharmony_ci kobject_put(p->cur_port); 8678c2ecf20Sopenharmony_ci kobject_put(p->cur_port); 8688c2ecf20Sopenharmony_ci kobject_put(p->cur_port); 8698c2ecf20Sopenharmony_ci kobject_put(p->cur_port); 8708c2ecf20Sopenharmony_ci kobject_put(p->dev->ports_parent); 8718c2ecf20Sopenharmony_ci kfree(p->dentr_ar); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_civoid mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci unregister_alias_guid_tree(device); 8788c2ecf20Sopenharmony_ci unregister_pkey_tree(device); 8798c2ecf20Sopenharmony_ci kobject_put(device->ports_parent); 8808c2ecf20Sopenharmony_ci kobject_put(device->iov_parent); 8818c2ecf20Sopenharmony_ci kobject_put(device->iov_parent); 8828c2ecf20Sopenharmony_ci} 883