18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2016, 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 <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/mlx5/vport.h> 358c2ecf20Sopenharmony_ci#include "mlx5_ib.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic inline u32 mlx_to_net_policy(enum port_state_policy mlx_policy) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci switch (mlx_policy) { 408c2ecf20Sopenharmony_ci case MLX5_POLICY_DOWN: 418c2ecf20Sopenharmony_ci return IFLA_VF_LINK_STATE_DISABLE; 428c2ecf20Sopenharmony_ci case MLX5_POLICY_UP: 438c2ecf20Sopenharmony_ci return IFLA_VF_LINK_STATE_ENABLE; 448c2ecf20Sopenharmony_ci case MLX5_POLICY_FOLLOW: 458c2ecf20Sopenharmony_ci return IFLA_VF_LINK_STATE_AUTO; 468c2ecf20Sopenharmony_ci default: 478c2ecf20Sopenharmony_ci return __IFLA_VF_LINK_STATE_MAX; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciint mlx5_ib_get_vf_config(struct ib_device *device, int vf, u8 port, 528c2ecf20Sopenharmony_ci struct ifla_vf_info *info) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(device); 558c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 568c2ecf20Sopenharmony_ci struct mlx5_hca_vport_context *rep; 578c2ecf20Sopenharmony_ci int err; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci rep = kzalloc(sizeof(*rep), GFP_KERNEL); 608c2ecf20Sopenharmony_ci if (!rep) 618c2ecf20Sopenharmony_ci return -ENOMEM; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci err = mlx5_query_hca_vport_context(mdev, 1, 1, vf + 1, rep); 648c2ecf20Sopenharmony_ci if (err) { 658c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "failed to query port policy for vf %d (%d)\n", 668c2ecf20Sopenharmony_ci vf, err); 678c2ecf20Sopenharmony_ci goto free; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 708c2ecf20Sopenharmony_ci info->linkstate = mlx_to_net_policy(rep->policy); 718c2ecf20Sopenharmony_ci if (info->linkstate == __IFLA_VF_LINK_STATE_MAX) 728c2ecf20Sopenharmony_ci err = -EINVAL; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cifree: 758c2ecf20Sopenharmony_ci kfree(rep); 768c2ecf20Sopenharmony_ci return err; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline enum port_state_policy net_to_mlx_policy(int policy) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci switch (policy) { 828c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 838c2ecf20Sopenharmony_ci return MLX5_POLICY_DOWN; 848c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 858c2ecf20Sopenharmony_ci return MLX5_POLICY_UP; 868c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 878c2ecf20Sopenharmony_ci return MLX5_POLICY_FOLLOW; 888c2ecf20Sopenharmony_ci default: 898c2ecf20Sopenharmony_ci return MLX5_POLICY_INVALID; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciint mlx5_ib_set_vf_link_state(struct ib_device *device, int vf, 948c2ecf20Sopenharmony_ci u8 port, int state) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(device); 978c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 988c2ecf20Sopenharmony_ci struct mlx5_hca_vport_context *in; 998c2ecf20Sopenharmony_ci struct mlx5_vf_context *vfs_ctx = mdev->priv.sriov.vfs_ctx; 1008c2ecf20Sopenharmony_ci int err; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci in = kzalloc(sizeof(*in), GFP_KERNEL); 1038c2ecf20Sopenharmony_ci if (!in) 1048c2ecf20Sopenharmony_ci return -ENOMEM; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci in->policy = net_to_mlx_policy(state); 1078c2ecf20Sopenharmony_ci if (in->policy == MLX5_POLICY_INVALID) { 1088c2ecf20Sopenharmony_ci err = -EINVAL; 1098c2ecf20Sopenharmony_ci goto out; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci in->field_select = MLX5_HCA_VPORT_SEL_STATE_POLICY; 1128c2ecf20Sopenharmony_ci err = mlx5_core_modify_hca_vport_context(mdev, 1, 1, vf + 1, in); 1138c2ecf20Sopenharmony_ci if (!err) 1148c2ecf20Sopenharmony_ci vfs_ctx[vf].policy = in->policy; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciout: 1178c2ecf20Sopenharmony_ci kfree(in); 1188c2ecf20Sopenharmony_ci return err; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciint mlx5_ib_get_vf_stats(struct ib_device *device, int vf, 1228c2ecf20Sopenharmony_ci u8 port, struct ifla_vf_stats *stats) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int out_sz = MLX5_ST_SZ_BYTES(query_vport_counter_out); 1258c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev; 1268c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev; 1278c2ecf20Sopenharmony_ci void *out; 1288c2ecf20Sopenharmony_ci int err; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci dev = to_mdev(device); 1318c2ecf20Sopenharmony_ci mdev = dev->mdev; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci out = kzalloc(out_sz, GFP_KERNEL); 1348c2ecf20Sopenharmony_ci if (!out) 1358c2ecf20Sopenharmony_ci return -ENOMEM; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci err = mlx5_core_query_vport_counter(mdev, true, vf, port, out); 1388c2ecf20Sopenharmony_ci if (err) 1398c2ecf20Sopenharmony_ci goto ex; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci stats->rx_packets = MLX5_GET64_PR(query_vport_counter_out, out, received_ib_unicast.packets); 1428c2ecf20Sopenharmony_ci stats->tx_packets = MLX5_GET64_PR(query_vport_counter_out, out, transmitted_ib_unicast.packets); 1438c2ecf20Sopenharmony_ci stats->rx_bytes = MLX5_GET64_PR(query_vport_counter_out, out, received_ib_unicast.octets); 1448c2ecf20Sopenharmony_ci stats->tx_bytes = MLX5_GET64_PR(query_vport_counter_out, out, transmitted_ib_unicast.octets); 1458c2ecf20Sopenharmony_ci stats->multicast = MLX5_GET64_PR(query_vport_counter_out, out, received_ib_multicast.packets); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ciex: 1488c2ecf20Sopenharmony_ci kfree(out); 1498c2ecf20Sopenharmony_ci return err; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int set_vf_node_guid(struct ib_device *device, int vf, u8 port, u64 guid) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(device); 1558c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 1568c2ecf20Sopenharmony_ci struct mlx5_hca_vport_context *in; 1578c2ecf20Sopenharmony_ci struct mlx5_vf_context *vfs_ctx = mdev->priv.sriov.vfs_ctx; 1588c2ecf20Sopenharmony_ci int err; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci in = kzalloc(sizeof(*in), GFP_KERNEL); 1618c2ecf20Sopenharmony_ci if (!in) 1628c2ecf20Sopenharmony_ci return -ENOMEM; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci in->field_select = MLX5_HCA_VPORT_SEL_NODE_GUID; 1658c2ecf20Sopenharmony_ci in->node_guid = guid; 1668c2ecf20Sopenharmony_ci err = mlx5_core_modify_hca_vport_context(mdev, 1, 1, vf + 1, in); 1678c2ecf20Sopenharmony_ci if (!err) { 1688c2ecf20Sopenharmony_ci vfs_ctx[vf].node_guid = guid; 1698c2ecf20Sopenharmony_ci vfs_ctx[vf].node_guid_valid = 1; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci kfree(in); 1728c2ecf20Sopenharmony_ci return err; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int set_vf_port_guid(struct ib_device *device, int vf, u8 port, u64 guid) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(device); 1788c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 1798c2ecf20Sopenharmony_ci struct mlx5_hca_vport_context *in; 1808c2ecf20Sopenharmony_ci struct mlx5_vf_context *vfs_ctx = mdev->priv.sriov.vfs_ctx; 1818c2ecf20Sopenharmony_ci int err; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci in = kzalloc(sizeof(*in), GFP_KERNEL); 1848c2ecf20Sopenharmony_ci if (!in) 1858c2ecf20Sopenharmony_ci return -ENOMEM; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci in->field_select = MLX5_HCA_VPORT_SEL_PORT_GUID; 1888c2ecf20Sopenharmony_ci in->port_guid = guid; 1898c2ecf20Sopenharmony_ci err = mlx5_core_modify_hca_vport_context(mdev, 1, 1, vf + 1, in); 1908c2ecf20Sopenharmony_ci if (!err) { 1918c2ecf20Sopenharmony_ci vfs_ctx[vf].port_guid = guid; 1928c2ecf20Sopenharmony_ci vfs_ctx[vf].port_guid_valid = 1; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci kfree(in); 1958c2ecf20Sopenharmony_ci return err; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciint mlx5_ib_set_vf_guid(struct ib_device *device, int vf, u8 port, 1998c2ecf20Sopenharmony_ci u64 guid, int type) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci if (type == IFLA_VF_IB_NODE_GUID) 2028c2ecf20Sopenharmony_ci return set_vf_node_guid(device, vf, port, guid); 2038c2ecf20Sopenharmony_ci else if (type == IFLA_VF_IB_PORT_GUID) 2048c2ecf20Sopenharmony_ci return set_vf_port_guid(device, vf, port, guid); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciint mlx5_ib_get_vf_guid(struct ib_device *device, int vf, u8 port, 2108c2ecf20Sopenharmony_ci struct ifla_vf_guid *node_guid, 2118c2ecf20Sopenharmony_ci struct ifla_vf_guid *port_guid) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(device); 2148c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 2158c2ecf20Sopenharmony_ci struct mlx5_vf_context *vfs_ctx = mdev->priv.sriov.vfs_ctx; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci node_guid->guid = 2188c2ecf20Sopenharmony_ci vfs_ctx[vf].node_guid_valid ? vfs_ctx[vf].node_guid : 0; 2198c2ecf20Sopenharmony_ci port_guid->guid = 2208c2ecf20Sopenharmony_ci vfs_ctx[vf].port_guid_valid ? vfs_ctx[vf].port_guid : 0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 224