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 37306486Shselasky#include <dev/mlx4/cmd.h> 38272027Shselasky#include <linux/module.h> 39279584Shselasky#include <linux/printk.h> 40219820Sjeff 41219820Sjeff#include "mlx4.h" 42219820Sjeff 43255932Salfredint mlx4_get_mgm_entry_size(struct mlx4_dev *dev) 44219820Sjeff{ 45255932Salfred return 1 << dev->oper_log_mgm_entry_size; 46255932Salfred} 47255932Salfred 48255932Salfredint mlx4_get_qp_per_mgm(struct mlx4_dev *dev) 49255932Salfred{ 50255932Salfred return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2); 51255932Salfred} 52255932Salfred 53255932Salfredstatic int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev, 54255932Salfred struct mlx4_cmd_mailbox *mailbox, 55255932Salfred u32 size, 56255932Salfred u64 *reg_id) 57255932Salfred{ 58255932Salfred u64 imm; 59255932Salfred int err = 0; 60255932Salfred 61255932Salfred err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0, 62255932Salfred MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 63255932Salfred MLX4_CMD_NATIVE); 64255932Salfred if (err) 65255932Salfred return err; 66255932Salfred *reg_id = imm; 67255932Salfred 68255932Salfred return err; 69255932Salfred} 70255932Salfred 71255932Salfredstatic int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid) 72255932Salfred{ 73255932Salfred int err = 0; 74255932Salfred 75255932Salfred err = mlx4_cmd(dev, regid, 0, 0, 76255932Salfred MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 77255932Salfred MLX4_CMD_NATIVE); 78255932Salfred 79255932Salfred return err; 80255932Salfred} 81255932Salfred 82255932Salfredstatic int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, 83255932Salfred struct mlx4_cmd_mailbox *mailbox) 84255932Salfred{ 85219820Sjeff return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, 86255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 87219820Sjeff} 88219820Sjeff 89255932Salfredstatic int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, 90255932Salfred struct mlx4_cmd_mailbox *mailbox) 91219820Sjeff{ 92219820Sjeff return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, 93255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 94219820Sjeff} 95219820Sjeff 96255932Salfredstatic int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer, 97255932Salfred struct mlx4_cmd_mailbox *mailbox) 98219820Sjeff{ 99255932Salfred u32 in_mod; 100255932Salfred 101255932Salfred in_mod = (u32) port << 16 | steer << 1; 102255932Salfred return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, 103255932Salfred MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A, 104255932Salfred MLX4_CMD_NATIVE); 105255932Salfred} 106255932Salfred 107255932Salfredstatic int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, 108255932Salfred u16 *hash, u8 op_mod) 109255932Salfred{ 110219820Sjeff u64 imm; 111219820Sjeff int err; 112219820Sjeff 113255932Salfred err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, 114255932Salfred MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A, 115255932Salfred MLX4_CMD_NATIVE); 116219820Sjeff 117219820Sjeff if (!err) 118219820Sjeff *hash = imm; 119219820Sjeff 120219820Sjeff return err; 121219820Sjeff} 122219820Sjeff 123255932Salfredstatic struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port, 124255932Salfred enum mlx4_steer_type steer, 125255932Salfred u32 qpn) 126255932Salfred{ 127272027Shselasky struct mlx4_steer *s_steer; 128255932Salfred struct mlx4_promisc_qp *pqp; 129255932Salfred 130272027Shselasky if (port < 1 || port > dev->caps.num_ports) 131272027Shselasky return NULL; 132272027Shselasky 133272027Shselasky s_steer = &mlx4_priv(dev)->steer[port - 1]; 134272027Shselasky 135255932Salfred list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { 136255932Salfred if (pqp->qpn == qpn) 137255932Salfred return pqp; 138255932Salfred } 139255932Salfred /* not found */ 140255932Salfred return NULL; 141255932Salfred} 142255932Salfred 143219820Sjeff/* 144255932Salfred * Add new entry to steering data structure. 145255932Salfred * All promisc QPs should be added as well 146255932Salfred */ 147255932Salfredstatic int new_steering_entry(struct mlx4_dev *dev, u8 port, 148255932Salfred enum mlx4_steer_type steer, 149255932Salfred unsigned int index, u32 qpn) 150255932Salfred{ 151255932Salfred struct mlx4_steer *s_steer; 152255932Salfred struct mlx4_cmd_mailbox *mailbox; 153255932Salfred struct mlx4_mgm *mgm; 154255932Salfred u32 members_count; 155255932Salfred struct mlx4_steer_index *new_entry; 156255932Salfred struct mlx4_promisc_qp *pqp; 157255932Salfred struct mlx4_promisc_qp *dqp = NULL; 158255932Salfred u32 prot; 159255932Salfred int err; 160255932Salfred 161272027Shselasky if (port < 1 || port > dev->caps.num_ports) 162272027Shselasky return -EINVAL; 163272027Shselasky 164255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 165255932Salfred new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); 166255932Salfred if (!new_entry) 167255932Salfred return -ENOMEM; 168255932Salfred 169255932Salfred INIT_LIST_HEAD(&new_entry->duplicates); 170255932Salfred new_entry->index = index; 171255932Salfred list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); 172255932Salfred 173255932Salfred /* If the given qpn is also a promisc qp, 174255932Salfred * it should be inserted to duplicates list 175255932Salfred */ 176255932Salfred pqp = get_promisc_qp(dev, port, steer, qpn); 177255932Salfred if (pqp) { 178255932Salfred dqp = kmalloc(sizeof *dqp, GFP_KERNEL); 179255932Salfred if (!dqp) { 180255932Salfred err = -ENOMEM; 181255932Salfred goto out_alloc; 182255932Salfred } 183255932Salfred dqp->qpn = qpn; 184255932Salfred list_add_tail(&dqp->list, &new_entry->duplicates); 185255932Salfred } 186255932Salfred 187255932Salfred /* if no promisc qps for this vep, we are done */ 188255932Salfred if (list_empty(&s_steer->promisc_qps[steer])) 189255932Salfred return 0; 190255932Salfred 191255932Salfred /* now need to add all the promisc qps to the new 192255932Salfred * steering entry, as they should also receive the packets 193255932Salfred * destined to this address */ 194255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 195255932Salfred if (IS_ERR(mailbox)) { 196255932Salfred err = -ENOMEM; 197255932Salfred goto out_alloc; 198255932Salfred } 199255932Salfred mgm = mailbox->buf; 200255932Salfred 201255932Salfred err = mlx4_READ_ENTRY(dev, index, mailbox); 202255932Salfred if (err) 203255932Salfred goto out_mailbox; 204255932Salfred 205255932Salfred members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 206255932Salfred prot = be32_to_cpu(mgm->members_count) >> 30; 207255932Salfred list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { 208255932Salfred /* don't add already existing qpn */ 209255932Salfred if (pqp->qpn == qpn) 210255932Salfred continue; 211255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 212255932Salfred /* out of space */ 213255932Salfred err = -ENOMEM; 214255932Salfred goto out_mailbox; 215255932Salfred } 216255932Salfred 217255932Salfred /* add the qpn */ 218255932Salfred mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); 219255932Salfred } 220255932Salfred /* update the qps count and update the entry with all the promisc qps*/ 221255932Salfred mgm->members_count = cpu_to_be32(members_count | (prot << 30)); 222255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 223255932Salfred 224255932Salfredout_mailbox: 225255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 226255932Salfred if (!err) 227255932Salfred return 0; 228255932Salfredout_alloc: 229255932Salfred if (dqp) { 230255932Salfred list_del(&dqp->list); 231255932Salfred kfree(dqp); 232255932Salfred } 233255932Salfred list_del(&new_entry->list); 234255932Salfred kfree(new_entry); 235255932Salfred return err; 236255932Salfred} 237255932Salfred 238255932Salfred/* update the data structures with existing steering entry */ 239255932Salfredstatic int existing_steering_entry(struct mlx4_dev *dev, u8 port, 240255932Salfred enum mlx4_steer_type steer, 241255932Salfred unsigned int index, u32 qpn) 242255932Salfred{ 243255932Salfred struct mlx4_steer *s_steer; 244255932Salfred struct mlx4_steer_index *tmp_entry, *entry = NULL; 245255932Salfred struct mlx4_promisc_qp *pqp; 246255932Salfred struct mlx4_promisc_qp *dqp; 247255932Salfred 248272027Shselasky if (port < 1 || port > dev->caps.num_ports) 249272027Shselasky return -EINVAL; 250272027Shselasky 251255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 252255932Salfred 253255932Salfred pqp = get_promisc_qp(dev, port, steer, qpn); 254255932Salfred if (!pqp) 255255932Salfred return 0; /* nothing to do */ 256255932Salfred 257255932Salfred list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { 258255932Salfred if (tmp_entry->index == index) { 259255932Salfred entry = tmp_entry; 260255932Salfred break; 261255932Salfred } 262255932Salfred } 263255932Salfred if (unlikely(!entry)) { 264255932Salfred mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); 265255932Salfred return -EINVAL; 266255932Salfred } 267255932Salfred 268255932Salfred /* the given qpn is listed as a promisc qpn 269255932Salfred * we need to add it as a duplicate to this entry 270255932Salfred * for future references */ 271255932Salfred list_for_each_entry(dqp, &entry->duplicates, list) { 272272027Shselasky if (qpn == dqp->qpn) 273255932Salfred return 0; /* qp is already duplicated */ 274255932Salfred } 275255932Salfred 276255932Salfred /* add the qp as a duplicate on this index */ 277255932Salfred dqp = kmalloc(sizeof *dqp, GFP_KERNEL); 278255932Salfred if (!dqp) 279255932Salfred return -ENOMEM; 280255932Salfred dqp->qpn = qpn; 281255932Salfred list_add_tail(&dqp->list, &entry->duplicates); 282255932Salfred 283255932Salfred return 0; 284255932Salfred} 285255932Salfred 286255932Salfred/* Check whether a qpn is a duplicate on steering entry 287255932Salfred * If so, it should not be removed from mgm */ 288255932Salfredstatic bool check_duplicate_entry(struct mlx4_dev *dev, u8 port, 289255932Salfred enum mlx4_steer_type steer, 290255932Salfred unsigned int index, u32 qpn) 291255932Salfred{ 292255932Salfred struct mlx4_steer *s_steer; 293255932Salfred struct mlx4_steer_index *tmp_entry, *entry = NULL; 294255932Salfred struct mlx4_promisc_qp *dqp, *tmp_dqp; 295255932Salfred 296272027Shselasky if (port < 1 || port > dev->caps.num_ports) 297272027Shselasky return NULL; 298272027Shselasky 299255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 300255932Salfred 301255932Salfred /* if qp is not promisc, it cannot be duplicated */ 302255932Salfred if (!get_promisc_qp(dev, port, steer, qpn)) 303255932Salfred return false; 304255932Salfred 305255932Salfred /* The qp is promisc qp so it is a duplicate on this index 306255932Salfred * Find the index entry, and remove the duplicate */ 307255932Salfred list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { 308255932Salfred if (tmp_entry->index == index) { 309255932Salfred entry = tmp_entry; 310255932Salfred break; 311255932Salfred } 312255932Salfred } 313255932Salfred if (unlikely(!entry)) { 314255932Salfred mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); 315255932Salfred return false; 316255932Salfred } 317255932Salfred list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { 318255932Salfred if (dqp->qpn == qpn) { 319255932Salfred list_del(&dqp->list); 320255932Salfred kfree(dqp); 321255932Salfred } 322255932Salfred } 323255932Salfred return true; 324255932Salfred} 325255932Salfred 326329159Shselasky/* Returns true if all the QPs != tqpn contained in this entry 327329159Shselasky * are Promisc QPs. Returns false otherwise. 328272027Shselasky */ 329272027Shselaskystatic bool promisc_steering_entry(struct mlx4_dev *dev, u8 port, 330329159Shselasky enum mlx4_steer_type steer, 331329159Shselasky unsigned int index, u32 tqpn, 332329159Shselasky u32 *members_count) 333255932Salfred{ 334255932Salfred struct mlx4_cmd_mailbox *mailbox; 335255932Salfred struct mlx4_mgm *mgm; 336272027Shselasky u32 m_count; 337255932Salfred bool ret = false; 338255932Salfred int i; 339255932Salfred 340272027Shselasky if (port < 1 || port > dev->caps.num_ports) 341272027Shselasky return false; 342272027Shselasky 343255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 344255932Salfred if (IS_ERR(mailbox)) 345255932Salfred return false; 346255932Salfred mgm = mailbox->buf; 347255932Salfred 348255932Salfred if (mlx4_READ_ENTRY(dev, index, mailbox)) 349255932Salfred goto out; 350272027Shselasky m_count = be32_to_cpu(mgm->members_count) & 0xffffff; 351272027Shselasky if (members_count) 352272027Shselasky *members_count = m_count; 353272027Shselasky 354272027Shselasky for (i = 0; i < m_count; i++) { 355272027Shselasky u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; 356255932Salfred if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) { 357255932Salfred /* the qp is not promisc, the entry can't be removed */ 358255932Salfred goto out; 359255932Salfred } 360255932Salfred } 361272027Shselasky ret = true; 362272027Shselaskyout: 363272027Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 364272027Shselasky return ret; 365272027Shselasky} 366272027Shselasky 367272027Shselasky/* IF a steering entry contains only promisc QPs, it can be removed. */ 368272027Shselaskystatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, 369272027Shselasky enum mlx4_steer_type steer, 370272027Shselasky unsigned int index, u32 tqpn) 371272027Shselasky{ 372272027Shselasky struct mlx4_steer *s_steer; 373272027Shselasky struct mlx4_steer_index *entry = NULL, *tmp_entry; 374272027Shselasky u32 members_count; 375272027Shselasky bool ret = false; 376272027Shselasky 377272027Shselasky if (port < 1 || port > dev->caps.num_ports) 378272027Shselasky return NULL; 379272027Shselasky 380272027Shselasky s_steer = &mlx4_priv(dev)->steer[port - 1]; 381272027Shselasky 382329159Shselasky if (!promisc_steering_entry(dev, port, steer, index, 383329159Shselasky tqpn, &members_count)) 384272027Shselasky goto out; 385272027Shselasky 386272027Shselasky /* All the qps currently registered for this entry are promiscuous, 387255932Salfred * Checking for duplicates */ 388255932Salfred ret = true; 389255932Salfred list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { 390255932Salfred if (entry->index == index) { 391329159Shselasky if (list_empty(&entry->duplicates) || 392329159Shselasky members_count == 1) { 393255932Salfred struct mlx4_promisc_qp *pqp, *tmp_pqp; 394329159Shselasky /* If there is only 1 entry in duplicates then 395255932Salfred * this is the QP we want to delete, going over 396255932Salfred * the list and deleting the entry. 397255932Salfred */ 398255932Salfred list_del(&entry->list); 399255932Salfred list_for_each_entry_safe(pqp, tmp_pqp, 400255932Salfred &entry->duplicates, 401255932Salfred list) { 402255932Salfred list_del(&pqp->list); 403255932Salfred kfree(pqp); 404255932Salfred } 405255932Salfred kfree(entry); 406255932Salfred } else { 407255932Salfred /* This entry contains duplicates so it shouldn't be removed */ 408255932Salfred ret = false; 409255932Salfred goto out; 410255932Salfred } 411255932Salfred } 412255932Salfred } 413255932Salfred 414255932Salfredout: 415255932Salfred return ret; 416255932Salfred} 417255932Salfred 418255932Salfredstatic int add_promisc_qp(struct mlx4_dev *dev, u8 port, 419255932Salfred enum mlx4_steer_type steer, u32 qpn) 420255932Salfred{ 421255932Salfred struct mlx4_steer *s_steer; 422255932Salfred struct mlx4_cmd_mailbox *mailbox; 423255932Salfred struct mlx4_mgm *mgm; 424255932Salfred struct mlx4_steer_index *entry; 425255932Salfred struct mlx4_promisc_qp *pqp; 426255932Salfred struct mlx4_promisc_qp *dqp; 427255932Salfred u32 members_count; 428255932Salfred u32 prot; 429255932Salfred int i; 430255932Salfred bool found; 431255932Salfred int err; 432255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 433255932Salfred 434272027Shselasky if (port < 1 || port > dev->caps.num_ports) 435272027Shselasky return -EINVAL; 436272027Shselasky 437255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 438255932Salfred 439255932Salfred mutex_lock(&priv->mcg_table.mutex); 440255932Salfred 441255932Salfred if (get_promisc_qp(dev, port, steer, qpn)) { 442255932Salfred err = 0; /* Noting to do, already exists */ 443255932Salfred goto out_mutex; 444255932Salfred } 445255932Salfred 446255932Salfred pqp = kmalloc(sizeof *pqp, GFP_KERNEL); 447255932Salfred if (!pqp) { 448255932Salfred err = -ENOMEM; 449255932Salfred goto out_mutex; 450255932Salfred } 451255932Salfred pqp->qpn = qpn; 452255932Salfred 453255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 454255932Salfred if (IS_ERR(mailbox)) { 455255932Salfred err = -ENOMEM; 456255932Salfred goto out_alloc; 457255932Salfred } 458255932Salfred mgm = mailbox->buf; 459255932Salfred 460272027Shselasky if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { 461329159Shselasky /* The promisc QP needs to be added for each one of the steering 462329159Shselasky * entries. If it already exists, needs to be added as 463329159Shselasky * a duplicate for this entry. 464329159Shselasky */ 465329159Shselasky list_for_each_entry(entry, 466329159Shselasky &s_steer->steer_entries[steer], 467329159Shselasky list) { 468272027Shselasky err = mlx4_READ_ENTRY(dev, entry->index, mailbox); 469272027Shselasky if (err) 470272027Shselasky goto out_mailbox; 471255932Salfred 472329159Shselasky members_count = be32_to_cpu(mgm->members_count) & 473329159Shselasky 0xffffff; 474272027Shselasky prot = be32_to_cpu(mgm->members_count) >> 30; 475272027Shselasky found = false; 476272027Shselasky for (i = 0; i < members_count; i++) { 477329159Shselasky if ((be32_to_cpu(mgm->qp[i]) & 478329159Shselasky MGM_QPN_MASK) == qpn) { 479329159Shselasky /* Entry already exists. 480329159Shselasky * Add to duplicates. 481329159Shselasky */ 482329159Shselasky dqp = kmalloc(sizeof(*dqp), GFP_KERNEL); 483272027Shselasky if (!dqp) { 484272027Shselasky err = -ENOMEM; 485272027Shselasky goto out_mailbox; 486272027Shselasky } 487272027Shselasky dqp->qpn = qpn; 488329159Shselasky list_add_tail(&dqp->list, 489329159Shselasky &entry->duplicates); 490272027Shselasky found = true; 491272027Shselasky } 492272027Shselasky } 493272027Shselasky if (!found) { 494272027Shselasky /* Need to add the qpn to mgm */ 495329159Shselasky if (members_count == 496329159Shselasky dev->caps.num_qp_per_mgm) { 497272027Shselasky /* entry is full */ 498255932Salfred err = -ENOMEM; 499255932Salfred goto out_mailbox; 500255932Salfred } 501329159Shselasky mgm->qp[members_count++] = 502329159Shselasky cpu_to_be32(qpn & MGM_QPN_MASK); 503329159Shselasky mgm->members_count = 504329159Shselasky cpu_to_be32(members_count | 505329159Shselasky (prot << 30)); 506329159Shselasky err = mlx4_WRITE_ENTRY(dev, entry->index, 507329159Shselasky mailbox); 508272027Shselasky if (err) 509272027Shselasky goto out_mailbox; 510255932Salfred } 511255932Salfred } 512255932Salfred } 513255932Salfred 514255932Salfred /* add the new qpn to list of promisc qps */ 515255932Salfred list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); 516255932Salfred /* now need to add all the promisc qps to default entry */ 517255932Salfred memset(mgm, 0, sizeof *mgm); 518255932Salfred members_count = 0; 519255932Salfred list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) { 520255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 521255932Salfred /* entry is full */ 522255932Salfred err = -ENOMEM; 523255932Salfred goto out_list; 524255932Salfred } 525255932Salfred mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); 526255932Salfred } 527255932Salfred mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); 528255932Salfred 529255932Salfred err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); 530255932Salfred if (err) 531255932Salfred goto out_list; 532255932Salfred 533255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 534255932Salfred mutex_unlock(&priv->mcg_table.mutex); 535255932Salfred return 0; 536255932Salfred 537255932Salfredout_list: 538255932Salfred list_del(&pqp->list); 539255932Salfredout_mailbox: 540255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 541255932Salfredout_alloc: 542255932Salfred kfree(pqp); 543255932Salfredout_mutex: 544255932Salfred mutex_unlock(&priv->mcg_table.mutex); 545255932Salfred return err; 546255932Salfred} 547255932Salfred 548255932Salfredstatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port, 549255932Salfred enum mlx4_steer_type steer, u32 qpn) 550255932Salfred{ 551255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 552255932Salfred struct mlx4_steer *s_steer; 553255932Salfred struct mlx4_cmd_mailbox *mailbox; 554255932Salfred struct mlx4_mgm *mgm; 555272027Shselasky struct mlx4_steer_index *entry, *tmp_entry; 556255932Salfred struct mlx4_promisc_qp *pqp; 557255932Salfred struct mlx4_promisc_qp *dqp; 558255932Salfred u32 members_count; 559255932Salfred bool found; 560255932Salfred bool back_to_list = false; 561329159Shselasky int i; 562255932Salfred int err; 563255932Salfred 564272027Shselasky if (port < 1 || port > dev->caps.num_ports) 565272027Shselasky return -EINVAL; 566272027Shselasky 567255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 568255932Salfred mutex_lock(&priv->mcg_table.mutex); 569255932Salfred 570255932Salfred pqp = get_promisc_qp(dev, port, steer, qpn); 571255932Salfred if (unlikely(!pqp)) { 572255932Salfred mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); 573255932Salfred /* nothing to do */ 574255932Salfred err = 0; 575255932Salfred goto out_mutex; 576255932Salfred } 577255932Salfred 578255932Salfred /*remove from list of promisc qps */ 579255932Salfred list_del(&pqp->list); 580255932Salfred 581255932Salfred /* set the default entry not to include the removed one */ 582255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 583255932Salfred if (IS_ERR(mailbox)) { 584255932Salfred err = -ENOMEM; 585255932Salfred back_to_list = true; 586255932Salfred goto out_list; 587255932Salfred } 588255932Salfred mgm = mailbox->buf; 589255932Salfred members_count = 0; 590255932Salfred list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) 591255932Salfred mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); 592255932Salfred mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); 593255932Salfred 594255932Salfred err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); 595255932Salfred if (err) 596255932Salfred goto out_mailbox; 597255932Salfred 598272027Shselasky if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { 599329159Shselasky /* Remove the QP from all the steering entries */ 600329159Shselasky list_for_each_entry_safe(entry, tmp_entry, 601329159Shselasky &s_steer->steer_entries[steer], 602329159Shselasky list) { 603272027Shselasky found = false; 604272027Shselasky list_for_each_entry(dqp, &entry->duplicates, list) { 605272027Shselasky if (dqp->qpn == qpn) { 606272027Shselasky found = true; 607255932Salfred break; 608255932Salfred } 609255932Salfred } 610272027Shselasky if (found) { 611329159Shselasky /* A duplicate, no need to change the MGM, 612329159Shselasky * only update the duplicates list 613329159Shselasky */ 614272027Shselasky list_del(&dqp->list); 615272027Shselasky kfree(dqp); 616272027Shselasky } else { 617329159Shselasky int loc = -1; 618329159Shselasky 619329159Shselasky err = mlx4_READ_ENTRY(dev, 620329159Shselasky entry->index, 621329159Shselasky mailbox); 622329159Shselasky if (err) 623329159Shselasky goto out_mailbox; 624329159Shselasky members_count = 625329159Shselasky be32_to_cpu(mgm->members_count) & 626329159Shselasky 0xffffff; 627272027Shselasky if (!members_count) { 628329159Shselasky mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0. deleting entry...\n", 629329159Shselasky qpn, entry->index); 630272027Shselasky list_del(&entry->list); 631272027Shselasky kfree(entry); 632272027Shselasky continue; 633272027Shselasky } 634255932Salfred 635272027Shselasky for (i = 0; i < members_count; ++i) 636329159Shselasky if ((be32_to_cpu(mgm->qp[i]) & 637329159Shselasky MGM_QPN_MASK) == qpn) { 638272027Shselasky loc = i; 639272027Shselasky break; 640272027Shselasky } 641255932Salfred 642272027Shselasky if (loc < 0) { 643272027Shselasky mlx4_err(dev, "QP %06x wasn't found in entry %d\n", 644272027Shselasky qpn, entry->index); 645272027Shselasky err = -EINVAL; 646255932Salfred goto out_mailbox; 647272027Shselasky } 648272027Shselasky 649329159Shselasky /* Copy the last QP in this MGM 650329159Shselasky * over removed QP 651329159Shselasky */ 652272027Shselasky mgm->qp[loc] = mgm->qp[members_count - 1]; 653272027Shselasky mgm->qp[members_count - 1] = 0; 654329159Shselasky mgm->members_count = 655329159Shselasky cpu_to_be32(--members_count | 656329159Shselasky (MLX4_PROT_ETH << 30)); 657272027Shselasky 658329159Shselasky err = mlx4_WRITE_ENTRY(dev, 659329159Shselasky entry->index, 660329159Shselasky mailbox); 661329159Shselasky if (err) 662329159Shselasky goto out_mailbox; 663272027Shselasky } 664255932Salfred } 665255932Salfred } 666255932Salfred 667255932Salfredout_mailbox: 668255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 669255932Salfredout_list: 670255932Salfred if (back_to_list) 671255932Salfred list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); 672255932Salfred else 673255932Salfred kfree(pqp); 674255932Salfredout_mutex: 675255932Salfred mutex_unlock(&priv->mcg_table.mutex); 676255932Salfred return err; 677255932Salfred} 678255932Salfred 679255932Salfred/* 680219820Sjeff * Caller must hold MCG table semaphore. gid and mgm parameters must 681219820Sjeff * be properly aligned for command interface. 682219820Sjeff * 683219820Sjeff * Returns 0 unless a firmware command error occurs. 684219820Sjeff * 685219820Sjeff * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 686219820Sjeff * and *mgm holds MGM entry. 687219820Sjeff * 688219820Sjeff * if GID is found in AMGM, *index = index in AMGM, *prev = index of 689219820Sjeff * previous entry in hash chain and *mgm holds AMGM entry. 690219820Sjeff * 691219820Sjeff * If no AMGM exists for given gid, *index = -1, *prev = index of last 692219820Sjeff * entry in hash chain and *mgm holds end of hash chain. 693219820Sjeff */ 694255932Salfredstatic int find_entry(struct mlx4_dev *dev, u8 port, 695255932Salfred u8 *gid, enum mlx4_protocol prot, 696255932Salfred struct mlx4_cmd_mailbox *mgm_mailbox, 697255932Salfred int *prev, int *index) 698219820Sjeff{ 699219820Sjeff struct mlx4_cmd_mailbox *mailbox; 700219820Sjeff struct mlx4_mgm *mgm = mgm_mailbox->buf; 701219820Sjeff u8 *mgid; 702219820Sjeff int err; 703255932Salfred u16 hash; 704255932Salfred u8 op_mod = (prot == MLX4_PROT_ETH) ? 705255932Salfred !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0; 706219820Sjeff 707219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 708219820Sjeff if (IS_ERR(mailbox)) 709219820Sjeff return -ENOMEM; 710219820Sjeff mgid = mailbox->buf; 711219820Sjeff 712219820Sjeff memcpy(mgid, gid, 16); 713219820Sjeff 714255932Salfred err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod); 715219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 716219820Sjeff if (err) 717219820Sjeff return err; 718219820Sjeff 719279584Shselasky if (0) { 720279584Shselasky mlx4_dbg(dev, "Hash for "GID_PRINT_FMT" is %04x\n", 721279584Shselasky GID_PRINT_ARGS(gid), hash); 722279584Shselasky } 723219820Sjeff 724255932Salfred *index = hash; 725219820Sjeff *prev = -1; 726219820Sjeff 727219820Sjeff do { 728255932Salfred err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); 729219820Sjeff if (err) 730219820Sjeff return err; 731219820Sjeff 732255932Salfred if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { 733255932Salfred if (*index != hash) { 734329159Shselasky mlx4_err(dev, "Found zero MGID in AMGM\n"); 735219820Sjeff err = -EINVAL; 736219820Sjeff } 737219820Sjeff return err; 738219820Sjeff } 739219820Sjeff 740219820Sjeff if (!memcmp(mgm->gid, gid, 16) && 741255932Salfred be32_to_cpu(mgm->members_count) >> 30 == prot) 742219820Sjeff return err; 743219820Sjeff 744219820Sjeff *prev = *index; 745219820Sjeff *index = be32_to_cpu(mgm->next_gid_index) >> 6; 746219820Sjeff } while (*index); 747219820Sjeff 748219820Sjeff *index = -1; 749219820Sjeff return err; 750219820Sjeff} 751219820Sjeff 752272027Shselaskystatic const u8 __promisc_mode[] = { 753272027Shselasky [MLX4_FS_REGULAR] = 0x0, 754272027Shselasky [MLX4_FS_ALL_DEFAULT] = 0x1, 755272027Shselasky [MLX4_FS_MC_DEFAULT] = 0x3, 756329159Shselasky [MLX4_FS_MIRROR_RX_PORT] = 0x4, 757329159Shselasky [MLX4_FS_MIRROR_SX_PORT] = 0x5, 758329159Shselasky [MLX4_FS_UC_SNIFFER] = 0x6, 759329159Shselasky [MLX4_FS_MC_SNIFFER] = 0x7, 760272027Shselasky}; 761272027Shselasky 762329159Shselaskyint mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev *dev, 763329159Shselasky enum mlx4_net_trans_promisc_mode flow_type) 764272027Shselasky{ 765329159Shselasky if (flow_type >= MLX4_FS_MODE_NUM) { 766272027Shselasky mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type); 767272027Shselasky return -EINVAL; 768272027Shselasky } 769272027Shselasky return __promisc_mode[flow_type]; 770272027Shselasky} 771329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_mode); 772272027Shselasky 773255932Salfredstatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, 774255932Salfred struct mlx4_net_trans_rule_hw_ctrl *hw) 775219820Sjeff{ 776272027Shselasky u8 flags = 0; 777255932Salfred 778272027Shselasky flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0; 779272027Shselasky flags |= ctrl->exclusive ? (1 << 2) : 0; 780272027Shselasky flags |= ctrl->allow_loopback ? (1 << 3) : 0; 781255932Salfred 782272027Shselasky hw->flags = flags; 783272027Shselasky hw->type = __promisc_mode[ctrl->promisc_mode]; 784272027Shselasky hw->prio = cpu_to_be16(ctrl->priority); 785255932Salfred hw->port = ctrl->port; 786255932Salfred hw->qpn = cpu_to_be32(ctrl->qpn); 787255932Salfred} 788255932Salfred 789255932Salfredconst u16 __sw_id_hw[] = { 790255932Salfred [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001, 791255932Salfred [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005, 792255932Salfred [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003, 793255932Salfred [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002, 794255932Salfred [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004, 795329159Shselasky [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006, 796329159Shselasky [MLX4_NET_TRANS_RULE_ID_VXLAN] = 0xE008 797255932Salfred}; 798255932Salfred 799329159Shselaskyint mlx4_map_sw_to_hw_steering_id(struct mlx4_dev *dev, 800329159Shselasky enum mlx4_net_trans_rule_id id) 801272027Shselasky{ 802329159Shselasky if (id >= MLX4_NET_TRANS_RULE_NUM) { 803272027Shselasky mlx4_err(dev, "Invalid network rule id. id = %d\n", id); 804272027Shselasky return -EINVAL; 805272027Shselasky } 806272027Shselasky return __sw_id_hw[id]; 807272027Shselasky} 808329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_id); 809272027Shselasky 810272027Shselaskystatic const int __rule_hw_sz[] = { 811272027Shselasky [MLX4_NET_TRANS_RULE_ID_ETH] = 812272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_eth), 813272027Shselasky [MLX4_NET_TRANS_RULE_ID_IB] = 814272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_ib), 815272027Shselasky [MLX4_NET_TRANS_RULE_ID_IPV6] = 0, 816272027Shselasky [MLX4_NET_TRANS_RULE_ID_IPV4] = 817272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_ipv4), 818272027Shselasky [MLX4_NET_TRANS_RULE_ID_TCP] = 819272027Shselasky sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), 820272027Shselasky [MLX4_NET_TRANS_RULE_ID_UDP] = 821329159Shselasky sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), 822329159Shselasky [MLX4_NET_TRANS_RULE_ID_VXLAN] = 823329159Shselasky sizeof(struct mlx4_net_trans_rule_hw_vxlan) 824272027Shselasky}; 825272027Shselasky 826329159Shselaskyint mlx4_hw_rule_sz(struct mlx4_dev *dev, 827272027Shselasky enum mlx4_net_trans_rule_id id) 828272027Shselasky{ 829329159Shselasky if (id >= MLX4_NET_TRANS_RULE_NUM) { 830272027Shselasky mlx4_err(dev, "Invalid network rule id. id = %d\n", id); 831272027Shselasky return -EINVAL; 832272027Shselasky } 833272027Shselasky 834272027Shselasky return __rule_hw_sz[id]; 835272027Shselasky} 836329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_hw_rule_sz); 837272027Shselasky 838255932Salfredstatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, 839255932Salfred struct _rule_hw *rule_hw) 840255932Salfred{ 841329159Shselasky if (mlx4_hw_rule_sz(dev, spec->id) < 0) 842255932Salfred return -EINVAL; 843329159Shselasky memset(rule_hw, 0, mlx4_hw_rule_sz(dev, spec->id)); 844255932Salfred rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]); 845329159Shselasky rule_hw->size = mlx4_hw_rule_sz(dev, spec->id) >> 2; 846255932Salfred 847255932Salfred switch (spec->id) { 848255932Salfred case MLX4_NET_TRANS_RULE_ID_ETH: 849255932Salfred memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN); 850255932Salfred memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk, 851255932Salfred ETH_ALEN); 852255932Salfred memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN); 853255932Salfred memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk, 854255932Salfred ETH_ALEN); 855255932Salfred if (spec->eth.ether_type_enable) { 856255932Salfred rule_hw->eth.ether_type_enable = 1; 857255932Salfred rule_hw->eth.ether_type = spec->eth.ether_type; 858255932Salfred } 859272027Shselasky rule_hw->eth.vlan_tag = spec->eth.vlan_id; 860272027Shselasky rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk; 861255932Salfred break; 862255932Salfred 863255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 864272027Shselasky rule_hw->ib.l3_qpn = spec->ib.l3_qpn; 865255932Salfred rule_hw->ib.qpn_mask = spec->ib.qpn_msk; 866255932Salfred memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16); 867255932Salfred memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16); 868255932Salfred break; 869255932Salfred 870255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV6: 871255932Salfred return -EOPNOTSUPP; 872255932Salfred 873255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 874255932Salfred rule_hw->ipv4.src_ip = spec->ipv4.src_ip; 875255932Salfred rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk; 876255932Salfred rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip; 877255932Salfred rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk; 878255932Salfred break; 879255932Salfred 880255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 881255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 882255932Salfred rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port; 883255932Salfred rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk; 884255932Salfred rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port; 885255932Salfred rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk; 886255932Salfred break; 887255932Salfred 888329159Shselasky case MLX4_NET_TRANS_RULE_ID_VXLAN: 889329159Shselasky rule_hw->vxlan.vni = 890329159Shselasky cpu_to_be32(be32_to_cpu(spec->vxlan.vni) << 8); 891329159Shselasky rule_hw->vxlan.vni_mask = 892329159Shselasky cpu_to_be32(be32_to_cpu(spec->vxlan.vni_mask) << 8); 893329159Shselasky break; 894329159Shselasky 895255932Salfred default: 896255932Salfred return -EINVAL; 897255932Salfred } 898255932Salfred 899255932Salfred return __rule_hw_sz[spec->id]; 900255932Salfred} 901255932Salfred 902255932Salfredstatic void mlx4_err_rule(struct mlx4_dev *dev, char *str, 903255932Salfred struct mlx4_net_trans_rule *rule) 904255932Salfred{ 905255932Salfred#define BUF_SIZE 256 906255932Salfred struct mlx4_spec_list *cur; 907255932Salfred char buf[BUF_SIZE]; 908255932Salfred int len = 0; 909255932Salfred 910255932Salfred mlx4_err(dev, "%s", str); 911255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 912255932Salfred "port = %d prio = 0x%x qp = 0x%x ", 913255932Salfred rule->port, rule->priority, rule->qpn); 914255932Salfred 915255932Salfred list_for_each_entry(cur, &rule->list, list) { 916255932Salfred switch (cur->id) { 917255932Salfred case MLX4_NET_TRANS_RULE_ID_ETH: 918255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 919329159Shselasky "dmac = 0x%02x%02x%02x%02x%02x%02x ", 920329159Shselasky cur->eth.dst_mac[0], cur->eth.dst_mac[1], 921329159Shselasky cur->eth.dst_mac[2], cur->eth.dst_mac[3], 922329159Shselasky cur->eth.dst_mac[4], cur->eth.dst_mac[5]); 923255932Salfred if (cur->eth.ether_type) 924255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 925255932Salfred "ethertype = 0x%x ", 926255932Salfred be16_to_cpu(cur->eth.ether_type)); 927255932Salfred if (cur->eth.vlan_id) 928255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 929255932Salfred "vlan-id = %d ", 930255932Salfred be16_to_cpu(cur->eth.vlan_id)); 931255932Salfred break; 932255932Salfred 933255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 934255932Salfred if (cur->ipv4.src_ip) 935255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 936255932Salfred "src-ip = %pI4 ", 937255932Salfred &cur->ipv4.src_ip); 938255932Salfred if (cur->ipv4.dst_ip) 939255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 940255932Salfred "dst-ip = %pI4 ", 941255932Salfred &cur->ipv4.dst_ip); 942255932Salfred break; 943255932Salfred 944255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 945255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 946255932Salfred if (cur->tcp_udp.src_port) 947255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 948255932Salfred "src-port = %d ", 949255932Salfred be16_to_cpu(cur->tcp_udp.src_port)); 950255932Salfred if (cur->tcp_udp.dst_port) 951255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 952255932Salfred "dst-port = %d ", 953255932Salfred be16_to_cpu(cur->tcp_udp.dst_port)); 954255932Salfred break; 955255932Salfred 956255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 957255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 958279584Shselasky "dst-gid = "GID_PRINT_FMT"\n", 959279584Shselasky GID_PRINT_ARGS(cur->ib.dst_gid)); 960255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 961279584Shselasky "dst-gid-mask = "GID_PRINT_FMT"\n", 962279584Shselasky GID_PRINT_ARGS(cur->ib.dst_gid_msk)); 963255932Salfred break; 964255932Salfred 965329159Shselasky case MLX4_NET_TRANS_RULE_ID_VXLAN: 966329159Shselasky len += snprintf(buf + len, BUF_SIZE - len, 967329159Shselasky "VNID = %d ", be32_to_cpu(cur->vxlan.vni)); 968329159Shselasky break; 969255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV6: 970255932Salfred break; 971255932Salfred 972255932Salfred default: 973255932Salfred break; 974255932Salfred } 975255932Salfred } 976255932Salfred len += snprintf(buf + len, BUF_SIZE - len, "\n"); 977255932Salfred mlx4_err(dev, "%s", buf); 978255932Salfred 979255932Salfred if (len >= BUF_SIZE) 980329159Shselasky mlx4_err(dev, "Network rule error message was truncated, print buffer is too small\n"); 981255932Salfred} 982255932Salfred 983255932Salfredint mlx4_flow_attach(struct mlx4_dev *dev, 984255932Salfred struct mlx4_net_trans_rule *rule, u64 *reg_id) 985255932Salfred{ 986255932Salfred struct mlx4_cmd_mailbox *mailbox; 987255932Salfred struct mlx4_spec_list *cur; 988255932Salfred u32 size = 0; 989255932Salfred int ret; 990255932Salfred 991255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 992255932Salfred if (IS_ERR(mailbox)) 993255932Salfred return PTR_ERR(mailbox); 994255932Salfred 995255932Salfred trans_rule_ctrl_to_hw(rule, mailbox->buf); 996255932Salfred 997255932Salfred size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); 998255932Salfred 999255932Salfred list_for_each_entry(cur, &rule->list, list) { 1000255932Salfred ret = parse_trans_rule(dev, cur, mailbox->buf + size); 1001255932Salfred if (ret < 0) { 1002255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1003329159Shselasky return ret; 1004255932Salfred } 1005255932Salfred size += ret; 1006255932Salfred } 1007255932Salfred 1008255932Salfred ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id); 1009329159Shselasky if (ret == -ENOMEM) { 1010255932Salfred mlx4_err_rule(dev, 1011329159Shselasky "mcg table is full. Fail to register network rule\n", 1012255932Salfred rule); 1013329159Shselasky } else if (ret) { 1014329159Shselasky if (ret == -ENXIO) { 1015329159Shselasky if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) 1016329159Shselasky mlx4_err_rule(dev, 1017329159Shselasky "DMFS is not enabled, " 1018329159Shselasky "failed to register network rule.\n", 1019329159Shselasky rule); 1020329159Shselasky else 1021329159Shselasky mlx4_err_rule(dev, 1022329159Shselasky "Rule exceeds the dmfs_high_rate_mode limitations, " 1023329159Shselasky "failed to register network rule.\n", 1024329159Shselasky rule); 1025255932Salfred 1026329159Shselasky } else { 1027329159Shselasky mlx4_err_rule(dev, "Fail to register network rule.\n", rule); 1028329159Shselasky } 1029329159Shselasky } 1030329159Shselasky 1031255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1032255932Salfred 1033255932Salfred return ret; 1034255932Salfred} 1035255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_attach); 1036255932Salfred 1037255932Salfredint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id) 1038255932Salfred{ 1039255932Salfred int err; 1040255932Salfred 1041255932Salfred err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id); 1042255932Salfred if (err) 1043255932Salfred mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n", 1044272027Shselasky (unsigned long long)reg_id); 1045255932Salfred return err; 1046255932Salfred} 1047255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_detach); 1048255932Salfred 1049329159Shselaskyint mlx4_tunnel_steer_add(struct mlx4_dev *dev, unsigned char *addr, 1050329159Shselasky int port, int qpn, u16 prio, u64 *reg_id) 1051255932Salfred{ 1052255932Salfred int err; 1053329159Shselasky struct mlx4_spec_list spec_eth_outer = { {NULL} }; 1054329159Shselasky struct mlx4_spec_list spec_vxlan = { {NULL} }; 1055329159Shselasky struct mlx4_spec_list spec_eth_inner = { {NULL} }; 1056329159Shselasky 1057329159Shselasky struct mlx4_net_trans_rule rule = { 1058329159Shselasky .queue_mode = MLX4_NET_TRANS_Q_FIFO, 1059329159Shselasky .exclusive = 0, 1060329159Shselasky .allow_loopback = 1, 1061329159Shselasky .promisc_mode = MLX4_FS_REGULAR, 1062329159Shselasky }; 1063329159Shselasky 1064329159Shselasky __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 1065329159Shselasky 1066329159Shselasky rule.port = port; 1067329159Shselasky rule.qpn = qpn; 1068329159Shselasky rule.priority = prio; 1069329159Shselasky INIT_LIST_HEAD(&rule.list); 1070329159Shselasky 1071329159Shselasky spec_eth_outer.id = MLX4_NET_TRANS_RULE_ID_ETH; 1072329159Shselasky memcpy(spec_eth_outer.eth.dst_mac, addr, ETH_ALEN); 1073329159Shselasky memcpy(spec_eth_outer.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 1074329159Shselasky 1075329159Shselasky spec_vxlan.id = MLX4_NET_TRANS_RULE_ID_VXLAN; /* any vxlan header */ 1076329159Shselasky spec_eth_inner.id = MLX4_NET_TRANS_RULE_ID_ETH; /* any inner eth header */ 1077329159Shselasky 1078329159Shselasky list_add_tail(&spec_eth_outer.list, &rule.list); 1079329159Shselasky list_add_tail(&spec_vxlan.list, &rule.list); 1080329159Shselasky list_add_tail(&spec_eth_inner.list, &rule.list); 1081329159Shselasky 1082329159Shselasky err = mlx4_flow_attach(dev, &rule, reg_id); 1083329159Shselasky return err; 1084329159Shselasky} 1085329159ShselaskyEXPORT_SYMBOL(mlx4_tunnel_steer_add); 1086329159Shselasky 1087329159Shselaskyint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, 1088329159Shselasky u32 max_range_qpn) 1089329159Shselasky{ 1090329159Shselasky int err; 1091255932Salfred u64 in_param; 1092255932Salfred 1093255932Salfred in_param = ((u64) min_range_qpn) << 32; 1094255932Salfred in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF; 1095255932Salfred 1096255932Salfred err = mlx4_cmd(dev, in_param, 0, 0, 1097255932Salfred MLX4_FLOW_STEERING_IB_UC_QP_RANGE, 1098255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1099255932Salfred 1100255932Salfred return err; 1101255932Salfred} 1102255932SalfredEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE); 1103255932Salfred 1104255932Salfredint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1105255932Salfred int block_mcast_loopback, enum mlx4_protocol prot, 1106255932Salfred enum mlx4_steer_type steer) 1107255932Salfred{ 1108219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1109219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1110219820Sjeff struct mlx4_mgm *mgm; 1111219820Sjeff u32 members_count; 1112329159Shselasky int index = -1, prev; 1113219820Sjeff int link = 0; 1114219820Sjeff int i; 1115219820Sjeff int err; 1116255932Salfred u8 port = gid[5]; 1117255932Salfred u8 new_entry = 0; 1118219820Sjeff 1119219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1120219820Sjeff if (IS_ERR(mailbox)) 1121219820Sjeff return PTR_ERR(mailbox); 1122219820Sjeff mgm = mailbox->buf; 1123219820Sjeff 1124219820Sjeff mutex_lock(&priv->mcg_table.mutex); 1125255932Salfred err = find_entry(dev, port, gid, prot, 1126255932Salfred mailbox, &prev, &index); 1127219820Sjeff if (err) 1128219820Sjeff goto out; 1129219820Sjeff 1130219820Sjeff if (index != -1) { 1131255932Salfred if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { 1132255932Salfred new_entry = 1; 1133219820Sjeff memcpy(mgm->gid, gid, 16); 1134255932Salfred } 1135219820Sjeff } else { 1136219820Sjeff link = 1; 1137219820Sjeff 1138219820Sjeff index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); 1139219820Sjeff if (index == -1) { 1140219820Sjeff mlx4_err(dev, "No AMGM entries left\n"); 1141219820Sjeff err = -ENOMEM; 1142219820Sjeff goto out; 1143219820Sjeff } 1144219820Sjeff index += dev->caps.num_mgms; 1145219820Sjeff 1146255932Salfred new_entry = 1; 1147219820Sjeff memset(mgm, 0, sizeof *mgm); 1148219820Sjeff memcpy(mgm->gid, gid, 16); 1149219820Sjeff } 1150219820Sjeff 1151219820Sjeff members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 1152255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 1153329159Shselasky mlx4_err(dev, "MGM at index %x is full\n", index); 1154219820Sjeff err = -ENOMEM; 1155219820Sjeff goto out; 1156219820Sjeff } 1157219820Sjeff 1158219820Sjeff for (i = 0; i < members_count; ++i) 1159219820Sjeff if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { 1160219820Sjeff mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); 1161219820Sjeff err = 0; 1162219820Sjeff goto out; 1163219820Sjeff } 1164219820Sjeff 1165329159Shselasky if (block_mcast_loopback) 1166329159Shselasky mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | 1167329159Shselasky (1U << MGM_BLCK_LB_BIT)); 1168329159Shselasky else 1169329159Shselasky mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); 1170219820Sjeff 1171255932Salfred mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); 1172219820Sjeff 1173255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1174219820Sjeff if (err) 1175219820Sjeff goto out; 1176219820Sjeff 1177219820Sjeff if (!link) 1178329159Shselasky goto out; 1179219820Sjeff 1180255932Salfred err = mlx4_READ_ENTRY(dev, prev, mailbox); 1181219820Sjeff if (err) 1182219820Sjeff goto out; 1183219820Sjeff 1184219820Sjeff mgm->next_gid_index = cpu_to_be32(index << 6); 1185219820Sjeff 1186255932Salfred err = mlx4_WRITE_ENTRY(dev, prev, mailbox); 1187219820Sjeff if (err) 1188219820Sjeff goto out; 1189219820Sjeff 1190329159Shselaskyout: 1191329159Shselasky if (prot == MLX4_PROT_ETH && index != -1) { 1192255932Salfred /* manage the steering entry for promisc mode */ 1193255932Salfred if (new_entry) 1194329159Shselasky err = new_steering_entry(dev, port, steer, 1195329159Shselasky index, qp->qpn); 1196255932Salfred else 1197329159Shselasky err = existing_steering_entry(dev, port, steer, 1198329159Shselasky index, qp->qpn); 1199255932Salfred } 1200219820Sjeff if (err && link && index != -1) { 1201219820Sjeff if (index < dev->caps.num_mgms) 1202329159Shselasky mlx4_warn(dev, "Got AMGM index %d < %d\n", 1203219820Sjeff index, dev->caps.num_mgms); 1204219820Sjeff else 1205219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1206272027Shselasky index - dev->caps.num_mgms, MLX4_USE_RR); 1207219820Sjeff } 1208219820Sjeff mutex_unlock(&priv->mcg_table.mutex); 1209219820Sjeff 1210219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1211219820Sjeff return err; 1212219820Sjeff} 1213219820Sjeff 1214255932Salfredint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1215255932Salfred enum mlx4_protocol prot, enum mlx4_steer_type steer) 1216219820Sjeff{ 1217219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1218219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1219219820Sjeff struct mlx4_mgm *mgm; 1220219820Sjeff u32 members_count; 1221219820Sjeff int prev, index; 1222255932Salfred int i, loc = -1; 1223219820Sjeff int err; 1224255932Salfred u8 port = gid[5]; 1225255932Salfred bool removed_entry = false; 1226219820Sjeff 1227219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1228219820Sjeff if (IS_ERR(mailbox)) 1229219820Sjeff return PTR_ERR(mailbox); 1230219820Sjeff mgm = mailbox->buf; 1231219820Sjeff 1232219820Sjeff mutex_lock(&priv->mcg_table.mutex); 1233219820Sjeff 1234255932Salfred err = find_entry(dev, port, gid, prot, 1235255932Salfred mailbox, &prev, &index); 1236219820Sjeff if (err) 1237219820Sjeff goto out; 1238219820Sjeff 1239219820Sjeff if (index == -1) { 1240279584Shselasky mlx4_err(dev, "MGID "GID_PRINT_FMT" not found\n", 1241279584Shselasky GID_PRINT_ARGS(gid)); 1242219820Sjeff err = -EINVAL; 1243219820Sjeff goto out; 1244219820Sjeff } 1245219820Sjeff 1246329159Shselasky /* If this QP is also a promisc QP, it shouldn't be removed only if 1247329159Shselasky * at least one none promisc QP is also attached to this MCG 1248329159Shselasky */ 1249255932Salfred if (prot == MLX4_PROT_ETH && 1250272027Shselasky check_duplicate_entry(dev, port, steer, index, qp->qpn) && 1251272027Shselasky !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL)) 1252272027Shselasky goto out; 1253255932Salfred 1254219820Sjeff members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 1255255932Salfred for (i = 0; i < members_count; ++i) 1256255932Salfred if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { 1257219820Sjeff loc = i; 1258255932Salfred break; 1259255932Salfred } 1260219820Sjeff 1261219820Sjeff if (loc == -1) { 1262219820Sjeff mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); 1263219820Sjeff err = -EINVAL; 1264219820Sjeff goto out; 1265219820Sjeff } 1266219820Sjeff 1267255932Salfred /* copy the last QP in this MGM over removed QP */ 1268255932Salfred mgm->qp[loc] = mgm->qp[members_count - 1]; 1269255932Salfred mgm->qp[members_count - 1] = 0; 1270255932Salfred mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); 1271219820Sjeff 1272255932Salfred if (prot == MLX4_PROT_ETH) 1273255932Salfred removed_entry = can_remove_steering_entry(dev, port, steer, 1274255932Salfred index, qp->qpn); 1275255932Salfred if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) { 1276255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1277219820Sjeff goto out; 1278219820Sjeff } 1279219820Sjeff 1280255932Salfred /* We are going to delete the entry, members count should be 0 */ 1281255932Salfred mgm->members_count = cpu_to_be32((u32) prot << 30); 1282255932Salfred 1283219820Sjeff if (prev == -1) { 1284219820Sjeff /* Remove entry from MGM */ 1285219820Sjeff int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; 1286219820Sjeff if (amgm_index) { 1287255932Salfred err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); 1288219820Sjeff if (err) 1289219820Sjeff goto out; 1290219820Sjeff } else 1291219820Sjeff memset(mgm->gid, 0, 16); 1292219820Sjeff 1293255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1294219820Sjeff if (err) 1295219820Sjeff goto out; 1296219820Sjeff 1297219820Sjeff if (amgm_index) { 1298219820Sjeff if (amgm_index < dev->caps.num_mgms) 1299329159Shselasky mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d\n", 1300219820Sjeff index, amgm_index, dev->caps.num_mgms); 1301219820Sjeff else 1302219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1303272027Shselasky amgm_index - dev->caps.num_mgms, MLX4_USE_RR); 1304219820Sjeff } 1305219820Sjeff } else { 1306219820Sjeff /* Remove entry from AMGM */ 1307219820Sjeff int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 1308255932Salfred err = mlx4_READ_ENTRY(dev, prev, mailbox); 1309219820Sjeff if (err) 1310219820Sjeff goto out; 1311219820Sjeff 1312219820Sjeff mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); 1313219820Sjeff 1314255932Salfred err = mlx4_WRITE_ENTRY(dev, prev, mailbox); 1315219820Sjeff if (err) 1316219820Sjeff goto out; 1317219820Sjeff 1318219820Sjeff if (index < dev->caps.num_mgms) 1319329159Shselasky mlx4_warn(dev, "entry %d had next AMGM index %d < %d\n", 1320219820Sjeff prev, index, dev->caps.num_mgms); 1321219820Sjeff else 1322219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1323272027Shselasky index - dev->caps.num_mgms, MLX4_USE_RR); 1324219820Sjeff } 1325219820Sjeff 1326219820Sjeffout: 1327219820Sjeff mutex_unlock(&priv->mcg_table.mutex); 1328219820Sjeff 1329219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1330329159Shselasky if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 1331329159Shselasky /* In case device is under an error, return success as a closing command */ 1332329159Shselasky err = 0; 1333219820Sjeff return err; 1334219820Sjeff} 1335255932Salfred 1336255932Salfredstatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, 1337255932Salfred u8 gid[16], u8 attach, u8 block_loopback, 1338255932Salfred enum mlx4_protocol prot) 1339255932Salfred{ 1340255932Salfred struct mlx4_cmd_mailbox *mailbox; 1341255932Salfred int err = 0; 1342255932Salfred int qpn; 1343255932Salfred 1344255932Salfred if (!mlx4_is_mfunc(dev)) 1345255932Salfred return -EBADF; 1346255932Salfred 1347255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1348255932Salfred if (IS_ERR(mailbox)) 1349255932Salfred return PTR_ERR(mailbox); 1350255932Salfred 1351255932Salfred memcpy(mailbox->buf, gid, 16); 1352255932Salfred qpn = qp->qpn; 1353255932Salfred qpn |= (prot << 28); 1354255932Salfred if (attach && block_loopback) 1355272027Shselasky qpn |= (1 << 31); 1356255932Salfred 1357255932Salfred err = mlx4_cmd(dev, mailbox->dma, qpn, attach, 1358255932Salfred MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A, 1359255932Salfred MLX4_CMD_WRAPPED); 1360255932Salfred 1361255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1362329159Shselasky if (err && !attach && 1363329159Shselasky dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 1364329159Shselasky err = 0; 1365255932Salfred return err; 1366255932Salfred} 1367255932Salfred 1368272027Shselaskyint mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, 1369272027Shselasky u8 gid[16], u8 port, 1370272027Shselasky int block_mcast_loopback, 1371272027Shselasky enum mlx4_protocol prot, u64 *reg_id) 1372255932Salfred{ 1373255932Salfred struct mlx4_spec_list spec = { {NULL} }; 1374255932Salfred __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 1375255932Salfred 1376255932Salfred struct mlx4_net_trans_rule rule = { 1377255932Salfred .queue_mode = MLX4_NET_TRANS_Q_FIFO, 1378255932Salfred .exclusive = 0, 1379255932Salfred .promisc_mode = MLX4_FS_REGULAR, 1380255932Salfred .priority = MLX4_DOMAIN_NIC, 1381255932Salfred }; 1382255932Salfred 1383255932Salfred rule.allow_loopback = !block_mcast_loopback; 1384255932Salfred rule.port = port; 1385255932Salfred rule.qpn = qp->qpn; 1386255932Salfred INIT_LIST_HEAD(&rule.list); 1387255932Salfred 1388255932Salfred switch (prot) { 1389255932Salfred case MLX4_PROT_ETH: 1390255932Salfred spec.id = MLX4_NET_TRANS_RULE_ID_ETH; 1391255932Salfred memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN); 1392255932Salfred memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 1393255932Salfred break; 1394255932Salfred 1395255932Salfred case MLX4_PROT_IB_IPV6: 1396255932Salfred spec.id = MLX4_NET_TRANS_RULE_ID_IB; 1397255932Salfred memcpy(spec.ib.dst_gid, gid, 16); 1398255932Salfred memset(&spec.ib.dst_gid_msk, 0xff, 16); 1399255932Salfred break; 1400255932Salfred default: 1401255932Salfred return -EINVAL; 1402255932Salfred } 1403255932Salfred list_add_tail(&spec.list, &rule.list); 1404255932Salfred 1405255932Salfred return mlx4_flow_attach(dev, &rule, reg_id); 1406272027Shselasky} 1407255932Salfred 1408272027Shselaskyint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1409272027Shselasky u8 port, int block_mcast_loopback, 1410272027Shselasky enum mlx4_protocol prot, u64 *reg_id) 1411272027Shselasky{ 1412272027Shselasky switch (dev->caps.steering_mode) { 1413272027Shselasky case MLX4_STEERING_MODE_A0: 1414272027Shselasky if (prot == MLX4_PROT_ETH) 1415272027Shselasky return 0; 1416272027Shselasky 1417272027Shselasky case MLX4_STEERING_MODE_B0: 1418272027Shselasky if (prot == MLX4_PROT_ETH) 1419329159Shselasky gid[7] |= (MLX4_MC_STEER << 1); 1420272027Shselasky 1421272027Shselasky if (mlx4_is_mfunc(dev)) 1422272027Shselasky return mlx4_QP_ATTACH(dev, qp, gid, 1, 1423272027Shselasky block_mcast_loopback, prot); 1424272027Shselasky return mlx4_qp_attach_common(dev, qp, gid, 1425272027Shselasky block_mcast_loopback, prot, 1426272027Shselasky MLX4_MC_STEER); 1427272027Shselasky 1428272027Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 1429272027Shselasky return mlx4_trans_to_dmfs_attach(dev, qp, gid, port, 1430272027Shselasky block_mcast_loopback, 1431272027Shselasky prot, reg_id); 1432255932Salfred default: 1433255932Salfred return -EINVAL; 1434255932Salfred } 1435255932Salfred} 1436255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_attach); 1437255932Salfred 1438255932Salfredint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1439255932Salfred enum mlx4_protocol prot, u64 reg_id) 1440255932Salfred{ 1441255932Salfred switch (dev->caps.steering_mode) { 1442255932Salfred case MLX4_STEERING_MODE_A0: 1443255932Salfred if (prot == MLX4_PROT_ETH) 1444255932Salfred return 0; 1445255932Salfred 1446255932Salfred case MLX4_STEERING_MODE_B0: 1447255932Salfred if (prot == MLX4_PROT_ETH) 1448329159Shselasky gid[7] |= (MLX4_MC_STEER << 1); 1449255932Salfred 1450255932Salfred if (mlx4_is_mfunc(dev)) 1451255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); 1452255932Salfred 1453255932Salfred return mlx4_qp_detach_common(dev, qp, gid, prot, 1454255932Salfred MLX4_MC_STEER); 1455255932Salfred 1456255932Salfred case MLX4_STEERING_MODE_DEVICE_MANAGED: 1457255932Salfred return mlx4_flow_detach(dev, reg_id); 1458255932Salfred 1459255932Salfred default: 1460255932Salfred return -EINVAL; 1461255932Salfred } 1462255932Salfred} 1463219820SjeffEXPORT_SYMBOL_GPL(mlx4_multicast_detach); 1464219820Sjeff 1465255932Salfredint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, 1466255932Salfred u32 qpn, enum mlx4_net_trans_promisc_mode mode) 1467255932Salfred{ 1468329159Shselasky struct mlx4_net_trans_rule rule = { 1469329159Shselasky .queue_mode = MLX4_NET_TRANS_Q_FIFO, 1470329159Shselasky .exclusive = 0, 1471329159Shselasky .allow_loopback = 1, 1472329159Shselasky }; 1473329159Shselasky 1474255932Salfred u64 *regid_p; 1475255932Salfred 1476255932Salfred switch (mode) { 1477255932Salfred case MLX4_FS_ALL_DEFAULT: 1478255932Salfred regid_p = &dev->regid_promisc_array[port]; 1479255932Salfred break; 1480255932Salfred case MLX4_FS_MC_DEFAULT: 1481255932Salfred regid_p = &dev->regid_allmulti_array[port]; 1482255932Salfred break; 1483255932Salfred default: 1484255932Salfred return -1; 1485255932Salfred } 1486255932Salfred 1487255932Salfred if (*regid_p != 0) 1488255932Salfred return -1; 1489255932Salfred 1490255932Salfred rule.promisc_mode = mode; 1491255932Salfred rule.port = port; 1492255932Salfred rule.qpn = qpn; 1493255932Salfred INIT_LIST_HEAD(&rule.list); 1494255932Salfred mlx4_err(dev, "going promisc on %x\n", port); 1495255932Salfred 1496255932Salfred return mlx4_flow_attach(dev, &rule, regid_p); 1497255932Salfred} 1498255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add); 1499255932Salfred 1500255932Salfredint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port, 1501255932Salfred enum mlx4_net_trans_promisc_mode mode) 1502255932Salfred{ 1503255932Salfred int ret; 1504255932Salfred u64 *regid_p; 1505255932Salfred 1506255932Salfred switch (mode) { 1507255932Salfred case MLX4_FS_ALL_DEFAULT: 1508255932Salfred regid_p = &dev->regid_promisc_array[port]; 1509255932Salfred break; 1510255932Salfred case MLX4_FS_MC_DEFAULT: 1511255932Salfred regid_p = &dev->regid_allmulti_array[port]; 1512255932Salfred break; 1513255932Salfred default: 1514255932Salfred return -1; 1515255932Salfred } 1516255932Salfred 1517255932Salfred if (*regid_p == 0) 1518255932Salfred return -1; 1519255932Salfred 1520255932Salfred ret = mlx4_flow_detach(dev, *regid_p); 1521255932Salfred if (ret == 0) 1522255932Salfred *regid_p = 0; 1523255932Salfred 1524255932Salfred return ret; 1525255932Salfred} 1526255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove); 1527255932Salfred 1528255932Salfredint mlx4_unicast_attach(struct mlx4_dev *dev, 1529255932Salfred struct mlx4_qp *qp, u8 gid[16], 1530255932Salfred int block_mcast_loopback, enum mlx4_protocol prot) 1531255932Salfred{ 1532255932Salfred if (prot == MLX4_PROT_ETH) 1533255932Salfred gid[7] |= (MLX4_UC_STEER << 1); 1534255932Salfred 1535255932Salfred if (mlx4_is_mfunc(dev)) 1536255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 1, 1537255932Salfred block_mcast_loopback, prot); 1538255932Salfred 1539255932Salfred return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback, 1540255932Salfred prot, MLX4_UC_STEER); 1541255932Salfred} 1542255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_attach); 1543255932Salfred 1544255932Salfredint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, 1545255932Salfred u8 gid[16], enum mlx4_protocol prot) 1546255932Salfred{ 1547255932Salfred if (prot == MLX4_PROT_ETH) 1548255932Salfred gid[7] |= (MLX4_UC_STEER << 1); 1549255932Salfred 1550255932Salfred if (mlx4_is_mfunc(dev)) 1551255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); 1552255932Salfred 1553255932Salfred return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER); 1554255932Salfred} 1555255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_detach); 1556255932Salfred 1557255932Salfredint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, 1558255932Salfred struct mlx4_vhcr *vhcr, 1559255932Salfred struct mlx4_cmd_mailbox *inbox, 1560255932Salfred struct mlx4_cmd_mailbox *outbox, 1561255932Salfred struct mlx4_cmd_info *cmd) 1562255932Salfred{ 1563255932Salfred u32 qpn = (u32) vhcr->in_param & 0xffffffff; 1564329159Shselasky int port = mlx4_slave_convert_port(dev, slave, vhcr->in_param >> 62); 1565255932Salfred enum mlx4_steer_type steer = vhcr->in_modifier; 1566255932Salfred 1567329159Shselasky if (port < 0) 1568329159Shselasky return -EINVAL; 1569329159Shselasky 1570329159Shselasky /* Promiscuous unicast is not allowed in mfunc */ 1571329159Shselasky if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER) 1572255932Salfred return 0; 1573255932Salfred 1574255932Salfred if (vhcr->op_modifier) 1575255932Salfred return add_promisc_qp(dev, port, steer, qpn); 1576255932Salfred else 1577255932Salfred return remove_promisc_qp(dev, port, steer, qpn); 1578255932Salfred} 1579255932Salfred 1580255932Salfredstatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn, 1581255932Salfred enum mlx4_steer_type steer, u8 add, u8 port) 1582255932Salfred{ 1583255932Salfred return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add, 1584255932Salfred MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A, 1585255932Salfred MLX4_CMD_WRAPPED); 1586255932Salfred} 1587255932Salfred 1588255932Salfredint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) 1589255932Salfred{ 1590255932Salfred if (mlx4_is_mfunc(dev)) 1591255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port); 1592255932Salfred 1593255932Salfred return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn); 1594255932Salfred} 1595255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); 1596255932Salfred 1597255932Salfredint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) 1598255932Salfred{ 1599255932Salfred if (mlx4_is_mfunc(dev)) 1600255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port); 1601255932Salfred 1602255932Salfred return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn); 1603255932Salfred} 1604255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); 1605255932Salfred 1606255932Salfredint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) 1607255932Salfred{ 1608255932Salfred if (mlx4_is_mfunc(dev)) 1609255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port); 1610255932Salfred 1611255932Salfred return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn); 1612255932Salfred} 1613255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); 1614255932Salfred 1615255932Salfredint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) 1616255932Salfred{ 1617255932Salfred if (mlx4_is_mfunc(dev)) 1618255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port); 1619255932Salfred 1620255932Salfred return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn); 1621255932Salfred} 1622255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); 1623255932Salfred 1624219820Sjeffint mlx4_init_mcg_table(struct mlx4_dev *dev) 1625219820Sjeff{ 1626219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1627219820Sjeff int err; 1628219820Sjeff 1629255932Salfred /* No need for mcg_table when fw managed the mcg table*/ 1630255932Salfred if (dev->caps.steering_mode == 1631255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 1632255932Salfred return 0; 1633219820Sjeff err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, 1634219820Sjeff dev->caps.num_amgms - 1, 0, 0); 1635219820Sjeff if (err) 1636219820Sjeff return err; 1637219820Sjeff 1638219820Sjeff mutex_init(&priv->mcg_table.mutex); 1639219820Sjeff 1640219820Sjeff return 0; 1641219820Sjeff} 1642219820Sjeff 1643219820Sjeffvoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev) 1644219820Sjeff{ 1645255932Salfred if (dev->caps.steering_mode != 1646255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 1647255932Salfred mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); 1648219820Sjeff} 1649