mlx4_port.c revision 306486
1219820Sjeff/* 2272027Shselasky * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff */ 32219820Sjeff 33300676Shselasky#define LINUXKPI_PARAM_PREFIX mlx4_ 34300676Shselasky 35219820Sjeff#include <linux/errno.h> 36219820Sjeff#include <linux/if_ether.h> 37272027Shselasky#include <linux/module.h> 38272027Shselasky#include <linux/err.h> 39219820Sjeff 40306486Shselasky#include <dev/mlx4/cmd.h> 41255932Salfred#include <linux/moduleparam.h> 42219820Sjeff#include "mlx4.h" 43306486Shselasky#include <dev/mlx4/stats.h> 44219820Sjeff 45272027Shselasky 46255932Salfredint mlx4_set_4k_mtu = -1; 47255932Salfredmodule_param_named(set_4k_mtu, mlx4_set_4k_mtu, int, 0444); 48255932SalfredMODULE_PARM_DESC(set_4k_mtu, 49255932Salfred "(Obsolete) attempt to set 4K MTU to all ConnectX ports"); 50219820Sjeff 51255932Salfred 52219820Sjeff#define MLX4_MAC_VALID (1ull << 63) 53219820Sjeff 54219820Sjeff#define MLX4_VLAN_VALID (1u << 31) 55219820Sjeff#define MLX4_VLAN_MASK 0xfff 56219820Sjeff 57219820Sjeffvoid mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) 58219820Sjeff{ 59219820Sjeff int i; 60219820Sjeff 61219820Sjeff mutex_init(&table->mutex); 62219820Sjeff for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 63219820Sjeff table->entries[i] = 0; 64219820Sjeff table->refs[i] = 0; 65219820Sjeff } 66219820Sjeff table->max = 1 << dev->caps.log_num_macs; 67219820Sjeff table->total = 0; 68219820Sjeff} 69219820Sjeff 70219820Sjeffvoid mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) 71219820Sjeff{ 72219820Sjeff int i; 73219820Sjeff 74219820Sjeff mutex_init(&table->mutex); 75219820Sjeff for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 76219820Sjeff table->entries[i] = 0; 77219820Sjeff table->refs[i] = 0; 78219820Sjeff } 79255932Salfred table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; 80219820Sjeff table->total = 0; 81219820Sjeff} 82219820Sjeff 83255932Salfredstatic int validate_index(struct mlx4_dev *dev, 84255932Salfred struct mlx4_mac_table *table, int index) 85255932Salfred{ 86255932Salfred int err = 0; 87255932Salfred 88272027Shselasky if (index < 0 || index >= table->max || !table->refs[index]) { 89255932Salfred mlx4_warn(dev, "No valid Mac entry for the given index\n"); 90255932Salfred err = -EINVAL; 91255932Salfred } 92255932Salfred return err; 93255932Salfred} 94255932Salfred 95255932Salfredstatic int find_index(struct mlx4_dev *dev, 96255932Salfred struct mlx4_mac_table *table, u64 mac) 97255932Salfred{ 98255932Salfred int i; 99255932Salfred 100255932Salfred for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 101255932Salfred if ((mac & MLX4_MAC_MASK) == 102255932Salfred (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 103255932Salfred return i; 104255932Salfred } 105255932Salfred /* Mac not found */ 106255932Salfred return -EINVAL; 107255932Salfred} 108255932Salfred 109219820Sjeffstatic int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 110219820Sjeff __be64 *entries) 111219820Sjeff{ 112219820Sjeff struct mlx4_cmd_mailbox *mailbox; 113219820Sjeff u32 in_mod; 114219820Sjeff int err; 115219820Sjeff 116219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 117219820Sjeff if (IS_ERR(mailbox)) 118219820Sjeff return PTR_ERR(mailbox); 119219820Sjeff 120219820Sjeff memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 121219820Sjeff 122219820Sjeff in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 123255932Salfred 124219820Sjeff err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 125255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 126219820Sjeff 127219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 128219820Sjeff return err; 129219820Sjeff} 130219820Sjeff 131255932Salfredint __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 132219820Sjeff{ 133255932Salfred struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 134255932Salfred struct mlx4_mac_table *table = &info->mac_table; 135219820Sjeff int i, err = 0; 136219820Sjeff int free = -1; 137219820Sjeff 138255932Salfred mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n", 139255932Salfred (unsigned long long) mac, port); 140255932Salfred 141219820Sjeff mutex_lock(&table->mutex); 142255932Salfred for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 143272027Shselasky if (free < 0 && !table->refs[i]) { 144219820Sjeff free = i; 145219820Sjeff continue; 146219820Sjeff } 147219820Sjeff 148272027Shselasky if ((mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) && 149272027Shselasky table->refs[i]) { 150255932Salfred /* MAC already registered, Must not have duplicates */ 151272027Shselasky err = i; 152219820Sjeff ++table->refs[i]; 153219820Sjeff goto out; 154219820Sjeff } 155219820Sjeff } 156219820Sjeff 157219820Sjeff mlx4_dbg(dev, "Free MAC index is %d\n", free); 158219820Sjeff 159219820Sjeff if (table->total == table->max) { 160219820Sjeff /* No free mac entries */ 161219820Sjeff err = -ENOSPC; 162219820Sjeff goto out; 163219820Sjeff } 164219820Sjeff 165219820Sjeff /* Register new MAC */ 166219820Sjeff table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 167219820Sjeff 168219820Sjeff err = mlx4_set_port_mac_table(dev, port, table->entries); 169219820Sjeff if (unlikely(err)) { 170255932Salfred mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 171255932Salfred (unsigned long long) mac); 172219820Sjeff table->entries[free] = 0; 173219820Sjeff goto out; 174219820Sjeff } 175255932Salfred table->refs[free] = 1; 176219820Sjeff 177255932Salfred err = free; 178219820Sjeff ++table->total; 179219820Sjeffout: 180219820Sjeff mutex_unlock(&table->mutex); 181219820Sjeff return err; 182219820Sjeff} 183255932SalfredEXPORT_SYMBOL_GPL(__mlx4_register_mac); 184255932Salfred 185255932Salfredint mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 186255932Salfred{ 187255932Salfred u64 out_param = 0; 188272027Shselasky int err = -EINVAL; 189255932Salfred 190255932Salfred if (mlx4_is_mfunc(dev)) { 191272027Shselasky if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 192272027Shselasky err = mlx4_cmd_imm(dev, mac, &out_param, 193272027Shselasky ((u32) port) << 8 | (u32) RES_MAC, 194272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 195272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 196272027Shselasky } 197272027Shselasky if (err && err == -EINVAL && mlx4_is_slave(dev)) { 198272027Shselasky /* retry using old REG_MAC format */ 199272027Shselasky set_param_l(&out_param, port); 200272027Shselasky err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 201272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 202272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 203272027Shselasky if (!err) 204272027Shselasky dev->flags |= MLX4_FLAG_OLD_REG_MAC; 205272027Shselasky } 206255932Salfred if (err) 207255932Salfred return err; 208255932Salfred 209255932Salfred return get_param_l(&out_param); 210255932Salfred } 211255932Salfred return __mlx4_register_mac(dev, port, mac); 212255932Salfred} 213219820SjeffEXPORT_SYMBOL_GPL(mlx4_register_mac); 214219820Sjeff 215255932Salfredint mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) 216219820Sjeff{ 217255932Salfred return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + 218255932Salfred (port - 1) * (1 << dev->caps.log_num_macs); 219255932Salfred} 220255932SalfredEXPORT_SYMBOL_GPL(mlx4_get_base_qpn); 221219820Sjeff 222255932Salfredvoid __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 223255932Salfred{ 224255932Salfred struct mlx4_port_info *info; 225255932Salfred struct mlx4_mac_table *table; 226255932Salfred int index; 227255932Salfred 228255932Salfred if (port < 1 || port > dev->caps.num_ports) { 229255932Salfred mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); 230255932Salfred return; 231255932Salfred } 232255932Salfred info = &mlx4_priv(dev)->port[port]; 233255932Salfred table = &info->mac_table; 234219820Sjeff mutex_lock(&table->mutex); 235255932Salfred 236255932Salfred index = find_index(dev, table, mac); 237255932Salfred 238255932Salfred if (validate_index(dev, table, index)) 239219820Sjeff goto out; 240255932Salfred 241219820Sjeff if (--table->refs[index]) { 242255932Salfred mlx4_dbg(dev, "Have more references for index %d," 243255932Salfred "no need to modify mac table\n", index); 244219820Sjeff goto out; 245219820Sjeff } 246255932Salfred 247219820Sjeff table->entries[index] = 0; 248219820Sjeff mlx4_set_port_mac_table(dev, port, table->entries); 249219820Sjeff --table->total; 250219820Sjeffout: 251219820Sjeff mutex_unlock(&table->mutex); 252219820Sjeff} 253255932SalfredEXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 254255932Salfred 255255932Salfredvoid mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 256255932Salfred{ 257255932Salfred u64 out_param = 0; 258255932Salfred 259255932Salfred if (mlx4_is_mfunc(dev)) { 260272027Shselasky if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 261272027Shselasky (void) mlx4_cmd_imm(dev, mac, &out_param, 262272027Shselasky ((u32) port) << 8 | (u32) RES_MAC, 263272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 264272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 265272027Shselasky } else { 266272027Shselasky /* use old unregister mac format */ 267272027Shselasky set_param_l(&out_param, port); 268272027Shselasky (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 269272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 270272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 271272027Shselasky } 272255932Salfred return; 273255932Salfred } 274255932Salfred __mlx4_unregister_mac(dev, port, mac); 275255932Salfred return; 276255932Salfred} 277219820SjeffEXPORT_SYMBOL_GPL(mlx4_unregister_mac); 278219820Sjeff 279255932Salfredint __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 280255932Salfred{ 281255932Salfred struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 282255932Salfred struct mlx4_mac_table *table = &info->mac_table; 283255932Salfred int index = qpn - info->base_qpn; 284255932Salfred int err = 0; 285255932Salfred 286255932Salfred /* CX1 doesn't support multi-functions */ 287255932Salfred mutex_lock(&table->mutex); 288255932Salfred 289255932Salfred err = validate_index(dev, table, index); 290255932Salfred if (err) 291255932Salfred goto out; 292255932Salfred 293255932Salfred table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 294255932Salfred 295255932Salfred err = mlx4_set_port_mac_table(dev, port, table->entries); 296255932Salfred if (unlikely(err)) { 297255932Salfred mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 298255932Salfred (unsigned long long) new_mac); 299255932Salfred table->entries[index] = 0; 300255932Salfred } 301255932Salfredout: 302255932Salfred mutex_unlock(&table->mutex); 303255932Salfred return err; 304255932Salfred} 305255932SalfredEXPORT_SYMBOL_GPL(__mlx4_replace_mac); 306255932Salfred 307219820Sjeffstatic int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 308219820Sjeff __be32 *entries) 309219820Sjeff{ 310219820Sjeff struct mlx4_cmd_mailbox *mailbox; 311219820Sjeff u32 in_mod; 312219820Sjeff int err; 313219820Sjeff 314219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 315219820Sjeff if (IS_ERR(mailbox)) 316219820Sjeff return PTR_ERR(mailbox); 317219820Sjeff 318219820Sjeff memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 319219820Sjeff in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 320219820Sjeff err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 321255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 322219820Sjeff 323219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 324219820Sjeff 325219820Sjeff return err; 326219820Sjeff} 327219820Sjeff 328219820Sjeffint mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 329219820Sjeff{ 330219820Sjeff struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 331219820Sjeff int i; 332219820Sjeff 333219820Sjeff for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 334219820Sjeff if (table->refs[i] && 335219820Sjeff (vid == (MLX4_VLAN_MASK & 336219820Sjeff be32_to_cpu(table->entries[i])))) { 337255932Salfred /* VLAN already registered, increase reference count */ 338219820Sjeff *idx = i; 339219820Sjeff return 0; 340219820Sjeff } 341219820Sjeff } 342219820Sjeff 343219820Sjeff return -ENOENT; 344219820Sjeff} 345219820SjeffEXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 346219820Sjeff 347255932Salfredint __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 348255932Salfred int *index) 349219820Sjeff{ 350219820Sjeff struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 351219820Sjeff int i, err = 0; 352219820Sjeff int free = -1; 353219820Sjeff 354219820Sjeff mutex_lock(&table->mutex); 355255932Salfred 356255932Salfred if (table->total == table->max) { 357255932Salfred /* No free vlan entries */ 358255932Salfred err = -ENOSPC; 359255932Salfred goto out; 360255932Salfred } 361255932Salfred 362219820Sjeff for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 363219820Sjeff if (free < 0 && (table->refs[i] == 0)) { 364219820Sjeff free = i; 365219820Sjeff continue; 366219820Sjeff } 367219820Sjeff 368219820Sjeff if (table->refs[i] && 369219820Sjeff (vlan == (MLX4_VLAN_MASK & 370219820Sjeff be32_to_cpu(table->entries[i])))) { 371255932Salfred /* Vlan already registered, increase references count */ 372219820Sjeff *index = i; 373219820Sjeff ++table->refs[i]; 374219820Sjeff goto out; 375219820Sjeff } 376219820Sjeff } 377219820Sjeff 378219820Sjeff if (free < 0) { 379219820Sjeff err = -ENOMEM; 380219820Sjeff goto out; 381219820Sjeff } 382219820Sjeff 383255932Salfred /* Register new VLAN */ 384219820Sjeff table->refs[free] = 1; 385219820Sjeff table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 386219820Sjeff 387219820Sjeff err = mlx4_set_port_vlan_table(dev, port, table->entries); 388219820Sjeff if (unlikely(err)) { 389219820Sjeff mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 390219820Sjeff table->refs[free] = 0; 391219820Sjeff table->entries[free] = 0; 392219820Sjeff goto out; 393219820Sjeff } 394219820Sjeff 395219820Sjeff *index = free; 396219820Sjeff ++table->total; 397219820Sjeffout: 398219820Sjeff mutex_unlock(&table->mutex); 399219820Sjeff return err; 400219820Sjeff} 401255932Salfred 402255932Salfredint mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 403255932Salfred{ 404255932Salfred u64 out_param = 0; 405255932Salfred int err; 406255932Salfred 407255932Salfred if (vlan > 4095) 408255932Salfred return -EINVAL; 409255932Salfred 410255932Salfred if (mlx4_is_mfunc(dev)) { 411255932Salfred err = mlx4_cmd_imm(dev, vlan, &out_param, 412255932Salfred ((u32) port) << 8 | (u32) RES_VLAN, 413255932Salfred RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 414255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 415255932Salfred if (!err) 416255932Salfred *index = get_param_l(&out_param); 417255932Salfred 418255932Salfred return err; 419255932Salfred } 420255932Salfred return __mlx4_register_vlan(dev, port, vlan, index); 421255932Salfred} 422219820SjeffEXPORT_SYMBOL_GPL(mlx4_register_vlan); 423219820Sjeff 424255932Salfredvoid __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 425219820Sjeff{ 426219820Sjeff struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 427255932Salfred int index; 428219820Sjeff 429255932Salfred mutex_lock(&table->mutex); 430255932Salfred if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 431255932Salfred mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 432255932Salfred goto out; 433255932Salfred } 434255932Salfred 435219820Sjeff if (index < MLX4_VLAN_REGULAR) { 436219820Sjeff mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 437255932Salfred goto out; 438219820Sjeff } 439219820Sjeff 440219820Sjeff if (--table->refs[index]) { 441255932Salfred mlx4_dbg(dev, "Have %d more references for index %d, " 442255932Salfred "no need to modify vlan table\n", table->refs[index], 443255932Salfred index); 444219820Sjeff goto out; 445219820Sjeff } 446219820Sjeff table->entries[index] = 0; 447219820Sjeff mlx4_set_port_vlan_table(dev, port, table->entries); 448219820Sjeff --table->total; 449219820Sjeffout: 450219820Sjeff mutex_unlock(&table->mutex); 451219820Sjeff} 452255932Salfred 453255932Salfredvoid mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 454255932Salfred{ 455255932Salfred u64 out_param = 0; 456255932Salfred 457255932Salfred if (mlx4_is_mfunc(dev)) { 458255932Salfred (void) mlx4_cmd_imm(dev, vlan, &out_param, 459255932Salfred ((u32) port) << 8 | (u32) RES_VLAN, 460255932Salfred RES_OP_RESERVE_AND_MAP, 461255932Salfred MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 462255932Salfred MLX4_CMD_WRAPPED); 463255932Salfred return; 464255932Salfred } 465255932Salfred __mlx4_unregister_vlan(dev, port, vlan); 466255932Salfred} 467219820SjeffEXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 468219820Sjeff 469219820Sjeffint mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 470219820Sjeff{ 471219820Sjeff struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 472219820Sjeff u8 *inbuf, *outbuf; 473219820Sjeff int err; 474219820Sjeff 475219820Sjeff inmailbox = mlx4_alloc_cmd_mailbox(dev); 476219820Sjeff if (IS_ERR(inmailbox)) 477219820Sjeff return PTR_ERR(inmailbox); 478219820Sjeff 479219820Sjeff outmailbox = mlx4_alloc_cmd_mailbox(dev); 480219820Sjeff if (IS_ERR(outmailbox)) { 481219820Sjeff mlx4_free_cmd_mailbox(dev, inmailbox); 482219820Sjeff return PTR_ERR(outmailbox); 483219820Sjeff } 484219820Sjeff 485219820Sjeff inbuf = inmailbox->buf; 486219820Sjeff outbuf = outmailbox->buf; 487219820Sjeff memset(inbuf, 0, 256); 488219820Sjeff memset(outbuf, 0, 256); 489219820Sjeff inbuf[0] = 1; 490219820Sjeff inbuf[1] = 1; 491219820Sjeff inbuf[2] = 1; 492219820Sjeff inbuf[3] = 1; 493219820Sjeff *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 494219820Sjeff *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 495219820Sjeff 496219820Sjeff err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 497255932Salfred MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 498255932Salfred MLX4_CMD_NATIVE); 499219820Sjeff if (!err) 500219820Sjeff *caps = *(__be32 *) (outbuf + 84); 501219820Sjeff mlx4_free_cmd_mailbox(dev, inmailbox); 502219820Sjeff mlx4_free_cmd_mailbox(dev, outmailbox); 503219820Sjeff return err; 504219820Sjeff} 505255932Salfredstatic struct mlx4_roce_gid_entry zgid_entry; 506219820Sjeff 507255932Salfredint mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave) 508219820Sjeff{ 509255932Salfred if (slave == 0) 510255932Salfred return MLX4_ROCE_PF_GIDS; 511255932Salfred if (slave <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % dev->num_vfs)) 512255932Salfred return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs) + 1; 513255932Salfred return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs; 514255932Salfred} 515255932Salfred 516255932Salfredint mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave) 517255932Salfred{ 518255932Salfred int gids; 519255932Salfred int vfs; 520255932Salfred 521255932Salfred gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 522255932Salfred vfs = dev->num_vfs; 523255932Salfred 524255932Salfred if (slave == 0) 525255932Salfred return 0; 526255932Salfred if (slave <= gids % vfs) 527255932Salfred return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); 528255932Salfred 529255932Salfred return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); 530255932Salfred} 531255932Salfred 532255932Salfredstatic int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 533255932Salfred u8 op_mod, struct mlx4_cmd_mailbox *inbox) 534255932Salfred{ 535255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 536255932Salfred struct mlx4_port_info *port_info; 537255932Salfred struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 538255932Salfred struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 539255932Salfred struct mlx4_set_port_rqp_calc_context *qpn_context; 540255932Salfred struct mlx4_set_port_general_context *gen_context; 541255932Salfred struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 542255932Salfred int reset_qkey_viols; 543255932Salfred int port; 544255932Salfred int is_eth; 545255932Salfred int num_gids; 546255932Salfred int base; 547255932Salfred u32 in_modifier; 548255932Salfred u32 promisc; 549255932Salfred u16 mtu, prev_mtu; 550219820Sjeff int err; 551255932Salfred int i, j; 552255932Salfred int offset; 553255932Salfred __be32 agg_cap_mask; 554255932Salfred __be32 slave_cap_mask; 555255932Salfred __be32 new_cap_mask; 556219820Sjeff 557255932Salfred port = in_mod & 0xff; 558272027Shselasky in_modifier = (in_mod >> 8) & 0xff; 559255932Salfred is_eth = op_mod; 560255932Salfred port_info = &priv->port[port]; 561255932Salfred 562272027Shselasky if (op_mod > 1) 563272027Shselasky return -EINVAL; 564272027Shselasky 565255932Salfred /* Slaves cannot perform SET_PORT operations except changing MTU */ 566255932Salfred if (is_eth) { 567255932Salfred if (slave != dev->caps.function && 568255932Salfred in_modifier != MLX4_SET_PORT_GENERAL && 569255932Salfred in_modifier != MLX4_SET_PORT_GID_TABLE) { 570272027Shselasky mlx4_warn(dev, "denying SET_PORT for slave:%d," 571272027Shselasky "port %d, config_select 0x%x\n", 572272027Shselasky slave, port, in_modifier); 573255932Salfred return -EINVAL; 574255932Salfred } 575255932Salfred switch (in_modifier) { 576255932Salfred case MLX4_SET_PORT_RQP_CALC: 577255932Salfred qpn_context = inbox->buf; 578255932Salfred qpn_context->base_qpn = 579255932Salfred cpu_to_be32(port_info->base_qpn); 580255932Salfred qpn_context->n_mac = 0x7; 581255932Salfred promisc = be32_to_cpu(qpn_context->promisc) >> 582255932Salfred SET_PORT_PROMISC_SHIFT; 583255932Salfred qpn_context->promisc = cpu_to_be32( 584255932Salfred promisc << SET_PORT_PROMISC_SHIFT | 585255932Salfred port_info->base_qpn); 586255932Salfred promisc = be32_to_cpu(qpn_context->mcast) >> 587255932Salfred SET_PORT_MC_PROMISC_SHIFT; 588255932Salfred qpn_context->mcast = cpu_to_be32( 589255932Salfred promisc << SET_PORT_MC_PROMISC_SHIFT | 590255932Salfred port_info->base_qpn); 591255932Salfred break; 592255932Salfred case MLX4_SET_PORT_GENERAL: 593255932Salfred gen_context = inbox->buf; 594255932Salfred /* Mtu is configured as the max MTU among all the 595255932Salfred * the functions on the port. */ 596255932Salfred mtu = be16_to_cpu(gen_context->mtu); 597272027Shselasky mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 598272027Shselasky ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 599255932Salfred prev_mtu = slave_st->mtu[port]; 600255932Salfred slave_st->mtu[port] = mtu; 601255932Salfred if (mtu > master->max_mtu[port]) 602255932Salfred master->max_mtu[port] = mtu; 603255932Salfred if (mtu < prev_mtu && prev_mtu == 604255932Salfred master->max_mtu[port]) { 605255932Salfred slave_st->mtu[port] = mtu; 606255932Salfred master->max_mtu[port] = mtu; 607255932Salfred for (i = 0; i < dev->num_slaves; i++) { 608255932Salfred master->max_mtu[port] = 609255932Salfred max(master->max_mtu[port], 610255932Salfred master->slave_state[i].mtu[port]); 611255932Salfred } 612255932Salfred } 613255932Salfred 614255932Salfred gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 615255932Salfred break; 616255932Salfred case MLX4_SET_PORT_GID_TABLE: 617255932Salfred /* change to MULTIPLE entries: number of guest's gids 618255932Salfred * need a FOR-loop here over number of gids the guest has. 619255932Salfred * 1. Check no duplicates in gids passed by slave 620255932Salfred */ 621255932Salfred num_gids = mlx4_get_slave_num_gids(dev, slave); 622255932Salfred base = mlx4_get_base_gid_ix(dev, slave); 623255932Salfred gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); 624255932Salfred for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 625255932Salfred if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 626255932Salfred sizeof(zgid_entry))) 627255932Salfred continue; 628255932Salfred gid_entry_mb1 = gid_entry_mbox + 1; 629255932Salfred for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 630255932Salfred if (!memcmp(gid_entry_mb1->raw, 631255932Salfred zgid_entry.raw, sizeof(zgid_entry))) 632255932Salfred continue; 633255932Salfred if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 634255932Salfred sizeof(gid_entry_mbox->raw))) { 635255932Salfred /* found duplicate */ 636255932Salfred return -EINVAL; 637255932Salfred } 638255932Salfred } 639255932Salfred } 640255932Salfred 641255932Salfred /* 2. Check that do not have duplicates in OTHER 642255932Salfred * entries in the port GID table 643255932Salfred */ 644255932Salfred for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 645255932Salfred if (i >= base && i < base + num_gids) 646255932Salfred continue; /* don't compare to slave's current gids */ 647255932Salfred gid_entry_tbl = &priv->roce_gids[port - 1][i]; 648255932Salfred if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 649255932Salfred continue; 650255932Salfred gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); 651255932Salfred for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 652255932Salfred if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 653255932Salfred sizeof(zgid_entry))) 654255932Salfred continue; 655255932Salfred if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 656255932Salfred sizeof(gid_entry_tbl->raw))) { 657255932Salfred /* found duplicate */ 658255932Salfred mlx4_warn(dev, "requested gid entry for slave:%d " 659255932Salfred "is a duplicate of gid at index %d\n", 660255932Salfred slave, i); 661255932Salfred return -EINVAL; 662255932Salfred } 663255932Salfred } 664255932Salfred } 665255932Salfred 666255932Salfred /* insert slave GIDs with memcpy, starting at slave's base index */ 667255932Salfred gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); 668255932Salfred for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 669255932Salfred memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16); 670255932Salfred 671255932Salfred /* Now, copy roce port gids table to current mailbox for passing to FW */ 672255932Salfred gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); 673255932Salfred for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 674255932Salfred memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16); 675255932Salfred 676255932Salfred break; 677255932Salfred } 678272027Shselasky return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 679255932Salfred MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 680255932Salfred MLX4_CMD_NATIVE); 681255932Salfred } 682255932Salfred 683255932Salfred /* For IB, we only consider: 684255932Salfred * - The capability mask, which is set to the aggregate of all 685255932Salfred * slave function capabilities 686255932Salfred * - The QKey violatin counter - reset according to each request. 687255932Salfred */ 688255932Salfred 689255932Salfred if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 690255932Salfred reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 691255932Salfred new_cap_mask = ((__be32 *) inbox->buf)[2]; 692255932Salfred } else { 693255932Salfred reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 694255932Salfred new_cap_mask = ((__be32 *) inbox->buf)[1]; 695255932Salfred } 696255932Salfred 697255932Salfred /* slave may not set the IS_SM capability for the port */ 698255932Salfred if (slave != mlx4_master_func_num(dev) && 699255932Salfred (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 700255932Salfred return -EINVAL; 701255932Salfred 702255932Salfred /* No DEV_MGMT in multifunc mode */ 703255932Salfred if (mlx4_is_mfunc(dev) && 704255932Salfred (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 705255932Salfred return -EINVAL; 706255932Salfred 707255932Salfred agg_cap_mask = 0; 708255932Salfred slave_cap_mask = 709255932Salfred priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 710255932Salfred priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 711255932Salfred for (i = 0; i < dev->num_slaves; i++) 712255932Salfred agg_cap_mask |= 713255932Salfred priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 714255932Salfred 715255932Salfred /* only clear mailbox for guests. Master may be setting 716255932Salfred * MTU or PKEY table size 717255932Salfred */ 718255932Salfred if (slave != dev->caps.function) 719255932Salfred memset(inbox->buf, 0, 256); 720255932Salfred if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 721255932Salfred *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 722255932Salfred ((__be32 *) inbox->buf)[2] = agg_cap_mask; 723255932Salfred } else { 724255932Salfred ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 725255932Salfred ((__be32 *) inbox->buf)[1] = agg_cap_mask; 726255932Salfred } 727255932Salfred 728255932Salfred err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 729255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 730255932Salfred if (err) 731255932Salfred priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 732255932Salfred slave_cap_mask; 733255932Salfred return err; 734255932Salfred} 735255932Salfred 736255932Salfredint mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 737255932Salfred struct mlx4_vhcr *vhcr, 738255932Salfred struct mlx4_cmd_mailbox *inbox, 739255932Salfred struct mlx4_cmd_mailbox *outbox, 740255932Salfred struct mlx4_cmd_info *cmd) 741255932Salfred{ 742255932Salfred return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 743255932Salfred vhcr->op_modifier, inbox); 744255932Salfred} 745255932Salfred 746255932Salfred/* bit locations for set port command with zero op modifier */ 747255932Salfredenum { 748255932Salfred MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 749255932Salfred MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 750255932Salfred MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 751255932Salfred MLX4_CHANGE_PORT_VL_CAP = 21, 752255932Salfred MLX4_CHANGE_PORT_MTU_CAP = 22, 753255932Salfred}; 754255932Salfred 755255932Salfredint mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 756255932Salfred{ 757255932Salfred struct mlx4_cmd_mailbox *mailbox; 758272027Shselasky int err = -EINVAL, vl_cap, pkey_tbl_flag = 0; 759255932Salfred u32 in_mod; 760255932Salfred 761255932Salfred if (dev->caps.port_type[port] == MLX4_PORT_TYPE_NONE) 762219820Sjeff return 0; 763219820Sjeff 764219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 765219820Sjeff if (IS_ERR(mailbox)) 766219820Sjeff return PTR_ERR(mailbox); 767219820Sjeff 768219820Sjeff memset(mailbox->buf, 0, 256); 769219820Sjeff 770255932Salfred if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { 771255932Salfred in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 772255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, 773255932Salfred MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 774255932Salfred MLX4_CMD_WRAPPED); 775255932Salfred } else { 776255932Salfred ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 777219820Sjeff 778255932Salfred if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 779255932Salfred pkey_tbl_flag = 1; 780255932Salfred ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 781255932Salfred } 782219820Sjeff 783255932Salfred /* IB VL CAP enum isn't used by the firmware, just numerical values */ 784272027Shselasky for (vl_cap = dev->caps.vl_cap[port]; 785272027Shselasky vl_cap >= 1; vl_cap >>= 1) { 786255932Salfred ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 787255932Salfred (1 << MLX4_CHANGE_PORT_MTU_CAP) | 788255932Salfred (1 << MLX4_CHANGE_PORT_VL_CAP) | 789255932Salfred (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 790255932Salfred (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 791255932Salfred (vl_cap << MLX4_SET_PORT_VL_CAP)); 792255932Salfred err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, 793255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 794255932Salfred if (err != -ENOMEM) 795255932Salfred break; 796255932Salfred } 797255932Salfred } 798255932Salfred 799219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 800219820Sjeff return err; 801219820Sjeff} 802255932Salfred 803255932Salfredint mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 804255932Salfred u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 805255932Salfred{ 806255932Salfred struct mlx4_cmd_mailbox *mailbox; 807255932Salfred struct mlx4_set_port_general_context *context; 808255932Salfred int err; 809255932Salfred u32 in_mod; 810255932Salfred 811255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 812255932Salfred if (IS_ERR(mailbox)) 813255932Salfred return PTR_ERR(mailbox); 814255932Salfred context = mailbox->buf; 815255932Salfred memset(context, 0, sizeof *context); 816255932Salfred 817255932Salfred context->flags = SET_PORT_GEN_ALL_VALID; 818255932Salfred context->mtu = cpu_to_be16(mtu); 819255932Salfred context->pptx = (pptx * (!pfctx)) << 7; 820255932Salfred context->pfctx = pfctx; 821255932Salfred context->pprx = (pprx * (!pfcrx)) << 7; 822255932Salfred context->pfcrx = pfcrx; 823255932Salfred 824255932Salfred in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 825255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 826255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 827255932Salfred 828255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 829255932Salfred return err; 830255932Salfred} 831255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_general); 832255932Salfred 833255932Salfredint mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 834255932Salfred u8 promisc) 835255932Salfred{ 836255932Salfred struct mlx4_cmd_mailbox *mailbox; 837255932Salfred struct mlx4_set_port_rqp_calc_context *context; 838255932Salfred int err; 839255932Salfred u32 in_mod; 840255932Salfred u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 841255932Salfred MCAST_DIRECT : MCAST_DEFAULT; 842272027Shselasky 843255932Salfred if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 844255932Salfred return 0; 845255932Salfred 846255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 847255932Salfred if (IS_ERR(mailbox)) 848255932Salfred return PTR_ERR(mailbox); 849255932Salfred context = mailbox->buf; 850255932Salfred memset(context, 0, sizeof *context); 851255932Salfred 852255932Salfred context->base_qpn = cpu_to_be32(base_qpn); 853272027Shselasky context->n_mac = dev->caps.log_num_macs; 854255932Salfred context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 855255932Salfred base_qpn); 856255932Salfred context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 857255932Salfred base_qpn); 858255932Salfred context->intra_no_vlan = 0; 859255932Salfred context->no_vlan = MLX4_NO_VLAN_IDX; 860255932Salfred context->intra_vlan_miss = 0; 861255932Salfred context->vlan_miss = MLX4_VLAN_MISS_IDX; 862255932Salfred 863255932Salfred in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; 864255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 865255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 866255932Salfred 867255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 868255932Salfred return err; 869255932Salfred} 870255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 871255932Salfred 872255932Salfredint mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) 873255932Salfred{ 874255932Salfred struct mlx4_cmd_mailbox *mailbox; 875255932Salfred struct mlx4_set_port_prio2tc_context *context; 876255932Salfred int err; 877255932Salfred u32 in_mod; 878255932Salfred int i; 879255932Salfred 880255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 881255932Salfred if (IS_ERR(mailbox)) 882255932Salfred return PTR_ERR(mailbox); 883255932Salfred context = mailbox->buf; 884255932Salfred memset(context, 0, sizeof *context); 885255932Salfred 886255932Salfred for (i = 0; i < MLX4_NUM_UP; i += 2) 887255932Salfred context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; 888255932Salfred 889255932Salfred in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; 890255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 891255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 892255932Salfred 893255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 894255932Salfred return err; 895255932Salfred} 896255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); 897255932Salfred 898255932Salfredint mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, 899255932Salfred u8 *pg, u16 *ratelimit) 900255932Salfred{ 901255932Salfred struct mlx4_cmd_mailbox *mailbox; 902255932Salfred struct mlx4_set_port_scheduler_context *context; 903255932Salfred int err; 904255932Salfred u32 in_mod; 905255932Salfred int i; 906255932Salfred 907255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 908255932Salfred if (IS_ERR(mailbox)) 909255932Salfred return PTR_ERR(mailbox); 910255932Salfred context = mailbox->buf; 911255932Salfred memset(context, 0, sizeof *context); 912255932Salfred 913255932Salfred for (i = 0; i < MLX4_NUM_TC; i++) { 914255932Salfred struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; 915255932Salfred u16 r; 916255932Salfred if (ratelimit && ratelimit[i]) { 917255932Salfred if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { 918255932Salfred r = ratelimit[i]; 919255932Salfred tc->max_bw_units = 920255932Salfred htons(MLX4_RATELIMIT_100M_UNITS); 921255932Salfred } else { 922255932Salfred r = ratelimit[i]/10; 923255932Salfred tc->max_bw_units = 924255932Salfred htons(MLX4_RATELIMIT_1G_UNITS); 925255932Salfred } 926255932Salfred tc->max_bw_value = htons(r); 927255932Salfred } else { 928255932Salfred tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); 929255932Salfred tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); 930255932Salfred } 931255932Salfred 932255932Salfred tc->pg = htons(pg[i]); 933255932Salfred tc->bw_precentage = htons(tc_tx_bw[i]); 934255932Salfred } 935255932Salfred 936255932Salfred in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; 937255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 938255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 939255932Salfred 940255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 941255932Salfred return err; 942255932Salfred} 943255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); 944255932Salfred 945255932Salfredint mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 946255932Salfred struct mlx4_vhcr *vhcr, 947255932Salfred struct mlx4_cmd_mailbox *inbox, 948255932Salfred struct mlx4_cmd_mailbox *outbox, 949255932Salfred struct mlx4_cmd_info *cmd) 950255932Salfred{ 951255932Salfred int err = 0; 952255932Salfred 953255932Salfred return err; 954255932Salfred} 955255932Salfred 956255932Salfredint mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 957255932Salfred u64 mac, u64 clear, u8 mode) 958255932Salfred{ 959255932Salfred return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 960255932Salfred MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 961255932Salfred MLX4_CMD_WRAPPED); 962255932Salfred} 963255932SalfredEXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 964255932Salfred 965255932Salfredint mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 966255932Salfred struct mlx4_vhcr *vhcr, 967255932Salfred struct mlx4_cmd_mailbox *inbox, 968255932Salfred struct mlx4_cmd_mailbox *outbox, 969255932Salfred struct mlx4_cmd_info *cmd) 970255932Salfred{ 971255932Salfred int err = 0; 972255932Salfred 973255932Salfred return err; 974255932Salfred} 975255932Salfred 976255932Salfredint mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 977255932Salfred struct mlx4_vhcr *vhcr, 978255932Salfred struct mlx4_cmd_mailbox *inbox, 979255932Salfred struct mlx4_cmd_mailbox *outbox, 980255932Salfred struct mlx4_cmd_info *cmd) 981255932Salfred{ 982272027Shselasky return 0; 983255932Salfred} 984255932Salfred 985272027Shselaskyvoid mlx4_set_stats_bitmap(struct mlx4_dev *dev, unsigned long *stats_bitmap) 986255932Salfred{ 987272027Shselasky int last_i = 0; 988272027Shselasky 989272027Shselasky bitmap_zero(stats_bitmap, NUM_ALL_STATS); 990272027Shselasky 991272027Shselasky if (mlx4_is_slave(dev)) { 992272027Shselasky last_i = dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN ? 993272027Shselasky NUM_PKT_STATS + NUM_FLOW_STATS : NUM_PKT_STATS; 994272027Shselasky } else { 995272027Shselasky bitmap_set(stats_bitmap, last_i, NUM_PKT_STATS); 996272027Shselasky last_i = NUM_PKT_STATS; 997272027Shselasky 998272027Shselasky if (dev->caps.flags2 & 999272027Shselasky MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) { 1000272027Shselasky bitmap_set(stats_bitmap, last_i, NUM_FLOW_STATS); 1001272027Shselasky last_i += NUM_FLOW_STATS; 1002272027Shselasky } 1003255932Salfred } 1004255932Salfred 1005272027Shselasky if (mlx4_is_slave(dev)) 1006272027Shselasky bitmap_set(stats_bitmap, last_i, NUM_VF_STATS); 1007272027Shselasky last_i += NUM_VF_STATS; 1008255932Salfred 1009255932Salfred if (mlx4_is_master(dev)) 1010272027Shselasky bitmap_set(stats_bitmap, last_i, NUM_VPORT_STATS); 1011272027Shselasky last_i += NUM_VPORT_STATS; 1012272027Shselasky 1013272027Shselasky bitmap_set(stats_bitmap, last_i, NUM_PORT_STATS); 1014255932Salfred} 1015255932SalfredEXPORT_SYMBOL(mlx4_set_stats_bitmap); 1016255932Salfred 1017255932Salfredint mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id) 1018255932Salfred{ 1019255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1020255932Salfred int i, found_ix = -1; 1021255932Salfred int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1022255932Salfred 1023255932Salfred if (!mlx4_is_mfunc(dev)) 1024255932Salfred return -EINVAL; 1025255932Salfred 1026255932Salfred for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1027255932Salfred if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) { 1028255932Salfred found_ix = i; 1029255932Salfred break; 1030255932Salfred } 1031255932Salfred } 1032255932Salfred 1033255932Salfred if (found_ix >= 0) { 1034255932Salfred if (found_ix < MLX4_ROCE_PF_GIDS) 1035255932Salfred *slave_id = 0; 1036255932Salfred else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % dev->num_vfs) * 1037255932Salfred (vf_gids / dev->num_vfs + 1)) 1038255932Salfred *slave_id = ((found_ix - MLX4_ROCE_PF_GIDS) / 1039255932Salfred (vf_gids / dev->num_vfs + 1)) + 1; 1040255932Salfred else 1041255932Salfred *slave_id = 1042255932Salfred ((found_ix - MLX4_ROCE_PF_GIDS - 1043255932Salfred ((vf_gids % dev->num_vfs) * ((vf_gids / dev->num_vfs + 1)))) / 1044255932Salfred (vf_gids / dev->num_vfs)) + vf_gids % dev->num_vfs + 1; 1045255932Salfred } 1046255932Salfred 1047255932Salfred return (found_ix >= 0) ? 0 : -EINVAL; 1048255932Salfred} 1049255932SalfredEXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 1050255932Salfred 1051255932Salfredint mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid) 1052255932Salfred{ 1053255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1054255932Salfred 1055255932Salfred if (!mlx4_is_master(dev)) 1056255932Salfred return -EINVAL; 1057255932Salfred 1058255932Salfred memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16); 1059255932Salfred return 0; 1060255932Salfred} 1061255932SalfredEXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 1062255932Salfred 1063283612Sglebius/* Cable Module Info */ 1064283612Sglebius#define MODULE_INFO_MAX_READ 48 1065283612Sglebius 1066283612Sglebius#define I2C_ADDR_LOW 0x50 1067283612Sglebius#define I2C_ADDR_HIGH 0x51 1068283612Sglebius#define I2C_PAGE_SIZE 256 1069283612Sglebius 1070283612Sglebius/* Module Info Data */ 1071283612Sglebiusstruct mlx4_cable_info { 1072283612Sglebius u8 i2c_addr; 1073283612Sglebius u8 page_num; 1074283612Sglebius __be16 dev_mem_address; 1075283612Sglebius __be16 reserved1; 1076283612Sglebius __be16 size; 1077283612Sglebius __be32 reserved2[2]; 1078283612Sglebius u8 data[MODULE_INFO_MAX_READ]; 1079283612Sglebius}; 1080283612Sglebius 1081283612Sglebiusenum cable_info_err { 1082283612Sglebius CABLE_INF_INV_PORT = 0x1, 1083283612Sglebius CABLE_INF_OP_NOSUP = 0x2, 1084283612Sglebius CABLE_INF_NOT_CONN = 0x3, 1085283612Sglebius CABLE_INF_NO_EEPRM = 0x4, 1086283612Sglebius CABLE_INF_PAGE_ERR = 0x5, 1087283612Sglebius CABLE_INF_INV_ADDR = 0x6, 1088283612Sglebius CABLE_INF_I2C_ADDR = 0x7, 1089283612Sglebius CABLE_INF_QSFP_VIO = 0x8, 1090283612Sglebius CABLE_INF_I2C_BUSY = 0x9, 1091283612Sglebius}; 1092283612Sglebius 1093283612Sglebius#define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) 1094283612Sglebius 1095283612Sglebius#ifdef DEBUG 1096283612Sglebiusstatic inline const char *cable_info_mad_err_str(u16 mad_status) 1097283612Sglebius{ 1098283612Sglebius u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); 1099283612Sglebius 1100283612Sglebius switch (err) { 1101283612Sglebius case CABLE_INF_INV_PORT: 1102283612Sglebius return "invalid port selected"; 1103283612Sglebius case CABLE_INF_OP_NOSUP: 1104283612Sglebius return "operation not supported for this port (the port is of type CX4 or internal)"; 1105283612Sglebius case CABLE_INF_NOT_CONN: 1106283612Sglebius return "cable is not connected"; 1107283612Sglebius case CABLE_INF_NO_EEPRM: 1108283612Sglebius return "the connected cable has no EPROM (passive copper cable)"; 1109283612Sglebius case CABLE_INF_PAGE_ERR: 1110283612Sglebius return "page number is greater than 15"; 1111283612Sglebius case CABLE_INF_INV_ADDR: 1112283612Sglebius return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; 1113283612Sglebius case CABLE_INF_I2C_ADDR: 1114283612Sglebius return "invalid I2C slave address"; 1115283612Sglebius case CABLE_INF_QSFP_VIO: 1116283612Sglebius return "at least one cable violates the QSFP specification and ignores the modsel signal"; 1117283612Sglebius case CABLE_INF_I2C_BUSY: 1118283612Sglebius return "I2C bus is constantly busy"; 1119283612Sglebius } 1120283612Sglebius return "Unknown Error"; 1121283612Sglebius} 1122283612Sglebius#endif /* DEBUG */ 1123283612Sglebius 1124283612Sglebius/** 1125283612Sglebius * mlx4_get_module_info - Read cable module eeprom data 1126283612Sglebius * @dev: mlx4_dev. 1127283612Sglebius * @port: port number. 1128283612Sglebius * @offset: byte offset in eeprom to start reading data from. 1129283612Sglebius * @size: num of bytes to read. 1130283612Sglebius * @data: output buffer to put the requested data into. 1131283612Sglebius * 1132283612Sglebius * Reads cable module eeprom data, puts the outcome data into 1133283612Sglebius * data pointer paramer. 1134283612Sglebius * Returns num of read bytes on success or a negative error 1135283612Sglebius * code. 1136283612Sglebius */ 1137283612Sglebiusint mlx4_get_module_info(struct mlx4_dev *dev, u8 port, u16 offset, 1138283612Sglebius u16 size, u8 *data) 1139283612Sglebius{ 1140283612Sglebius struct mlx4_cmd_mailbox *inbox, *outbox; 1141283612Sglebius struct mlx4_mad_ifc *inmad, *outmad; 1142283612Sglebius struct mlx4_cable_info *cable_info; 1143283612Sglebius u16 i2c_addr; 1144283612Sglebius int ret; 1145283612Sglebius 1146283612Sglebius if (size > MODULE_INFO_MAX_READ) 1147283612Sglebius size = MODULE_INFO_MAX_READ; 1148283612Sglebius 1149283612Sglebius inbox = mlx4_alloc_cmd_mailbox(dev); 1150291694Shselasky if (IS_ERR(inbox)) { 1151291694Shselasky mlx4_err(dev, 1152291694Shselasky "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(inbox)); 1153283612Sglebius return PTR_ERR(inbox); 1154291694Shselasky } 1155283612Sglebius 1156283612Sglebius outbox = mlx4_alloc_cmd_mailbox(dev); 1157283612Sglebius if (IS_ERR(outbox)) { 1158283612Sglebius mlx4_free_cmd_mailbox(dev, inbox); 1159291694Shselasky mlx4_err(dev, 1160291694Shselasky "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(outbox)); 1161283612Sglebius return PTR_ERR(outbox); 1162283612Sglebius } 1163283612Sglebius 1164283612Sglebius inmad = (struct mlx4_mad_ifc *)(inbox->buf); 1165283612Sglebius outmad = (struct mlx4_mad_ifc *)(outbox->buf); 1166283612Sglebius 1167283612Sglebius inmad->method = 0x1; /* Get */ 1168283612Sglebius inmad->class_version = 0x1; 1169283612Sglebius inmad->mgmt_class = 0x1; 1170283612Sglebius inmad->base_version = 0x1; 1171283612Sglebius inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ 1172283612Sglebius 1173283612Sglebius if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) 1174283612Sglebius /* Cross pages reads are not allowed 1175283612Sglebius * read until offset 256 in low page 1176283612Sglebius */ 1177283612Sglebius size -= offset + size - I2C_PAGE_SIZE; 1178283612Sglebius 1179283612Sglebius i2c_addr = I2C_ADDR_LOW; 1180283612Sglebius if (offset >= I2C_PAGE_SIZE) { 1181283612Sglebius /* Reset offset to high page */ 1182283612Sglebius i2c_addr = I2C_ADDR_HIGH; 1183283612Sglebius offset -= I2C_PAGE_SIZE; 1184283612Sglebius } 1185283612Sglebius 1186283612Sglebius cable_info = (struct mlx4_cable_info *)inmad->data; 1187283612Sglebius cable_info->dev_mem_address = cpu_to_be16(offset); 1188283612Sglebius cable_info->page_num = 0; 1189283612Sglebius cable_info->i2c_addr = i2c_addr; 1190283612Sglebius cable_info->size = cpu_to_be16(size); 1191283612Sglebius 1192283612Sglebius ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 1193283612Sglebius MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 1194283612Sglebius if (ret) 1195283612Sglebius goto out; 1196283612Sglebius 1197283612Sglebius if (be16_to_cpu(outmad->status)) { 1198283612Sglebius /* Mad returned with bad status */ 1199283612Sglebius ret = be16_to_cpu(outmad->status); 1200283612Sglebius#ifdef DEBUG 1201283612Sglebius mlx4_warn(dev, "MLX4_CMD_MAD_IFC Get Module info attr(%x) " 1202283612Sglebius "port(%d) i2c_addr(%x) offset(%d) size(%d): Response " 1203283612Sglebius "Mad Status(%x) - %s\n", 0xFF60, port, i2c_addr, offset, 1204283612Sglebius size, ret, cable_info_mad_err_str(ret)); 1205283612Sglebius#endif 1206283612Sglebius if (i2c_addr == I2C_ADDR_HIGH && 1207283612Sglebius MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) 1208283612Sglebius /* Some SFP cables do not support i2c slave 1209283612Sglebius * address 0x51 (high page), abort silently. 1210283612Sglebius */ 1211283612Sglebius ret = 0; 1212283612Sglebius else 1213283612Sglebius ret = -ret; 1214283612Sglebius goto out; 1215283612Sglebius } 1216283612Sglebius cable_info = (struct mlx4_cable_info *)outmad->data; 1217283612Sglebius memcpy(data, cable_info->data, size); 1218283612Sglebius ret = size; 1219283612Sglebiusout: 1220283612Sglebius mlx4_free_cmd_mailbox(dev, inbox); 1221283612Sglebius mlx4_free_cmd_mailbox(dev, outbox); 1222283612Sglebius return ret; 1223283612Sglebius} 1224283612SglebiusEXPORT_SYMBOL(mlx4_get_module_info); 1225