1219820Sjeff/* 2219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. 3272407Shselasky * 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> 35272407Shselasky#include <linux/etherdevice.h> 36219820Sjeff 37219820Sjeff#include <linux/mlx4/cmd.h> 38272407Shselasky#include <linux/module.h> 39279731Shselasky#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{ 127272407Shselasky struct mlx4_steer *s_steer; 128255932Salfred struct mlx4_promisc_qp *pqp; 129255932Salfred 130272407Shselasky if (port < 1 || port > dev->caps.num_ports) 131272407Shselasky return NULL; 132272407Shselasky 133272407Shselasky s_steer = &mlx4_priv(dev)->steer[port - 1]; 134272407Shselasky 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 161272407Shselasky if (port < 1 || port > dev->caps.num_ports) 162272407Shselasky return -EINVAL; 163272407Shselasky 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 248272407Shselasky if (port < 1 || port > dev->caps.num_ports) 249272407Shselasky return -EINVAL; 250272407Shselasky 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) { 272272407Shselasky 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 296272407Shselasky if (port < 1 || port > dev->caps.num_ports) 297272407Shselasky return NULL; 298272407Shselasky 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 326272407Shselasky/* 327272407Shselasky * returns true if all the QPs != tqpn contained in this entry 328272407Shselasky * are Promisc QPs. return false otherwise. 329272407Shselasky */ 330272407Shselaskystatic bool promisc_steering_entry(struct mlx4_dev *dev, u8 port, 331255932Salfred enum mlx4_steer_type steer, 332272407Shselasky unsigned int index, u32 tqpn, u32 *members_count) 333255932Salfred{ 334255932Salfred struct mlx4_steer *s_steer; 335255932Salfred struct mlx4_cmd_mailbox *mailbox; 336255932Salfred struct mlx4_mgm *mgm; 337272407Shselasky u32 m_count; 338255932Salfred bool ret = false; 339255932Salfred int i; 340255932Salfred 341272407Shselasky if (port < 1 || port > dev->caps.num_ports) 342272407Shselasky return false; 343272407Shselasky 344255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 345255932Salfred 346255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 347255932Salfred if (IS_ERR(mailbox)) 348255932Salfred return false; 349255932Salfred mgm = mailbox->buf; 350255932Salfred 351255932Salfred if (mlx4_READ_ENTRY(dev, index, mailbox)) 352255932Salfred goto out; 353272407Shselasky m_count = be32_to_cpu(mgm->members_count) & 0xffffff; 354272407Shselasky if (members_count) 355272407Shselasky *members_count = m_count; 356272407Shselasky 357272407Shselasky for (i = 0; i < m_count; i++) { 358272407Shselasky u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; 359255932Salfred if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) { 360255932Salfred /* the qp is not promisc, the entry can't be removed */ 361255932Salfred goto out; 362255932Salfred } 363255932Salfred } 364272407Shselasky ret = true; 365272407Shselaskyout: 366272407Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 367272407Shselasky return ret; 368272407Shselasky} 369272407Shselasky 370272407Shselasky/* IF a steering entry contains only promisc QPs, it can be removed. */ 371272407Shselaskystatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, 372272407Shselasky enum mlx4_steer_type steer, 373272407Shselasky unsigned int index, u32 tqpn) 374272407Shselasky{ 375272407Shselasky struct mlx4_steer *s_steer; 376272407Shselasky struct mlx4_steer_index *entry = NULL, *tmp_entry; 377272407Shselasky u32 members_count; 378272407Shselasky bool ret = false; 379272407Shselasky 380272407Shselasky if (port < 1 || port > dev->caps.num_ports) 381272407Shselasky return NULL; 382272407Shselasky 383272407Shselasky s_steer = &mlx4_priv(dev)->steer[port - 1]; 384272407Shselasky 385272407Shselasky if (!promisc_steering_entry(dev, port, steer, index, tqpn, &members_count)) 386272407Shselasky goto out; 387272407Shselasky 388272407Shselasky /* All the qps currently registered for this entry are promiscuous, 389255932Salfred * Checking for duplicates */ 390255932Salfred ret = true; 391255932Salfred list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { 392255932Salfred if (entry->index == index) { 393255932Salfred if (list_empty(&entry->duplicates) || members_count == 1) { 394255932Salfred struct mlx4_promisc_qp *pqp, *tmp_pqp; 395255932Salfred /* 396255932Salfred * If there is only 1 entry in duplicates than 397255932Salfred * this is the QP we want to delete, going over 398255932Salfred * the list and deleting the entry. 399255932Salfred */ 400255932Salfred list_del(&entry->list); 401255932Salfred list_for_each_entry_safe(pqp, tmp_pqp, 402255932Salfred &entry->duplicates, 403255932Salfred list) { 404255932Salfred list_del(&pqp->list); 405255932Salfred kfree(pqp); 406255932Salfred } 407255932Salfred kfree(entry); 408255932Salfred } else { 409255932Salfred /* This entry contains duplicates so it shouldn't be removed */ 410255932Salfred ret = false; 411255932Salfred goto out; 412255932Salfred } 413255932Salfred } 414255932Salfred } 415255932Salfred 416255932Salfredout: 417255932Salfred return ret; 418255932Salfred} 419255932Salfred 420255932Salfredstatic int add_promisc_qp(struct mlx4_dev *dev, u8 port, 421255932Salfred enum mlx4_steer_type steer, u32 qpn) 422255932Salfred{ 423255932Salfred struct mlx4_steer *s_steer; 424255932Salfred struct mlx4_cmd_mailbox *mailbox; 425255932Salfred struct mlx4_mgm *mgm; 426255932Salfred struct mlx4_steer_index *entry; 427255932Salfred struct mlx4_promisc_qp *pqp; 428255932Salfred struct mlx4_promisc_qp *dqp; 429255932Salfred u32 members_count; 430255932Salfred u32 prot; 431255932Salfred int i; 432255932Salfred bool found; 433255932Salfred int err; 434255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 435255932Salfred 436272407Shselasky if (port < 1 || port > dev->caps.num_ports) 437272407Shselasky return -EINVAL; 438272407Shselasky 439255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 440255932Salfred 441255932Salfred mutex_lock(&priv->mcg_table.mutex); 442255932Salfred 443255932Salfred if (get_promisc_qp(dev, port, steer, qpn)) { 444255932Salfred err = 0; /* Noting to do, already exists */ 445255932Salfred goto out_mutex; 446255932Salfred } 447255932Salfred 448255932Salfred pqp = kmalloc(sizeof *pqp, GFP_KERNEL); 449255932Salfred if (!pqp) { 450255932Salfred err = -ENOMEM; 451255932Salfred goto out_mutex; 452255932Salfred } 453255932Salfred pqp->qpn = qpn; 454255932Salfred 455255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 456255932Salfred if (IS_ERR(mailbox)) { 457255932Salfred err = -ENOMEM; 458255932Salfred goto out_alloc; 459255932Salfred } 460255932Salfred mgm = mailbox->buf; 461255932Salfred 462272407Shselasky if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { 463272407Shselasky /* the promisc qp needs to be added for each one of the steering 464272407Shselasky * entries, if it already exists, needs to be added as a duplicate 465272407Shselasky * for this entry */ 466272407Shselasky list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { 467272407Shselasky err = mlx4_READ_ENTRY(dev, entry->index, mailbox); 468272407Shselasky if (err) 469272407Shselasky goto out_mailbox; 470255932Salfred 471272407Shselasky members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 472272407Shselasky prot = be32_to_cpu(mgm->members_count) >> 30; 473272407Shselasky found = false; 474272407Shselasky for (i = 0; i < members_count; i++) { 475272407Shselasky if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { 476272407Shselasky /* Entry already exists, add to duplicates */ 477272407Shselasky dqp = kmalloc(sizeof *dqp, GFP_KERNEL); 478272407Shselasky if (!dqp) { 479272407Shselasky err = -ENOMEM; 480272407Shselasky goto out_mailbox; 481272407Shselasky } 482272407Shselasky dqp->qpn = qpn; 483272407Shselasky list_add_tail(&dqp->list, &entry->duplicates); 484272407Shselasky found = true; 485272407Shselasky } 486272407Shselasky } 487272407Shselasky if (!found) { 488272407Shselasky /* Need to add the qpn to mgm */ 489272407Shselasky if (members_count == dev->caps.num_qp_per_mgm) { 490272407Shselasky /* entry is full */ 491255932Salfred err = -ENOMEM; 492255932Salfred goto out_mailbox; 493255932Salfred } 494272407Shselasky mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); 495272407Shselasky mgm->members_count = cpu_to_be32(members_count | (prot << 30)); 496272407Shselasky err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); 497272407Shselasky if (err) 498272407Shselasky goto out_mailbox; 499255932Salfred } 500255932Salfred } 501255932Salfred } 502255932Salfred 503255932Salfred /* add the new qpn to list of promisc qps */ 504255932Salfred list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); 505255932Salfred /* now need to add all the promisc qps to default entry */ 506255932Salfred memset(mgm, 0, sizeof *mgm); 507255932Salfred members_count = 0; 508255932Salfred list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) { 509255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 510255932Salfred /* entry is full */ 511255932Salfred err = -ENOMEM; 512255932Salfred goto out_list; 513255932Salfred } 514255932Salfred mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); 515255932Salfred } 516255932Salfred mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); 517255932Salfred 518255932Salfred err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); 519255932Salfred if (err) 520255932Salfred goto out_list; 521255932Salfred 522255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 523255932Salfred mutex_unlock(&priv->mcg_table.mutex); 524255932Salfred return 0; 525255932Salfred 526255932Salfredout_list: 527255932Salfred list_del(&pqp->list); 528255932Salfredout_mailbox: 529255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 530255932Salfredout_alloc: 531255932Salfred kfree(pqp); 532255932Salfredout_mutex: 533255932Salfred mutex_unlock(&priv->mcg_table.mutex); 534255932Salfred return err; 535255932Salfred} 536255932Salfred 537255932Salfredstatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port, 538255932Salfred enum mlx4_steer_type steer, u32 qpn) 539255932Salfred{ 540255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 541255932Salfred struct mlx4_steer *s_steer; 542255932Salfred struct mlx4_cmd_mailbox *mailbox; 543255932Salfred struct mlx4_mgm *mgm; 544272407Shselasky struct mlx4_steer_index *entry, *tmp_entry; 545255932Salfred struct mlx4_promisc_qp *pqp; 546255932Salfred struct mlx4_promisc_qp *dqp; 547255932Salfred u32 members_count; 548255932Salfred bool found; 549255932Salfred bool back_to_list = false; 550255932Salfred int i, loc = -1; 551255932Salfred int err; 552255932Salfred 553272407Shselasky if (port < 1 || port > dev->caps.num_ports) 554272407Shselasky return -EINVAL; 555272407Shselasky 556255932Salfred s_steer = &mlx4_priv(dev)->steer[port - 1]; 557255932Salfred mutex_lock(&priv->mcg_table.mutex); 558255932Salfred 559255932Salfred pqp = get_promisc_qp(dev, port, steer, qpn); 560255932Salfred if (unlikely(!pqp)) { 561255932Salfred mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); 562255932Salfred /* nothing to do */ 563255932Salfred err = 0; 564255932Salfred goto out_mutex; 565255932Salfred } 566255932Salfred 567255932Salfred /*remove from list of promisc qps */ 568255932Salfred list_del(&pqp->list); 569255932Salfred 570255932Salfred /* set the default entry not to include the removed one */ 571255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 572255932Salfred if (IS_ERR(mailbox)) { 573255932Salfred err = -ENOMEM; 574255932Salfred back_to_list = true; 575255932Salfred goto out_list; 576255932Salfred } 577255932Salfred mgm = mailbox->buf; 578255932Salfred memset(mgm, 0, sizeof *mgm); 579255932Salfred members_count = 0; 580255932Salfred list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) 581255932Salfred mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); 582255932Salfred mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); 583255932Salfred 584255932Salfred err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); 585255932Salfred if (err) 586255932Salfred goto out_mailbox; 587255932Salfred 588272407Shselasky if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { 589272407Shselasky /* remove the qp from all the steering entries*/ 590272407Shselasky list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { 591272407Shselasky found = false; 592272407Shselasky list_for_each_entry(dqp, &entry->duplicates, list) { 593272407Shselasky if (dqp->qpn == qpn) { 594272407Shselasky found = true; 595255932Salfred break; 596255932Salfred } 597255932Salfred } 598272407Shselasky if (found) { 599272407Shselasky /* a duplicate, no need to change the mgm, 600272407Shselasky * only update the duplicates list */ 601272407Shselasky list_del(&dqp->list); 602272407Shselasky kfree(dqp); 603272407Shselasky } else { 604272407Shselasky err = mlx4_READ_ENTRY(dev, entry->index, mailbox); 605272407Shselasky if (err) 606272407Shselasky goto out_mailbox; 607272407Shselasky members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 608272407Shselasky if (!members_count) { 609272407Shselasky mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0." 610272407Shselasky " deleting entry...\n", qpn, entry->index); 611272407Shselasky list_del(&entry->list); 612272407Shselasky kfree(entry); 613272407Shselasky continue; 614272407Shselasky } 615255932Salfred 616272407Shselasky for (i = 0; i < members_count; ++i) 617272407Shselasky if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { 618272407Shselasky loc = i; 619272407Shselasky break; 620272407Shselasky } 621255932Salfred 622272407Shselasky if (loc < 0) { 623272407Shselasky mlx4_err(dev, "QP %06x wasn't found in entry %d\n", 624272407Shselasky qpn, entry->index); 625272407Shselasky err = -EINVAL; 626255932Salfred goto out_mailbox; 627272407Shselasky } 628272407Shselasky 629272407Shselasky /* copy the last QP in this MGM over removed QP */ 630272407Shselasky mgm->qp[loc] = mgm->qp[members_count - 1]; 631272407Shselasky mgm->qp[members_count - 1] = 0; 632272407Shselasky mgm->members_count = cpu_to_be32(--members_count | 633272407Shselasky (MLX4_PROT_ETH << 30)); 634272407Shselasky 635272407Shselasky err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); 636272407Shselasky if (err) 637272407Shselasky goto out_mailbox; 638272407Shselasky } 639255932Salfred } 640255932Salfred } 641255932Salfred 642255932Salfredout_mailbox: 643255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 644255932Salfredout_list: 645255932Salfred if (back_to_list) 646255932Salfred list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); 647255932Salfred else 648255932Salfred kfree(pqp); 649255932Salfredout_mutex: 650255932Salfred mutex_unlock(&priv->mcg_table.mutex); 651255932Salfred return err; 652255932Salfred} 653255932Salfred 654255932Salfred/* 655219820Sjeff * Caller must hold MCG table semaphore. gid and mgm parameters must 656219820Sjeff * be properly aligned for command interface. 657219820Sjeff * 658219820Sjeff * Returns 0 unless a firmware command error occurs. 659219820Sjeff * 660219820Sjeff * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 661219820Sjeff * and *mgm holds MGM entry. 662219820Sjeff * 663219820Sjeff * if GID is found in AMGM, *index = index in AMGM, *prev = index of 664219820Sjeff * previous entry in hash chain and *mgm holds AMGM entry. 665219820Sjeff * 666219820Sjeff * If no AMGM exists for given gid, *index = -1, *prev = index of last 667219820Sjeff * entry in hash chain and *mgm holds end of hash chain. 668219820Sjeff */ 669255932Salfredstatic int find_entry(struct mlx4_dev *dev, u8 port, 670255932Salfred u8 *gid, enum mlx4_protocol prot, 671255932Salfred struct mlx4_cmd_mailbox *mgm_mailbox, 672255932Salfred int *prev, int *index) 673219820Sjeff{ 674219820Sjeff struct mlx4_cmd_mailbox *mailbox; 675219820Sjeff struct mlx4_mgm *mgm = mgm_mailbox->buf; 676219820Sjeff u8 *mgid; 677219820Sjeff int err; 678255932Salfred u16 hash; 679255932Salfred u8 op_mod = (prot == MLX4_PROT_ETH) ? 680255932Salfred !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0; 681219820Sjeff 682219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 683219820Sjeff if (IS_ERR(mailbox)) 684219820Sjeff return -ENOMEM; 685219820Sjeff mgid = mailbox->buf; 686219820Sjeff 687219820Sjeff memcpy(mgid, gid, 16); 688219820Sjeff 689255932Salfred err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod); 690219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 691219820Sjeff if (err) 692219820Sjeff return err; 693219820Sjeff 694279731Shselasky if (0) { 695279731Shselasky mlx4_dbg(dev, "Hash for "GID_PRINT_FMT" is %04x\n", 696279731Shselasky GID_PRINT_ARGS(gid), hash); 697279731Shselasky } 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 727272407Shselaskystatic const u8 __promisc_mode[] = { 728272407Shselasky [MLX4_FS_REGULAR] = 0x0, 729272407Shselasky [MLX4_FS_ALL_DEFAULT] = 0x1, 730272407Shselasky [MLX4_FS_MC_DEFAULT] = 0x3, 731272407Shselasky [MLX4_FS_UC_SNIFFER] = 0x4, 732272407Shselasky [MLX4_FS_MC_SNIFFER] = 0x5, 733272407Shselasky}; 734272407Shselasky 735272407Shselaskyint map_sw_to_hw_steering_mode(struct mlx4_dev *dev, 736272407Shselasky enum mlx4_net_trans_promisc_mode flow_type) 737272407Shselasky{ 738272407Shselasky if (flow_type >= MLX4_FS_MODE_NUM || flow_type < 0) { 739272407Shselasky mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type); 740272407Shselasky return -EINVAL; 741272407Shselasky } 742272407Shselasky return __promisc_mode[flow_type]; 743272407Shselasky} 744272407ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_mode); 745272407Shselasky 746255932Salfredstatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, 747255932Salfred struct mlx4_net_trans_rule_hw_ctrl *hw) 748219820Sjeff{ 749272407Shselasky u8 flags = 0; 750255932Salfred 751272407Shselasky flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0; 752272407Shselasky flags |= ctrl->exclusive ? (1 << 2) : 0; 753272407Shselasky flags |= ctrl->allow_loopback ? (1 << 3) : 0; 754255932Salfred 755272407Shselasky hw->flags = flags; 756272407Shselasky hw->type = __promisc_mode[ctrl->promisc_mode]; 757272407Shselasky 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 771272407Shselaskyint map_sw_to_hw_steering_id(struct mlx4_dev *dev, 772272407Shselasky enum mlx4_net_trans_rule_id id) 773272407Shselasky{ 774272407Shselasky if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { 775272407Shselasky mlx4_err(dev, "Invalid network rule id. id = %d\n", id); 776272407Shselasky return -EINVAL; 777272407Shselasky } 778272407Shselasky return __sw_id_hw[id]; 779272407Shselasky} 780272407ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_id); 781272407Shselasky 782272407Shselaskystatic const int __rule_hw_sz[] = { 783272407Shselasky [MLX4_NET_TRANS_RULE_ID_ETH] = 784272407Shselasky sizeof(struct mlx4_net_trans_rule_hw_eth), 785272407Shselasky [MLX4_NET_TRANS_RULE_ID_IB] = 786272407Shselasky sizeof(struct mlx4_net_trans_rule_hw_ib), 787272407Shselasky [MLX4_NET_TRANS_RULE_ID_IPV6] = 0, 788272407Shselasky [MLX4_NET_TRANS_RULE_ID_IPV4] = 789272407Shselasky sizeof(struct mlx4_net_trans_rule_hw_ipv4), 790272407Shselasky [MLX4_NET_TRANS_RULE_ID_TCP] = 791272407Shselasky sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), 792272407Shselasky [MLX4_NET_TRANS_RULE_ID_UDP] = 793272407Shselasky sizeof(struct mlx4_net_trans_rule_hw_tcp_udp) 794272407Shselasky}; 795272407Shselasky 796272407Shselaskyint hw_rule_sz(struct mlx4_dev *dev, 797272407Shselasky enum mlx4_net_trans_rule_id id) 798272407Shselasky{ 799272407Shselasky if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { 800272407Shselasky mlx4_err(dev, "Invalid network rule id. id = %d\n", id); 801272407Shselasky return -EINVAL; 802272407Shselasky } 803272407Shselasky 804272407Shselasky return __rule_hw_sz[id]; 805272407Shselasky} 806272407ShselaskyEXPORT_SYMBOL_GPL(hw_rule_sz); 807272407Shselasky 808255932Salfredstatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, 809255932Salfred struct _rule_hw *rule_hw) 810255932Salfred{ 811272407Shselasky if (hw_rule_sz(dev, spec->id) < 0) 812255932Salfred return -EINVAL; 813272407Shselasky memset(rule_hw, 0, hw_rule_sz(dev, spec->id)); 814255932Salfred rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]); 815272407Shselasky 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 } 829272407Shselasky rule_hw->eth.vlan_tag = spec->eth.vlan_id; 830272407Shselasky rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk; 831255932Salfred break; 832255932Salfred 833255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 834272407Shselasky 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, 918279731Shselasky "dst-gid = "GID_PRINT_FMT"\n", 919279731Shselasky GID_PRINT_ARGS(cur->ib.dst_gid)); 920255932Salfred len += snprintf(buf + len, BUF_SIZE - len, 921279731Shselasky "dst-gid-mask = "GID_PRINT_FMT"\n", 922279731Shselasky GID_PRINT_ARGS(cur->ib.dst_gid_msk)); 923255932Salfred break; 924255932Salfred 925255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV6: 926255932Salfred break; 927255932Salfred 928255932Salfred default: 929255932Salfred break; 930255932Salfred } 931255932Salfred } 932255932Salfred len += snprintf(buf + len, BUF_SIZE - len, "\n"); 933255932Salfred mlx4_err(dev, "%s", buf); 934255932Salfred 935255932Salfred if (len >= BUF_SIZE) 936255932Salfred mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n"); 937255932Salfred} 938255932Salfred 939255932Salfredint mlx4_flow_attach(struct mlx4_dev *dev, 940255932Salfred struct mlx4_net_trans_rule *rule, u64 *reg_id) 941255932Salfred{ 942255932Salfred struct mlx4_cmd_mailbox *mailbox; 943255932Salfred struct mlx4_spec_list *cur; 944255932Salfred u32 size = 0; 945255932Salfred int ret; 946255932Salfred 947255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 948255932Salfred if (IS_ERR(mailbox)) 949255932Salfred return PTR_ERR(mailbox); 950255932Salfred 951255932Salfred memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl)); 952255932Salfred trans_rule_ctrl_to_hw(rule, mailbox->buf); 953255932Salfred 954255932Salfred size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); 955255932Salfred 956255932Salfred list_for_each_entry(cur, &rule->list, list) { 957255932Salfred ret = parse_trans_rule(dev, cur, mailbox->buf + size); 958255932Salfred if (ret < 0) { 959255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 960255932Salfred return -EINVAL; 961255932Salfred } 962255932Salfred size += ret; 963255932Salfred } 964255932Salfred 965255932Salfred ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id); 966255932Salfred if (ret == -ENOMEM) 967255932Salfred mlx4_err_rule(dev, 968255932Salfred "mcg table is full. Fail to register network rule.\n", 969255932Salfred rule); 970255932Salfred else if (ret) 971255932Salfred mlx4_err_rule(dev, "Fail to register network rule.\n", rule); 972255932Salfred 973255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 974255932Salfred 975255932Salfred return ret; 976255932Salfred} 977255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_attach); 978255932Salfred 979255932Salfredint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id) 980255932Salfred{ 981255932Salfred int err; 982255932Salfred 983255932Salfred err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id); 984255932Salfred if (err) 985255932Salfred mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n", 986272407Shselasky (unsigned long long)reg_id); 987255932Salfred return err; 988255932Salfred} 989255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_detach); 990255932Salfred 991255932Salfredint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn) 992255932Salfred{ 993255932Salfred int err; 994255932Salfred u64 in_param; 995255932Salfred 996255932Salfred in_param = ((u64) min_range_qpn) << 32; 997255932Salfred in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF; 998255932Salfred 999255932Salfred err = mlx4_cmd(dev, in_param, 0, 0, 1000255932Salfred MLX4_FLOW_STEERING_IB_UC_QP_RANGE, 1001255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1002255932Salfred 1003255932Salfred return err; 1004255932Salfred} 1005255932SalfredEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE); 1006255932Salfred 1007255932Salfredint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1008255932Salfred int block_mcast_loopback, enum mlx4_protocol prot, 1009255932Salfred enum mlx4_steer_type steer) 1010255932Salfred{ 1011219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1012219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1013219820Sjeff struct mlx4_mgm *mgm; 1014219820Sjeff u32 members_count; 1015219820Sjeff int index, prev; 1016219820Sjeff int link = 0; 1017219820Sjeff int i; 1018219820Sjeff int err; 1019255932Salfred u8 port = gid[5]; 1020255932Salfred u8 new_entry = 0; 1021219820Sjeff 1022219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1023219820Sjeff if (IS_ERR(mailbox)) 1024219820Sjeff return PTR_ERR(mailbox); 1025219820Sjeff mgm = mailbox->buf; 1026219820Sjeff 1027219820Sjeff mutex_lock(&priv->mcg_table.mutex); 1028255932Salfred err = find_entry(dev, port, gid, prot, 1029255932Salfred mailbox, &prev, &index); 1030219820Sjeff if (err) 1031219820Sjeff goto out; 1032219820Sjeff 1033219820Sjeff if (index != -1) { 1034255932Salfred if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { 1035255932Salfred new_entry = 1; 1036219820Sjeff memcpy(mgm->gid, gid, 16); 1037255932Salfred } 1038219820Sjeff } else { 1039219820Sjeff link = 1; 1040219820Sjeff 1041219820Sjeff index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); 1042219820Sjeff if (index == -1) { 1043219820Sjeff mlx4_err(dev, "No AMGM entries left\n"); 1044219820Sjeff err = -ENOMEM; 1045219820Sjeff goto out; 1046219820Sjeff } 1047219820Sjeff index += dev->caps.num_mgms; 1048219820Sjeff 1049255932Salfred new_entry = 1; 1050219820Sjeff memset(mgm, 0, sizeof *mgm); 1051219820Sjeff memcpy(mgm->gid, gid, 16); 1052219820Sjeff } 1053219820Sjeff 1054219820Sjeff members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 1055255932Salfred if (members_count == dev->caps.num_qp_per_mgm) { 1056219820Sjeff mlx4_err(dev, "MGM at index %x is full.\n", index); 1057219820Sjeff err = -ENOMEM; 1058219820Sjeff goto out; 1059219820Sjeff } 1060219820Sjeff 1061219820Sjeff for (i = 0; i < members_count; ++i) 1062219820Sjeff if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { 1063219820Sjeff mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); 1064219820Sjeff err = 0; 1065219820Sjeff goto out; 1066219820Sjeff } 1067219820Sjeff 1068219820Sjeff mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | 1069219820Sjeff (!!mlx4_blck_lb << MGM_BLCK_LB_BIT)); 1070219820Sjeff 1071255932Salfred mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); 1072219820Sjeff 1073255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1074219820Sjeff if (err) 1075219820Sjeff goto out; 1076219820Sjeff 1077272407Shselasky /* if !link, still add the new entry. */ 1078219820Sjeff if (!link) 1079272407Shselasky goto skip_link; 1080219820Sjeff 1081255932Salfred err = mlx4_READ_ENTRY(dev, prev, mailbox); 1082219820Sjeff if (err) 1083219820Sjeff goto out; 1084219820Sjeff 1085219820Sjeff mgm->next_gid_index = cpu_to_be32(index << 6); 1086219820Sjeff 1087255932Salfred err = mlx4_WRITE_ENTRY(dev, prev, mailbox); 1088219820Sjeff if (err) 1089219820Sjeff goto out; 1090219820Sjeff 1091272407Shselaskyskip_link: 1092255932Salfred if (prot == MLX4_PROT_ETH) { 1093255932Salfred /* manage the steering entry for promisc mode */ 1094255932Salfred if (new_entry) 1095255932Salfred new_steering_entry(dev, port, steer, index, qp->qpn); 1096255932Salfred else 1097255932Salfred existing_steering_entry(dev, port, steer, 1098255932Salfred index, qp->qpn); 1099255932Salfred } 1100255932Salfred 1101219820Sjeffout: 1102219820Sjeff if (err && link && index != -1) { 1103219820Sjeff if (index < dev->caps.num_mgms) 1104219820Sjeff mlx4_warn(dev, "Got AMGM index %d < %d", 1105219820Sjeff index, dev->caps.num_mgms); 1106219820Sjeff else 1107219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1108272407Shselasky index - dev->caps.num_mgms, MLX4_USE_RR); 1109219820Sjeff } 1110219820Sjeff mutex_unlock(&priv->mcg_table.mutex); 1111219820Sjeff 1112219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1113219820Sjeff return err; 1114219820Sjeff} 1115219820Sjeff 1116255932Salfredint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1117255932Salfred enum mlx4_protocol prot, enum mlx4_steer_type steer) 1118219820Sjeff{ 1119219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1120219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1121219820Sjeff struct mlx4_mgm *mgm; 1122219820Sjeff u32 members_count; 1123219820Sjeff int prev, index; 1124255932Salfred int i, loc = -1; 1125219820Sjeff int err; 1126255932Salfred u8 port = gid[5]; 1127255932Salfred bool removed_entry = false; 1128219820Sjeff 1129219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1130219820Sjeff if (IS_ERR(mailbox)) 1131219820Sjeff return PTR_ERR(mailbox); 1132219820Sjeff mgm = mailbox->buf; 1133219820Sjeff 1134219820Sjeff mutex_lock(&priv->mcg_table.mutex); 1135219820Sjeff 1136255932Salfred err = find_entry(dev, port, gid, prot, 1137255932Salfred mailbox, &prev, &index); 1138219820Sjeff if (err) 1139219820Sjeff goto out; 1140219820Sjeff 1141219820Sjeff if (index == -1) { 1142279731Shselasky mlx4_err(dev, "MGID "GID_PRINT_FMT" not found\n", 1143279731Shselasky GID_PRINT_ARGS(gid)); 1144219820Sjeff err = -EINVAL; 1145219820Sjeff goto out; 1146219820Sjeff } 1147219820Sjeff 1148272407Shselasky /* 1149272407Shselasky if this QP is also a promisc QP, it shouldn't be removed only if 1150272407Shselasky at least one none promisc QP is also attached to this MCG 1151272407Shselasky */ 1152255932Salfred if (prot == MLX4_PROT_ETH && 1153272407Shselasky check_duplicate_entry(dev, port, steer, index, qp->qpn) && 1154272407Shselasky !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL)) 1155272407Shselasky goto out; 1156255932Salfred 1157219820Sjeff members_count = be32_to_cpu(mgm->members_count) & 0xffffff; 1158255932Salfred for (i = 0; i < members_count; ++i) 1159255932Salfred if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { 1160219820Sjeff loc = i; 1161255932Salfred break; 1162255932Salfred } 1163219820Sjeff 1164219820Sjeff if (loc == -1) { 1165219820Sjeff mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); 1166219820Sjeff err = -EINVAL; 1167219820Sjeff goto out; 1168219820Sjeff } 1169219820Sjeff 1170255932Salfred /* copy the last QP in this MGM over removed QP */ 1171255932Salfred mgm->qp[loc] = mgm->qp[members_count - 1]; 1172255932Salfred mgm->qp[members_count - 1] = 0; 1173255932Salfred mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); 1174219820Sjeff 1175255932Salfred if (prot == MLX4_PROT_ETH) 1176255932Salfred removed_entry = can_remove_steering_entry(dev, port, steer, 1177255932Salfred index, qp->qpn); 1178255932Salfred if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) { 1179255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1180219820Sjeff goto out; 1181219820Sjeff } 1182219820Sjeff 1183255932Salfred /* We are going to delete the entry, members count should be 0 */ 1184255932Salfred mgm->members_count = cpu_to_be32((u32) prot << 30); 1185255932Salfred 1186219820Sjeff if (prev == -1) { 1187219820Sjeff /* Remove entry from MGM */ 1188219820Sjeff int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; 1189219820Sjeff if (amgm_index) { 1190255932Salfred err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); 1191219820Sjeff if (err) 1192219820Sjeff goto out; 1193219820Sjeff } else 1194219820Sjeff memset(mgm->gid, 0, 16); 1195219820Sjeff 1196255932Salfred err = mlx4_WRITE_ENTRY(dev, index, mailbox); 1197219820Sjeff if (err) 1198219820Sjeff goto out; 1199219820Sjeff 1200219820Sjeff if (amgm_index) { 1201219820Sjeff if (amgm_index < dev->caps.num_mgms) 1202219820Sjeff mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", 1203219820Sjeff index, amgm_index, dev->caps.num_mgms); 1204219820Sjeff else 1205219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1206272407Shselasky amgm_index - dev->caps.num_mgms, MLX4_USE_RR); 1207219820Sjeff } 1208219820Sjeff } else { 1209219820Sjeff /* Remove entry from AMGM */ 1210219820Sjeff int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 1211255932Salfred err = mlx4_READ_ENTRY(dev, prev, mailbox); 1212219820Sjeff if (err) 1213219820Sjeff goto out; 1214219820Sjeff 1215219820Sjeff mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); 1216219820Sjeff 1217255932Salfred err = mlx4_WRITE_ENTRY(dev, prev, mailbox); 1218219820Sjeff if (err) 1219219820Sjeff goto out; 1220219820Sjeff 1221219820Sjeff if (index < dev->caps.num_mgms) 1222219820Sjeff mlx4_warn(dev, "entry %d had next AMGM index %d < %d", 1223219820Sjeff prev, index, dev->caps.num_mgms); 1224219820Sjeff else 1225219820Sjeff mlx4_bitmap_free(&priv->mcg_table.bitmap, 1226272407Shselasky index - dev->caps.num_mgms, MLX4_USE_RR); 1227219820Sjeff } 1228219820Sjeff 1229219820Sjeffout: 1230219820Sjeff mutex_unlock(&priv->mcg_table.mutex); 1231219820Sjeff 1232219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1233219820Sjeff return err; 1234219820Sjeff} 1235255932Salfred 1236255932Salfredstatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, 1237255932Salfred u8 gid[16], u8 attach, u8 block_loopback, 1238255932Salfred enum mlx4_protocol prot) 1239255932Salfred{ 1240255932Salfred struct mlx4_cmd_mailbox *mailbox; 1241255932Salfred int err = 0; 1242255932Salfred int qpn; 1243255932Salfred 1244255932Salfred if (!mlx4_is_mfunc(dev)) 1245255932Salfred return -EBADF; 1246255932Salfred 1247255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1248255932Salfred if (IS_ERR(mailbox)) 1249255932Salfred return PTR_ERR(mailbox); 1250255932Salfred 1251255932Salfred memcpy(mailbox->buf, gid, 16); 1252255932Salfred qpn = qp->qpn; 1253255932Salfred qpn |= (prot << 28); 1254255932Salfred if (attach && block_loopback) 1255272407Shselasky qpn |= (1 << 31); 1256255932Salfred 1257255932Salfred err = mlx4_cmd(dev, mailbox->dma, qpn, attach, 1258255932Salfred MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A, 1259255932Salfred MLX4_CMD_WRAPPED); 1260255932Salfred 1261255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1262255932Salfred return err; 1263255932Salfred} 1264255932Salfred 1265272407Shselaskyint mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, 1266272407Shselasky u8 gid[16], u8 port, 1267272407Shselasky int block_mcast_loopback, 1268272407Shselasky enum mlx4_protocol prot, u64 *reg_id) 1269255932Salfred{ 1270255932Salfred struct mlx4_spec_list spec = { {NULL} }; 1271255932Salfred __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 1272255932Salfred 1273255932Salfred struct mlx4_net_trans_rule rule = { 1274255932Salfred .queue_mode = MLX4_NET_TRANS_Q_FIFO, 1275255932Salfred .exclusive = 0, 1276255932Salfred .promisc_mode = MLX4_FS_REGULAR, 1277255932Salfred .priority = MLX4_DOMAIN_NIC, 1278255932Salfred }; 1279255932Salfred 1280255932Salfred rule.allow_loopback = !block_mcast_loopback; 1281255932Salfred rule.port = port; 1282255932Salfred rule.qpn = qp->qpn; 1283255932Salfred INIT_LIST_HEAD(&rule.list); 1284255932Salfred 1285255932Salfred switch (prot) { 1286255932Salfred case MLX4_PROT_ETH: 1287255932Salfred spec.id = MLX4_NET_TRANS_RULE_ID_ETH; 1288255932Salfred memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN); 1289255932Salfred memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 1290255932Salfred break; 1291255932Salfred 1292255932Salfred case MLX4_PROT_IB_IPV6: 1293255932Salfred spec.id = MLX4_NET_TRANS_RULE_ID_IB; 1294255932Salfred memcpy(spec.ib.dst_gid, gid, 16); 1295255932Salfred memset(&spec.ib.dst_gid_msk, 0xff, 16); 1296255932Salfred break; 1297255932Salfred default: 1298255932Salfred return -EINVAL; 1299255932Salfred } 1300255932Salfred list_add_tail(&spec.list, &rule.list); 1301255932Salfred 1302255932Salfred return mlx4_flow_attach(dev, &rule, reg_id); 1303272407Shselasky} 1304255932Salfred 1305272407Shselaskyint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1306272407Shselasky u8 port, int block_mcast_loopback, 1307272407Shselasky enum mlx4_protocol prot, u64 *reg_id) 1308272407Shselasky{ 1309272407Shselasky enum mlx4_steer_type steer; 1310272407Shselasky steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; 1311272407Shselasky 1312272407Shselasky switch (dev->caps.steering_mode) { 1313272407Shselasky case MLX4_STEERING_MODE_A0: 1314272407Shselasky if (prot == MLX4_PROT_ETH) 1315272407Shselasky return 0; 1316272407Shselasky 1317272407Shselasky case MLX4_STEERING_MODE_B0: 1318272407Shselasky if (prot == MLX4_PROT_ETH) 1319272407Shselasky gid[7] |= (steer << 1); 1320272407Shselasky 1321272407Shselasky if (mlx4_is_mfunc(dev)) 1322272407Shselasky return mlx4_QP_ATTACH(dev, qp, gid, 1, 1323272407Shselasky block_mcast_loopback, prot); 1324272407Shselasky return mlx4_qp_attach_common(dev, qp, gid, 1325272407Shselasky block_mcast_loopback, prot, 1326272407Shselasky MLX4_MC_STEER); 1327272407Shselasky 1328272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 1329272407Shselasky return mlx4_trans_to_dmfs_attach(dev, qp, gid, port, 1330272407Shselasky block_mcast_loopback, 1331272407Shselasky prot, reg_id); 1332255932Salfred default: 1333255932Salfred return -EINVAL; 1334255932Salfred } 1335255932Salfred} 1336255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_attach); 1337255932Salfred 1338255932Salfredint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 1339255932Salfred enum mlx4_protocol prot, u64 reg_id) 1340255932Salfred{ 1341272407Shselasky enum mlx4_steer_type steer; 1342272407Shselasky steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; 1343272407Shselasky 1344255932Salfred switch (dev->caps.steering_mode) { 1345255932Salfred case MLX4_STEERING_MODE_A0: 1346255932Salfred if (prot == MLX4_PROT_ETH) 1347255932Salfred return 0; 1348255932Salfred 1349255932Salfred case MLX4_STEERING_MODE_B0: 1350255932Salfred if (prot == MLX4_PROT_ETH) 1351272407Shselasky gid[7] |= (steer << 1); 1352255932Salfred 1353255932Salfred if (mlx4_is_mfunc(dev)) 1354255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); 1355255932Salfred 1356255932Salfred return mlx4_qp_detach_common(dev, qp, gid, prot, 1357255932Salfred MLX4_MC_STEER); 1358255932Salfred 1359255932Salfred case MLX4_STEERING_MODE_DEVICE_MANAGED: 1360255932Salfred return mlx4_flow_detach(dev, reg_id); 1361255932Salfred 1362255932Salfred default: 1363255932Salfred return -EINVAL; 1364255932Salfred } 1365255932Salfred} 1366219820SjeffEXPORT_SYMBOL_GPL(mlx4_multicast_detach); 1367219820Sjeff 1368255932Salfredint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, 1369255932Salfred u32 qpn, enum mlx4_net_trans_promisc_mode mode) 1370255932Salfred{ 1371255932Salfred struct mlx4_net_trans_rule rule; 1372255932Salfred u64 *regid_p; 1373255932Salfred 1374255932Salfred switch (mode) { 1375255932Salfred case MLX4_FS_ALL_DEFAULT: 1376255932Salfred regid_p = &dev->regid_promisc_array[port]; 1377255932Salfred break; 1378255932Salfred case MLX4_FS_MC_DEFAULT: 1379255932Salfred regid_p = &dev->regid_allmulti_array[port]; 1380255932Salfred break; 1381255932Salfred default: 1382255932Salfred return -1; 1383255932Salfred } 1384255932Salfred 1385255932Salfred if (*regid_p != 0) 1386255932Salfred return -1; 1387255932Salfred 1388255932Salfred rule.promisc_mode = mode; 1389255932Salfred rule.port = port; 1390255932Salfred rule.qpn = qpn; 1391255932Salfred INIT_LIST_HEAD(&rule.list); 1392255932Salfred mlx4_err(dev, "going promisc on %x\n", port); 1393255932Salfred 1394255932Salfred return mlx4_flow_attach(dev, &rule, regid_p); 1395255932Salfred} 1396255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add); 1397255932Salfred 1398255932Salfredint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port, 1399255932Salfred enum mlx4_net_trans_promisc_mode mode) 1400255932Salfred{ 1401255932Salfred int ret; 1402255932Salfred u64 *regid_p; 1403255932Salfred 1404255932Salfred switch (mode) { 1405255932Salfred case MLX4_FS_ALL_DEFAULT: 1406255932Salfred regid_p = &dev->regid_promisc_array[port]; 1407255932Salfred break; 1408255932Salfred case MLX4_FS_MC_DEFAULT: 1409255932Salfred regid_p = &dev->regid_allmulti_array[port]; 1410255932Salfred break; 1411255932Salfred default: 1412255932Salfred return -1; 1413255932Salfred } 1414255932Salfred 1415255932Salfred if (*regid_p == 0) 1416255932Salfred return -1; 1417255932Salfred 1418255932Salfred ret = mlx4_flow_detach(dev, *regid_p); 1419255932Salfred if (ret == 0) 1420255932Salfred *regid_p = 0; 1421255932Salfred 1422255932Salfred return ret; 1423255932Salfred} 1424255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove); 1425255932Salfred 1426255932Salfredint mlx4_unicast_attach(struct mlx4_dev *dev, 1427255932Salfred struct mlx4_qp *qp, u8 gid[16], 1428255932Salfred int block_mcast_loopback, enum mlx4_protocol prot) 1429255932Salfred{ 1430255932Salfred if (prot == MLX4_PROT_ETH) 1431255932Salfred gid[7] |= (MLX4_UC_STEER << 1); 1432255932Salfred 1433255932Salfred if (mlx4_is_mfunc(dev)) 1434255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 1, 1435255932Salfred block_mcast_loopback, prot); 1436255932Salfred 1437255932Salfred return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback, 1438255932Salfred prot, MLX4_UC_STEER); 1439255932Salfred} 1440255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_attach); 1441255932Salfred 1442255932Salfredint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, 1443255932Salfred u8 gid[16], enum mlx4_protocol prot) 1444255932Salfred{ 1445255932Salfred if (prot == MLX4_PROT_ETH) 1446255932Salfred gid[7] |= (MLX4_UC_STEER << 1); 1447255932Salfred 1448255932Salfred if (mlx4_is_mfunc(dev)) 1449255932Salfred return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); 1450255932Salfred 1451255932Salfred return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER); 1452255932Salfred} 1453255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_detach); 1454255932Salfred 1455255932Salfredint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, 1456255932Salfred struct mlx4_vhcr *vhcr, 1457255932Salfred struct mlx4_cmd_mailbox *inbox, 1458255932Salfred struct mlx4_cmd_mailbox *outbox, 1459255932Salfred struct mlx4_cmd_info *cmd) 1460255932Salfred{ 1461255932Salfred u32 qpn = (u32) vhcr->in_param & 0xffffffff; 1462255932Salfred u8 port = vhcr->in_param >> 62; 1463255932Salfred enum mlx4_steer_type steer = vhcr->in_modifier; 1464255932Salfred 1465272407Shselasky /* Promiscuous unicast is not allowed in mfunc for VFs */ 1466272407Shselasky if ((slave != dev->caps.function) && (steer == MLX4_UC_STEER)) 1467255932Salfred return 0; 1468255932Salfred 1469255932Salfred if (vhcr->op_modifier) 1470255932Salfred return add_promisc_qp(dev, port, steer, qpn); 1471255932Salfred else 1472255932Salfred return remove_promisc_qp(dev, port, steer, qpn); 1473255932Salfred} 1474255932Salfred 1475255932Salfredstatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn, 1476255932Salfred enum mlx4_steer_type steer, u8 add, u8 port) 1477255932Salfred{ 1478255932Salfred return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add, 1479255932Salfred MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A, 1480255932Salfred MLX4_CMD_WRAPPED); 1481255932Salfred} 1482255932Salfred 1483255932Salfredint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) 1484255932Salfred{ 1485255932Salfred if (mlx4_is_mfunc(dev)) 1486255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port); 1487255932Salfred 1488255932Salfred return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn); 1489255932Salfred} 1490255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); 1491255932Salfred 1492255932Salfredint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) 1493255932Salfred{ 1494255932Salfred if (mlx4_is_mfunc(dev)) 1495255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port); 1496255932Salfred 1497255932Salfred return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn); 1498255932Salfred} 1499255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); 1500255932Salfred 1501255932Salfredint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) 1502255932Salfred{ 1503255932Salfred if (mlx4_is_mfunc(dev)) 1504255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port); 1505255932Salfred 1506255932Salfred return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn); 1507255932Salfred} 1508255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); 1509255932Salfred 1510255932Salfredint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) 1511255932Salfred{ 1512255932Salfred if (mlx4_is_mfunc(dev)) 1513255932Salfred return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port); 1514255932Salfred 1515255932Salfred return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn); 1516255932Salfred} 1517255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); 1518255932Salfred 1519219820Sjeffint mlx4_init_mcg_table(struct mlx4_dev *dev) 1520219820Sjeff{ 1521219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1522219820Sjeff int err; 1523219820Sjeff 1524255932Salfred /* No need for mcg_table when fw managed the mcg table*/ 1525255932Salfred if (dev->caps.steering_mode == 1526255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 1527255932Salfred return 0; 1528219820Sjeff err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, 1529219820Sjeff dev->caps.num_amgms - 1, 0, 0); 1530219820Sjeff if (err) 1531219820Sjeff return err; 1532219820Sjeff 1533219820Sjeff mutex_init(&priv->mcg_table.mutex); 1534219820Sjeff 1535219820Sjeff return 0; 1536219820Sjeff} 1537219820Sjeff 1538219820Sjeffvoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev) 1539219820Sjeff{ 1540255932Salfred if (dev->caps.steering_mode != 1541255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 1542255932Salfred mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); 1543219820Sjeff} 1544