mlx4_mcg.c revision 272027
1219820Sjeff/* 2219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. 3272027Shselasky * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#include <linux/string.h> 35272027Shselasky#include <linux/etherdevice.h> 36219820Sjeff 37219820Sjeff#include <linux/mlx4/cmd.h> 38272027Shselasky#include <linux/module.h> 39219820Sjeff 40219820Sjeff#include "mlx4.h" 41219820Sjeff 42219820Sjeff 43219820Sjeffstatic const u8 zero_gid[16]; /* automatically initialized to 0 */ 44219820Sjeff 45255932Salfredint mlx4_get_mgm_entry_size(struct mlx4_dev *dev) 46219820Sjeff{ 47255932Salfred return 1 << dev->oper_log_mgm_entry_size; 48255932Salfred} 49255932Salfred 50255932Salfredint mlx4_get_qp_per_mgm(struct mlx4_dev *dev) 51255932Salfred{ 52255932Salfred return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2); 53255932Salfred} 54255932Salfred 55255932Salfredstatic int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev, 56255932Salfred struct mlx4_cmd_mailbox *mailbox, 57255932Salfred u32 size, 58255932Salfred u64 *reg_id) 59255932Salfred{ 60255932Salfred u64 imm; 61255932Salfred int err = 0; 62255932Salfred 63255932Salfred err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0, 64255932Salfred MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 65255932Salfred MLX4_CMD_NATIVE); 66255932Salfred if (err) 67255932Salfred return err; 68255932Salfred *reg_id = imm; 69255932Salfred 70255932Salfred return err; 71255932Salfred} 72255932Salfred 73255932Salfredstatic int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid) 74255932Salfred{ 75255932Salfred int err = 0; 76255932Salfred 77255932Salfred err = mlx4_cmd(dev, regid, 0, 0, 78255932Salfred MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 79255932Salfred MLX4_CMD_NATIVE); 80255932Salfred 81255932Salfred return err; 82255932Salfred} 83255932Salfred 84255932Salfredstatic int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, 85255932Salfred struct mlx4_cmd_mailbox *mailbox) 86255932Salfred{ 87219820Sjeff return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, 88255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 89219820Sjeff} 90219820Sjeff 91255932Salfredstatic int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, 92255932Salfred struct mlx4_cmd_mailbox *mailbox) 93219820Sjeff{ 94219820Sjeff return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, 95255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 96219820Sjeff} 97219820Sjeff 98255932Salfredstatic int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer, 99255932Salfred struct mlx4_cmd_mailbox *mailbox) 100219820Sjeff{ 101255932Salfred u32 in_mod; 102255932Salfred 103255932Salfred in_mod = (u32) port << 16 | steer << 1; 104255932Salfred return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, 105255932Salfred MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A, 106255932Salfred MLX4_CMD_NATIVE); 107255932Salfred} 108255932Salfred 109255932Salfredstatic int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, 110255932Salfred u16 *hash, u8 op_mod) 111255932Salfred{ 112219820Sjeff u64 imm; 113219820Sjeff int err; 114219820Sjeff 115255932Salfred err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, 116255932Salfred MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A, 117255932Salfred MLX4_CMD_NATIVE); 118219820Sjeff 119219820Sjeff if (!err) 120219820Sjeff *hash = imm; 121219820Sjeff 122219820Sjeff return err; 123219820Sjeff} 124219820Sjeff 125255932Salfredstatic struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port, 126255932Salfred enum mlx4_steer_type steer, 127255932Salfred u32 qpn) 128255932Salfred{ 129272027Shselasky struct mlx4_steer *s_steer; 130255932Salfred struct mlx4_promisc_qp *pqp; 131255932Salfred 132272027Shselasky if (port < 1 || port > dev->caps.num_ports) 133272027Shselasky return NULL; 134272027Shselasky 135272027Shselasky s_steer = &mlx4_priv(dev)->steer[port - 1]; 136272027Shselasky 137255932Salfred list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { 138255932Salfred if (pqp->qpn == qpn) 139255932Salfred return pqp; 140255932Salfred } 141255932Salfred /* not found */ 142255932Salfred return NULL; 143255932Salfred} 144255932Salfred 145219820Sjeff/* 146255932Salfred * Add new entry to steering data structure. 147255932Salfred * All promisc QPs should be added as well 148255932Salfred */ 149255932Salfredstatic int new_steering_entry(struct mlx4_dev *dev, u8 port, 150255932Salfred enum mlx4_steer_type steer, 151255932Salfred unsigned int index, u32 qpn) 152255932Salfred{ 153255932Salfred struct mlx4_steer *s_steer; 154255932Salfred struct mlx4_cmd_mailbox *mailbox; 155255932Salfred struct mlx4_mgm *mgm; 156255932Salfred u32 members_count; 157255932Salfred struct mlx4_steer_index *new_entry; 158255932Salfred struct mlx4_promisc_qp *pqp; 159255932Salfred struct mlx4_promisc_qp *dqp = NULL; 160255932Salfred u32 prot; 161255932Salfred int err; 162255932Salfred 163272027Shselasky if (port < 1 || port > dev->caps.num_ports) 164272027Shselasky return -EINVAL; 165272027Shselasky 166255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 167255932Salfred new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); 168255932Salfred if (!new_entry) 169255932Salfred return -ENOMEM; 170255932Salfred 171255932Salfred INIT_LIST_HEAD(&new_entry->duplicates); 172255932Salfred new_entry->index = index; 173255932Salfred list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); 174255932Salfred 175255932Salfred /* If the given qpn is also a promisc qp, 176255932Salfred * it should be inserted to duplicates list 177255932Salfred */ 178255932Salfred pqp = get_promisc_qp(dev, port, steer, qpn); 179255932Salfred if (pqp) { 180255932Salfred dqp = kmalloc(sizeof *dqp, GFP_KERNEL); 181255932Salfred if (!dqp) { 182255932Salfred err = -ENOMEM; 183255932Salfred goto out_alloc; 184255932Salfred } 185255932Salfred dqp->qpn = qpn; 186255932Salfred list_add_tail(&dqp->list, &new_entry->duplicates); 187255932Salfred } 188255932Salfred 189255932Salfred /* if no promisc qps for this vep, we are done */ 190255932Salfred if (list_empty(&s_steer->promisc_qps[steer])) 191255932Salfred return 0; 192255932Salfred 193255932Salfred /* now need to add all the promisc qps to the new 194255932Salfred * steering entry, as they should also receive the packets 195255932Salfred * destined to this address */ 196255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 197255932Salfred if (IS_ERR(mailbox)) { 198255932Salfred err = -ENOMEM; 199255932Salfred goto out_alloc; 200255932Salfred } 201255932Salfred mgm = mailbox->buf; 202255932Salfred 203255932Salfred err = mlx4_READ_ENTRY(dev, index, mailbox); 204255932Salfred if (err) 205255932Salfred goto out_mailbox; 206255932Salfred 207255932Salfred members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 208255932Salfred prot = be32_to_cpu(mgm->members_count) >> 30; 209255932Salfred list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { 210255932Salfred /* don't add already existing qpn */ 211255932Salfred if (pqp->qpn == qpn) 212255932Salfred continue; 213255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 214255932Salfred /* out of space */ 215255932Salfred err = -ENOMEM; 216255932Salfred goto out_mailbox; 217255932Salfred } 218255932Salfred 219255932Salfred /* add the qpn */ 220255932Salfred mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); 221255932Salfred } 222255932Salfred /* update the qps count and update the entry with all the promisc qps*/ 223255932Salfred mgm->members_count = cpu_to_be32(members_count | (prot << 30)); 224255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 225255932Salfred 226255932Salfredout_mailbox: 227255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 228255932Salfred if (!err) 229255932Salfred return 0; 230255932Salfredout_alloc: 231255932Salfred if (dqp) { 232255932Salfred list_del(&dqp->list); 233255932Salfred kfree(dqp); 234255932Salfred } 235255932Salfred list_del(&new_entry->list); 236255932Salfred kfree(new_entry); 237255932Salfred return err; 238255932Salfred} 239255932Salfred 240255932Salfred/* update the data structures with existing steering entry */ 241255932Salfredstatic int existing_steering_entry(struct mlx4_dev *dev, u8 port, 242255932Salfred enum mlx4_steer_type steer, 243255932Salfred unsigned int index, u32 qpn) 244255932Salfred{ 245255932Salfred struct mlx4_steer *s_steer; 246255932Salfred struct mlx4_steer_index *tmp_entry, *entry = NULL; 247255932Salfred struct mlx4_promisc_qp *pqp; 248255932Salfred struct mlx4_promisc_qp *dqp; 249255932Salfred 250272027Shselasky if (port < 1 || port > dev->caps.num_ports) 251272027Shselasky return -EINVAL; 252272027Shselasky 253255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 254255932Salfred 255255932Salfred pqp = get_promisc_qp(dev, port, steer, qpn); 256255932Salfred if (!pqp) 257255932Salfred return 0; /* nothing to do */ 258255932Salfred 259255932Salfred list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { 260255932Salfred if (tmp_entry->index == index) { 261255932Salfred entry = tmp_entry; 262255932Salfred break; 263255932Salfred } 264255932Salfred } 265255932Salfred if (unlikely(!entry)) { 266255932Salfred mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); 267255932Salfred return -EINVAL; 268255932Salfred } 269255932Salfred 270255932Salfred /* the given qpn is listed as a promisc qpn 271255932Salfred * we need to add it as a duplicate to this entry 272255932Salfred * for future references */ 273255932Salfred list_for_each_entry(dqp, &entry->duplicates, list) { 274272027Shselasky if (qpn == dqp->qpn) 275255932Salfred return 0; /* qp is already duplicated */ 276255932Salfred } 277255932Salfred 278255932Salfred /* add the qp as a duplicate on this index */ 279255932Salfred dqp = kmalloc(sizeof *dqp, GFP_KERNEL); 280255932Salfred if (!dqp) 281255932Salfred return -ENOMEM; 282255932Salfred dqp->qpn = qpn; 283255932Salfred list_add_tail(&dqp->list, &entry->duplicates); 284255932Salfred 285255932Salfred return 0; 286255932Salfred} 287255932Salfred 288255932Salfred/* Check whether a qpn is a duplicate on steering entry 289255932Salfred * If so, it should not be removed from mgm */ 290255932Salfredstatic bool check_duplicate_entry(struct mlx4_dev *dev, u8 port, 291255932Salfred enum mlx4_steer_type steer, 292255932Salfred unsigned int index, u32 qpn) 293255932Salfred{ 294255932Salfred struct mlx4_steer *s_steer; 295255932Salfred struct mlx4_steer_index *tmp_entry, *entry = NULL; 296255932Salfred struct mlx4_promisc_qp *dqp, *tmp_dqp; 297255932Salfred 298272027Shselasky if (port < 1 || port > dev->caps.num_ports) 299272027Shselasky return NULL; 300272027Shselasky 301255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 302255932Salfred 303255932Salfred /* if qp is not promisc, it cannot be duplicated */ 304255932Salfred if (!get_promisc_qp(dev, port, steer, qpn)) 305255932Salfred return false; 306255932Salfred 307255932Salfred /* The qp is promisc qp so it is a duplicate on this index 308255932Salfred * Find the index entry, and remove the duplicate */ 309255932Salfred list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { 310255932Salfred if (tmp_entry->index == index) { 311255932Salfred entry = tmp_entry; 312255932Salfred break; 313255932Salfred } 314255932Salfred } 315255932Salfred if (unlikely(!entry)) { 316255932Salfred mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); 317255932Salfred return false; 318255932Salfred } 319255932Salfred list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { 320255932Salfred if (dqp->qpn == qpn) { 321255932Salfred list_del(&dqp->list); 322255932Salfred kfree(dqp); 323255932Salfred } 324255932Salfred } 325255932Salfred return true; 326255932Salfred} 327255932Salfred 328272027Shselasky/* 329272027Shselasky * returns true if all the QPs != tqpn contained in this entry 330272027Shselasky * are Promisc QPs. return false otherwise. 331272027Shselasky */ 332272027Shselaskystatic bool promisc_steering_entry(struct mlx4_dev *dev, u8 port, 333255932Salfred enum mlx4_steer_type steer, 334272027Shselasky unsigned int index, u32 tqpn, u32 *members_count) 335255932Salfred{ 336255932Salfred struct mlx4_steer *s_steer; 337255932Salfred struct mlx4_cmd_mailbox *mailbox; 338255932Salfred struct mlx4_mgm *mgm; 339272027Shselasky u32 m_count; 340255932Salfred bool ret = false; 341255932Salfred int i; 342255932Salfred 343272027Shselasky if (port < 1 || port > dev->caps.num_ports) 344272027Shselasky return false; 345272027Shselasky 346255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 347255932Salfred 348255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 349255932Salfred if (IS_ERR(mailbox)) 350255932Salfred return false; 351255932Salfred mgm = mailbox->buf; 352255932Salfred 353255932Salfred if (mlx4_READ_ENTRY(dev, index, mailbox)) 354255932Salfred goto out; 355272027Shselasky m_count = be32_to_cpu(mgm->members_count) & 0xffffff; 356272027Shselasky if (members_count) 357272027Shselasky *members_count = m_count; 358272027Shselasky 359272027Shselasky for (i = 0; i < m_count; i++) { 360272027Shselasky u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; 361255932Salfred if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) { 362255932Salfred /* the qp is not promisc, the entry can't be removed */ 363255932Salfred goto out; 364255932Salfred } 365255932Salfred } 366272027Shselasky ret = true; 367272027Shselaskyout: 368272027Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 369272027Shselasky return ret; 370272027Shselasky} 371272027Shselasky 372272027Shselasky/* IF a steering entry contains only promisc QPs, it can be removed. */ 373272027Shselaskystatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, 374272027Shselasky enum mlx4_steer_type steer, 375272027Shselasky unsigned int index, u32 tqpn) 376272027Shselasky{ 377272027Shselasky struct mlx4_steer *s_steer; 378272027Shselasky struct mlx4_steer_index *entry = NULL, *tmp_entry; 379272027Shselasky u32 members_count; 380272027Shselasky bool ret = false; 381272027Shselasky 382272027Shselasky if (port < 1 || port > dev->caps.num_ports) 383272027Shselasky return NULL; 384272027Shselasky 385272027Shselasky s_steer = &mlx4_priv(dev)->steer[port - 1]; 386272027Shselasky 387272027Shselasky if (!promisc_steering_entry(dev, port, steer, index, tqpn, &members_count)) 388272027Shselasky goto out; 389272027Shselasky 390272027Shselasky /* All the qps currently registered for this entry are promiscuous, 391255932Salfred * Checking for duplicates */ 392255932Salfred ret = true; 393255932Salfred list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { 394255932Salfred if (entry->index == index) { 395255932Salfred if (list_empty(&entry->duplicates) || members_count == 1) { 396255932Salfred struct mlx4_promisc_qp *pqp, *tmp_pqp; 397255932Salfred /* 398255932Salfred * If there is only 1 entry in duplicates than 399255932Salfred * this is the QP we want to delete, going over 400255932Salfred * the list and deleting the entry. 401255932Salfred */ 402255932Salfred list_del(&entry->list); 403255932Salfred list_for_each_entry_safe(pqp, tmp_pqp, 404255932Salfred &entry->duplicates, 405255932Salfred list) { 406255932Salfred list_del(&pqp->list); 407255932Salfred kfree(pqp); 408255932Salfred } 409255932Salfred kfree(entry); 410255932Salfred } else { 411255932Salfred /* This entry contains duplicates so it shouldn't be removed */ 412255932Salfred ret = false; 413255932Salfred goto out; 414255932Salfred } 415255932Salfred } 416255932Salfred } 417255932Salfred 418255932Salfredout: 419255932Salfred return ret; 420255932Salfred} 421255932Salfred 422255932Salfredstatic int add_promisc_qp(struct mlx4_dev *dev, u8 port, 423255932Salfred enum mlx4_steer_type steer, u32 qpn) 424255932Salfred{ 425255932Salfred struct mlx4_steer *s_steer; 426255932Salfred struct mlx4_cmd_mailbox *mailbox; 427255932Salfred struct mlx4_mgm *mgm; 428255932Salfred struct mlx4_steer_index *entry; 429255932Salfred struct mlx4_promisc_qp *pqp; 430255932Salfred struct mlx4_promisc_qp *dqp; 431255932Salfred u32 members_count; 432255932Salfred u32 prot; 433255932Salfred int i; 434255932Salfred bool found; 435255932Salfred int err; 436255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 437255932Salfred 438272027Shselasky if (port < 1 || port > dev->caps.num_ports) 439272027Shselasky return -EINVAL; 440272027Shselasky 441255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 442255932Salfred 443255932Salfred mutex_lock(&priv->mcg_table.mutex); 444255932Salfred 445255932Salfred if (get_promisc_qp(dev, port, steer, qpn)) { 446255932Salfred err = 0; /* Noting to do, already exists */ 447255932Salfred goto out_mutex; 448255932Salfred } 449255932Salfred 450255932Salfred pqp = kmalloc(sizeof *pqp, GFP_KERNEL); 451255932Salfred if (!pqp) { 452255932Salfred err = -ENOMEM; 453255932Salfred goto out_mutex; 454255932Salfred } 455255932Salfred pqp->qpn = qpn; 456255932Salfred 457255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 458255932Salfred if (IS_ERR(mailbox)) { 459255932Salfred err = -ENOMEM; 460255932Salfred goto out_alloc; 461255932Salfred } 462255932Salfred mgm = mailbox->buf; 463255932Salfred 464272027Shselasky if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { 465272027Shselasky /* the promisc qp needs to be added for each one of the steering 466272027Shselasky * entries, if it already exists, needs to be added as a duplicate 467272027Shselasky * for this entry */ 468272027Shselasky list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { 469272027Shselasky err = mlx4_READ_ENTRY(dev, entry->index, mailbox); 470272027Shselasky if (err) 471272027Shselasky goto out_mailbox; 472255932Salfred 473272027Shselasky members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 474272027Shselasky prot = be32_to_cpu(mgm->members_count) >> 30; 475272027Shselasky found = false; 476272027Shselasky for (i = 0; i < members_count; i++) { 477272027Shselasky if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { 478272027Shselasky /* Entry already exists, add to duplicates */ 479272027Shselasky dqp = kmalloc(sizeof *dqp, GFP_KERNEL); 480272027Shselasky if (!dqp) { 481272027Shselasky err = -ENOMEM; 482272027Shselasky goto out_mailbox; 483272027Shselasky } 484272027Shselasky dqp->qpn = qpn; 485272027Shselasky list_add_tail(&dqp->list, &entry->duplicates); 486272027Shselasky found = true; 487272027Shselasky } 488272027Shselasky } 489272027Shselasky if (!found) { 490272027Shselasky /* Need to add the qpn to mgm */ 491272027Shselasky if (members_count == dev->caps.num_qp_per_mgm) { 492272027Shselasky /* entry is full */ 493255932Salfred err = -ENOMEM; 494255932Salfred goto out_mailbox; 495255932Salfred } 496272027Shselasky mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); 497272027Shselasky mgm->members_count = cpu_to_be32(members_count | (prot << 30)); 498272027Shselasky err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); 499272027Shselasky if (err) 500272027Shselasky goto out_mailbox; 501255932Salfred } 502255932Salfred } 503255932Salfred } 504255932Salfred 505255932Salfred /* add the new qpn to list of promisc qps */ 506255932Salfred list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); 507255932Salfred /* now need to add all the promisc qps to default entry */ 508255932Salfred memset(mgm, 0, sizeof *mgm); 509255932Salfred members_count = 0; 510255932Salfred list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) { 511255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 512255932Salfred /* entry is full */ 513255932Salfred err = -ENOMEM; 514255932Salfred goto out_list; 515255932Salfred } 516255932Salfred mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); 517255932Salfred } 518255932Salfred mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); 519255932Salfred 520255932Salfred err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); 521255932Salfred if (err) 522255932Salfred goto out_list; 523255932Salfred 524255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 525255932Salfred mutex_unlock(&priv->mcg_table.mutex); 526255932Salfred return 0; 527255932Salfred 528255932Salfredout_list: 529255932Salfred list_del(&pqp->list); 530255932Salfredout_mailbox: 531255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 532255932Salfredout_alloc: 533255932Salfred kfree(pqp); 534255932Salfredout_mutex: 535255932Salfred mutex_unlock(&priv->mcg_table.mutex); 536255932Salfred return err; 537255932Salfred} 538255932Salfred 539255932Salfredstatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port, 540255932Salfred enum mlx4_steer_type steer, u32 qpn) 541255932Salfred{ 542255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 543255932Salfred struct mlx4_steer *s_steer; 544255932Salfred struct mlx4_cmd_mailbox *mailbox; 545255932Salfred struct mlx4_mgm *mgm; 546272027Shselasky struct mlx4_steer_index *entry, *tmp_entry; 547255932Salfred struct mlx4_promisc_qp *pqp; 548255932Salfred struct mlx4_promisc_qp *dqp; 549255932Salfred u32 members_count; 550255932Salfred bool found; 551255932Salfred bool back_to_list = false; 552255932Salfred int i, loc = -1; 553255932Salfred int err; 554255932Salfred 555272027Shselasky if (port < 1 || port > dev->caps.num_ports) 556272027Shselasky return -EINVAL; 557272027Shselasky 558255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 559255932Salfred mutex_lock(&priv->mcg_table.mutex); 560255932Salfred 561255932Salfred pqp = get_promisc_qp(dev, port, steer, qpn); 562255932Salfred if (unlikely(!pqp)) { 563255932Salfred mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); 564255932Salfred /* nothing to do */ 565255932Salfred err = 0; 566255932Salfred goto out_mutex; 567255932Salfred } 568255932Salfred 569255932Salfred /*remove from list of promisc qps */ 570255932Salfred list_del(&pqp->list); 571255932Salfred 572255932Salfred /* set the default entry not to include the removed one */ 573255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 574255932Salfred if (IS_ERR(mailbox)) { 575255932Salfred err = -ENOMEM; 576255932Salfred back_to_list = true; 577255932Salfred goto out_list; 578255932Salfred } 579255932Salfred mgm = mailbox->buf; 580255932Salfred memset(mgm, 0, sizeof *mgm); 581255932Salfred members_count = 0; 582255932Salfred list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) 583255932Salfred mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); 584255932Salfred mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); 585255932Salfred 586255932Salfred err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); 587255932Salfred if (err) 588255932Salfred goto out_mailbox; 589255932Salfred 590272027Shselasky if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { 591272027Shselasky /* remove the qp from all the steering entries*/ 592272027Shselasky list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { 593272027Shselasky found = false; 594272027Shselasky list_for_each_entry(dqp, &entry->duplicates, list) { 595272027Shselasky if (dqp->qpn == qpn) { 596272027Shselasky found = true; 597255932Salfred break; 598255932Salfred } 599255932Salfred } 600272027Shselasky if (found) { 601272027Shselasky /* a duplicate, no need to change the mgm, 602272027Shselasky * only update the duplicates list */ 603272027Shselasky list_del(&dqp->list); 604272027Shselasky kfree(dqp); 605272027Shselasky } else { 606272027Shselasky err = mlx4_READ_ENTRY(dev, entry->index, mailbox); 607272027Shselasky if (err) 608272027Shselasky goto out_mailbox; 609272027Shselasky members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 610272027Shselasky if (!members_count) { 611272027Shselasky mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0." 612272027Shselasky " deleting entry...\n", qpn, entry->index); 613272027Shselasky list_del(&entry->list); 614272027Shselasky kfree(entry); 615272027Shselasky continue; 616272027Shselasky } 617255932Salfred 618272027Shselasky for (i = 0; i < members_count; ++i) 619272027Shselasky if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { 620272027Shselasky loc = i; 621272027Shselasky break; 622272027Shselasky } 623255932Salfred 624272027Shselasky if (loc < 0) { 625272027Shselasky mlx4_err(dev, "QP %06x wasn't found in entry %d\n", 626272027Shselasky qpn, entry->index); 627272027Shselasky err = -EINVAL; 628255932Salfred goto out_mailbox; 629272027Shselasky } 630272027Shselasky 631272027Shselasky /* copy the last QP in this MGM over removed QP */ 632272027Shselasky mgm->qp[loc] = mgm->qp[members_count - 1]; 633272027Shselasky mgm->qp[members_count - 1] = 0; 634272027Shselasky mgm->members_count = cpu_to_be32(--members_count | 635272027Shselasky (MLX4_PROT_ETH << 30)); 636272027Shselasky 637272027Shselasky err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); 638272027Shselasky if (err) 639272027Shselasky goto out_mailbox; 640272027Shselasky } 641255932Salfred } 642255932Salfred } 643255932Salfred 644255932Salfredout_mailbox: 645255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 646255932Salfredout_list: 647255932Salfred if (back_to_list) 648255932Salfred list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); 649255932Salfred else 650255932Salfred kfree(pqp); 651255932Salfredout_mutex: 652255932Salfred mutex_unlock(&priv->mcg_table.mutex); 653255932Salfred return err; 654255932Salfred} 655255932Salfred 656255932Salfred/* 657219820Sjeff * Caller must hold MCG table semaphore. gid and mgm parameters must 658219820Sjeff * be properly aligned for command interface. 659219820Sjeff * 660219820Sjeff * Returns 0 unless a firmware command error occurs. 661219820Sjeff * 662219820Sjeff * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 663219820Sjeff * and *mgm holds MGM entry. 664219820Sjeff * 665219820Sjeff * if GID is found in AMGM, *index = index in AMGM, *prev = index of 666219820Sjeff * previous entry in hash chain and *mgm holds AMGM entry. 667219820Sjeff * 668219820Sjeff * If no AMGM exists for given gid, *index = -1, *prev = index of last 669219820Sjeff * entry in hash chain and *mgm holds end of hash chain. 670219820Sjeff */ 671255932Salfredstatic int find_entry(struct mlx4_dev *dev, u8 port, 672255932Salfred u8 *gid, enum mlx4_protocol prot, 673255932Salfred struct mlx4_cmd_mailbox *mgm_mailbox, 674255932Salfred int *prev, int *index) 675219820Sjeff{ 676219820Sjeff struct mlx4_cmd_mailbox *mailbox; 677219820Sjeff struct mlx4_mgm *mgm = mgm_mailbox->buf; 678219820Sjeff u8 *mgid; 679219820Sjeff int err; 680255932Salfred u16 hash; 681255932Salfred u8 op_mod = (prot == MLX4_PROT_ETH) ? 682255932Salfred !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0; 683219820Sjeff 684219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 685219820Sjeff if (IS_ERR(mailbox)) 686219820Sjeff return -ENOMEM; 687219820Sjeff mgid = mailbox->buf; 688219820Sjeff 689219820Sjeff memcpy(mgid, gid, 16); 690219820Sjeff 691255932Salfred err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod); 692219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 693219820Sjeff if (err) 694219820Sjeff return err; 695219820Sjeff 696219820Sjeff if (0) 697255932Salfred mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, hash); 698219820Sjeff 699255932Salfred *index = hash; 700219820Sjeff *prev = -1; 701219820Sjeff 702219820Sjeff do { 703255932Salfred err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); 704219820Sjeff if (err) 705219820Sjeff return err; 706219820Sjeff 707255932Salfred if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { 708255932Salfred if (*index != hash) { 709219820Sjeff mlx4_err(dev, "Found zero MGID in AMGM.\n"); 710219820Sjeff err = -EINVAL; 711219820Sjeff } 712219820Sjeff return err; 713219820Sjeff } 714219820Sjeff 715219820Sjeff if (!memcmp(mgm->gid, gid, 16) && 716255932Salfred be32_to_cpu(mgm->members_count) >> 30 == prot) 717219820Sjeff return err; 718219820Sjeff 719219820Sjeff *prev = *index; 720219820Sjeff *index = be32_to_cpu(mgm->next_gid_index) >> 6; 721219820Sjeff } while (*index); 722219820Sjeff 723219820Sjeff *index = -1; 724219820Sjeff return err; 725219820Sjeff} 726219820Sjeff 727272027Shselaskystatic const u8 __promisc_mode[] = { 728272027Shselasky [MLX4_FS_REGULAR] = 0x0, 729272027Shselasky [MLX4_FS_ALL_DEFAULT] = 0x1, 730272027Shselasky [MLX4_FS_MC_DEFAULT] = 0x3, 731272027Shselasky [MLX4_FS_UC_SNIFFER] = 0x4, 732272027Shselasky [MLX4_FS_MC_SNIFFER] = 0x5, 733272027Shselasky}; 734272027Shselasky 735272027Shselaskyint map_sw_to_hw_steering_mode(struct mlx4_dev *dev, 736272027Shselasky enum mlx4_net_trans_promisc_mode flow_type) 737272027Shselasky{ 738272027Shselasky if (flow_type >= MLX4_FS_MODE_NUM || flow_type < 0) { 739272027Shselasky mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type); 740272027Shselasky return -EINVAL; 741272027Shselasky } 742272027Shselasky return __promisc_mode[flow_type]; 743272027Shselasky} 744272027ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_mode); 745272027Shselasky 746255932Salfredstatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, 747255932Salfred struct mlx4_net_trans_rule_hw_ctrl *hw) 748219820Sjeff{ 749272027Shselasky u8 flags = 0; 750255932Salfred 751272027Shselasky flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0; 752272027Shselasky flags |= ctrl->exclusive ? (1 << 2) : 0; 753272027Shselasky flags |= ctrl->allow_loopback ? (1 << 3) : 0; 754255932Salfred 755272027Shselasky hw->flags = flags; 756272027Shselasky hw->type = __promisc_mode[ctrl->promisc_mode]; 757272027Shselasky hw->prio = cpu_to_be16(ctrl->priority); 758255932Salfred hw->port = ctrl->port; 759255932Salfred hw->qpn = cpu_to_be32(ctrl->qpn); 760255932Salfred} 761255932Salfred 762255932Salfredconst u16 __sw_id_hw[] = { 763255932Salfred [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001, 764255932Salfred [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005, 765255932Salfred [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003, 766255932Salfred [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002, 767255932Salfred [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004, 768255932Salfred [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006 769255932Salfred}; 770255932Salfred 771272027Shselaskyint map_sw_to_hw_steering_id(struct mlx4_dev *dev, 772272027Shselasky enum mlx4_net_trans_rule_id id) 773272027Shselasky{ 774272027Shselasky if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { 775272027Shselasky mlx4_err(dev, "Invalid network rule id. id = %d\n", id); 776272027Shselasky return -EINVAL; 777272027Shselasky } 778272027Shselasky return __sw_id_hw[id]; 779272027Shselasky} 780272027ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_id); 781272027Shselasky 782272027Shselaskystatic const int __rule_hw_sz[] = { 783272027Shselasky [MLX4_NET_TRANS_RULE_ID_ETH] = 784272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_eth), 785272027Shselasky [MLX4_NET_TRANS_RULE_ID_IB] = 786272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_ib), 787272027Shselasky [MLX4_NET_TRANS_RULE_ID_IPV6] = 0, 788272027Shselasky [MLX4_NET_TRANS_RULE_ID_IPV4] = 789272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_ipv4), 790272027Shselasky [MLX4_NET_TRANS_RULE_ID_TCP] = 791272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), 792272027Shselasky [MLX4_NET_TRANS_RULE_ID_UDP] = 793272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_tcp_udp) 794272027Shselasky}; 795272027Shselasky 796272027Shselaskyint hw_rule_sz(struct mlx4_dev *dev, 797272027Shselasky enum mlx4_net_trans_rule_id id) 798272027Shselasky{ 799272027Shselasky if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { 800272027Shselasky mlx4_err(dev, "Invalid network rule id. id = %d\n", id); 801272027Shselasky return -EINVAL; 802272027Shselasky } 803272027Shselasky 804272027Shselasky return __rule_hw_sz[id]; 805272027Shselasky} 806272027ShselaskyEXPORT_SYMBOL_GPL(hw_rule_sz); 807272027Shselasky 808255932Salfredstatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, 809255932Salfred struct _rule_hw *rule_hw) 810255932Salfred{ 811272027Shselasky if (hw_rule_sz(dev, spec->id) < 0) 812255932Salfred return -EINVAL; 813272027Shselasky memset(rule_hw, 0, hw_rule_sz(dev, spec->id)); 814255932Salfred rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]); 815272027Shselasky rule_hw->size = hw_rule_sz(dev, spec->id) >> 2; 816255932Salfred 817255932Salfred switch (spec->id) { 818255932Salfred case MLX4_NET_TRANS_RULE_ID_ETH: 819255932Salfred memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN); 820255932Salfred memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk, 821255932Salfred ETH_ALEN); 822255932Salfred memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN); 823255932Salfred memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk, 824255932Salfred ETH_ALEN); 825255932Salfred if (spec->eth.ether_type_enable) { 826255932Salfred rule_hw->eth.ether_type_enable = 1; 827255932Salfred rule_hw->eth.ether_type = spec->eth.ether_type; 828255932Salfred } 829272027Shselasky rule_hw->eth.vlan_tag = spec->eth.vlan_id; 830272027Shselasky rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk; 831255932Salfred break; 832255932Salfred 833255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 834272027Shselasky rule_hw->ib.l3_qpn = spec->ib.l3_qpn; 835255932Salfred rule_hw->ib.qpn_mask = spec->ib.qpn_msk; 836255932Salfred memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16); 837255932Salfred memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16); 838255932Salfred break; 839255932Salfred 840255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV6: 841255932Salfred return -EOPNOTSUPP; 842255932Salfred 843255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 844255932Salfred rule_hw->ipv4.src_ip = spec->ipv4.src_ip; 845255932Salfred rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk; 846255932Salfred rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip; 847255932Salfred rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk; 848255932Salfred break; 849255932Salfred 850255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 851255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 852255932Salfred rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port; 853255932Salfred rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk; 854255932Salfred rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port; 855255932Salfred rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk; 856255932Salfred break; 857255932Salfred 858255932Salfred default: 859255932Salfred return -EINVAL; 860255932Salfred } 861255932Salfred 862255932Salfred return __rule_hw_sz[spec->id]; 863255932Salfred} 864255932Salfred 865255932Salfredstatic void mlx4_err_rule(struct mlx4_dev *dev, char *str, 866255932Salfred struct mlx4_net_trans_rule *rule) 867255932Salfred{ 868255932Salfred#define BUF_SIZE 256 869255932Salfred struct mlx4_spec_list *cur; 870255932Salfred char buf[BUF_SIZE]; 871255932Salfred int len = 0; 872255932Salfred 873255932Salfred mlx4_err(dev, "%s", str); 874255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 875255932Salfred "port = %d prio = 0x%x qp = 0x%x ", 876255932Salfred rule->port, rule->priority, rule->qpn); 877255932Salfred 878255932Salfred list_for_each_entry(cur, &rule->list, list) { 879255932Salfred switch (cur->id) { 880255932Salfred case MLX4_NET_TRANS_RULE_ID_ETH: 881255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 882255932Salfred "dmac = %pM ", &cur->eth.dst_mac); 883255932Salfred if (cur->eth.ether_type) 884255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 885255932Salfred "ethertype = 0x%x ", 886255932Salfred be16_to_cpu(cur->eth.ether_type)); 887255932Salfred if (cur->eth.vlan_id) 888255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 889255932Salfred "vlan-id = %d ", 890255932Salfred be16_to_cpu(cur->eth.vlan_id)); 891255932Salfred break; 892255932Salfred 893255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 894255932Salfred if (cur->ipv4.src_ip) 895255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 896255932Salfred "src-ip = %pI4 ", 897255932Salfred &cur->ipv4.src_ip); 898255932Salfred if (cur->ipv4.dst_ip) 899255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 900255932Salfred "dst-ip = %pI4 ", 901255932Salfred &cur->ipv4.dst_ip); 902255932Salfred break; 903255932Salfred 904255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 905255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 906255932Salfred if (cur->tcp_udp.src_port) 907255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 908255932Salfred "src-port = %d ", 909255932Salfred be16_to_cpu(cur->tcp_udp.src_port)); 910255932Salfred if (cur->tcp_udp.dst_port) 911255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 912255932Salfred "dst-port = %d ", 913255932Salfred be16_to_cpu(cur->tcp_udp.dst_port)); 914255932Salfred break; 915255932Salfred 916255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 917255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 918255932Salfred "dst-gid = %pI6\n", cur->ib.dst_gid); 919255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 920255932Salfred "dst-gid-mask = %pI6\n", 921255932Salfred cur->ib.dst_gid_msk); 922255932Salfred break; 923255932Salfred 924255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV6: 925255932Salfred break; 926255932Salfred 927255932Salfred default: 928255932Salfred break; 929255932Salfred } 930255932Salfred } 931255932Salfred len += snprintf(buf + len, BUF_SIZE - len, "\n"); 932255932Salfred mlx4_err(dev, "%s", buf); 933255932Salfred 934255932Salfred if (len >= BUF_SIZE) 935255932Salfred mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n"); 936255932Salfred} 937255932Salfred 938255932Salfredint mlx4_flow_attach(struct mlx4_dev *dev, 939255932Salfred struct mlx4_net_trans_rule *rule, u64 *reg_id) 940255932Salfred{ 941255932Salfred struct mlx4_cmd_mailbox *mailbox; 942255932Salfred struct mlx4_spec_list *cur; 943255932Salfred u32 size = 0; 944255932Salfred int ret; 945255932Salfred 946255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 947255932Salfred if (IS_ERR(mailbox)) 948255932Salfred return PTR_ERR(mailbox); 949255932Salfred 950255932Salfred memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl)); 951255932Salfred trans_rule_ctrl_to_hw(rule, mailbox->buf); 952255932Salfred 953255932Salfred size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); 954255932Salfred 955255932Salfred list_for_each_entry(cur, &rule->list, list) { 956255932Salfred ret = parse_trans_rule(dev, cur, mailbox->buf + size); 957255932Salfred if (ret < 0) { 958255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 959255932Salfred return -EINVAL; 960255932Salfred } 961255932Salfred size += ret; 962255932Salfred } 963255932Salfred 964255932Salfred ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id); 965255932Salfred if (ret == -ENOMEM) 966255932Salfred mlx4_err_rule(dev, 967255932Salfred "mcg table is full. Fail to register network rule.\n", 968255932Salfred rule); 969255932Salfred else if (ret) 970255932Salfred mlx4_err_rule(dev, "Fail to register network rule.\n", rule); 971255932Salfred 972255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 973255932Salfred 974255932Salfred return ret; 975255932Salfred} 976255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_attach); 977255932Salfred 978255932Salfredint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id) 979255932Salfred{ 980255932Salfred int err; 981255932Salfred 982255932Salfred err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id); 983255932Salfred if (err) 984255932Salfred mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n", 985272027Shselasky (unsigned long long)reg_id); 986255932Salfred return err; 987255932Salfred} 988255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_detach); 989255932Salfred 990255932Salfredint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn) 991255932Salfred{ 992255932Salfred int err; 993255932Salfred u64 in_param; 994255932Salfred 995255932Salfred in_param = ((u64) min_range_qpn) << 32; 996255932Salfred in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF; 997255932Salfred 998255932Salfred err = mlx4_cmd(dev, in_param, 0, 0, 999255932Salfred MLX4_FLOW_STEERING_IB_UC_QP_RANGE, 1000255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1001255932Salfred 1002255932Salfred return err; 1003255932Salfred} 1004255932SalfredEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE); 1005255932Salfred 1006255932Salfredint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1007255932Salfred int block_mcast_loopback, enum mlx4_protocol prot, 1008255932Salfred enum mlx4_steer_type steer) 1009255932Salfred{ 1010219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1011219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1012219820Sjeff struct mlx4_mgm *mgm; 1013219820Sjeff u32 members_count; 1014219820Sjeff int index, prev; 1015219820Sjeff int link = 0; 1016219820Sjeff int i; 1017219820Sjeff int err; 1018255932Salfred u8 port = gid[5]; 1019255932Salfred u8 new_entry = 0; 1020219820Sjeff 1021219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1022219820Sjeff if (IS_ERR(mailbox)) 1023219820Sjeff return PTR_ERR(mailbox); 1024219820Sjeff mgm = mailbox->buf; 1025219820Sjeff 1026219820Sjeff mutex_lock(&priv->mcg_table.mutex); 1027255932Salfred err = find_entry(dev, port, gid, prot, 1028255932Salfred mailbox, &prev, &index); 1029219820Sjeff if (err) 1030219820Sjeff goto out; 1031219820Sjeff 1032219820Sjeff if (index != -1) { 1033255932Salfred if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { 1034255932Salfred new_entry = 1; 1035219820Sjeff memcpy(mgm->gid, gid, 16); 1036255932Salfred } 1037219820Sjeff } else { 1038219820Sjeff link = 1; 1039219820Sjeff 1040219820Sjeff index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); 1041219820Sjeff if (index == -1) { 1042219820Sjeff mlx4_err(dev, "No AMGM entries left\n"); 1043219820Sjeff err = -ENOMEM; 1044219820Sjeff goto out; 1045219820Sjeff } 1046219820Sjeff index += dev->caps.num_mgms; 1047219820Sjeff 1048255932Salfred new_entry = 1; 1049219820Sjeff memset(mgm, 0, sizeof *mgm); 1050219820Sjeff memcpy(mgm->gid, gid, 16); 1051219820Sjeff } 1052219820Sjeff 1053219820Sjeff members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 1054255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 1055219820Sjeff mlx4_err(dev, "MGM at index %x is full.\n", index); 1056219820Sjeff err = -ENOMEM; 1057219820Sjeff goto out; 1058219820Sjeff } 1059219820Sjeff 1060219820Sjeff for (i = 0; i < members_count; ++i) 1061219820Sjeff if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { 1062219820Sjeff mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); 1063219820Sjeff err = 0; 1064219820Sjeff goto out; 1065219820Sjeff } 1066219820Sjeff 1067219820Sjeff mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | 1068219820Sjeff (!!mlx4_blck_lb << MGM_BLCK_LB_BIT)); 1069219820Sjeff 1070255932Salfred mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); 1071219820Sjeff 1072255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1073219820Sjeff if (err) 1074219820Sjeff goto out; 1075219820Sjeff 1076272027Shselasky /* if !link, still add the new entry. */ 1077219820Sjeff if (!link) 1078272027Shselasky goto skip_link; 1079219820Sjeff 1080255932Salfred err = mlx4_READ_ENTRY(dev, prev, mailbox); 1081219820Sjeff if (err) 1082219820Sjeff goto out; 1083219820Sjeff 1084219820Sjeff mgm->next_gid_index = cpu_to_be32(index << 6); 1085219820Sjeff 1086255932Salfred err = mlx4_WRITE_ENTRY(dev, prev, mailbox); 1087219820Sjeff if (err) 1088219820Sjeff goto out; 1089219820Sjeff 1090272027Shselaskyskip_link: 1091255932Salfred if (prot == MLX4_PROT_ETH) { 1092255932Salfred /* manage the steering entry for promisc mode */ 1093255932Salfred if (new_entry) 1094255932Salfred new_steering_entry(dev, port, steer, index, qp->qpn); 1095255932Salfred else 1096255932Salfred existing_steering_entry(dev, port, steer, 1097255932Salfred index, qp->qpn); 1098255932Salfred } 1099255932Salfred 1100219820Sjeffout: 1101219820Sjeff if (err && link && index != -1) { 1102219820Sjeff if (index < dev->caps.num_mgms) 1103219820Sjeff mlx4_warn(dev, "Got AMGM index %d < %d", 1104219820Sjeff index, dev->caps.num_mgms); 1105219820Sjeff else 1106219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1107272027Shselasky index - dev->caps.num_mgms, MLX4_USE_RR); 1108219820Sjeff } 1109219820Sjeff mutex_unlock(&priv->mcg_table.mutex); 1110219820Sjeff 1111219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1112219820Sjeff return err; 1113219820Sjeff} 1114219820Sjeff 1115255932Salfredint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1116255932Salfred enum mlx4_protocol prot, enum mlx4_steer_type steer) 1117219820Sjeff{ 1118219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1119219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1120219820Sjeff struct mlx4_mgm *mgm; 1121219820Sjeff u32 members_count; 1122219820Sjeff int prev, index; 1123255932Salfred int i, loc = -1; 1124219820Sjeff int err; 1125255932Salfred u8 port = gid[5]; 1126255932Salfred bool removed_entry = false; 1127219820Sjeff 1128219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1129219820Sjeff if (IS_ERR(mailbox)) 1130219820Sjeff return PTR_ERR(mailbox); 1131219820Sjeff mgm = mailbox->buf; 1132219820Sjeff 1133219820Sjeff mutex_lock(&priv->mcg_table.mutex); 1134219820Sjeff 1135255932Salfred err = find_entry(dev, port, gid, prot, 1136255932Salfred mailbox, &prev, &index); 1137219820Sjeff if (err) 1138219820Sjeff goto out; 1139219820Sjeff 1140219820Sjeff if (index == -1) { 1141219820Sjeff mlx4_err(dev, "MGID %pI6 not found\n", gid); 1142219820Sjeff err = -EINVAL; 1143219820Sjeff goto out; 1144219820Sjeff } 1145219820Sjeff 1146272027Shselasky /* 1147272027Shselasky if this QP is also a promisc QP, it shouldn't be removed only if 1148272027Shselasky at least one none promisc QP is also attached to this MCG 1149272027Shselasky */ 1150255932Salfred if (prot == MLX4_PROT_ETH && 1151272027Shselasky check_duplicate_entry(dev, port, steer, index, qp->qpn) && 1152272027Shselasky !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL)) 1153272027Shselasky goto out; 1154255932Salfred 1155219820Sjeff members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 1156255932Salfred for (i = 0; i < members_count; ++i) 1157255932Salfred if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { 1158219820Sjeff loc = i; 1159255932Salfred break; 1160255932Salfred } 1161219820Sjeff 1162219820Sjeff if (loc == -1) { 1163219820Sjeff mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); 1164219820Sjeff err = -EINVAL; 1165219820Sjeff goto out; 1166219820Sjeff } 1167219820Sjeff 1168255932Salfred /* copy the last QP in this MGM over removed QP */ 1169255932Salfred mgm->qp[loc] = mgm->qp[members_count - 1]; 1170255932Salfred mgm->qp[members_count - 1] = 0; 1171255932Salfred mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); 1172219820Sjeff 1173255932Salfred if (prot == MLX4_PROT_ETH) 1174255932Salfred removed_entry = can_remove_steering_entry(dev, port, steer, 1175255932Salfred index, qp->qpn); 1176255932Salfred if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) { 1177255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1178219820Sjeff goto out; 1179219820Sjeff } 1180219820Sjeff 1181255932Salfred /* We are going to delete the entry, members count should be 0 */ 1182255932Salfred mgm->members_count = cpu_to_be32((u32) prot << 30); 1183255932Salfred 1184219820Sjeff if (prev == -1) { 1185219820Sjeff /* Remove entry from MGM */ 1186219820Sjeff int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; 1187219820Sjeff if (amgm_index) { 1188255932Salfred err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); 1189219820Sjeff if (err) 1190219820Sjeff goto out; 1191219820Sjeff } else 1192219820Sjeff memset(mgm->gid, 0, 16); 1193219820Sjeff 1194255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1195219820Sjeff if (err) 1196219820Sjeff goto out; 1197219820Sjeff 1198219820Sjeff if (amgm_index) { 1199219820Sjeff if (amgm_index < dev->caps.num_mgms) 1200219820Sjeff mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", 1201219820Sjeff index, amgm_index, dev->caps.num_mgms); 1202219820Sjeff else 1203219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1204272027Shselasky amgm_index - dev->caps.num_mgms, MLX4_USE_RR); 1205219820Sjeff } 1206219820Sjeff } else { 1207219820Sjeff /* Remove entry from AMGM */ 1208219820Sjeff int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 1209255932Salfred err = mlx4_READ_ENTRY(dev, prev, mailbox); 1210219820Sjeff if (err) 1211219820Sjeff goto out; 1212219820Sjeff 1213219820Sjeff mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); 1214219820Sjeff 1215255932Salfred err = mlx4_WRITE_ENTRY(dev, prev, mailbox); 1216219820Sjeff if (err) 1217219820Sjeff goto out; 1218219820Sjeff 1219219820Sjeff if (index < dev->caps.num_mgms) 1220219820Sjeff mlx4_warn(dev, "entry %d had next AMGM index %d < %d", 1221219820Sjeff prev, index, dev->caps.num_mgms); 1222219820Sjeff else 1223219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1224272027Shselasky index - dev->caps.num_mgms, MLX4_USE_RR); 1225219820Sjeff } 1226219820Sjeff 1227219820Sjeffout: 1228219820Sjeff mutex_unlock(&priv->mcg_table.mutex); 1229219820Sjeff 1230219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1231219820Sjeff return err; 1232219820Sjeff} 1233255932Salfred 1234255932Salfredstatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, 1235255932Salfred u8 gid[16], u8 attach, u8 block_loopback, 1236255932Salfred enum mlx4_protocol prot) 1237255932Salfred{ 1238255932Salfred struct mlx4_cmd_mailbox *mailbox; 1239255932Salfred int err = 0; 1240255932Salfred int qpn; 1241255932Salfred 1242255932Salfred if (!mlx4_is_mfunc(dev)) 1243255932Salfred return -EBADF; 1244255932Salfred 1245255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1246255932Salfred if (IS_ERR(mailbox)) 1247255932Salfred return PTR_ERR(mailbox); 1248255932Salfred 1249255932Salfred memcpy(mailbox->buf, gid, 16); 1250255932Salfred qpn = qp->qpn; 1251255932Salfred qpn |= (prot << 28); 1252255932Salfred if (attach && block_loopback) 1253272027Shselasky qpn |= (1 << 31); 1254255932Salfred 1255255932Salfred err = mlx4_cmd(dev, mailbox->dma, qpn, attach, 1256255932Salfred MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A, 1257255932Salfred MLX4_CMD_WRAPPED); 1258255932Salfred 1259255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1260255932Salfred return err; 1261255932Salfred} 1262255932Salfred 1263272027Shselaskyint mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, 1264272027Shselasky u8 gid[16], u8 port, 1265272027Shselasky int block_mcast_loopback, 1266272027Shselasky enum mlx4_protocol prot, u64 *reg_id) 1267255932Salfred{ 1268255932Salfred struct mlx4_spec_list spec = { {NULL} }; 1269255932Salfred __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 1270255932Salfred 1271255932Salfred struct mlx4_net_trans_rule rule = { 1272255932Salfred .queue_mode = MLX4_NET_TRANS_Q_FIFO, 1273255932Salfred .exclusive = 0, 1274255932Salfred .promisc_mode = MLX4_FS_REGULAR, 1275255932Salfred .priority = MLX4_DOMAIN_NIC, 1276255932Salfred }; 1277255932Salfred 1278255932Salfred rule.allow_loopback = !block_mcast_loopback; 1279255932Salfred rule.port = port; 1280255932Salfred rule.qpn = qp->qpn; 1281255932Salfred INIT_LIST_HEAD(&rule.list); 1282255932Salfred 1283255932Salfred switch (prot) { 1284255932Salfred case MLX4_PROT_ETH: 1285255932Salfred spec.id = MLX4_NET_TRANS_RULE_ID_ETH; 1286255932Salfred memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN); 1287255932Salfred memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 1288255932Salfred break; 1289255932Salfred 1290255932Salfred case MLX4_PROT_IB_IPV6: 1291255932Salfred spec.id = MLX4_NET_TRANS_RULE_ID_IB; 1292255932Salfred memcpy(spec.ib.dst_gid, gid, 16); 1293255932Salfred memset(&spec.ib.dst_gid_msk, 0xff, 16); 1294255932Salfred break; 1295255932Salfred default: 1296255932Salfred return -EINVAL; 1297255932Salfred } 1298255932Salfred list_add_tail(&spec.list, &rule.list); 1299255932Salfred 1300255932Salfred return mlx4_flow_attach(dev, &rule, reg_id); 1301272027Shselasky} 1302255932Salfred 1303272027Shselaskyint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1304272027Shselasky u8 port, int block_mcast_loopback, 1305272027Shselasky enum mlx4_protocol prot, u64 *reg_id) 1306272027Shselasky{ 1307272027Shselasky enum mlx4_steer_type steer; 1308272027Shselasky steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; 1309272027Shselasky 1310272027Shselasky switch (dev->caps.steering_mode) { 1311272027Shselasky case MLX4_STEERING_MODE_A0: 1312272027Shselasky if (prot == MLX4_PROT_ETH) 1313272027Shselasky return 0; 1314272027Shselasky 1315272027Shselasky case MLX4_STEERING_MODE_B0: 1316272027Shselasky if (prot == MLX4_PROT_ETH) 1317272027Shselasky gid[7] |= (steer << 1); 1318272027Shselasky 1319272027Shselasky if (mlx4_is_mfunc(dev)) 1320272027Shselasky return mlx4_QP_ATTACH(dev, qp, gid, 1, 1321272027Shselasky block_mcast_loopback, prot); 1322272027Shselasky return mlx4_qp_attach_common(dev, qp, gid, 1323272027Shselasky block_mcast_loopback, prot, 1324272027Shselasky MLX4_MC_STEER); 1325272027Shselasky 1326272027Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 1327272027Shselasky return mlx4_trans_to_dmfs_attach(dev, qp, gid, port, 1328272027Shselasky block_mcast_loopback, 1329272027Shselasky prot, reg_id); 1330255932Salfred default: 1331255932Salfred return -EINVAL; 1332255932Salfred } 1333255932Salfred} 1334255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_attach); 1335255932Salfred 1336255932Salfredint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1337255932Salfred enum mlx4_protocol prot, u64 reg_id) 1338255932Salfred{ 1339272027Shselasky enum mlx4_steer_type steer; 1340272027Shselasky steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; 1341272027Shselasky 1342255932Salfred switch (dev->caps.steering_mode) { 1343255932Salfred case MLX4_STEERING_MODE_A0: 1344255932Salfred if (prot == MLX4_PROT_ETH) 1345255932Salfred return 0; 1346255932Salfred 1347255932Salfred case MLX4_STEERING_MODE_B0: 1348255932Salfred if (prot == MLX4_PROT_ETH) 1349272027Shselasky gid[7] |= (steer << 1); 1350255932Salfred 1351255932Salfred if (mlx4_is_mfunc(dev)) 1352255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); 1353255932Salfred 1354255932Salfred return mlx4_qp_detach_common(dev, qp, gid, prot, 1355255932Salfred MLX4_MC_STEER); 1356255932Salfred 1357255932Salfred case MLX4_STEERING_MODE_DEVICE_MANAGED: 1358255932Salfred return mlx4_flow_detach(dev, reg_id); 1359255932Salfred 1360255932Salfred default: 1361255932Salfred return -EINVAL; 1362255932Salfred } 1363255932Salfred} 1364219820SjeffEXPORT_SYMBOL_GPL(mlx4_multicast_detach); 1365219820Sjeff 1366255932Salfredint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, 1367255932Salfred u32 qpn, enum mlx4_net_trans_promisc_mode mode) 1368255932Salfred{ 1369255932Salfred struct mlx4_net_trans_rule rule; 1370255932Salfred u64 *regid_p; 1371255932Salfred 1372255932Salfred switch (mode) { 1373255932Salfred case MLX4_FS_ALL_DEFAULT: 1374255932Salfred regid_p = &dev->regid_promisc_array[port]; 1375255932Salfred break; 1376255932Salfred case MLX4_FS_MC_DEFAULT: 1377255932Salfred regid_p = &dev->regid_allmulti_array[port]; 1378255932Salfred break; 1379255932Salfred default: 1380255932Salfred return -1; 1381255932Salfred } 1382255932Salfred 1383255932Salfred if (*regid_p != 0) 1384255932Salfred return -1; 1385255932Salfred 1386255932Salfred rule.promisc_mode = mode; 1387255932Salfred rule.port = port; 1388255932Salfred rule.qpn = qpn; 1389255932Salfred INIT_LIST_HEAD(&rule.list); 1390255932Salfred mlx4_err(dev, "going promisc on %x\n", port); 1391255932Salfred 1392255932Salfred return mlx4_flow_attach(dev, &rule, regid_p); 1393255932Salfred} 1394255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add); 1395255932Salfred 1396255932Salfredint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port, 1397255932Salfred enum mlx4_net_trans_promisc_mode mode) 1398255932Salfred{ 1399255932Salfred int ret; 1400255932Salfred u64 *regid_p; 1401255932Salfred 1402255932Salfred switch (mode) { 1403255932Salfred case MLX4_FS_ALL_DEFAULT: 1404255932Salfred regid_p = &dev->regid_promisc_array[port]; 1405255932Salfred break; 1406255932Salfred case MLX4_FS_MC_DEFAULT: 1407255932Salfred regid_p = &dev->regid_allmulti_array[port]; 1408255932Salfred break; 1409255932Salfred default: 1410255932Salfred return -1; 1411255932Salfred } 1412255932Salfred 1413255932Salfred if (*regid_p == 0) 1414255932Salfred return -1; 1415255932Salfred 1416255932Salfred ret = mlx4_flow_detach(dev, *regid_p); 1417255932Salfred if (ret == 0) 1418255932Salfred *regid_p = 0; 1419255932Salfred 1420255932Salfred return ret; 1421255932Salfred} 1422255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove); 1423255932Salfred 1424255932Salfredint mlx4_unicast_attach(struct mlx4_dev *dev, 1425255932Salfred struct mlx4_qp *qp, u8 gid[16], 1426255932Salfred int block_mcast_loopback, enum mlx4_protocol prot) 1427255932Salfred{ 1428255932Salfred if (prot == MLX4_PROT_ETH) 1429255932Salfred gid[7] |= (MLX4_UC_STEER << 1); 1430255932Salfred 1431255932Salfred if (mlx4_is_mfunc(dev)) 1432255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 1, 1433255932Salfred block_mcast_loopback, prot); 1434255932Salfred 1435255932Salfred return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback, 1436255932Salfred prot, MLX4_UC_STEER); 1437255932Salfred} 1438255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_attach); 1439255932Salfred 1440255932Salfredint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, 1441255932Salfred u8 gid[16], enum mlx4_protocol prot) 1442255932Salfred{ 1443255932Salfred if (prot == MLX4_PROT_ETH) 1444255932Salfred gid[7] |= (MLX4_UC_STEER << 1); 1445255932Salfred 1446255932Salfred if (mlx4_is_mfunc(dev)) 1447255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); 1448255932Salfred 1449255932Salfred return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER); 1450255932Salfred} 1451255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_detach); 1452255932Salfred 1453255932Salfredint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, 1454255932Salfred struct mlx4_vhcr *vhcr, 1455255932Salfred struct mlx4_cmd_mailbox *inbox, 1456255932Salfred struct mlx4_cmd_mailbox *outbox, 1457255932Salfred struct mlx4_cmd_info *cmd) 1458255932Salfred{ 1459255932Salfred u32 qpn = (u32) vhcr->in_param & 0xffffffff; 1460255932Salfred u8 port = vhcr->in_param >> 62; 1461255932Salfred enum mlx4_steer_type steer = vhcr->in_modifier; 1462255932Salfred 1463272027Shselasky /* Promiscuous unicast is not allowed in mfunc for VFs */ 1464272027Shselasky if ((slave != dev->caps.function) && (steer == MLX4_UC_STEER)) 1465255932Salfred return 0; 1466255932Salfred 1467255932Salfred if (vhcr->op_modifier) 1468255932Salfred return add_promisc_qp(dev, port, steer, qpn); 1469255932Salfred else 1470255932Salfred return remove_promisc_qp(dev, port, steer, qpn); 1471255932Salfred} 1472255932Salfred 1473255932Salfredstatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn, 1474255932Salfred enum mlx4_steer_type steer, u8 add, u8 port) 1475255932Salfred{ 1476255932Salfred return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add, 1477255932Salfred MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A, 1478255932Salfred MLX4_CMD_WRAPPED); 1479255932Salfred} 1480255932Salfred 1481255932Salfredint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) 1482255932Salfred{ 1483255932Salfred if (mlx4_is_mfunc(dev)) 1484255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port); 1485255932Salfred 1486255932Salfred return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn); 1487255932Salfred} 1488255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); 1489255932Salfred 1490255932Salfredint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) 1491255932Salfred{ 1492255932Salfred if (mlx4_is_mfunc(dev)) 1493255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port); 1494255932Salfred 1495255932Salfred return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn); 1496255932Salfred} 1497255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); 1498255932Salfred 1499255932Salfredint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) 1500255932Salfred{ 1501255932Salfred if (mlx4_is_mfunc(dev)) 1502255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port); 1503255932Salfred 1504255932Salfred return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn); 1505255932Salfred} 1506255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); 1507255932Salfred 1508255932Salfredint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) 1509255932Salfred{ 1510255932Salfred if (mlx4_is_mfunc(dev)) 1511255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port); 1512255932Salfred 1513255932Salfred return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn); 1514255932Salfred} 1515255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); 1516255932Salfred 1517219820Sjeffint mlx4_init_mcg_table(struct mlx4_dev *dev) 1518219820Sjeff{ 1519219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1520219820Sjeff int err; 1521219820Sjeff 1522255932Salfred /* No need for mcg_table when fw managed the mcg table*/ 1523255932Salfred if (dev->caps.steering_mode == 1524255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 1525255932Salfred return 0; 1526219820Sjeff err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, 1527219820Sjeff dev->caps.num_amgms - 1, 0, 0); 1528219820Sjeff if (err) 1529219820Sjeff return err; 1530219820Sjeff 1531219820Sjeff mutex_init(&priv->mcg_table.mutex); 1532219820Sjeff 1533219820Sjeff return 0; 1534219820Sjeff} 1535219820Sjeff 1536219820Sjeffvoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev) 1537219820Sjeff{ 1538255932Salfred if (dev->caps.steering_mode != 1539255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 1540255932Salfred mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); 1541219820Sjeff} 1542