1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3272027Shselasky * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. 4219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff */ 34219820Sjeff 35300676Shselasky#define LINUXKPI_PARAM_PREFIX mlx4_ 36300676Shselasky 37272027Shselasky#include <linux/etherdevice.h> 38306486Shselasky#include <dev/mlx4/cmd.h> 39255932Salfred#include <linux/module.h> 40272027Shselasky#include <linux/cache.h> 41219820Sjeff 42329159Shselasky#include <net/ipv6.h> 43329159Shselasky 44219820Sjeff#include "fw.h" 45219820Sjeff#include "icm.h" 46219820Sjeff 47219820Sjeffenum { 48219820Sjeff MLX4_COMMAND_INTERFACE_MIN_REV = 2, 49219820Sjeff MLX4_COMMAND_INTERFACE_MAX_REV = 3, 50219820Sjeff MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS = 3, 51219820Sjeff}; 52219820Sjeff 53219820Sjeffextern void __buggy_use_of_MLX4_GET(void); 54219820Sjeffextern void __buggy_use_of_MLX4_PUT(void); 55219820Sjeff 56329159Shselaskystatic bool enable_qos; 57329159Shselaskymodule_param(enable_qos, bool, 0444); 58329159ShselaskyMODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: off)"); 59219820Sjeff 60219820Sjeff#define MLX4_GET(dest, source, offset) \ 61219820Sjeff do { \ 62219820Sjeff void *__p = (char *) (source) + (offset); \ 63329159Shselasky typedef struct { u64 value; } __packed u64_p_t; \ 64329159Shselasky u64 val; \ 65219820Sjeff switch (sizeof (dest)) { \ 66219820Sjeff case 1: (dest) = *(u8 *) __p; break; \ 67219820Sjeff case 2: (dest) = be16_to_cpup(__p); break; \ 68219820Sjeff case 4: (dest) = be32_to_cpup(__p); break; \ 69329159Shselasky case 8: val = ((u64_p_t *)__p)->value; \ 70329159Shselasky (dest) = be64_to_cpu(val); break; \ 71219820Sjeff default: __buggy_use_of_MLX4_GET(); \ 72219820Sjeff } \ 73219820Sjeff } while (0) 74219820Sjeff 75219820Sjeff#define MLX4_PUT(dest, source, offset) \ 76219820Sjeff do { \ 77219820Sjeff void *__d = ((char *) (dest) + (offset)); \ 78219820Sjeff switch (sizeof(source)) { \ 79219820Sjeff case 1: *(u8 *) __d = (source); break; \ 80219820Sjeff case 2: *(__be16 *) __d = cpu_to_be16(source); break; \ 81219820Sjeff case 4: *(__be32 *) __d = cpu_to_be32(source); break; \ 82219820Sjeff case 8: *(__be64 *) __d = cpu_to_be64(source); break; \ 83219820Sjeff default: __buggy_use_of_MLX4_PUT(); \ 84219820Sjeff } \ 85219820Sjeff } while (0) 86219820Sjeff 87219820Sjeffstatic void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) 88219820Sjeff{ 89219820Sjeff static const char *fname[] = { 90219820Sjeff [ 0] = "RC transport", 91219820Sjeff [ 1] = "UC transport", 92219820Sjeff [ 2] = "UD transport", 93219820Sjeff [ 3] = "XRC transport", 94219820Sjeff [ 6] = "SRQ support", 95219820Sjeff [ 7] = "IPoIB checksum offload", 96219820Sjeff [ 8] = "P_Key violation counter", 97219820Sjeff [ 9] = "Q_Key violation counter", 98329159Shselasky [12] = "Dual Port Different Protocol (DPDP) support", 99255932Salfred [15] = "Big LSO headers", 100219820Sjeff [16] = "MW support", 101219820Sjeff [17] = "APM support", 102219820Sjeff [18] = "Atomic ops support", 103219820Sjeff [19] = "Raw multicast support", 104219820Sjeff [20] = "Address vector port checking support", 105219820Sjeff [21] = "UD multicast support", 106219820Sjeff [30] = "IBoE support", 107255932Salfred [32] = "Unicast loopback support", 108255932Salfred [34] = "FCS header control", 109329159Shselasky [37] = "Wake On LAN (port1) support", 110329159Shselasky [38] = "Wake On LAN (port2) support", 111255932Salfred [40] = "UDP RSS support", 112255932Salfred [41] = "Unicast VEP steering support", 113255932Salfred [42] = "Multicast VEP steering support", 114255932Salfred [48] = "Counters support", 115329159Shselasky [52] = "RSS IP fragments support", 116329159Shselasky [53] = "Port ETS Scheduler support", 117329159Shselasky [55] = "Port link type sensing support", 118255932Salfred [59] = "Port management change event support", 119255932Salfred [61] = "64 byte EQE support", 120255932Salfred [62] = "64 byte CQE support", 121219820Sjeff }; 122219820Sjeff int i; 123219820Sjeff 124219820Sjeff mlx4_dbg(dev, "DEV_CAP flags:\n"); 125219820Sjeff for (i = 0; i < ARRAY_SIZE(fname); ++i) 126219820Sjeff if (fname[i] && (flags & (1LL << i))) 127219820Sjeff mlx4_dbg(dev, " %s\n", fname[i]); 128219820Sjeff} 129219820Sjeff 130255932Salfredstatic void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) 131255932Salfred{ 132255932Salfred static const char * const fname[] = { 133255932Salfred [0] = "RSS support", 134255932Salfred [1] = "RSS Toeplitz Hash Function support", 135255932Salfred [2] = "RSS XOR Hash Function support", 136329159Shselasky [3] = "Device managed flow steering support", 137329159Shselasky [4] = "Automatic MAC reassignment support", 138329159Shselasky [5] = "Time stamping support", 139329159Shselasky [6] = "VST (control vlan insertion/stripping) support", 140329159Shselasky [7] = "FSM (MAC anti-spoofing) support", 141329159Shselasky [8] = "Dynamic QP updates support", 142329159Shselasky [9] = "Device managed flow steering IPoIB support", 143329159Shselasky [10] = "TCP/IP offloads/flow-steering for VXLAN support", 144329159Shselasky [11] = "MAD DEMUX (Secure-Host) support", 145329159Shselasky [12] = "Large cache line (>64B) CQE stride support", 146329159Shselasky [13] = "Large cache line (>64B) EQE stride support", 147329159Shselasky [14] = "Ethernet protocol control support", 148329159Shselasky [15] = "Ethernet Backplane autoneg support", 149329159Shselasky [16] = "CONFIG DEV support", 150329159Shselasky [17] = "Asymmetric EQs support", 151329159Shselasky [18] = "More than 80 VFs support", 152329159Shselasky [19] = "Performance optimized for limited rule configuration flow steering support", 153329159Shselasky [20] = "Recoverable error events support", 154329159Shselasky [21] = "Port Remap support", 155329159Shselasky [22] = "QCN support", 156329159Shselasky [23] = "QP rate limiting support", 157329159Shselasky [24] = "Ethernet Flow control statistics support", 158329159Shselasky [25] = "Granular QoS per VF support", 159329159Shselasky [26] = "Port ETS Scheduler support", 160329159Shselasky [27] = "Port beacon support", 161329159Shselasky [28] = "RX-ALL support", 162329159Shselasky [29] = "802.1ad offload support", 163329159Shselasky [31] = "Modifying loopback source checks using UPDATE_QP support", 164329159Shselasky [32] = "Loopback source checks support", 165329159Shselasky [33] = "RoCEv2 support", 166329159Shselasky [34] = "DMFS Sniffer support (UC & MC)", 167329159Shselasky [35] = "QinQ VST mode support", 168329159Shselasky [36] = "sl to vl mapping table change event support" 169255932Salfred }; 170255932Salfred int i; 171255932Salfred 172255932Salfred for (i = 0; i < ARRAY_SIZE(fname); ++i) 173255932Salfred if (fname[i] && (flags & (1LL << i))) 174255932Salfred mlx4_dbg(dev, " %s\n", fname[i]); 175255932Salfred} 176255932Salfred 177219820Sjeffint mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg) 178219820Sjeff{ 179219820Sjeff struct mlx4_cmd_mailbox *mailbox; 180219820Sjeff u32 *inbox; 181219820Sjeff int err = 0; 182219820Sjeff 183219820Sjeff#define MOD_STAT_CFG_IN_SIZE 0x100 184219820Sjeff 185219820Sjeff#define MOD_STAT_CFG_PG_SZ_M_OFFSET 0x002 186219820Sjeff#define MOD_STAT_CFG_PG_SZ_OFFSET 0x003 187219820Sjeff 188219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 189219820Sjeff if (IS_ERR(mailbox)) 190219820Sjeff return PTR_ERR(mailbox); 191219820Sjeff inbox = mailbox->buf; 192219820Sjeff 193219820Sjeff MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET); 194219820Sjeff MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET); 195219820Sjeff 196219820Sjeff err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_MOD_STAT_CFG, 197255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 198219820Sjeff 199219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 200219820Sjeff return err; 201219820Sjeff} 202219820Sjeff 203329159Shselaskyint mlx4_QUERY_FUNC(struct mlx4_dev *dev, struct mlx4_func *func, int slave) 204329159Shselasky{ 205329159Shselasky struct mlx4_cmd_mailbox *mailbox; 206329159Shselasky u32 *outbox; 207329159Shselasky u8 in_modifier; 208329159Shselasky u8 field; 209329159Shselasky u16 field16; 210329159Shselasky int err; 211329159Shselasky 212329159Shselasky#define QUERY_FUNC_BUS_OFFSET 0x00 213329159Shselasky#define QUERY_FUNC_DEVICE_OFFSET 0x01 214329159Shselasky#define QUERY_FUNC_FUNCTION_OFFSET 0x01 215329159Shselasky#define QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET 0x03 216329159Shselasky#define QUERY_FUNC_RSVD_EQS_OFFSET 0x04 217329159Shselasky#define QUERY_FUNC_MAX_EQ_OFFSET 0x06 218329159Shselasky#define QUERY_FUNC_RSVD_UARS_OFFSET 0x0b 219329159Shselasky 220329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 221329159Shselasky if (IS_ERR(mailbox)) 222329159Shselasky return PTR_ERR(mailbox); 223329159Shselasky outbox = mailbox->buf; 224329159Shselasky 225329159Shselasky in_modifier = slave; 226329159Shselasky 227329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, 0, 228329159Shselasky MLX4_CMD_QUERY_FUNC, 229329159Shselasky MLX4_CMD_TIME_CLASS_A, 230329159Shselasky MLX4_CMD_NATIVE); 231329159Shselasky if (err) 232329159Shselasky goto out; 233329159Shselasky 234329159Shselasky MLX4_GET(field, outbox, QUERY_FUNC_BUS_OFFSET); 235329159Shselasky func->bus = field & 0xf; 236329159Shselasky MLX4_GET(field, outbox, QUERY_FUNC_DEVICE_OFFSET); 237329159Shselasky func->device = field & 0xf1; 238329159Shselasky MLX4_GET(field, outbox, QUERY_FUNC_FUNCTION_OFFSET); 239329159Shselasky func->function = field & 0x7; 240329159Shselasky MLX4_GET(field, outbox, QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET); 241329159Shselasky func->physical_function = field & 0xf; 242329159Shselasky MLX4_GET(field16, outbox, QUERY_FUNC_RSVD_EQS_OFFSET); 243329159Shselasky func->rsvd_eqs = field16 & 0xffff; 244329159Shselasky MLX4_GET(field16, outbox, QUERY_FUNC_MAX_EQ_OFFSET); 245329159Shselasky func->max_eq = field16 & 0xffff; 246329159Shselasky MLX4_GET(field, outbox, QUERY_FUNC_RSVD_UARS_OFFSET); 247329159Shselasky func->rsvd_uars = field & 0x0f; 248329159Shselasky 249329159Shselasky mlx4_dbg(dev, "Bus: %d, Device: %d, Function: %d, Physical function: %d, Max EQs: %d, Reserved EQs: %d, Reserved UARs: %d\n", 250329159Shselasky func->bus, func->device, func->function, func->physical_function, 251329159Shselasky func->max_eq, func->rsvd_eqs, func->rsvd_uars); 252329159Shselasky 253329159Shselaskyout: 254329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 255329159Shselasky return err; 256329159Shselasky} 257329159Shselasky 258329159Shselaskystatic int mlx4_activate_vst_qinq(struct mlx4_priv *priv, int slave, int port) 259329159Shselasky{ 260329159Shselasky struct mlx4_vport_oper_state *vp_oper; 261329159Shselasky struct mlx4_vport_state *vp_admin; 262329159Shselasky int err; 263329159Shselasky 264329159Shselasky vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 265329159Shselasky vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 266329159Shselasky 267329159Shselasky if (vp_admin->default_vlan != vp_oper->state.default_vlan) { 268329159Shselasky err = __mlx4_register_vlan(&priv->dev, port, 269329159Shselasky vp_admin->default_vlan, 270329159Shselasky &vp_oper->vlan_idx); 271329159Shselasky if (err) { 272329159Shselasky vp_oper->vlan_idx = NO_INDX; 273329159Shselasky mlx4_warn(&priv->dev, 274329159Shselasky "No vlan resources slave %d, port %d\n", 275329159Shselasky slave, port); 276329159Shselasky return err; 277329159Shselasky } 278329159Shselasky mlx4_dbg(&priv->dev, "alloc vlan %d idx %d slave %d port %d\n", 279329159Shselasky (int)(vp_oper->state.default_vlan), 280329159Shselasky vp_oper->vlan_idx, slave, port); 281329159Shselasky } 282329159Shselasky vp_oper->state.vlan_proto = vp_admin->vlan_proto; 283329159Shselasky vp_oper->state.default_vlan = vp_admin->default_vlan; 284329159Shselasky vp_oper->state.default_qos = vp_admin->default_qos; 285329159Shselasky 286329159Shselasky return 0; 287329159Shselasky} 288329159Shselasky 289329159Shselaskystatic int mlx4_handle_vst_qinq(struct mlx4_priv *priv, int slave, int port) 290329159Shselasky{ 291329159Shselasky struct mlx4_vport_oper_state *vp_oper; 292329159Shselasky struct mlx4_slave_state *slave_state; 293329159Shselasky struct mlx4_vport_state *vp_admin; 294329159Shselasky int err; 295329159Shselasky 296329159Shselasky vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 297329159Shselasky vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 298329159Shselasky slave_state = &priv->mfunc.master.slave_state[slave]; 299329159Shselasky 300329159Shselasky if ((vp_admin->vlan_proto != htons(ETH_P_8021AD)) || 301329159Shselasky (!slave_state->active)) 302329159Shselasky return 0; 303329159Shselasky 304329159Shselasky if (vp_oper->state.vlan_proto == vp_admin->vlan_proto && 305329159Shselasky vp_oper->state.default_vlan == vp_admin->default_vlan && 306329159Shselasky vp_oper->state.default_qos == vp_admin->default_qos) 307329159Shselasky return 0; 308329159Shselasky 309329159Shselasky if (!slave_state->vst_qinq_supported) { 310329159Shselasky /* Warn and revert the request to set vst QinQ mode */ 311329159Shselasky vp_admin->vlan_proto = vp_oper->state.vlan_proto; 312329159Shselasky vp_admin->default_vlan = vp_oper->state.default_vlan; 313329159Shselasky vp_admin->default_qos = vp_oper->state.default_qos; 314329159Shselasky 315329159Shselasky mlx4_warn(&priv->dev, 316329159Shselasky "Slave %d does not support VST QinQ mode\n", slave); 317329159Shselasky return 0; 318329159Shselasky } 319329159Shselasky 320329159Shselasky err = mlx4_activate_vst_qinq(priv, slave, port); 321329159Shselasky return err; 322329159Shselasky} 323329159Shselasky 324255932Salfredint mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, 325255932Salfred struct mlx4_vhcr *vhcr, 326255932Salfred struct mlx4_cmd_mailbox *inbox, 327255932Salfred struct mlx4_cmd_mailbox *outbox, 328255932Salfred struct mlx4_cmd_info *cmd) 329255932Salfred{ 330255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 331272027Shselasky u8 field, port; 332329159Shselasky u32 size, proxy_qp, qkey; 333255932Salfred int err = 0; 334329159Shselasky struct mlx4_func func; 335255932Salfred 336255932Salfred#define QUERY_FUNC_CAP_FLAGS_OFFSET 0x0 337255932Salfred#define QUERY_FUNC_CAP_NUM_PORTS_OFFSET 0x1 338255932Salfred#define QUERY_FUNC_CAP_PF_BHVR_OFFSET 0x4 339255932Salfred#define QUERY_FUNC_CAP_FMR_OFFSET 0x8 340272027Shselasky#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP 0x10 341272027Shselasky#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP 0x14 342272027Shselasky#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP 0x18 343272027Shselasky#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP 0x20 344272027Shselasky#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP 0x24 345272027Shselasky#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP 0x28 346255932Salfred#define QUERY_FUNC_CAP_MAX_EQ_OFFSET 0x2c 347255932Salfred#define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET 0x30 348329159Shselasky#define QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET 0x48 349255932Salfred 350272027Shselasky#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET 0x50 351272027Shselasky#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET 0x54 352272027Shselasky#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET 0x58 353272027Shselasky#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET 0x60 354272027Shselasky#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET 0x64 355272027Shselasky#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET 0x68 356272027Shselasky 357329159Shselasky#define QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET 0x6c 358329159Shselasky 359255932Salfred#define QUERY_FUNC_CAP_FMR_FLAG 0x80 360255932Salfred#define QUERY_FUNC_CAP_FLAG_RDMA 0x40 361255932Salfred#define QUERY_FUNC_CAP_FLAG_ETH 0x80 362272027Shselasky#define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10 363329159Shselasky#define QUERY_FUNC_CAP_FLAG_RESD_LKEY 0x08 364329159Shselasky#define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX 0x04 365255932Salfred 366329159Shselasky#define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG (1UL << 31) 367329159Shselasky#define QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG (1UL << 30) 368329159Shselasky 369255932Salfred/* when opcode modifier = 1 */ 370255932Salfred#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET 0x3 371329159Shselasky#define QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET 0x4 372272027Shselasky#define QUERY_FUNC_CAP_FLAGS0_OFFSET 0x8 373272027Shselasky#define QUERY_FUNC_CAP_FLAGS1_OFFSET 0xc 374255932Salfred 375255932Salfred#define QUERY_FUNC_CAP_QP0_TUNNEL 0x10 376255932Salfred#define QUERY_FUNC_CAP_QP0_PROXY 0x14 377255932Salfred#define QUERY_FUNC_CAP_QP1_TUNNEL 0x18 378255932Salfred#define QUERY_FUNC_CAP_QP1_PROXY 0x1c 379329159Shselasky#define QUERY_FUNC_CAP_PHYS_PORT_ID 0x28 380255932Salfred 381329159Shselasky#define QUERY_FUNC_CAP_FLAGS1_FORCE_MAC 0x40 382329159Shselasky#define QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN 0x80 383329159Shselasky#define QUERY_FUNC_CAP_FLAGS1_NIC_INFO 0x10 384329159Shselasky#define QUERY_FUNC_CAP_VF_ENABLE_QP0 0x08 385255932Salfred 386329159Shselasky#define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80 387329159Shselasky#define QUERY_FUNC_CAP_PHV_BIT 0x40 388329159Shselasky#define QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE 0x20 389255932Salfred 390329159Shselasky#define QUERY_FUNC_CAP_SUPPORTS_VST_QINQ BIT(30) 391329159Shselasky#define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS BIT(31) 392329159Shselasky 393255932Salfred if (vhcr->op_modifier == 1) { 394329159Shselasky struct mlx4_active_ports actv_ports = 395329159Shselasky mlx4_get_active_ports(dev, slave); 396329159Shselasky int converted_port = mlx4_slave_convert_port( 397329159Shselasky dev, slave, vhcr->in_modifier); 398329159Shselasky struct mlx4_vport_oper_state *vp_oper; 399272027Shselasky 400329159Shselasky if (converted_port < 0) 401329159Shselasky return -EINVAL; 402255932Salfred 403329159Shselasky vhcr->in_modifier = converted_port; 404329159Shselasky /* phys-port = logical-port */ 405329159Shselasky field = vhcr->in_modifier - 406329159Shselasky find_first_bit(actv_ports.ports, dev->caps.num_ports); 407329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET); 408329159Shselasky 409329159Shselasky port = vhcr->in_modifier; 410329159Shselasky proxy_qp = dev->phys_caps.base_proxy_sqpn + 8 * slave + port - 1; 411329159Shselasky 412329159Shselasky /* Set nic_info bit to mark new fields support */ 413329159Shselasky field = QUERY_FUNC_CAP_FLAGS1_NIC_INFO; 414329159Shselasky 415329159Shselasky if (mlx4_vf_smi_enabled(dev, slave, port) && 416329159Shselasky !mlx4_get_parav_qkey(dev, proxy_qp, &qkey)) { 417329159Shselasky field |= QUERY_FUNC_CAP_VF_ENABLE_QP0; 418329159Shselasky MLX4_PUT(outbox->buf, qkey, 419329159Shselasky QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET); 420329159Shselasky } 421272027Shselasky MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET); 422255932Salfred 423255932Salfred /* size is now the QP number */ 424272027Shselasky size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + port - 1; 425255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL); 426255932Salfred 427255932Salfred size += 2; 428255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL); 429255932Salfred 430329159Shselasky MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP0_PROXY); 431329159Shselasky proxy_qp += 2; 432329159Shselasky MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP1_PROXY); 433255932Salfred 434329159Shselasky MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier], 435329159Shselasky QUERY_FUNC_CAP_PHYS_PORT_ID); 436255932Salfred 437329159Shselasky vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 438329159Shselasky err = mlx4_handle_vst_qinq(priv, slave, port); 439329159Shselasky if (err) 440329159Shselasky return err; 441329159Shselasky 442329159Shselasky field = 0; 443329159Shselasky if (dev->caps.phv_bit[port]) 444329159Shselasky field |= QUERY_FUNC_CAP_PHV_BIT; 445329159Shselasky if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) 446329159Shselasky field |= QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE; 447329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS0_OFFSET); 448329159Shselasky 449255932Salfred } else if (vhcr->op_modifier == 0) { 450329159Shselasky struct mlx4_active_ports actv_ports = 451329159Shselasky mlx4_get_active_ports(dev, slave); 452329159Shselasky struct mlx4_slave_state *slave_state = 453329159Shselasky &priv->mfunc.master.slave_state[slave]; 454329159Shselasky 455329159Shselasky /* enable rdma and ethernet interfaces, new quota locations, 456329159Shselasky * and reserved lkey 457329159Shselasky */ 458272027Shselasky field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA | 459329159Shselasky QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX | 460329159Shselasky QUERY_FUNC_CAP_FLAG_RESD_LKEY); 461255932Salfred MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET); 462255932Salfred 463329159Shselasky field = min( 464329159Shselasky bitmap_weight(actv_ports.ports, dev->caps.num_ports), 465329159Shselasky dev->caps.num_ports); 466255932Salfred MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); 467255932Salfred 468255932Salfred size = dev->caps.function_caps; /* set PF behaviours */ 469255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_PF_BHVR_OFFSET); 470255932Salfred 471255932Salfred field = 0; /* protected FMR support not available as yet */ 472255932Salfred MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FMR_OFFSET); 473255932Salfred 474255932Salfred size = priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[slave]; 475255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET); 476272027Shselasky size = dev->caps.num_qps; 477272027Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP); 478255932Salfred 479255932Salfred size = priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[slave]; 480255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET); 481272027Shselasky size = dev->caps.num_srqs; 482272027Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP); 483255932Salfred 484255932Salfred size = priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[slave]; 485255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET); 486272027Shselasky size = dev->caps.num_cqs; 487272027Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP); 488255932Salfred 489329159Shselasky if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) || 490329159Shselasky mlx4_QUERY_FUNC(dev, &func, slave)) { 491329159Shselasky size = vhcr->in_modifier & 492329159Shselasky QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ? 493329159Shselasky dev->caps.num_eqs : 494329159Shselasky rounddown_pow_of_two(dev->caps.num_eqs); 495329159Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET); 496329159Shselasky size = dev->caps.reserved_eqs; 497329159Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); 498329159Shselasky } else { 499329159Shselasky size = vhcr->in_modifier & 500329159Shselasky QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ? 501329159Shselasky func.max_eq : 502329159Shselasky rounddown_pow_of_two(func.max_eq); 503329159Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET); 504329159Shselasky size = func.rsvd_eqs; 505329159Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); 506329159Shselasky } 507255932Salfred 508255932Salfred size = priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[slave]; 509255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET); 510272027Shselasky size = dev->caps.num_mpts; 511272027Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP); 512255932Salfred 513255932Salfred size = priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[slave]; 514255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET); 515272027Shselasky size = dev->caps.num_mtts; 516272027Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP); 517255932Salfred 518255932Salfred size = dev->caps.num_mgms + dev->caps.num_amgms; 519255932Salfred MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET); 520272027Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP); 521255932Salfred 522329159Shselasky size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG | 523329159Shselasky QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG; 524329159Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET); 525329159Shselasky 526329159Shselasky size = dev->caps.reserved_lkey + ((slave << 8) & 0xFF00); 527329159Shselasky MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET); 528329159Shselasky 529329159Shselasky if (vhcr->in_modifier & QUERY_FUNC_CAP_SUPPORTS_VST_QINQ) 530329159Shselasky slave_state->vst_qinq_supported = true; 531329159Shselasky 532255932Salfred } else 533255932Salfred err = -EINVAL; 534255932Salfred 535255932Salfred return err; 536255932Salfred} 537255932Salfred 538329159Shselaskyint mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port, 539255932Salfred struct mlx4_func_cap *func_cap) 540255932Salfred{ 541255932Salfred struct mlx4_cmd_mailbox *mailbox; 542255932Salfred u32 *outbox; 543255932Salfred u8 field, op_modifier; 544329159Shselasky u32 size, qkey; 545272027Shselasky int err = 0, quotas = 0; 546329159Shselasky u32 in_modifier; 547329159Shselasky u32 slave_caps; 548255932Salfred 549255932Salfred op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */ 550329159Shselasky slave_caps = QUERY_FUNC_CAP_SUPPORTS_VST_QINQ | 551329159Shselasky QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS; 552329159Shselasky in_modifier = op_modifier ? gen_or_port : slave_caps; 553255932Salfred 554255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 555255932Salfred if (IS_ERR(mailbox)) 556255932Salfred return PTR_ERR(mailbox); 557255932Salfred 558329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, op_modifier, 559255932Salfred MLX4_CMD_QUERY_FUNC_CAP, 560255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 561255932Salfred if (err) 562255932Salfred goto out; 563255932Salfred 564255932Salfred outbox = mailbox->buf; 565255932Salfred 566255932Salfred if (!op_modifier) { 567255932Salfred MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS_OFFSET); 568255932Salfred if (!(field & (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA))) { 569255932Salfred mlx4_err(dev, "The host supports neither eth nor rdma interfaces\n"); 570255932Salfred err = -EPROTONOSUPPORT; 571255932Salfred goto out; 572255932Salfred } 573255932Salfred func_cap->flags = field; 574272027Shselasky quotas = !!(func_cap->flags & QUERY_FUNC_CAP_FLAG_QUOTAS); 575255932Salfred 576255932Salfred MLX4_GET(field, outbox, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); 577255932Salfred func_cap->num_ports = field; 578255932Salfred 579255932Salfred MLX4_GET(size, outbox, QUERY_FUNC_CAP_PF_BHVR_OFFSET); 580255932Salfred func_cap->pf_context_behaviour = size; 581255932Salfred 582272027Shselasky if (quotas) { 583272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET); 584272027Shselasky func_cap->qp_quota = size & 0xFFFFFF; 585255932Salfred 586272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET); 587272027Shselasky func_cap->srq_quota = size & 0xFFFFFF; 588255932Salfred 589272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET); 590272027Shselasky func_cap->cq_quota = size & 0xFFFFFF; 591255932Salfred 592272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET); 593272027Shselasky func_cap->mpt_quota = size & 0xFFFFFF; 594272027Shselasky 595272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET); 596272027Shselasky func_cap->mtt_quota = size & 0xFFFFFF; 597272027Shselasky 598272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET); 599272027Shselasky func_cap->mcg_quota = size & 0xFFFFFF; 600272027Shselasky 601272027Shselasky } else { 602272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP); 603272027Shselasky func_cap->qp_quota = size & 0xFFFFFF; 604272027Shselasky 605272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP); 606272027Shselasky func_cap->srq_quota = size & 0xFFFFFF; 607272027Shselasky 608272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP); 609272027Shselasky func_cap->cq_quota = size & 0xFFFFFF; 610272027Shselasky 611272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP); 612272027Shselasky func_cap->mpt_quota = size & 0xFFFFFF; 613272027Shselasky 614272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP); 615272027Shselasky func_cap->mtt_quota = size & 0xFFFFFF; 616272027Shselasky 617272027Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP); 618272027Shselasky func_cap->mcg_quota = size & 0xFFFFFF; 619272027Shselasky } 620255932Salfred MLX4_GET(size, outbox, QUERY_FUNC_CAP_MAX_EQ_OFFSET); 621255932Salfred func_cap->max_eq = size & 0xFFFFFF; 622255932Salfred 623255932Salfred MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); 624255932Salfred func_cap->reserved_eq = size & 0xFFFFFF; 625255932Salfred 626329159Shselasky if (func_cap->flags & QUERY_FUNC_CAP_FLAG_RESD_LKEY) { 627329159Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET); 628329159Shselasky func_cap->reserved_lkey = size; 629329159Shselasky } else { 630329159Shselasky func_cap->reserved_lkey = 0; 631329159Shselasky } 632329159Shselasky 633329159Shselasky func_cap->extra_flags = 0; 634329159Shselasky 635329159Shselasky /* Mailbox data from 0x6c and onward should only be treated if 636329159Shselasky * QUERY_FUNC_CAP_FLAG_VALID_MAILBOX is set in func_cap->flags 637329159Shselasky */ 638329159Shselasky if (func_cap->flags & QUERY_FUNC_CAP_FLAG_VALID_MAILBOX) { 639329159Shselasky MLX4_GET(size, outbox, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET); 640329159Shselasky if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG) 641329159Shselasky func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_BF_RES_QP; 642329159Shselasky if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG) 643329159Shselasky func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_A0_RES_QP; 644329159Shselasky } 645329159Shselasky 646255932Salfred goto out; 647255932Salfred } 648255932Salfred 649255932Salfred /* logical port query */ 650255932Salfred if (gen_or_port > dev->caps.num_ports) { 651255932Salfred err = -EINVAL; 652255932Salfred goto out; 653255932Salfred } 654255932Salfred 655329159Shselasky MLX4_GET(func_cap->flags1, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET); 656255932Salfred if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) { 657329159Shselasky if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN) { 658255932Salfred mlx4_err(dev, "VLAN is enforced on this port\n"); 659255932Salfred err = -EPROTONOSUPPORT; 660255932Salfred goto out; 661255932Salfred } 662255932Salfred 663329159Shselasky if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_FORCE_MAC) { 664255932Salfred mlx4_err(dev, "Force mac is enabled on this port\n"); 665255932Salfred err = -EPROTONOSUPPORT; 666255932Salfred goto out; 667255932Salfred } 668255932Salfred } else if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_IB) { 669272027Shselasky MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET); 670329159Shselasky if (field & QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID) { 671329159Shselasky mlx4_err(dev, "phy_wqe_gid is enforced on this ib port\n"); 672255932Salfred err = -EPROTONOSUPPORT; 673255932Salfred goto out; 674255932Salfred } 675255932Salfred } 676255932Salfred 677255932Salfred MLX4_GET(field, outbox, QUERY_FUNC_CAP_PHYS_PORT_OFFSET); 678255932Salfred func_cap->physical_port = field; 679255932Salfred if (func_cap->physical_port != gen_or_port) { 680255932Salfred err = -ENOSYS; 681255932Salfred goto out; 682255932Salfred } 683255932Salfred 684329159Shselasky if (func_cap->flags1 & QUERY_FUNC_CAP_VF_ENABLE_QP0) { 685329159Shselasky MLX4_GET(qkey, outbox, QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET); 686329159Shselasky func_cap->qp0_qkey = qkey; 687272027Shselasky } else { 688329159Shselasky func_cap->qp0_qkey = 0; 689272027Shselasky } 690272027Shselasky 691255932Salfred MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL); 692255932Salfred func_cap->qp0_tunnel_qpn = size & 0xFFFFFF; 693255932Salfred 694255932Salfred MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_PROXY); 695255932Salfred func_cap->qp0_proxy_qpn = size & 0xFFFFFF; 696255932Salfred 697255932Salfred MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_TUNNEL); 698255932Salfred func_cap->qp1_tunnel_qpn = size & 0xFFFFFF; 699255932Salfred 700255932Salfred MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_PROXY); 701255932Salfred func_cap->qp1_proxy_qpn = size & 0xFFFFFF; 702255932Salfred 703329159Shselasky if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_NIC_INFO) 704329159Shselasky MLX4_GET(func_cap->phys_port_id, outbox, 705329159Shselasky QUERY_FUNC_CAP_PHYS_PORT_ID); 706329159Shselasky 707329159Shselasky MLX4_GET(func_cap->flags0, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET); 708329159Shselasky 709255932Salfred /* All other resources are allocated by the master, but we still report 710255932Salfred * 'num' and 'reserved' capabilities as follows: 711255932Salfred * - num remains the maximum resource index 712255932Salfred * - 'num - reserved' is the total available objects of a resource, but 713255932Salfred * resource indices may be less than 'reserved' 714255932Salfred * TODO: set per-resource quotas */ 715255932Salfred 716255932Salfredout: 717255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 718255932Salfred 719255932Salfred return err; 720255932Salfred} 721255932Salfred 722329159Shselaskystatic void disable_unsupported_roce_caps(void *buf); 723329159Shselasky 724219820Sjeffint mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) 725219820Sjeff{ 726219820Sjeff struct mlx4_cmd_mailbox *mailbox; 727219820Sjeff u32 *outbox; 728219820Sjeff u8 field; 729255932Salfred u32 field32, flags, ext_flags; 730219820Sjeff u16 size; 731219820Sjeff u16 stat_rate; 732219820Sjeff int err; 733219820Sjeff int i; 734219820Sjeff 735219820Sjeff#define QUERY_DEV_CAP_OUT_SIZE 0x100 736219820Sjeff#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET 0x10 737219820Sjeff#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET 0x11 738219820Sjeff#define QUERY_DEV_CAP_RSVD_QP_OFFSET 0x12 739219820Sjeff#define QUERY_DEV_CAP_MAX_QP_OFFSET 0x13 740219820Sjeff#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET 0x14 741219820Sjeff#define QUERY_DEV_CAP_MAX_SRQ_OFFSET 0x15 742219820Sjeff#define QUERY_DEV_CAP_RSVD_EEC_OFFSET 0x16 743219820Sjeff#define QUERY_DEV_CAP_MAX_EEC_OFFSET 0x17 744219820Sjeff#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET 0x19 745219820Sjeff#define QUERY_DEV_CAP_RSVD_CQ_OFFSET 0x1a 746219820Sjeff#define QUERY_DEV_CAP_MAX_CQ_OFFSET 0x1b 747219820Sjeff#define QUERY_DEV_CAP_MAX_MPT_OFFSET 0x1d 748219820Sjeff#define QUERY_DEV_CAP_RSVD_EQ_OFFSET 0x1e 749219820Sjeff#define QUERY_DEV_CAP_MAX_EQ_OFFSET 0x1f 750219820Sjeff#define QUERY_DEV_CAP_RSVD_MTT_OFFSET 0x20 751219820Sjeff#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET 0x21 752219820Sjeff#define QUERY_DEV_CAP_RSVD_MRW_OFFSET 0x22 753219820Sjeff#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET 0x23 754329159Shselasky#define QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET 0x26 755219820Sjeff#define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27 756219820Sjeff#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 757219820Sjeff#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b 758219820Sjeff#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d 759255932Salfred#define QUERY_DEV_CAP_RSS_OFFSET 0x2e 760219820Sjeff#define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f 761219820Sjeff#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 762329159Shselasky#define QUERY_DEV_CAP_PORT_BEACON_OFFSET 0x34 763219820Sjeff#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 764219820Sjeff#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET 0x36 765219820Sjeff#define QUERY_DEV_CAP_VL_PORT_OFFSET 0x37 766219820Sjeff#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET 0x38 767219820Sjeff#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b 768219820Sjeff#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c 769255932Salfred#define QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET 0x3e 770219820Sjeff#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f 771219820Sjeff#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET 0x40 772219820Sjeff#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 773219820Sjeff#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 774219820Sjeff#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 775219820Sjeff#define QUERY_DEV_CAP_PAGE_SZ_OFFSET 0x4b 776219820Sjeff#define QUERY_DEV_CAP_BF_OFFSET 0x4c 777219820Sjeff#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET 0x4d 778219820Sjeff#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET 0x4e 779219820Sjeff#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET 0x4f 780219820Sjeff#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET 0x51 781219820Sjeff#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET 0x52 782219820Sjeff#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET 0x55 783219820Sjeff#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET 0x56 784329159Shselasky#define QUERY_DEV_CAP_SVLAN_BY_QP_OFFSET 0x5D 785219820Sjeff#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET 0x61 786219820Sjeff#define QUERY_DEV_CAP_RSVD_MCG_OFFSET 0x62 787219820Sjeff#define QUERY_DEV_CAP_MAX_MCG_OFFSET 0x63 788219820Sjeff#define QUERY_DEV_CAP_RSVD_PD_OFFSET 0x64 789219820Sjeff#define QUERY_DEV_CAP_MAX_PD_OFFSET 0x65 790219820Sjeff#define QUERY_DEV_CAP_RSVD_XRC_OFFSET 0x66 791219820Sjeff#define QUERY_DEV_CAP_MAX_XRC_OFFSET 0x67 792329159Shselasky#define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET 0x68 793272027Shselasky#define QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET 0x70 794329159Shselasky#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET 0x70 795329159Shselasky#define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET 0x74 796255932Salfred#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76 797255932Salfred#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77 798329159Shselasky#define QUERY_DEV_CAP_SL2VL_EVENT_OFFSET 0x78 799329159Shselasky#define QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE 0x7a 800329159Shselasky#define QUERY_DEV_CAP_ECN_QCN_VER_OFFSET 0x7b 801219820Sjeff#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80 802219820Sjeff#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82 803219820Sjeff#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET 0x84 804219820Sjeff#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET 0x86 805219820Sjeff#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET 0x88 806219820Sjeff#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET 0x8a 807219820Sjeff#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET 0x8c 808219820Sjeff#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET 0x8e 809219820Sjeff#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET 0x90 810219820Sjeff#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92 811219820Sjeff#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94 812329159Shselasky#define QUERY_DEV_CAP_CONFIG_DEV_OFFSET 0x94 813329159Shselasky#define QUERY_DEV_CAP_PHV_EN_OFFSET 0x96 814219820Sjeff#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 815219820Sjeff#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 816329159Shselasky#define QUERY_DEV_CAP_ETH_BACKPL_OFFSET 0x9c 817329159Shselasky#define QUERY_DEV_CAP_DIAG_RPRT_PER_PORT 0x9c 818329159Shselasky#define QUERY_DEV_CAP_FW_REASSIGN_MAC 0x9d 819329159Shselasky#define QUERY_DEV_CAP_VXLAN 0x9e 820329159Shselasky#define QUERY_DEV_CAP_MAD_DEMUX_OFFSET 0xb0 821329159Shselasky#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET 0xa8 822329159Shselasky#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET 0xac 823329159Shselasky#define QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET 0xcc 824329159Shselasky#define QUERY_DEV_CAP_QP_RATE_LIMIT_MAX_OFFSET 0xd0 825329159Shselasky#define QUERY_DEV_CAP_QP_RATE_LIMIT_MIN_OFFSET 0xd2 826219820Sjeff 827329159Shselasky 828255932Salfred dev_cap->flags2 = 0; 829219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 830219820Sjeff if (IS_ERR(mailbox)) 831219820Sjeff return PTR_ERR(mailbox); 832219820Sjeff outbox = mailbox->buf; 833219820Sjeff 834219820Sjeff err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, 835255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 836219820Sjeff if (err) 837219820Sjeff goto out; 838219820Sjeff 839329159Shselasky if (mlx4_is_mfunc(dev)) 840329159Shselasky disable_unsupported_roce_caps(outbox); 841219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET); 842219820Sjeff dev_cap->reserved_qps = 1 << (field & 0xf); 843219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET); 844219820Sjeff dev_cap->max_qps = 1 << (field & 0x1f); 845219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET); 846219820Sjeff dev_cap->reserved_srqs = 1 << (field >> 4); 847219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET); 848219820Sjeff dev_cap->max_srqs = 1 << (field & 0x1f); 849219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET); 850219820Sjeff dev_cap->max_cq_sz = 1 << field; 851219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET); 852219820Sjeff dev_cap->reserved_cqs = 1 << (field & 0xf); 853219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET); 854219820Sjeff dev_cap->max_cqs = 1 << (field & 0x1f); 855219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET); 856219820Sjeff dev_cap->max_mpts = 1 << (field & 0x3f); 857219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET); 858329159Shselasky dev_cap->reserved_eqs = 1 << (field & 0xf); 859219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET); 860219820Sjeff dev_cap->max_eqs = 1 << (field & 0xf); 861219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET); 862219820Sjeff dev_cap->reserved_mtts = 1 << (field >> 4); 863219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET); 864219820Sjeff dev_cap->reserved_mrws = 1 << (field & 0xf); 865329159Shselasky MLX4_GET(size, outbox, QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET); 866329159Shselasky dev_cap->num_sys_eqs = size & 0xfff; 867219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET); 868219820Sjeff dev_cap->max_requester_per_qp = 1 << (field & 0x3f); 869219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET); 870219820Sjeff dev_cap->max_responder_per_qp = 1 << (field & 0x3f); 871219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET); 872219820Sjeff field &= 0x1f; 873219820Sjeff if (!field) 874219820Sjeff dev_cap->max_gso_sz = 0; 875219820Sjeff else 876219820Sjeff dev_cap->max_gso_sz = 1 << field; 877219820Sjeff 878255932Salfred MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET); 879255932Salfred if (field & 0x20) 880255932Salfred dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR; 881255932Salfred if (field & 0x10) 882255932Salfred dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP; 883255932Salfred field &= 0xf; 884255932Salfred if (field) { 885255932Salfred dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS; 886255932Salfred dev_cap->max_rss_tbl_sz = 1 << field; 887255932Salfred } else 888255932Salfred dev_cap->max_rss_tbl_sz = 0; 889219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); 890219820Sjeff dev_cap->max_rdma_global = 1 << (field & 0x3f); 891219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); 892219820Sjeff dev_cap->local_ca_ack_delay = field & 0x1f; 893219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); 894219820Sjeff dev_cap->num_ports = field & 0xf; 895219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET); 896219820Sjeff dev_cap->max_msg_sz = 1 << (field & 0x1f); 897272027Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET); 898272027Shselasky if (field & 0x10) 899272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN; 900255932Salfred MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); 901255932Salfred if (field & 0x80) 902255932Salfred dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FS_EN; 903329159Shselasky dev_cap->fs_log_max_ucast_qp_range_size = field & 0x1f; 904329159Shselasky if (field & 0x20) 905329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_UC_MC_SNIFFER; 906329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_BEACON_OFFSET); 907329159Shselasky if (field & 0x80) 908329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_BEACON; 909272027Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET); 910272027Shselasky if (field & 0x80) 911272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB; 912255932Salfred MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET); 913255932Salfred dev_cap->fs_max_num_qp_per_entry = field; 914329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_SL2VL_EVENT_OFFSET); 915329159Shselasky if (field & (1 << 5)) 916329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT; 917329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET); 918329159Shselasky if (field & 0x1) 919329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QCN; 920219820Sjeff MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); 921219820Sjeff dev_cap->stat_rate_support = stat_rate; 922255932Salfred MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET); 923272027Shselasky if (field & 0x80) 924272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_TS; 925255932Salfred MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); 926255932Salfred MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); 927255932Salfred dev_cap->flags = flags | (u64)ext_flags << 32; 928219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); 929219820Sjeff dev_cap->reserved_uars = field >> 4; 930219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET); 931219820Sjeff dev_cap->uar_size = 1 << ((field & 0x3f) + 20); 932219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET); 933219820Sjeff dev_cap->min_page_sz = 1 << field; 934219820Sjeff 935219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET); 936219820Sjeff if (field & 0x80) { 937219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET); 938219820Sjeff dev_cap->bf_reg_size = 1 << (field & 0x1f); 939219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET); 940255932Salfred if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) 941219820Sjeff field = 3; 942219820Sjeff dev_cap->bf_regs_per_page = 1 << (field & 0x3f); 943219820Sjeff } else { 944219820Sjeff dev_cap->bf_reg_size = 0; 945219820Sjeff } 946219820Sjeff 947219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET); 948219820Sjeff dev_cap->max_sq_sg = field; 949219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET); 950219820Sjeff dev_cap->max_sq_desc_sz = size; 951219820Sjeff 952329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_SVLAN_BY_QP_OFFSET); 953329159Shselasky if (field & 0x1) 954329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP; 955219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET); 956219820Sjeff dev_cap->max_qp_per_mcg = 1 << field; 957219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET); 958219820Sjeff dev_cap->reserved_mgms = field & 0xf; 959219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET); 960219820Sjeff dev_cap->max_mcgs = 1 << field; 961219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET); 962219820Sjeff dev_cap->reserved_pds = field >> 4; 963219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET); 964219820Sjeff dev_cap->max_pds = 1 << (field & 0x3f); 965219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_XRC_OFFSET); 966219820Sjeff dev_cap->reserved_xrcds = field >> 4; 967219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_XRC_OFFSET); 968219820Sjeff dev_cap->max_xrcds = 1 << (field & 0x1f); 969219820Sjeff 970219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET); 971219820Sjeff dev_cap->rdmarc_entry_sz = size; 972219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET); 973219820Sjeff dev_cap->qpc_entry_sz = size; 974219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET); 975219820Sjeff dev_cap->aux_entry_sz = size; 976219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET); 977219820Sjeff dev_cap->altc_entry_sz = size; 978219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET); 979219820Sjeff dev_cap->eqc_entry_sz = size; 980219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET); 981219820Sjeff dev_cap->cqc_entry_sz = size; 982219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET); 983219820Sjeff dev_cap->srq_entry_sz = size; 984219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET); 985219820Sjeff dev_cap->cmpt_entry_sz = size; 986219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET); 987219820Sjeff dev_cap->mtt_entry_sz = size; 988219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET); 989219820Sjeff dev_cap->dmpt_entry_sz = size; 990219820Sjeff 991219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET); 992219820Sjeff dev_cap->max_srq_sz = 1 << field; 993219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET); 994219820Sjeff dev_cap->max_qp_sz = 1 << field; 995219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET); 996219820Sjeff dev_cap->resize_srq = field & 1; 997219820Sjeff MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET); 998219820Sjeff dev_cap->max_rq_sg = field; 999219820Sjeff MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET); 1000219820Sjeff dev_cap->max_rq_desc_sz = size; 1001329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE); 1002329159Shselasky if (field & (1 << 4)) 1003329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QOS_VPP; 1004329159Shselasky if (field & (1 << 5)) 1005329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL; 1006329159Shselasky if (field & (1 << 6)) 1007329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CQE_STRIDE; 1008329159Shselasky if (field & (1 << 7)) 1009329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE; 1010219820Sjeff MLX4_GET(dev_cap->bmme_flags, outbox, 1011219820Sjeff QUERY_DEV_CAP_BMME_FLAGS_OFFSET); 1012329159Shselasky if (dev_cap->bmme_flags & MLX4_FLAG_ROCE_V1_V2) 1013329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ROCE_V1_V2; 1014329159Shselasky if (dev_cap->bmme_flags & MLX4_FLAG_PORT_REMAP) 1015329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_REMAP; 1016329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); 1017329159Shselasky if (field & 0x20) 1018329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV; 1019329159Shselasky if (field & (1 << 2)) 1020329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_IGNORE_FCS; 1021329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_PHV_EN_OFFSET); 1022329159Shselasky if (field & 0x80) 1023329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PHV_EN; 1024329159Shselasky if (field & 0x40) 1025329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN; 1026329159Shselasky 1027219820Sjeff MLX4_GET(dev_cap->reserved_lkey, outbox, 1028219820Sjeff QUERY_DEV_CAP_RSVD_LKEY_OFFSET); 1029329159Shselasky MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET); 1030272027Shselasky if (field32 & (1 << 0)) 1031272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP; 1032272027Shselasky if (field32 & (1 << 7)) 1033272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT; 1034329159Shselasky MLX4_GET(field32, outbox, QUERY_DEV_CAP_DIAG_RPRT_PER_PORT); 1035329159Shselasky if (field32 & (1 << 17)) 1036329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT; 1037329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC); 1038329159Shselasky if (field & (1 << 6)) 1039329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN; 1040329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN); 1041329159Shselasky if (field & (1 << 3)) 1042329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS; 1043329159Shselasky if (field & (1 << 5)) 1044272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG; 1045219820Sjeff MLX4_GET(dev_cap->max_icm_sz, outbox, 1046219820Sjeff QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET); 1047255932Salfred if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS) 1048329159Shselasky MLX4_GET(dev_cap->max_counters, outbox, 1049329159Shselasky QUERY_DEV_CAP_MAX_COUNTERS_OFFSET); 1050219820Sjeff 1051329159Shselasky MLX4_GET(field32, outbox, 1052329159Shselasky QUERY_DEV_CAP_MAD_DEMUX_OFFSET); 1053329159Shselasky if (field32 & (1 << 0)) 1054329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_MAD_DEMUX; 1055329159Shselasky 1056329159Shselasky MLX4_GET(dev_cap->dmfs_high_rate_qpn_base, outbox, 1057329159Shselasky QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET); 1058329159Shselasky dev_cap->dmfs_high_rate_qpn_base &= MGM_QPN_MASK; 1059329159Shselasky MLX4_GET(dev_cap->dmfs_high_rate_qpn_range, outbox, 1060329159Shselasky QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET); 1061329159Shselasky dev_cap->dmfs_high_rate_qpn_range &= MGM_QPN_MASK; 1062329159Shselasky 1063329159Shselasky MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET); 1064329159Shselasky dev_cap->rl_caps.num_rates = size; 1065329159Shselasky if (dev_cap->rl_caps.num_rates) { 1066329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT; 1067329159Shselasky MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_MAX_OFFSET); 1068329159Shselasky dev_cap->rl_caps.max_val = size & 0xfff; 1069329159Shselasky dev_cap->rl_caps.max_unit = size >> 14; 1070329159Shselasky MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_MIN_OFFSET); 1071329159Shselasky dev_cap->rl_caps.min_val = size & 0xfff; 1072329159Shselasky dev_cap->rl_caps.min_unit = size >> 14; 1073329159Shselasky } 1074329159Shselasky 1075272027Shselasky MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); 1076272027Shselasky if (field32 & (1 << 16)) 1077272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP; 1078329159Shselasky if (field32 & (1 << 18)) 1079329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB; 1080272027Shselasky if (field32 & (1 << 19)) 1081272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_LB_SRC_CHK; 1082329159Shselasky if (field32 & (1 << 26)) 1083329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL; 1084272027Shselasky if (field32 & (1 << 20)) 1085272027Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM; 1086329159Shselasky if (field32 & (1 << 21)) 1087329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_80_VFS; 1088272027Shselasky 1089329159Shselasky for (i = 1; i <= dev_cap->num_ports; i++) { 1090329159Shselasky err = mlx4_QUERY_PORT(dev, i, dev_cap->port_cap + i); 1091329159Shselasky if (err) 1092329159Shselasky goto out; 1093219820Sjeff } 1094219820Sjeff 1095219820Sjeff /* 1096219820Sjeff * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then 1097219820Sjeff * we can't use any EQs whose doorbell falls on that page, 1098219820Sjeff * even if the EQ itself isn't reserved. 1099219820Sjeff */ 1100329159Shselasky if (dev_cap->num_sys_eqs == 0) 1101329159Shselasky dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4, 1102329159Shselasky dev_cap->reserved_eqs); 1103329159Shselasky else 1104329159Shselasky dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SYS_EQS; 1105219820Sjeff 1106329159Shselaskyout: 1107329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 1108329159Shselasky return err; 1109329159Shselasky} 1110329159Shselasky 1111329159Shselaskyvoid mlx4_dev_cap_dump(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) 1112329159Shselasky{ 1113329159Shselasky if (dev_cap->bf_reg_size > 0) 1114329159Shselasky mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n", 1115329159Shselasky dev_cap->bf_reg_size, dev_cap->bf_regs_per_page); 1116329159Shselasky else 1117329159Shselasky mlx4_dbg(dev, "BlueFlame not available\n"); 1118329159Shselasky 1119329159Shselasky mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n", 1120329159Shselasky dev_cap->bmme_flags, dev_cap->reserved_lkey); 1121219820Sjeff mlx4_dbg(dev, "Max ICM size %lld MB\n", 1122219820Sjeff (unsigned long long) dev_cap->max_icm_sz >> 20); 1123219820Sjeff mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n", 1124219820Sjeff dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz); 1125219820Sjeff mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n", 1126219820Sjeff dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz); 1127219820Sjeff mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n", 1128219820Sjeff dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz); 1129329159Shselasky mlx4_dbg(dev, "Num sys EQs: %d, max EQs: %d, reserved EQs: %d, entry size: %d\n", 1130329159Shselasky dev_cap->num_sys_eqs, dev_cap->max_eqs, dev_cap->reserved_eqs, 1131329159Shselasky dev_cap->eqc_entry_sz); 1132219820Sjeff mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n", 1133219820Sjeff dev_cap->reserved_mrws, dev_cap->reserved_mtts); 1134219820Sjeff mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n", 1135219820Sjeff dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars); 1136219820Sjeff mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", 1137219820Sjeff dev_cap->max_pds, dev_cap->reserved_mgms); 1138219820Sjeff mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", 1139219820Sjeff dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz); 1140219820Sjeff mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n", 1141329159Shselasky dev_cap->local_ca_ack_delay, 128 << dev_cap->port_cap[1].ib_mtu, 1142329159Shselasky dev_cap->port_cap[1].max_port_width); 1143219820Sjeff mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n", 1144219820Sjeff dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg); 1145219820Sjeff mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n", 1146219820Sjeff dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); 1147219820Sjeff mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); 1148329159Shselasky mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters); 1149255932Salfred mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz); 1150329159Shselasky mlx4_dbg(dev, "DMFS high rate steer QPn base: %d\n", 1151329159Shselasky dev_cap->dmfs_high_rate_qpn_base); 1152329159Shselasky mlx4_dbg(dev, "DMFS high rate steer QPn range: %d\n", 1153329159Shselasky dev_cap->dmfs_high_rate_qpn_range); 1154219820Sjeff 1155329159Shselasky if (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT) { 1156329159Shselasky struct mlx4_rate_limit_caps *rl_caps = &dev_cap->rl_caps; 1157329159Shselasky 1158329159Shselasky mlx4_dbg(dev, "QP Rate-Limit: #rates %d, unit/val max %d/%d, min %d/%d\n", 1159329159Shselasky rl_caps->num_rates, rl_caps->max_unit, rl_caps->max_val, 1160329159Shselasky rl_caps->min_unit, rl_caps->min_val); 1161329159Shselasky } 1162329159Shselasky 1163219820Sjeff dump_dev_cap_flags(dev, dev_cap->flags); 1164255932Salfred dump_dev_cap_flags2(dev, dev_cap->flags2); 1165329159Shselasky} 1166219820Sjeff 1167329159Shselaskyint mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_cap) 1168329159Shselasky{ 1169329159Shselasky struct mlx4_cmd_mailbox *mailbox; 1170329159Shselasky u32 *outbox; 1171329159Shselasky u8 field; 1172329159Shselasky u32 field32; 1173329159Shselasky int err; 1174329159Shselasky 1175329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 1176329159Shselasky if (IS_ERR(mailbox)) 1177329159Shselasky return PTR_ERR(mailbox); 1178329159Shselasky outbox = mailbox->buf; 1179329159Shselasky 1180329159Shselasky if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1181329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, 1182329159Shselasky MLX4_CMD_TIME_CLASS_A, 1183329159Shselasky MLX4_CMD_NATIVE); 1184329159Shselasky 1185329159Shselasky if (err) 1186329159Shselasky goto out; 1187329159Shselasky 1188329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); 1189329159Shselasky port_cap->max_vl = field >> 4; 1190329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET); 1191329159Shselasky port_cap->ib_mtu = field >> 4; 1192329159Shselasky port_cap->max_port_width = field & 0xf; 1193329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET); 1194329159Shselasky port_cap->max_gids = 1 << (field & 0xf); 1195329159Shselasky MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET); 1196329159Shselasky port_cap->max_pkeys = 1 << (field & 0xf); 1197329159Shselasky } else { 1198329159Shselasky#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00 1199329159Shselasky#define QUERY_PORT_MTU_OFFSET 0x01 1200329159Shselasky#define QUERY_PORT_ETH_MTU_OFFSET 0x02 1201329159Shselasky#define QUERY_PORT_WIDTH_OFFSET 0x06 1202329159Shselasky#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07 1203329159Shselasky#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a 1204329159Shselasky#define QUERY_PORT_MAX_VL_OFFSET 0x0b 1205329159Shselasky#define QUERY_PORT_MAC_OFFSET 0x10 1206329159Shselasky#define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18 1207329159Shselasky#define QUERY_PORT_WAVELENGTH_OFFSET 0x1c 1208329159Shselasky#define QUERY_PORT_TRANS_CODE_OFFSET 0x20 1209329159Shselasky 1210329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, port, 0, MLX4_CMD_QUERY_PORT, 1211329159Shselasky MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1212329159Shselasky if (err) 1213329159Shselasky goto out; 1214329159Shselasky 1215329159Shselasky MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET); 1216329159Shselasky port_cap->link_state = (field & 0x80) >> 7; 1217329159Shselasky port_cap->supported_port_types = field & 3; 1218329159Shselasky port_cap->suggested_type = (field >> 3) & 1; 1219329159Shselasky port_cap->default_sense = (field >> 4) & 1; 1220329159Shselasky port_cap->dmfs_optimized_state = (field >> 5) & 1; 1221329159Shselasky MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET); 1222329159Shselasky port_cap->ib_mtu = field & 0xf; 1223329159Shselasky MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET); 1224329159Shselasky port_cap->max_port_width = field & 0xf; 1225329159Shselasky MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET); 1226329159Shselasky port_cap->max_gids = 1 << (field >> 4); 1227329159Shselasky port_cap->max_pkeys = 1 << (field & 0xf); 1228329159Shselasky MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET); 1229329159Shselasky port_cap->max_vl = field & 0xf; 1230329159Shselasky port_cap->max_tc_eth = field >> 4; 1231329159Shselasky MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET); 1232329159Shselasky port_cap->log_max_macs = field & 0xf; 1233329159Shselasky port_cap->log_max_vlans = field >> 4; 1234329159Shselasky MLX4_GET(port_cap->eth_mtu, outbox, QUERY_PORT_ETH_MTU_OFFSET); 1235329159Shselasky MLX4_GET(port_cap->def_mac, outbox, QUERY_PORT_MAC_OFFSET); 1236329159Shselasky MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET); 1237329159Shselasky port_cap->trans_type = field32 >> 24; 1238329159Shselasky port_cap->vendor_oui = field32 & 0xffffff; 1239329159Shselasky MLX4_GET(port_cap->wavelength, outbox, QUERY_PORT_WAVELENGTH_OFFSET); 1240329159Shselasky MLX4_GET(port_cap->trans_code, outbox, QUERY_PORT_TRANS_CODE_OFFSET); 1241329159Shselasky } 1242329159Shselasky 1243219820Sjeffout: 1244219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1245219820Sjeff return err; 1246219820Sjeff} 1247219820Sjeff 1248329159Shselasky#define DEV_CAP_EXT_2_FLAG_PFC_COUNTERS (1 << 28) 1249329159Shselasky#define DEV_CAP_EXT_2_FLAG_VLAN_CONTROL (1 << 26) 1250329159Shselasky#define DEV_CAP_EXT_2_FLAG_80_VFS (1 << 21) 1251329159Shselasky#define DEV_CAP_EXT_2_FLAG_FSM (1 << 20) 1252329159Shselasky 1253255932Salfredint mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, 1254255932Salfred struct mlx4_vhcr *vhcr, 1255255932Salfred struct mlx4_cmd_mailbox *inbox, 1256255932Salfred struct mlx4_cmd_mailbox *outbox, 1257255932Salfred struct mlx4_cmd_info *cmd) 1258255932Salfred{ 1259255932Salfred u64 flags; 1260255932Salfred int err = 0; 1261255932Salfred u8 field; 1262329159Shselasky u16 field16; 1263329159Shselasky u32 bmme_flags, field32; 1264329159Shselasky int real_port; 1265329159Shselasky int slave_port; 1266329159Shselasky int first_port; 1267329159Shselasky struct mlx4_active_ports actv_ports; 1268255932Salfred 1269255932Salfred err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, 1270255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1271255932Salfred if (err) 1272255932Salfred return err; 1273255932Salfred 1274329159Shselasky disable_unsupported_roce_caps(outbox->buf); 1275329159Shselasky /* add port mng change event capability and disable mw type 1 1276329159Shselasky * unconditionally to slaves 1277329159Shselasky */ 1278255932Salfred MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); 1279255932Salfred flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV; 1280329159Shselasky flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW; 1281329159Shselasky actv_ports = mlx4_get_active_ports(dev, slave); 1282329159Shselasky first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports); 1283329159Shselasky for (slave_port = 0, real_port = first_port; 1284329159Shselasky real_port < first_port + 1285329159Shselasky bitmap_weight(actv_ports.ports, dev->caps.num_ports); 1286329159Shselasky ++real_port, ++slave_port) { 1287329159Shselasky if (flags & (MLX4_DEV_CAP_FLAG_WOL_PORT1 << real_port)) 1288329159Shselasky flags |= MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port; 1289329159Shselasky else 1290329159Shselasky flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port); 1291329159Shselasky } 1292329159Shselasky for (; slave_port < dev->caps.num_ports; ++slave_port) 1293329159Shselasky flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port); 1294329159Shselasky 1295329159Shselasky /* Not exposing RSS IP fragments to guests */ 1296329159Shselasky flags &= ~MLX4_DEV_CAP_FLAG_RSS_IP_FRAG; 1297255932Salfred MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); 1298255932Salfred 1299329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VL_PORT_OFFSET); 1300329159Shselasky field &= ~0x0F; 1301329159Shselasky field |= bitmap_weight(actv_ports.ports, dev->caps.num_ports) & 0x0F; 1302329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VL_PORT_OFFSET); 1303329159Shselasky 1304329159Shselasky /* For guests, disable timestamp */ 1305329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET); 1306329159Shselasky field &= 0x7f; 1307329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET); 1308329159Shselasky 1309329159Shselasky /* For guests, disable vxlan tunneling and QoS support */ 1310329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN); 1311329159Shselasky field &= 0xd7; 1312329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN); 1313329159Shselasky 1314329159Shselasky /* For guests, disable port BEACON */ 1315329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_PORT_BEACON_OFFSET); 1316329159Shselasky field &= 0x7f; 1317329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_PORT_BEACON_OFFSET); 1318329159Shselasky 1319255932Salfred /* For guests, report Blueflame disabled */ 1320255932Salfred MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET); 1321255932Salfred field &= 0x7f; 1322255932Salfred MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET); 1323255932Salfred 1324329159Shselasky /* For guests, disable mw type 2 and port remap*/ 1325329159Shselasky MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); 1326329159Shselasky bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN; 1327329159Shselasky bmme_flags &= ~MLX4_FLAG_PORT_REMAP; 1328329159Shselasky MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); 1329329159Shselasky 1330272027Shselasky /* turn off device-managed steering capability if not enabled */ 1331272027Shselasky if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) { 1332272027Shselasky MLX4_GET(field, outbox->buf, 1333272027Shselasky QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); 1334272027Shselasky field &= 0x7f; 1335272027Shselasky MLX4_PUT(outbox->buf, field, 1336272027Shselasky QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); 1337272027Shselasky } 1338329159Shselasky 1339329159Shselasky /* turn off ipoib managed steering for guests */ 1340329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET); 1341329159Shselasky field &= ~0x80; 1342329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET); 1343329159Shselasky 1344329159Shselasky /* turn off host side virt features (VST, FSM, etc) for guests */ 1345329159Shselasky MLX4_GET(field32, outbox->buf, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); 1346329159Shselasky field32 &= ~(DEV_CAP_EXT_2_FLAG_VLAN_CONTROL | DEV_CAP_EXT_2_FLAG_80_VFS | 1347329159Shselasky DEV_CAP_EXT_2_FLAG_FSM | DEV_CAP_EXT_2_FLAG_PFC_COUNTERS); 1348329159Shselasky MLX4_PUT(outbox->buf, field32, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); 1349329159Shselasky 1350329159Shselasky /* turn off QCN for guests */ 1351329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET); 1352329159Shselasky field &= 0xfe; 1353329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET); 1354329159Shselasky 1355329159Shselasky /* turn off QP max-rate limiting for guests */ 1356329159Shselasky field16 = 0; 1357329159Shselasky MLX4_PUT(outbox->buf, field16, QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET); 1358329159Shselasky 1359329159Shselasky /* turn off QoS per VF support for guests */ 1360329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE); 1361329159Shselasky field &= 0xef; 1362329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE); 1363329159Shselasky 1364329159Shselasky /* turn off ignore FCS feature for guests */ 1365329159Shselasky MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); 1366329159Shselasky field &= 0xfb; 1367329159Shselasky MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); 1368329159Shselasky 1369255932Salfred return 0; 1370255932Salfred} 1371255932Salfred 1372329159Shselaskystatic void disable_unsupported_roce_caps(void *buf) 1373329159Shselasky{ 1374329159Shselasky u32 flags; 1375329159Shselasky 1376329159Shselasky MLX4_GET(flags, buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); 1377329159Shselasky flags &= ~(1UL << 31); 1378329159Shselasky MLX4_PUT(buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); 1379329159Shselasky MLX4_GET(flags, buf, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); 1380329159Shselasky flags &= ~(1UL << 24); 1381329159Shselasky MLX4_PUT(buf, flags, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); 1382329159Shselasky MLX4_GET(flags, buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); 1383329159Shselasky flags &= ~(MLX4_FLAG_ROCE_V1_V2); 1384329159Shselasky MLX4_PUT(buf, flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); 1385329159Shselasky} 1386329159Shselasky 1387255932Salfredint mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, 1388255932Salfred struct mlx4_vhcr *vhcr, 1389255932Salfred struct mlx4_cmd_mailbox *inbox, 1390255932Salfred struct mlx4_cmd_mailbox *outbox, 1391255932Salfred struct mlx4_cmd_info *cmd) 1392255932Salfred{ 1393255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1394255932Salfred u64 def_mac; 1395255932Salfred u8 port_type; 1396255932Salfred u16 short_field; 1397255932Salfred int err; 1398329159Shselasky int port = mlx4_slave_convert_port(dev, slave, 1399329159Shselasky vhcr->in_modifier & 0xFF); 1400255932Salfred 1401255932Salfred#define MLX4_VF_PORT_NO_LINK_SENSE_MASK 0xE0 1402272027Shselasky#define MLX4_PORT_LINK_UP_MASK 0x80 1403255932Salfred#define QUERY_PORT_CUR_MAX_PKEY_OFFSET 0x0c 1404255932Salfred#define QUERY_PORT_CUR_MAX_GID_OFFSET 0x0e 1405255932Salfred 1406329159Shselasky if (port < 0) 1407329159Shselasky return -EINVAL; 1408329159Shselasky 1409329159Shselasky /* Protect against untrusted guests: enforce that this is the 1410329159Shselasky * QUERY_PORT general query. 1411329159Shselasky */ 1412329159Shselasky if (vhcr->op_modifier || vhcr->in_modifier & ~0xFF) 1413329159Shselasky return -EINVAL; 1414329159Shselasky 1415329159Shselasky vhcr->in_modifier = port; 1416329159Shselasky 1417255932Salfred err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0, 1418255932Salfred MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, 1419255932Salfred MLX4_CMD_NATIVE); 1420255932Salfred 1421255932Salfred if (!err && dev->caps.function != slave) { 1422272027Shselasky def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; 1423255932Salfred MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET); 1424255932Salfred 1425255932Salfred /* get port type - currently only eth is enabled */ 1426255932Salfred MLX4_GET(port_type, outbox->buf, 1427255932Salfred QUERY_PORT_SUPPORTED_TYPE_OFFSET); 1428255932Salfred 1429255932Salfred /* No link sensing allowed */ 1430255932Salfred port_type &= MLX4_VF_PORT_NO_LINK_SENSE_MASK; 1431255932Salfred /* set port type to currently operating port type */ 1432255932Salfred port_type |= (dev->caps.port_type[vhcr->in_modifier] & 0x3); 1433255932Salfred 1434329159Shselasky if (0 /* IFLA_VF_LINK_STATE_ENABLE == admin_link_state */) 1435272027Shselasky port_type |= MLX4_PORT_LINK_UP_MASK; 1436329159Shselasky else if (1 /* IFLA_VF_LINK_STATE_DISABLE == admin_link_state */) 1437272027Shselasky port_type &= ~MLX4_PORT_LINK_UP_MASK; 1438329159Shselasky else if (0 /* IFLA_VF_LINK_STATE_AUTO == admin_link_state && mlx4_is_bonded(dev) */) { 1439329159Shselasky int other_port = (port == 1) ? 2 : 1; 1440329159Shselasky struct mlx4_port_cap port_cap; 1441272027Shselasky 1442329159Shselasky err = mlx4_QUERY_PORT(dev, other_port, &port_cap); 1443329159Shselasky if (err) 1444329159Shselasky goto out; 1445329159Shselasky port_type |= (port_cap.link_state << 7); 1446329159Shselasky } 1447329159Shselasky 1448255932Salfred MLX4_PUT(outbox->buf, port_type, 1449255932Salfred QUERY_PORT_SUPPORTED_TYPE_OFFSET); 1450255932Salfred 1451255932Salfred if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH) 1452329159Shselasky short_field = mlx4_get_slave_num_gids(dev, slave, port); 1453255932Salfred else 1454255932Salfred short_field = 1; /* slave max gids */ 1455255932Salfred MLX4_PUT(outbox->buf, short_field, 1456255932Salfred QUERY_PORT_CUR_MAX_GID_OFFSET); 1457255932Salfred 1458255932Salfred short_field = dev->caps.pkey_table_len[vhcr->in_modifier]; 1459255932Salfred MLX4_PUT(outbox->buf, short_field, 1460255932Salfred QUERY_PORT_CUR_MAX_PKEY_OFFSET); 1461255932Salfred } 1462329159Shselaskyout: 1463255932Salfred return err; 1464255932Salfred} 1465255932Salfred 1466255932Salfredint mlx4_get_slave_pkey_gid_tbl_len(struct mlx4_dev *dev, u8 port, 1467255932Salfred int *gid_tbl_len, int *pkey_tbl_len) 1468255932Salfred{ 1469255932Salfred struct mlx4_cmd_mailbox *mailbox; 1470255932Salfred u32 *outbox; 1471255932Salfred u16 field; 1472255932Salfred int err; 1473255932Salfred 1474255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1475255932Salfred if (IS_ERR(mailbox)) 1476255932Salfred return PTR_ERR(mailbox); 1477255932Salfred 1478255932Salfred err = mlx4_cmd_box(dev, 0, mailbox->dma, port, 0, 1479255932Salfred MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, 1480255932Salfred MLX4_CMD_WRAPPED); 1481255932Salfred if (err) 1482255932Salfred goto out; 1483255932Salfred 1484255932Salfred outbox = mailbox->buf; 1485255932Salfred 1486255932Salfred MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_GID_OFFSET); 1487255932Salfred *gid_tbl_len = field; 1488255932Salfred 1489255932Salfred MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_PKEY_OFFSET); 1490255932Salfred *pkey_tbl_len = field; 1491255932Salfred 1492255932Salfredout: 1493255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1494255932Salfred return err; 1495255932Salfred} 1496255932SalfredEXPORT_SYMBOL(mlx4_get_slave_pkey_gid_tbl_len); 1497255932Salfred 1498219820Sjeffint mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt) 1499219820Sjeff{ 1500219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1501219820Sjeff struct mlx4_icm_iter iter; 1502219820Sjeff __be64 *pages; 1503219820Sjeff int lg; 1504219820Sjeff int nent = 0; 1505219820Sjeff int i; 1506219820Sjeff int err = 0; 1507219820Sjeff int ts = 0, tc = 0; 1508219820Sjeff 1509219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1510219820Sjeff if (IS_ERR(mailbox)) 1511219820Sjeff return PTR_ERR(mailbox); 1512219820Sjeff pages = mailbox->buf; 1513219820Sjeff 1514219820Sjeff for (mlx4_icm_first(icm, &iter); 1515219820Sjeff !mlx4_icm_last(&iter); 1516219820Sjeff mlx4_icm_next(&iter)) { 1517219820Sjeff /* 1518219820Sjeff * We have to pass pages that are aligned to their 1519219820Sjeff * size, so find the least significant 1 in the 1520219820Sjeff * address or size and use that as our log2 size. 1521219820Sjeff */ 1522219820Sjeff lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1; 1523219820Sjeff if (lg < MLX4_ICM_PAGE_SHIFT) { 1524329159Shselasky mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx)\n", 1525329159Shselasky MLX4_ICM_PAGE_SIZE, 1526329159Shselasky (unsigned long long) mlx4_icm_addr(&iter), 1527329159Shselasky mlx4_icm_size(&iter)); 1528219820Sjeff err = -EINVAL; 1529219820Sjeff goto out; 1530219820Sjeff } 1531219820Sjeff 1532219820Sjeff for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) { 1533219820Sjeff if (virt != -1) { 1534219820Sjeff pages[nent * 2] = cpu_to_be64(virt); 1535219820Sjeff virt += 1 << lg; 1536219820Sjeff } 1537219820Sjeff 1538219820Sjeff pages[nent * 2 + 1] = 1539219820Sjeff cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) | 1540219820Sjeff (lg - MLX4_ICM_PAGE_SHIFT)); 1541219820Sjeff ts += 1 << (lg - 10); 1542219820Sjeff ++tc; 1543219820Sjeff 1544219820Sjeff if (++nent == MLX4_MAILBOX_SIZE / 16) { 1545219820Sjeff err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, 1546255932Salfred MLX4_CMD_TIME_CLASS_B, 1547255932Salfred MLX4_CMD_NATIVE); 1548219820Sjeff if (err) 1549219820Sjeff goto out; 1550219820Sjeff nent = 0; 1551219820Sjeff } 1552219820Sjeff } 1553219820Sjeff } 1554219820Sjeff 1555219820Sjeff if (nent) 1556255932Salfred err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, 1557255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1558219820Sjeff if (err) 1559219820Sjeff goto out; 1560219820Sjeff 1561219820Sjeff switch (op) { 1562219820Sjeff case MLX4_CMD_MAP_FA: 1563329159Shselasky mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW\n", tc, ts); 1564219820Sjeff break; 1565219820Sjeff case MLX4_CMD_MAP_ICM_AUX: 1566329159Shselasky mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux\n", tc, ts); 1567219820Sjeff break; 1568219820Sjeff case MLX4_CMD_MAP_ICM: 1569329159Shselasky mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM\n", 1570329159Shselasky tc, ts, (unsigned long long) virt - (ts << 10)); 1571219820Sjeff break; 1572219820Sjeff } 1573219820Sjeff 1574219820Sjeffout: 1575219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1576219820Sjeff return err; 1577219820Sjeff} 1578219820Sjeff 1579219820Sjeffint mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm) 1580219820Sjeff{ 1581219820Sjeff return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1); 1582219820Sjeff} 1583219820Sjeff 1584219820Sjeffint mlx4_UNMAP_FA(struct mlx4_dev *dev) 1585219820Sjeff{ 1586255932Salfred return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA, 1587255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1588219820Sjeff} 1589219820Sjeff 1590219820Sjeff 1591219820Sjeffint mlx4_RUN_FW(struct mlx4_dev *dev) 1592219820Sjeff{ 1593255932Salfred return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW, 1594255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1595219820Sjeff} 1596219820Sjeff 1597219820Sjeffint mlx4_QUERY_FW(struct mlx4_dev *dev) 1598219820Sjeff{ 1599219820Sjeff struct mlx4_fw *fw = &mlx4_priv(dev)->fw; 1600219820Sjeff struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 1601219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1602219820Sjeff u32 *outbox; 1603219820Sjeff int err = 0; 1604219820Sjeff u64 fw_ver; 1605219820Sjeff u16 cmd_if_rev; 1606219820Sjeff u8 lg; 1607219820Sjeff 1608219820Sjeff#define QUERY_FW_OUT_SIZE 0x100 1609219820Sjeff#define QUERY_FW_VER_OFFSET 0x00 1610255932Salfred#define QUERY_FW_PPF_ID 0x09 1611219820Sjeff#define QUERY_FW_CMD_IF_REV_OFFSET 0x0a 1612219820Sjeff#define QUERY_FW_MAX_CMD_OFFSET 0x0f 1613219820Sjeff#define QUERY_FW_ERR_START_OFFSET 0x30 1614219820Sjeff#define QUERY_FW_ERR_SIZE_OFFSET 0x38 1615219820Sjeff#define QUERY_FW_ERR_BAR_OFFSET 0x3c 1616219820Sjeff 1617219820Sjeff#define QUERY_FW_SIZE_OFFSET 0x00 1618219820Sjeff#define QUERY_FW_CLR_INT_BASE_OFFSET 0x20 1619219820Sjeff#define QUERY_FW_CLR_INT_BAR_OFFSET 0x28 1620219820Sjeff 1621255932Salfred#define QUERY_FW_COMM_BASE_OFFSET 0x40 1622255932Salfred#define QUERY_FW_COMM_BAR_OFFSET 0x48 1623255932Salfred 1624255932Salfred#define QUERY_FW_CLOCK_OFFSET 0x50 1625255932Salfred#define QUERY_FW_CLOCK_BAR 0x58 1626255932Salfred 1627219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1628219820Sjeff if (IS_ERR(mailbox)) 1629219820Sjeff return PTR_ERR(mailbox); 1630219820Sjeff outbox = mailbox->buf; 1631219820Sjeff 1632219820Sjeff err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW, 1633255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1634219820Sjeff if (err) 1635219820Sjeff goto out; 1636219820Sjeff 1637219820Sjeff MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET); 1638219820Sjeff /* 1639219820Sjeff * FW subminor version is at more significant bits than minor 1640219820Sjeff * version, so swap here. 1641219820Sjeff */ 1642219820Sjeff dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) | 1643219820Sjeff ((fw_ver & 0xffff0000ull) >> 16) | 1644219820Sjeff ((fw_ver & 0x0000ffffull) << 16); 1645219820Sjeff 1646255932Salfred MLX4_GET(lg, outbox, QUERY_FW_PPF_ID); 1647255932Salfred dev->caps.function = lg; 1648255932Salfred 1649255932Salfred if (mlx4_is_slave(dev)) 1650255932Salfred goto out; 1651255932Salfred 1652255932Salfred 1653219820Sjeff MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET); 1654219820Sjeff if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV || 1655219820Sjeff cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) { 1656329159Shselasky mlx4_err(dev, "Installed FW has unsupported command interface revision %d\n", 1657219820Sjeff cmd_if_rev); 1658219820Sjeff mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n", 1659219820Sjeff (int) (dev->caps.fw_ver >> 32), 1660219820Sjeff (int) (dev->caps.fw_ver >> 16) & 0xffff, 1661219820Sjeff (int) dev->caps.fw_ver & 0xffff); 1662329159Shselasky mlx4_err(dev, "This driver version supports only revisions %d to %d\n", 1663219820Sjeff MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV); 1664219820Sjeff err = -ENODEV; 1665219820Sjeff goto out; 1666219820Sjeff } 1667219820Sjeff 1668219820Sjeff if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS) 1669219820Sjeff dev->flags |= MLX4_FLAG_OLD_PORT_CMDS; 1670219820Sjeff 1671219820Sjeff MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); 1672219820Sjeff cmd->max_cmds = 1 << lg; 1673219820Sjeff 1674219820Sjeff mlx4_dbg(dev, "FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n", 1675219820Sjeff (int) (dev->caps.fw_ver >> 32), 1676219820Sjeff (int) (dev->caps.fw_ver >> 16) & 0xffff, 1677219820Sjeff (int) dev->caps.fw_ver & 0xffff, 1678219820Sjeff cmd_if_rev, cmd->max_cmds); 1679219820Sjeff 1680219820Sjeff MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET); 1681219820Sjeff MLX4_GET(fw->catas_size, outbox, QUERY_FW_ERR_SIZE_OFFSET); 1682219820Sjeff MLX4_GET(fw->catas_bar, outbox, QUERY_FW_ERR_BAR_OFFSET); 1683219820Sjeff fw->catas_bar = (fw->catas_bar >> 6) * 2; 1684219820Sjeff 1685219820Sjeff mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n", 1686219820Sjeff (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar); 1687219820Sjeff 1688219820Sjeff MLX4_GET(fw->fw_pages, outbox, QUERY_FW_SIZE_OFFSET); 1689219820Sjeff MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); 1690219820Sjeff MLX4_GET(fw->clr_int_bar, outbox, QUERY_FW_CLR_INT_BAR_OFFSET); 1691219820Sjeff fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2; 1692219820Sjeff 1693255932Salfred MLX4_GET(fw->comm_base, outbox, QUERY_FW_COMM_BASE_OFFSET); 1694255932Salfred MLX4_GET(fw->comm_bar, outbox, QUERY_FW_COMM_BAR_OFFSET); 1695255932Salfred fw->comm_bar = (fw->comm_bar >> 6) * 2; 1696255932Salfred mlx4_dbg(dev, "Communication vector bar:%d offset:0x%llx\n", 1697272027Shselasky fw->comm_bar, (unsigned long long)fw->comm_base); 1698219820Sjeff mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2); 1699219820Sjeff 1700255932Salfred MLX4_GET(fw->clock_offset, outbox, QUERY_FW_CLOCK_OFFSET); 1701255932Salfred MLX4_GET(fw->clock_bar, outbox, QUERY_FW_CLOCK_BAR); 1702255932Salfred fw->clock_bar = (fw->clock_bar >> 6) * 2; 1703255932Salfred mlx4_dbg(dev, "Internal clock bar:%d offset:0x%llx\n", 1704329159Shselasky fw->clock_bar, (unsigned long long)fw->clock_offset); 1705255932Salfred 1706219820Sjeff /* 1707219820Sjeff * Round up number of system pages needed in case 1708219820Sjeff * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. 1709219820Sjeff */ 1710219820Sjeff fw->fw_pages = 1711219820Sjeff ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> 1712219820Sjeff (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); 1713219820Sjeff 1714219820Sjeff mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n", 1715219820Sjeff (unsigned long long) fw->clr_int_base, fw->clr_int_bar); 1716219820Sjeff 1717219820Sjeffout: 1718219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1719219820Sjeff return err; 1720219820Sjeff} 1721219820Sjeff 1722255932Salfredint mlx4_QUERY_FW_wrapper(struct mlx4_dev *dev, int slave, 1723255932Salfred struct mlx4_vhcr *vhcr, 1724255932Salfred struct mlx4_cmd_mailbox *inbox, 1725255932Salfred struct mlx4_cmd_mailbox *outbox, 1726255932Salfred struct mlx4_cmd_info *cmd) 1727255932Salfred{ 1728255932Salfred u8 *outbuf; 1729255932Salfred int err; 1730255932Salfred 1731255932Salfred outbuf = outbox->buf; 1732255932Salfred err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_FW, 1733255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1734255932Salfred if (err) 1735255932Salfred return err; 1736255932Salfred 1737255932Salfred /* for slaves, set pci PPF ID to invalid and zero out everything 1738255932Salfred * else except FW version */ 1739255932Salfred outbuf[0] = outbuf[1] = 0; 1740255932Salfred memset(&outbuf[8], 0, QUERY_FW_OUT_SIZE - 8); 1741255932Salfred outbuf[QUERY_FW_PPF_ID] = MLX4_INVALID_SLAVE_ID; 1742255932Salfred 1743255932Salfred return 0; 1744255932Salfred} 1745255932Salfred 1746329159Shselaskystatic void get_board_id(void *vsd, char *board_id) 1747219820Sjeff{ 1748219820Sjeff int i; 1749219820Sjeff 1750219820Sjeff#define VSD_OFFSET_SIG1 0x00 1751219820Sjeff#define VSD_OFFSET_SIG2 0xde 1752219820Sjeff#define VSD_OFFSET_MLX_BOARD_ID 0xd0 1753219820Sjeff#define VSD_OFFSET_TS_BOARD_ID 0x20 1754219820Sjeff 1755219820Sjeff#define VSD_SIGNATURE_TOPSPIN 0x5ad 1756219820Sjeff 1757219820Sjeff memset(board_id, 0, MLX4_BOARD_ID_LEN); 1758219820Sjeff 1759219820Sjeff if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN && 1760219820Sjeff be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) { 1761219820Sjeff strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN); 1762219820Sjeff } else { 1763219820Sjeff /* 1764219820Sjeff * The board ID is a string but the firmware byte 1765219820Sjeff * swaps each 4-byte word before passing it back to 1766219820Sjeff * us. Therefore we need to swab it before printing. 1767219820Sjeff */ 1768329159Shselasky u32 *bid_u32 = (u32 *)board_id; 1769329159Shselasky 1770329159Shselasky for (i = 0; i < 4; ++i) { 1771329159Shselasky typedef struct { u32 value; } __packed u64_p_t; 1772329159Shselasky 1773329159Shselasky u32 *addr; 1774329159Shselasky u32 val; 1775329159Shselasky 1776329159Shselasky addr = (u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4); 1777329159Shselasky val = ((u64_p_t *)addr)->value; 1778329159Shselasky val = swab32(val); 1779329159Shselasky ((u64_p_t *)&bid_u32[i])->value = val; 1780329159Shselasky } 1781219820Sjeff } 1782219820Sjeff} 1783219820Sjeff 1784219820Sjeffint mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter) 1785219820Sjeff{ 1786219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1787219820Sjeff u32 *outbox; 1788219820Sjeff int err; 1789219820Sjeff 1790219820Sjeff#define QUERY_ADAPTER_OUT_SIZE 0x100 1791219820Sjeff#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10 1792219820Sjeff#define QUERY_ADAPTER_VSD_OFFSET 0x20 1793219820Sjeff 1794219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1795219820Sjeff if (IS_ERR(mailbox)) 1796219820Sjeff return PTR_ERR(mailbox); 1797219820Sjeff outbox = mailbox->buf; 1798219820Sjeff 1799219820Sjeff err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER, 1800255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 1801219820Sjeff if (err) 1802219820Sjeff goto out; 1803219820Sjeff 1804219820Sjeff MLX4_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET); 1805219820Sjeff 1806219820Sjeff get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4, 1807329159Shselasky adapter->board_id); 1808219820Sjeff 1809219820Sjeffout: 1810219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1811219820Sjeff return err; 1812219820Sjeff} 1813219820Sjeff 1814219820Sjeffint mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) 1815219820Sjeff{ 1816219820Sjeff struct mlx4_cmd_mailbox *mailbox; 1817219820Sjeff __be32 *inbox; 1818219820Sjeff int err; 1819329159Shselasky static const u8 a0_dmfs_hw_steering[] = { 1820329159Shselasky [MLX4_STEERING_DMFS_A0_DEFAULT] = 0, 1821329159Shselasky [MLX4_STEERING_DMFS_A0_DYNAMIC] = 1, 1822329159Shselasky [MLX4_STEERING_DMFS_A0_STATIC] = 2, 1823329159Shselasky [MLX4_STEERING_DMFS_A0_DISABLE] = 3 1824329159Shselasky }; 1825219820Sjeff 1826219820Sjeff#define INIT_HCA_IN_SIZE 0x200 1827219820Sjeff#define INIT_HCA_VERSION_OFFSET 0x000 1828219820Sjeff#define INIT_HCA_VERSION 2 1829329159Shselasky#define INIT_HCA_VXLAN_OFFSET 0x0c 1830219820Sjeff#define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e 1831219820Sjeff#define INIT_HCA_FLAGS_OFFSET 0x014 1832272027Shselasky#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018 1833219820Sjeff#define INIT_HCA_QPC_OFFSET 0x020 1834219820Sjeff#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) 1835219820Sjeff#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) 1836219820Sjeff#define INIT_HCA_SRQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x28) 1837219820Sjeff#define INIT_HCA_LOG_SRQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x2f) 1838219820Sjeff#define INIT_HCA_CQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x30) 1839219820Sjeff#define INIT_HCA_LOG_CQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x37) 1840255932Salfred#define INIT_HCA_EQE_CQE_OFFSETS (INIT_HCA_QPC_OFFSET + 0x38) 1841329159Shselasky#define INIT_HCA_EQE_CQE_STRIDE_OFFSET (INIT_HCA_QPC_OFFSET + 0x3b) 1842219820Sjeff#define INIT_HCA_ALTC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x40) 1843219820Sjeff#define INIT_HCA_AUXC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50) 1844219820Sjeff#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60) 1845219820Sjeff#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67) 1846329159Shselasky#define INIT_HCA_NUM_SYS_EQS_OFFSET (INIT_HCA_QPC_OFFSET + 0x6a) 1847219820Sjeff#define INIT_HCA_RDMARC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70) 1848219820Sjeff#define INIT_HCA_LOG_RD_OFFSET (INIT_HCA_QPC_OFFSET + 0x77) 1849219820Sjeff#define INIT_HCA_MCAST_OFFSET 0x0c0 1850219820Sjeff#define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) 1851219820Sjeff#define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) 1852219820Sjeff#define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) 1853255932Salfred#define INIT_HCA_UC_STEERING_OFFSET (INIT_HCA_MCAST_OFFSET + 0x18) 1854219820Sjeff#define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) 1855255932Salfred#define INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN 0x6 1856255932Salfred#define INIT_HCA_FS_PARAM_OFFSET 0x1d0 1857255932Salfred#define INIT_HCA_FS_BASE_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x00) 1858255932Salfred#define INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x12) 1859329159Shselasky#define INIT_HCA_FS_A0_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x18) 1860255932Salfred#define INIT_HCA_FS_LOG_TABLE_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x1b) 1861255932Salfred#define INIT_HCA_FS_ETH_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x21) 1862255932Salfred#define INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22) 1863255932Salfred#define INIT_HCA_FS_IB_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x25) 1864255932Salfred#define INIT_HCA_FS_IB_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x26) 1865219820Sjeff#define INIT_HCA_TPT_OFFSET 0x0f0 1866219820Sjeff#define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) 1867272027Shselasky#define INIT_HCA_TPT_MW_OFFSET (INIT_HCA_TPT_OFFSET + 0x08) 1868219820Sjeff#define INIT_HCA_LOG_MPT_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x0b) 1869219820Sjeff#define INIT_HCA_MTT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x10) 1870219820Sjeff#define INIT_HCA_CMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x18) 1871219820Sjeff#define INIT_HCA_UAR_OFFSET 0x120 1872219820Sjeff#define INIT_HCA_LOG_UAR_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0a) 1873219820Sjeff#define INIT_HCA_UAR_PAGE_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0b) 1874219820Sjeff 1875219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1876219820Sjeff if (IS_ERR(mailbox)) 1877219820Sjeff return PTR_ERR(mailbox); 1878219820Sjeff inbox = mailbox->buf; 1879219820Sjeff 1880219820Sjeff *((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION; 1881219820Sjeff 1882255932Salfred *((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) = 1883329159Shselasky (ilog2(cache_line_size()) - 4) << 5; 1884255932Salfred 1885219820Sjeff#if defined(__LITTLE_ENDIAN) 1886219820Sjeff *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1); 1887219820Sjeff#elif defined(__BIG_ENDIAN) 1888219820Sjeff *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1); 1889219820Sjeff#else 1890219820Sjeff#error Host endianness not defined 1891219820Sjeff#endif 1892219820Sjeff /* Check port for UD address vector: */ 1893219820Sjeff *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1); 1894219820Sjeff 1895219820Sjeff /* Enable IPoIB checksumming if we can: */ 1896219820Sjeff if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) 1897219820Sjeff *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); 1898219820Sjeff 1899219820Sjeff /* Enable QoS support if module parameter set */ 1900329159Shselasky if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG && enable_qos) 1901219820Sjeff *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2); 1902219820Sjeff 1903255932Salfred /* enable counters */ 1904255932Salfred if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS) 1905255932Salfred *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4); 1906255932Salfred 1907329159Shselasky /* Enable RSS spread to fragmented IP packets when supported */ 1908329159Shselasky if (dev->caps.flags & MLX4_DEV_CAP_FLAG_RSS_IP_FRAG) 1909329159Shselasky *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 13); 1910329159Shselasky 1911329159Shselasky /* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */ 1912255932Salfred if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_EQE) { 1913255932Salfred *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 29); 1914255932Salfred dev->caps.eqe_size = 64; 1915255932Salfred dev->caps.eqe_factor = 1; 1916255932Salfred } else { 1917255932Salfred dev->caps.eqe_size = 32; 1918255932Salfred dev->caps.eqe_factor = 0; 1919255932Salfred } 1920255932Salfred 1921255932Salfred if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_CQE) { 1922255932Salfred *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 30); 1923255932Salfred dev->caps.cqe_size = 64; 1924329159Shselasky dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE; 1925255932Salfred } else { 1926255932Salfred dev->caps.cqe_size = 32; 1927255932Salfred } 1928255932Salfred 1929329159Shselasky#if 0 1930329159Shselasky /* XXX not currently supported by the FreeBSD's mlxen */ 1931329159Shselasky /* CX3 is capable of extending CQEs\EQEs to strides larger than 64B */ 1932329159Shselasky if ((dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_EQE_STRIDE) && 1933329159Shselasky (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_CQE_STRIDE)) { 1934329159Shselasky dev->caps.eqe_size = cache_line_size(); 1935329159Shselasky dev->caps.cqe_size = cache_line_size(); 1936329159Shselasky dev->caps.eqe_factor = 0; 1937329159Shselasky MLX4_PUT(inbox, (u8)((ilog2(dev->caps.eqe_size) - 5) << 4 | 1938329159Shselasky (ilog2(dev->caps.eqe_size) - 5)), 1939329159Shselasky INIT_HCA_EQE_CQE_STRIDE_OFFSET); 1940329159Shselasky 1941329159Shselasky /* User still need to know to support CQE > 32B */ 1942329159Shselasky dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE; 1943329159Shselasky } 1944329159Shselasky#endif 1945329159Shselasky 1946272027Shselasky if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) 1947272027Shselasky *(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31); 1948272027Shselasky 1949219820Sjeff /* QPC/EEC/CQC/EQC/RDMARC attributes */ 1950219820Sjeff 1951219820Sjeff MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); 1952219820Sjeff MLX4_PUT(inbox, param->log_num_qps, INIT_HCA_LOG_QP_OFFSET); 1953219820Sjeff MLX4_PUT(inbox, param->srqc_base, INIT_HCA_SRQC_BASE_OFFSET); 1954219820Sjeff MLX4_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET); 1955219820Sjeff MLX4_PUT(inbox, param->cqc_base, INIT_HCA_CQC_BASE_OFFSET); 1956219820Sjeff MLX4_PUT(inbox, param->log_num_cqs, INIT_HCA_LOG_CQ_OFFSET); 1957219820Sjeff MLX4_PUT(inbox, param->altc_base, INIT_HCA_ALTC_BASE_OFFSET); 1958219820Sjeff MLX4_PUT(inbox, param->auxc_base, INIT_HCA_AUXC_BASE_OFFSET); 1959219820Sjeff MLX4_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET); 1960219820Sjeff MLX4_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET); 1961329159Shselasky MLX4_PUT(inbox, param->num_sys_eqs, INIT_HCA_NUM_SYS_EQS_OFFSET); 1962219820Sjeff MLX4_PUT(inbox, param->rdmarc_base, INIT_HCA_RDMARC_BASE_OFFSET); 1963219820Sjeff MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET); 1964219820Sjeff 1965255932Salfred /* steering attributes */ 1966255932Salfred if (dev->caps.steering_mode == 1967255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) { 1968255932Salfred *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= 1969255932Salfred cpu_to_be32(1 << 1970255932Salfred INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN); 1971219820Sjeff 1972255932Salfred MLX4_PUT(inbox, param->mc_base, INIT_HCA_FS_BASE_OFFSET); 1973255932Salfred MLX4_PUT(inbox, param->log_mc_entry_sz, 1974255932Salfred INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); 1975255932Salfred MLX4_PUT(inbox, param->log_mc_table_sz, 1976255932Salfred INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); 1977255932Salfred /* Enable Ethernet flow steering 1978255932Salfred * with udp unicast and tcp unicast 1979255932Salfred */ 1980329159Shselasky if (dev->caps.dmfs_high_steer_mode != 1981329159Shselasky MLX4_STEERING_DMFS_A0_STATIC) 1982329159Shselasky MLX4_PUT(inbox, 1983329159Shselasky (u8)(MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN), 1984329159Shselasky INIT_HCA_FS_ETH_BITS_OFFSET); 1985255932Salfred MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR, 1986255932Salfred INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET); 1987255932Salfred /* Enable IPoIB flow steering 1988255932Salfred * with udp unicast and tcp unicast 1989255932Salfred */ 1990255932Salfred MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN), 1991255932Salfred INIT_HCA_FS_IB_BITS_OFFSET); 1992255932Salfred MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR, 1993255932Salfred INIT_HCA_FS_IB_NUM_ADDRS_OFFSET); 1994329159Shselasky 1995329159Shselasky if (dev->caps.dmfs_high_steer_mode != 1996329159Shselasky MLX4_STEERING_DMFS_A0_NOT_SUPPORTED) 1997329159Shselasky MLX4_PUT(inbox, 1998329159Shselasky ((u8)(a0_dmfs_hw_steering[dev->caps.dmfs_high_steer_mode] 1999329159Shselasky << 6)), 2000329159Shselasky INIT_HCA_FS_A0_OFFSET); 2001255932Salfred } else { 2002255932Salfred MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); 2003255932Salfred MLX4_PUT(inbox, param->log_mc_entry_sz, 2004255932Salfred INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); 2005255932Salfred MLX4_PUT(inbox, param->log_mc_hash_sz, 2006255932Salfred INIT_HCA_LOG_MC_HASH_SZ_OFFSET); 2007255932Salfred MLX4_PUT(inbox, param->log_mc_table_sz, 2008255932Salfred INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); 2009272027Shselasky if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0) 2010255932Salfred MLX4_PUT(inbox, (u8) (1 << 3), 2011255932Salfred INIT_HCA_UC_STEERING_OFFSET); 2012255932Salfred } 2013219820Sjeff 2014219820Sjeff /* TPT attributes */ 2015219820Sjeff 2016219820Sjeff MLX4_PUT(inbox, param->dmpt_base, INIT_HCA_DMPT_BASE_OFFSET); 2017329159Shselasky MLX4_PUT(inbox, param->mw_enabled, INIT_HCA_TPT_MW_OFFSET); 2018219820Sjeff MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET); 2019219820Sjeff MLX4_PUT(inbox, param->mtt_base, INIT_HCA_MTT_BASE_OFFSET); 2020219820Sjeff MLX4_PUT(inbox, param->cmpt_base, INIT_HCA_CMPT_BASE_OFFSET); 2021219820Sjeff 2022219820Sjeff /* UAR attributes */ 2023219820Sjeff 2024255932Salfred MLX4_PUT(inbox, param->uar_page_sz, INIT_HCA_UAR_PAGE_SZ_OFFSET); 2025219820Sjeff MLX4_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); 2026219820Sjeff 2027329159Shselasky /* set parser VXLAN attributes */ 2028329159Shselasky if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS) { 2029329159Shselasky u8 parser_params = 0; 2030329159Shselasky MLX4_PUT(inbox, parser_params, INIT_HCA_VXLAN_OFFSET); 2031329159Shselasky } 2032219820Sjeff 2033329159Shselasky err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 2034329159Shselasky MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 2035329159Shselasky 2036219820Sjeff if (err) 2037219820Sjeff mlx4_err(dev, "INIT_HCA returns %d\n", err); 2038219820Sjeff 2039219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 2040219820Sjeff return err; 2041219820Sjeff} 2042219820Sjeff 2043255932Salfredint mlx4_QUERY_HCA(struct mlx4_dev *dev, 2044255932Salfred struct mlx4_init_hca_param *param) 2045255932Salfred{ 2046255932Salfred struct mlx4_cmd_mailbox *mailbox; 2047255932Salfred __be32 *outbox; 2048255932Salfred u32 dword_field; 2049255932Salfred int err; 2050255932Salfred u8 byte_field; 2051329159Shselasky static const u8 a0_dmfs_query_hw_steering[] = { 2052329159Shselasky [0] = MLX4_STEERING_DMFS_A0_DEFAULT, 2053329159Shselasky [1] = MLX4_STEERING_DMFS_A0_DYNAMIC, 2054329159Shselasky [2] = MLX4_STEERING_DMFS_A0_STATIC, 2055329159Shselasky [3] = MLX4_STEERING_DMFS_A0_DISABLE 2056329159Shselasky }; 2057255932Salfred 2058255932Salfred#define QUERY_HCA_GLOBAL_CAPS_OFFSET 0x04 2059255932Salfred#define QUERY_HCA_CORE_CLOCK_OFFSET 0x0c 2060255932Salfred 2061255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 2062255932Salfred if (IS_ERR(mailbox)) 2063255932Salfred return PTR_ERR(mailbox); 2064255932Salfred outbox = mailbox->buf; 2065255932Salfred 2066255932Salfred err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, 2067255932Salfred MLX4_CMD_QUERY_HCA, 2068255932Salfred MLX4_CMD_TIME_CLASS_B, 2069255932Salfred !mlx4_is_slave(dev)); 2070255932Salfred if (err) 2071255932Salfred goto out; 2072255932Salfred 2073255932Salfred MLX4_GET(param->global_caps, outbox, QUERY_HCA_GLOBAL_CAPS_OFFSET); 2074255932Salfred MLX4_GET(param->hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET); 2075255932Salfred 2076255932Salfred /* QPC/EEC/CQC/EQC/RDMARC attributes */ 2077255932Salfred 2078255932Salfred MLX4_GET(param->qpc_base, outbox, INIT_HCA_QPC_BASE_OFFSET); 2079255932Salfred MLX4_GET(param->log_num_qps, outbox, INIT_HCA_LOG_QP_OFFSET); 2080255932Salfred MLX4_GET(param->srqc_base, outbox, INIT_HCA_SRQC_BASE_OFFSET); 2081255932Salfred MLX4_GET(param->log_num_srqs, outbox, INIT_HCA_LOG_SRQ_OFFSET); 2082255932Salfred MLX4_GET(param->cqc_base, outbox, INIT_HCA_CQC_BASE_OFFSET); 2083255932Salfred MLX4_GET(param->log_num_cqs, outbox, INIT_HCA_LOG_CQ_OFFSET); 2084255932Salfred MLX4_GET(param->altc_base, outbox, INIT_HCA_ALTC_BASE_OFFSET); 2085255932Salfred MLX4_GET(param->auxc_base, outbox, INIT_HCA_AUXC_BASE_OFFSET); 2086255932Salfred MLX4_GET(param->eqc_base, outbox, INIT_HCA_EQC_BASE_OFFSET); 2087255932Salfred MLX4_GET(param->log_num_eqs, outbox, INIT_HCA_LOG_EQ_OFFSET); 2088329159Shselasky MLX4_GET(param->num_sys_eqs, outbox, INIT_HCA_NUM_SYS_EQS_OFFSET); 2089255932Salfred MLX4_GET(param->rdmarc_base, outbox, INIT_HCA_RDMARC_BASE_OFFSET); 2090255932Salfred MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET); 2091255932Salfred 2092255932Salfred MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET); 2093255932Salfred if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) { 2094255932Salfred param->steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED; 2095255932Salfred } else { 2096255932Salfred MLX4_GET(byte_field, outbox, INIT_HCA_UC_STEERING_OFFSET); 2097272027Shselasky if (byte_field & 0x8) 2098255932Salfred param->steering_mode = MLX4_STEERING_MODE_B0; 2099272027Shselasky else 2100255932Salfred param->steering_mode = MLX4_STEERING_MODE_A0; 2101255932Salfred } 2102329159Shselasky 2103329159Shselasky if (dword_field & (1 << 13)) 2104329159Shselasky param->rss_ip_frags = 1; 2105329159Shselasky 2106272027Shselasky /* steering attributes */ 2107255932Salfred if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { 2108255932Salfred MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET); 2109255932Salfred MLX4_GET(param->log_mc_entry_sz, outbox, 2110255932Salfred INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); 2111255932Salfred MLX4_GET(param->log_mc_table_sz, outbox, 2112255932Salfred INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); 2113329159Shselasky MLX4_GET(byte_field, outbox, 2114329159Shselasky INIT_HCA_FS_A0_OFFSET); 2115329159Shselasky param->dmfs_high_steer_mode = 2116329159Shselasky a0_dmfs_query_hw_steering[(byte_field >> 6) & 3]; 2117255932Salfred } else { 2118255932Salfred MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET); 2119255932Salfred MLX4_GET(param->log_mc_entry_sz, outbox, 2120255932Salfred INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); 2121255932Salfred MLX4_GET(param->log_mc_hash_sz, outbox, 2122255932Salfred INIT_HCA_LOG_MC_HASH_SZ_OFFSET); 2123255932Salfred MLX4_GET(param->log_mc_table_sz, outbox, 2124255932Salfred INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); 2125255932Salfred } 2126255932Salfred 2127329159Shselasky /* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */ 2128255932Salfred MLX4_GET(byte_field, outbox, INIT_HCA_EQE_CQE_OFFSETS); 2129255932Salfred if (byte_field & 0x20) /* 64-bytes eqe enabled */ 2130255932Salfred param->dev_cap_enabled |= MLX4_DEV_CAP_64B_EQE_ENABLED; 2131255932Salfred if (byte_field & 0x40) /* 64-bytes cqe enabled */ 2132255932Salfred param->dev_cap_enabled |= MLX4_DEV_CAP_64B_CQE_ENABLED; 2133255932Salfred 2134329159Shselasky /* CX3 is capable of extending CQEs\EQEs to strides larger than 64B */ 2135329159Shselasky MLX4_GET(byte_field, outbox, INIT_HCA_EQE_CQE_STRIDE_OFFSET); 2136329159Shselasky if (byte_field) { 2137329159Shselasky param->dev_cap_enabled |= MLX4_DEV_CAP_EQE_STRIDE_ENABLED; 2138329159Shselasky param->dev_cap_enabled |= MLX4_DEV_CAP_CQE_STRIDE_ENABLED; 2139329159Shselasky param->cqe_size = 1 << ((byte_field & 2140329159Shselasky MLX4_CQE_SIZE_MASK_STRIDE) + 5); 2141329159Shselasky param->eqe_size = 1 << (((byte_field & 2142329159Shselasky MLX4_EQE_SIZE_MASK_STRIDE) >> 4) + 5); 2143329159Shselasky } 2144329159Shselasky 2145255932Salfred /* TPT attributes */ 2146255932Salfred 2147255932Salfred MLX4_GET(param->dmpt_base, outbox, INIT_HCA_DMPT_BASE_OFFSET); 2148329159Shselasky MLX4_GET(param->mw_enabled, outbox, INIT_HCA_TPT_MW_OFFSET); 2149255932Salfred MLX4_GET(param->log_mpt_sz, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET); 2150255932Salfred MLX4_GET(param->mtt_base, outbox, INIT_HCA_MTT_BASE_OFFSET); 2151255932Salfred MLX4_GET(param->cmpt_base, outbox, INIT_HCA_CMPT_BASE_OFFSET); 2152255932Salfred 2153255932Salfred /* UAR attributes */ 2154255932Salfred 2155255932Salfred MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET); 2156255932Salfred MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET); 2157255932Salfred 2158329159Shselasky /* phv_check enable */ 2159329159Shselasky MLX4_GET(byte_field, outbox, INIT_HCA_CACHELINE_SZ_OFFSET); 2160329159Shselasky if (byte_field & 0x2) 2161329159Shselasky param->phv_check_en = 1; 2162255932Salfredout: 2163255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 2164255932Salfred 2165255932Salfred return err; 2166255932Salfred} 2167255932Salfred 2168329159Shselaskystatic int mlx4_hca_core_clock_update(struct mlx4_dev *dev) 2169329159Shselasky{ 2170329159Shselasky struct mlx4_cmd_mailbox *mailbox; 2171329159Shselasky __be32 *outbox; 2172329159Shselasky int err; 2173329159Shselasky 2174329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 2175329159Shselasky if (IS_ERR(mailbox)) { 2176329159Shselasky mlx4_warn(dev, "hca_core_clock mailbox allocation failed\n"); 2177329159Shselasky return PTR_ERR(mailbox); 2178329159Shselasky } 2179329159Shselasky outbox = mailbox->buf; 2180329159Shselasky 2181329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, 2182329159Shselasky MLX4_CMD_QUERY_HCA, 2183329159Shselasky MLX4_CMD_TIME_CLASS_B, 2184329159Shselasky !mlx4_is_slave(dev)); 2185329159Shselasky if (err) { 2186329159Shselasky mlx4_warn(dev, "hca_core_clock update failed\n"); 2187329159Shselasky goto out; 2188329159Shselasky } 2189329159Shselasky 2190329159Shselasky MLX4_GET(dev->caps.hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET); 2191329159Shselasky 2192329159Shselaskyout: 2193329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 2194329159Shselasky 2195329159Shselasky return err; 2196329159Shselasky} 2197329159Shselasky 2198255932Salfred/* for IB-type ports only in SRIOV mode. Checks that both proxy QP0 2199255932Salfred * and real QP0 are active, so that the paravirtualized QP0 is ready 2200255932Salfred * to operate */ 2201255932Salfredstatic int check_qp0_state(struct mlx4_dev *dev, int function, int port) 2202255932Salfred{ 2203255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2204255932Salfred /* irrelevant if not infiniband */ 2205255932Salfred if (priv->mfunc.master.qp0_state[port].proxy_qp0_active && 2206255932Salfred priv->mfunc.master.qp0_state[port].qp0_active) 2207255932Salfred return 1; 2208255932Salfred return 0; 2209255932Salfred} 2210255932Salfred 2211255932Salfredint mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave, 2212255932Salfred struct mlx4_vhcr *vhcr, 2213255932Salfred struct mlx4_cmd_mailbox *inbox, 2214255932Salfred struct mlx4_cmd_mailbox *outbox, 2215255932Salfred struct mlx4_cmd_info *cmd) 2216255932Salfred{ 2217255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2218329159Shselasky int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier); 2219255932Salfred int err; 2220255932Salfred 2221329159Shselasky if (port < 0) 2222329159Shselasky return -EINVAL; 2223329159Shselasky 2224255932Salfred if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port)) 2225255932Salfred return 0; 2226255932Salfred 2227255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { 2228255932Salfred /* Enable port only if it was previously disabled */ 2229255932Salfred if (!priv->mfunc.master.init_port_ref[port]) { 2230255932Salfred err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, 2231255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2232255932Salfred if (err) 2233255932Salfred return err; 2234255932Salfred } 2235255932Salfred priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); 2236255932Salfred } else { 2237255932Salfred if (slave == mlx4_master_func_num(dev)) { 2238255932Salfred if (check_qp0_state(dev, slave, port) && 2239255932Salfred !priv->mfunc.master.qp0_state[port].port_active) { 2240255932Salfred err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, 2241255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2242255932Salfred if (err) 2243255932Salfred return err; 2244255932Salfred priv->mfunc.master.qp0_state[port].port_active = 1; 2245255932Salfred priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); 2246255932Salfred } 2247255932Salfred } else 2248255932Salfred priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); 2249255932Salfred } 2250255932Salfred ++priv->mfunc.master.init_port_ref[port]; 2251255932Salfred return 0; 2252255932Salfred} 2253255932Salfred 2254219820Sjeffint mlx4_INIT_PORT(struct mlx4_dev *dev, int port) 2255219820Sjeff{ 2256219820Sjeff struct mlx4_cmd_mailbox *mailbox; 2257219820Sjeff u32 *inbox; 2258219820Sjeff int err; 2259219820Sjeff u32 flags; 2260219820Sjeff u16 field; 2261219820Sjeff 2262219820Sjeff if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 2263219820Sjeff#define INIT_PORT_IN_SIZE 256 2264219820Sjeff#define INIT_PORT_FLAGS_OFFSET 0x00 2265219820Sjeff#define INIT_PORT_FLAG_SIG (1 << 18) 2266219820Sjeff#define INIT_PORT_FLAG_NG (1 << 17) 2267219820Sjeff#define INIT_PORT_FLAG_G0 (1 << 16) 2268219820Sjeff#define INIT_PORT_VL_SHIFT 4 2269219820Sjeff#define INIT_PORT_PORT_WIDTH_SHIFT 8 2270219820Sjeff#define INIT_PORT_MTU_OFFSET 0x04 2271219820Sjeff#define INIT_PORT_MAX_GID_OFFSET 0x06 2272219820Sjeff#define INIT_PORT_MAX_PKEY_OFFSET 0x0a 2273219820Sjeff#define INIT_PORT_GUID0_OFFSET 0x10 2274219820Sjeff#define INIT_PORT_NODE_GUID_OFFSET 0x18 2275219820Sjeff#define INIT_PORT_SI_GUID_OFFSET 0x20 2276219820Sjeff 2277219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 2278219820Sjeff if (IS_ERR(mailbox)) 2279219820Sjeff return PTR_ERR(mailbox); 2280219820Sjeff inbox = mailbox->buf; 2281219820Sjeff 2282219820Sjeff flags = 0; 2283219820Sjeff flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT; 2284219820Sjeff flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT; 2285219820Sjeff MLX4_PUT(inbox, flags, INIT_PORT_FLAGS_OFFSET); 2286219820Sjeff 2287219820Sjeff field = 128 << dev->caps.ib_mtu_cap[port]; 2288219820Sjeff MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET); 2289219820Sjeff field = dev->caps.gid_table_len[port]; 2290219820Sjeff MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET); 2291219820Sjeff field = dev->caps.pkey_table_len[port]; 2292219820Sjeff MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET); 2293219820Sjeff 2294219820Sjeff err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT, 2295255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2296219820Sjeff 2297219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 2298219820Sjeff } else 2299219820Sjeff err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, 2300255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 2301219820Sjeff 2302329159Shselasky if (!err) 2303329159Shselasky mlx4_hca_core_clock_update(dev); 2304329159Shselasky 2305219820Sjeff return err; 2306219820Sjeff} 2307219820SjeffEXPORT_SYMBOL_GPL(mlx4_INIT_PORT); 2308219820Sjeff 2309255932Salfredint mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, 2310255932Salfred struct mlx4_vhcr *vhcr, 2311255932Salfred struct mlx4_cmd_mailbox *inbox, 2312255932Salfred struct mlx4_cmd_mailbox *outbox, 2313255932Salfred struct mlx4_cmd_info *cmd) 2314255932Salfred{ 2315255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2316329159Shselasky int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier); 2317255932Salfred int err; 2318255932Salfred 2319329159Shselasky if (port < 0) 2320329159Shselasky return -EINVAL; 2321329159Shselasky 2322255932Salfred if (!(priv->mfunc.master.slave_state[slave].init_port_mask & 2323255932Salfred (1 << port))) 2324255932Salfred return 0; 2325255932Salfred 2326255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { 2327255932Salfred if (priv->mfunc.master.init_port_ref[port] == 1) { 2328255932Salfred err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 2329329159Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2330255932Salfred if (err) 2331255932Salfred return err; 2332255932Salfred } 2333255932Salfred priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); 2334255932Salfred } else { 2335255932Salfred /* infiniband port */ 2336255932Salfred if (slave == mlx4_master_func_num(dev)) { 2337255932Salfred if (!priv->mfunc.master.qp0_state[port].qp0_active && 2338255932Salfred priv->mfunc.master.qp0_state[port].port_active) { 2339255932Salfred err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 2340329159Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2341255932Salfred if (err) 2342255932Salfred return err; 2343255932Salfred priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); 2344255932Salfred priv->mfunc.master.qp0_state[port].port_active = 0; 2345255932Salfred } 2346255932Salfred } else 2347255932Salfred priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); 2348255932Salfred } 2349255932Salfred --priv->mfunc.master.init_port_ref[port]; 2350255932Salfred return 0; 2351255932Salfred} 2352255932Salfred 2353219820Sjeffint mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port) 2354219820Sjeff{ 2355329159Shselasky return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 2356329159Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 2357219820Sjeff} 2358219820SjeffEXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT); 2359219820Sjeff 2360219820Sjeffint mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic) 2361219820Sjeff{ 2362329159Shselasky return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 2363329159Shselasky MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 2364219820Sjeff} 2365219820Sjeff 2366329159Shselaskystruct mlx4_config_dev { 2367329159Shselasky __be32 update_flags; 2368329159Shselasky __be32 rsvd1[3]; 2369329159Shselasky __be16 vxlan_udp_dport; 2370329159Shselasky __be16 rsvd2; 2371329159Shselasky __be16 roce_v2_entropy; 2372329159Shselasky __be16 roce_v2_udp_dport; 2373329159Shselasky __be32 roce_flags; 2374329159Shselasky __be32 rsvd4[25]; 2375329159Shselasky __be16 rsvd5; 2376329159Shselasky u8 rsvd6; 2377329159Shselasky u8 rx_checksum_val; 2378329159Shselasky}; 2379329159Shselasky 2380329159Shselasky#define MLX4_VXLAN_UDP_DPORT (1 << 0) 2381329159Shselasky#define MLX4_ROCE_V2_UDP_DPORT BIT(3) 2382329159Shselasky#define MLX4_DISABLE_RX_PORT BIT(18) 2383329159Shselasky 2384329159Shselaskystatic int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev) 2385329159Shselasky{ 2386329159Shselasky int err; 2387329159Shselasky struct mlx4_cmd_mailbox *mailbox; 2388329159Shselasky 2389329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 2390329159Shselasky if (IS_ERR(mailbox)) 2391329159Shselasky return PTR_ERR(mailbox); 2392329159Shselasky 2393329159Shselasky memcpy(mailbox->buf, config_dev, sizeof(*config_dev)); 2394329159Shselasky 2395329159Shselasky err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_CONFIG_DEV, 2396329159Shselasky MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 2397329159Shselasky 2398329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 2399329159Shselasky return err; 2400329159Shselasky} 2401329159Shselasky 2402329159Shselaskystatic int mlx4_CONFIG_DEV_get(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev) 2403329159Shselasky{ 2404329159Shselasky int err; 2405329159Shselasky struct mlx4_cmd_mailbox *mailbox; 2406329159Shselasky 2407329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 2408329159Shselasky if (IS_ERR(mailbox)) 2409329159Shselasky return PTR_ERR(mailbox); 2410329159Shselasky 2411329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 1, MLX4_CMD_CONFIG_DEV, 2412329159Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2413329159Shselasky 2414329159Shselasky if (!err) 2415329159Shselasky memcpy(config_dev, mailbox->buf, sizeof(*config_dev)); 2416329159Shselasky 2417329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 2418329159Shselasky return err; 2419329159Shselasky} 2420329159Shselasky 2421329159Shselasky/* Conversion between the HW values and the actual functionality. 2422329159Shselasky * The value represented by the array index, 2423329159Shselasky * and the functionality determined by the flags. 2424329159Shselasky */ 2425329159Shselaskystatic const u8 config_dev_csum_flags[] = { 2426329159Shselasky [0] = 0, 2427329159Shselasky [1] = MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP, 2428329159Shselasky [2] = MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP | 2429329159Shselasky MLX4_RX_CSUM_MODE_L4, 2430329159Shselasky [3] = MLX4_RX_CSUM_MODE_L4 | 2431329159Shselasky MLX4_RX_CSUM_MODE_IP_OK_IP_NON_TCP_UDP | 2432329159Shselasky MLX4_RX_CSUM_MODE_MULTI_VLAN 2433329159Shselasky}; 2434329159Shselasky 2435329159Shselaskyint mlx4_config_dev_retrieval(struct mlx4_dev *dev, 2436329159Shselasky struct mlx4_config_dev_params *params) 2437329159Shselasky{ 2438329159Shselasky struct mlx4_config_dev config_dev = {0}; 2439329159Shselasky int err; 2440329159Shselasky u8 csum_mask; 2441329159Shselasky 2442329159Shselasky#define CONFIG_DEV_RX_CSUM_MODE_MASK 0x7 2443329159Shselasky#define CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET 0 2444329159Shselasky#define CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET 4 2445329159Shselasky 2446329159Shselasky if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_CONFIG_DEV)) 2447329159Shselasky return -ENOTSUPP; 2448329159Shselasky 2449329159Shselasky err = mlx4_CONFIG_DEV_get(dev, &config_dev); 2450329159Shselasky if (err) 2451329159Shselasky return err; 2452329159Shselasky 2453329159Shselasky csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET) & 2454329159Shselasky CONFIG_DEV_RX_CSUM_MODE_MASK; 2455329159Shselasky 2456329159Shselasky if (csum_mask >= sizeof(config_dev_csum_flags)/sizeof(config_dev_csum_flags[0])) 2457329159Shselasky return -EINVAL; 2458329159Shselasky params->rx_csum_flags_port_1 = config_dev_csum_flags[csum_mask]; 2459329159Shselasky 2460329159Shselasky csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET) & 2461329159Shselasky CONFIG_DEV_RX_CSUM_MODE_MASK; 2462329159Shselasky 2463329159Shselasky if (csum_mask >= sizeof(config_dev_csum_flags)/sizeof(config_dev_csum_flags[0])) 2464329159Shselasky return -EINVAL; 2465329159Shselasky params->rx_csum_flags_port_2 = config_dev_csum_flags[csum_mask]; 2466329159Shselasky 2467329159Shselasky params->vxlan_udp_dport = be16_to_cpu(config_dev.vxlan_udp_dport); 2468329159Shselasky 2469329159Shselasky return 0; 2470329159Shselasky} 2471329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_config_dev_retrieval); 2472329159Shselasky 2473329159Shselaskyint mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port) 2474329159Shselasky{ 2475329159Shselasky struct mlx4_config_dev config_dev; 2476329159Shselasky 2477329159Shselasky memset(&config_dev, 0, sizeof(config_dev)); 2478329159Shselasky config_dev.update_flags = cpu_to_be32(MLX4_VXLAN_UDP_DPORT); 2479329159Shselasky config_dev.vxlan_udp_dport = udp_port; 2480329159Shselasky 2481329159Shselasky return mlx4_CONFIG_DEV_set(dev, &config_dev); 2482329159Shselasky} 2483329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_config_vxlan_port); 2484329159Shselasky 2485329159Shselasky#define CONFIG_DISABLE_RX_PORT BIT(15) 2486329159Shselaskyint mlx4_disable_rx_port_check(struct mlx4_dev *dev, bool dis) 2487329159Shselasky{ 2488329159Shselasky struct mlx4_config_dev config_dev; 2489329159Shselasky 2490329159Shselasky memset(&config_dev, 0, sizeof(config_dev)); 2491329159Shselasky config_dev.update_flags = cpu_to_be32(MLX4_DISABLE_RX_PORT); 2492329159Shselasky if (dis) 2493329159Shselasky config_dev.roce_flags = 2494329159Shselasky cpu_to_be32(CONFIG_DISABLE_RX_PORT); 2495329159Shselasky 2496329159Shselasky return mlx4_CONFIG_DEV_set(dev, &config_dev); 2497329159Shselasky} 2498329159Shselasky 2499329159Shselaskyint mlx4_config_roce_v2_port(struct mlx4_dev *dev, u16 udp_port) 2500329159Shselasky{ 2501329159Shselasky struct mlx4_config_dev config_dev; 2502329159Shselasky 2503329159Shselasky memset(&config_dev, 0, sizeof(config_dev)); 2504329159Shselasky config_dev.update_flags = cpu_to_be32(MLX4_ROCE_V2_UDP_DPORT); 2505329159Shselasky config_dev.roce_v2_udp_dport = cpu_to_be16(udp_port); 2506329159Shselasky 2507329159Shselasky return mlx4_CONFIG_DEV_set(dev, &config_dev); 2508329159Shselasky} 2509329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_config_roce_v2_port); 2510329159Shselasky 2511329159Shselaskyint mlx4_virt2phy_port_map(struct mlx4_dev *dev, u32 port1, u32 port2) 2512329159Shselasky{ 2513329159Shselasky struct mlx4_cmd_mailbox *mailbox; 2514329159Shselasky struct { 2515329159Shselasky __be32 v_port1; 2516329159Shselasky __be32 v_port2; 2517329159Shselasky } *v2p; 2518329159Shselasky int err; 2519329159Shselasky 2520329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 2521329159Shselasky if (IS_ERR(mailbox)) 2522329159Shselasky return -ENOMEM; 2523329159Shselasky 2524329159Shselasky v2p = mailbox->buf; 2525329159Shselasky v2p->v_port1 = cpu_to_be32(port1); 2526329159Shselasky v2p->v_port2 = cpu_to_be32(port2); 2527329159Shselasky 2528329159Shselasky err = mlx4_cmd(dev, mailbox->dma, 0, 2529329159Shselasky MLX4_SET_PORT_VIRT2PHY, MLX4_CMD_VIRT_PORT_MAP, 2530329159Shselasky MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 2531329159Shselasky 2532329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 2533329159Shselasky return err; 2534329159Shselasky} 2535329159Shselasky 2536329159Shselasky 2537219820Sjeffint mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) 2538219820Sjeff{ 2539219820Sjeff int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0, 2540219820Sjeff MLX4_CMD_SET_ICM_SIZE, 2541255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2542219820Sjeff if (ret) 2543219820Sjeff return ret; 2544219820Sjeff 2545219820Sjeff /* 2546219820Sjeff * Round up number of system pages needed in case 2547219820Sjeff * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. 2548219820Sjeff */ 2549219820Sjeff *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> 2550219820Sjeff (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); 2551219820Sjeff 2552219820Sjeff return 0; 2553219820Sjeff} 2554219820Sjeff 2555219820Sjeffint mlx4_NOP(struct mlx4_dev *dev) 2556219820Sjeff{ 2557219820Sjeff /* Input modifier of 0x1f means "finish as soon as possible." */ 2558329159Shselasky return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A, 2559329159Shselasky MLX4_CMD_NATIVE); 2560219820Sjeff} 2561219820Sjeff 2562329159Shselaskyint mlx4_query_diag_counters(struct mlx4_dev *dev, u8 op_modifier, 2563329159Shselasky const u32 offset[], 2564329159Shselasky u32 value[], size_t array_len, u8 port) 2565255932Salfred{ 2566255932Salfred struct mlx4_cmd_mailbox *mailbox; 2567255932Salfred u32 *outbox; 2568329159Shselasky size_t i; 2569255932Salfred int ret; 2570255932Salfred 2571255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 2572255932Salfred if (IS_ERR(mailbox)) 2573255932Salfred return PTR_ERR(mailbox); 2574329159Shselasky 2575255932Salfred outbox = mailbox->buf; 2576255932Salfred 2577329159Shselasky ret = mlx4_cmd_box(dev, 0, mailbox->dma, port, op_modifier, 2578255932Salfred MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A, 2579255932Salfred MLX4_CMD_NATIVE); 2580255932Salfred if (ret) 2581255932Salfred goto out; 2582255932Salfred 2583329159Shselasky for (i = 0; i < array_len; i++) { 2584329159Shselasky if (offset[i] > MLX4_MAILBOX_SIZE) { 2585255932Salfred ret = -EINVAL; 2586255932Salfred goto out; 2587255932Salfred } 2588255932Salfred 2589329159Shselasky MLX4_GET(value[i], outbox, offset[i]); 2590255932Salfred } 2591255932Salfred 2592255932Salfredout: 2593255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 2594255932Salfred return ret; 2595255932Salfred} 2596329159ShselaskyEXPORT_SYMBOL(mlx4_query_diag_counters); 2597255932Salfred 2598329159Shselaskyint mlx4_get_phys_port_id(struct mlx4_dev *dev) 2599272027Shselasky{ 2600329159Shselasky u8 port; 2601329159Shselasky u32 *outbox; 2602329159Shselasky struct mlx4_cmd_mailbox *mailbox; 2603329159Shselasky u32 in_mod; 2604329159Shselasky u32 guid_hi, guid_lo; 2605329159Shselasky int err, ret = 0; 2606329159Shselasky#define MOD_STAT_CFG_PORT_OFFSET 8 2607329159Shselasky#define MOD_STAT_CFG_GUID_H 0X14 2608329159Shselasky#define MOD_STAT_CFG_GUID_L 0X1c 2609329159Shselasky 2610329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 2611329159Shselasky if (IS_ERR(mailbox)) 2612329159Shselasky return PTR_ERR(mailbox); 2613329159Shselasky outbox = mailbox->buf; 2614329159Shselasky 2615329159Shselasky for (port = 1; port <= dev->caps.num_ports; port++) { 2616329159Shselasky in_mod = port << MOD_STAT_CFG_PORT_OFFSET; 2617329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, in_mod, 0x2, 2618329159Shselasky MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A, 2619329159Shselasky MLX4_CMD_NATIVE); 2620329159Shselasky if (err) { 2621329159Shselasky mlx4_err(dev, "Fail to get port %d uplink guid\n", 2622329159Shselasky port); 2623329159Shselasky ret = err; 2624329159Shselasky } else { 2625329159Shselasky MLX4_GET(guid_hi, outbox, MOD_STAT_CFG_GUID_H); 2626329159Shselasky MLX4_GET(guid_lo, outbox, MOD_STAT_CFG_GUID_L); 2627329159Shselasky dev->caps.phys_port_id[port] = (u64)guid_lo | 2628329159Shselasky (u64)guid_hi << 32; 2629329159Shselasky } 2630329159Shselasky } 2631329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 2632329159Shselasky return ret; 2633272027Shselasky} 2634272027Shselasky 2635220016Sjeff#define MLX4_WOL_SETUP_MODE (5 << 28) 2636220016Sjeffint mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) 2637220016Sjeff{ 2638220016Sjeff u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; 2639220016Sjeff 2640220016Sjeff return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3, 2641255932Salfred MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A, 2642255932Salfred MLX4_CMD_NATIVE); 2643220016Sjeff} 2644220016SjeffEXPORT_SYMBOL_GPL(mlx4_wol_read); 2645220016Sjeff 2646220016Sjeffint mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) 2647220016Sjeff{ 2648220016Sjeff u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; 2649220016Sjeff 2650220016Sjeff return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG, 2651255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 2652220016Sjeff} 2653220016SjeffEXPORT_SYMBOL_GPL(mlx4_wol_write); 2654220016Sjeff 2655255932Salfredenum { 2656255932Salfred ADD_TO_MCG = 0x26, 2657255932Salfred}; 2658255932Salfred 2659255932Salfred 2660255932Salfredvoid mlx4_opreq_action(struct work_struct *work) 2661219820Sjeff{ 2662329159Shselasky struct mlx4_priv *priv = container_of(work, struct mlx4_priv, 2663329159Shselasky opreq_task); 2664255932Salfred struct mlx4_dev *dev = &priv->dev; 2665255932Salfred int num_tasks = atomic_read(&priv->opreq_count); 2666219820Sjeff struct mlx4_cmd_mailbox *mailbox; 2667255932Salfred struct mlx4_mgm *mgm; 2668219820Sjeff u32 *outbox; 2669255932Salfred u32 modifier; 2670255932Salfred u16 token; 2671255932Salfred u16 type; 2672255932Salfred int err; 2673255932Salfred u32 num_qps; 2674255932Salfred struct mlx4_qp qp; 2675219820Sjeff int i; 2676255932Salfred u8 rem_mcg; 2677255932Salfred u8 prot; 2678219820Sjeff 2679255932Salfred#define GET_OP_REQ_MODIFIER_OFFSET 0x08 2680255932Salfred#define GET_OP_REQ_TOKEN_OFFSET 0x14 2681255932Salfred#define GET_OP_REQ_TYPE_OFFSET 0x1a 2682255932Salfred#define GET_OP_REQ_DATA_OFFSET 0x20 2683255932Salfred 2684219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 2685255932Salfred if (IS_ERR(mailbox)) { 2686255932Salfred mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n"); 2687255932Salfred return; 2688255932Salfred } 2689219820Sjeff outbox = mailbox->buf; 2690219820Sjeff 2691255932Salfred while (num_tasks) { 2692255932Salfred err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, 2693255932Salfred MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, 2694255932Salfred MLX4_CMD_NATIVE); 2695255932Salfred if (err) { 2696329159Shselasky mlx4_err(dev, "Failed to retrieve required operation: %d\n", 2697329159Shselasky err); 2698255932Salfred return; 2699255932Salfred } 2700255932Salfred MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET); 2701255932Salfred MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET); 2702255932Salfred MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET); 2703255932Salfred type &= 0xfff; 2704219820Sjeff 2705255932Salfred switch (type) { 2706255932Salfred case ADD_TO_MCG: 2707329159Shselasky if (dev->caps.steering_mode == 2708329159Shselasky MLX4_STEERING_MODE_DEVICE_MANAGED) { 2709329159Shselasky mlx4_warn(dev, "ADD MCG operation is not supported in DEVICE_MANAGED steering mode\n"); 2710255932Salfred err = EPERM; 2711255932Salfred break; 2712255932Salfred } 2713329159Shselasky mgm = (struct mlx4_mgm *)((u8 *)(outbox) + 2714329159Shselasky GET_OP_REQ_DATA_OFFSET); 2715329159Shselasky num_qps = be32_to_cpu(mgm->members_count) & 2716329159Shselasky MGM_QPN_MASK; 2717329159Shselasky rem_mcg = ((u8 *)(&mgm->members_count))[0] & 1; 2718329159Shselasky prot = ((u8 *)(&mgm->members_count))[0] >> 6; 2719255932Salfred 2720255932Salfred for (i = 0; i < num_qps; i++) { 2721255932Salfred qp.qpn = be32_to_cpu(mgm->qp[i]); 2722255932Salfred if (rem_mcg) 2723329159Shselasky err = mlx4_multicast_detach(dev, &qp, 2724329159Shselasky mgm->gid, 2725329159Shselasky prot, 0); 2726255932Salfred else 2727329159Shselasky err = mlx4_multicast_attach(dev, &qp, 2728329159Shselasky mgm->gid, 2729329159Shselasky mgm->gid[5] 2730329159Shselasky , 0, prot, 2731329159Shselasky NULL); 2732255932Salfred if (err) 2733255932Salfred break; 2734255932Salfred } 2735255932Salfred break; 2736255932Salfred default: 2737255932Salfred mlx4_warn(dev, "Bad type for required operation\n"); 2738255932Salfred err = EINVAL; 2739255932Salfred break; 2740255932Salfred } 2741329159Shselasky err = mlx4_cmd(dev, 0, ((u32) err | 2742329159Shselasky (__force u32)cpu_to_be32(token) << 16), 2743329159Shselasky 1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, 2744255932Salfred MLX4_CMD_NATIVE); 2745255932Salfred if (err) { 2746329159Shselasky mlx4_err(dev, "Failed to acknowledge required request: %d\n", 2747329159Shselasky err); 2748219820Sjeff goto out; 2749219820Sjeff } 2750255932Salfred memset(outbox, 0, 0xffc); 2751255932Salfred num_tasks = atomic_dec_return(&priv->opreq_count); 2752219820Sjeff } 2753219820Sjeff 2754219820Sjeffout: 2755219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 2756219820Sjeff} 2757329159Shselasky 2758329159Shselaskystatic int mlx4_check_smp_firewall_active(struct mlx4_dev *dev, 2759329159Shselasky struct mlx4_cmd_mailbox *mailbox) 2760329159Shselasky{ 2761329159Shselasky#define MLX4_CMD_MAD_DEMUX_SET_ATTR_OFFSET 0x10 2762329159Shselasky#define MLX4_CMD_MAD_DEMUX_GETRESP_ATTR_OFFSET 0x20 2763329159Shselasky#define MLX4_CMD_MAD_DEMUX_TRAP_ATTR_OFFSET 0x40 2764329159Shselasky#define MLX4_CMD_MAD_DEMUX_TRAP_REPRESS_ATTR_OFFSET 0x70 2765329159Shselasky 2766329159Shselasky u32 set_attr_mask, getresp_attr_mask; 2767329159Shselasky u32 trap_attr_mask, traprepress_attr_mask; 2768329159Shselasky 2769329159Shselasky MLX4_GET(set_attr_mask, mailbox->buf, 2770329159Shselasky MLX4_CMD_MAD_DEMUX_SET_ATTR_OFFSET); 2771329159Shselasky mlx4_dbg(dev, "SMP firewall set_attribute_mask = 0x%x\n", 2772329159Shselasky set_attr_mask); 2773329159Shselasky 2774329159Shselasky MLX4_GET(getresp_attr_mask, mailbox->buf, 2775329159Shselasky MLX4_CMD_MAD_DEMUX_GETRESP_ATTR_OFFSET); 2776329159Shselasky mlx4_dbg(dev, "SMP firewall getresp_attribute_mask = 0x%x\n", 2777329159Shselasky getresp_attr_mask); 2778329159Shselasky 2779329159Shselasky MLX4_GET(trap_attr_mask, mailbox->buf, 2780329159Shselasky MLX4_CMD_MAD_DEMUX_TRAP_ATTR_OFFSET); 2781329159Shselasky mlx4_dbg(dev, "SMP firewall trap_attribute_mask = 0x%x\n", 2782329159Shselasky trap_attr_mask); 2783329159Shselasky 2784329159Shselasky MLX4_GET(traprepress_attr_mask, mailbox->buf, 2785329159Shselasky MLX4_CMD_MAD_DEMUX_TRAP_REPRESS_ATTR_OFFSET); 2786329159Shselasky mlx4_dbg(dev, "SMP firewall traprepress_attribute_mask = 0x%x\n", 2787329159Shselasky traprepress_attr_mask); 2788329159Shselasky 2789329159Shselasky if (set_attr_mask && getresp_attr_mask && trap_attr_mask && 2790329159Shselasky traprepress_attr_mask) 2791329159Shselasky return 1; 2792329159Shselasky 2793329159Shselasky return 0; 2794329159Shselasky} 2795329159Shselasky 2796329159Shselaskyint mlx4_config_mad_demux(struct mlx4_dev *dev) 2797329159Shselasky{ 2798329159Shselasky struct mlx4_cmd_mailbox *mailbox; 2799329159Shselasky int err; 2800329159Shselasky 2801329159Shselasky /* Check if mad_demux is supported */ 2802329159Shselasky if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_MAD_DEMUX)) 2803329159Shselasky return 0; 2804329159Shselasky 2805329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 2806329159Shselasky if (IS_ERR(mailbox)) { 2807329159Shselasky mlx4_warn(dev, "Failed to allocate mailbox for cmd MAD_DEMUX"); 2808329159Shselasky return -ENOMEM; 2809329159Shselasky } 2810329159Shselasky 2811329159Shselasky /* Query mad_demux to find out which MADs are handled by internal sma */ 2812329159Shselasky err = mlx4_cmd_box(dev, 0, mailbox->dma, 0x01 /* subn mgmt class */, 2813329159Shselasky MLX4_CMD_MAD_DEMUX_QUERY_RESTR, MLX4_CMD_MAD_DEMUX, 2814329159Shselasky MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 2815329159Shselasky if (err) { 2816329159Shselasky mlx4_warn(dev, "MLX4_CMD_MAD_DEMUX: query restrictions failed (%d)\n", 2817329159Shselasky err); 2818329159Shselasky goto out; 2819329159Shselasky } 2820329159Shselasky 2821329159Shselasky if (mlx4_check_smp_firewall_active(dev, mailbox)) 2822329159Shselasky dev->flags |= MLX4_FLAG_SECURE_HOST; 2823329159Shselasky 2824329159Shselasky /* Config mad_demux to handle all MADs returned by the query above */ 2825329159Shselasky err = mlx4_cmd(dev, mailbox->dma, 0x01 /* subn mgmt class */, 2826329159Shselasky MLX4_CMD_MAD_DEMUX_CONFIG, MLX4_CMD_MAD_DEMUX, 2827329159Shselasky MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 2828329159Shselasky if (err) { 2829329159Shselasky mlx4_warn(dev, "MLX4_CMD_MAD_DEMUX: configure failed (%d)\n", err); 2830329159Shselasky goto out; 2831329159Shselasky } 2832329159Shselasky 2833329159Shselasky if (dev->flags & MLX4_FLAG_SECURE_HOST) 2834329159Shselasky mlx4_warn(dev, "HCA operating in secure-host mode. SMP firewall activated.\n"); 2835329159Shselaskyout: 2836329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 2837329159Shselasky return err; 2838329159Shselasky} 2839329159Shselasky 2840329159Shselasky/* Access Reg commands */ 2841329159Shselaskyenum mlx4_access_reg_masks { 2842329159Shselasky MLX4_ACCESS_REG_STATUS_MASK = 0x7f, 2843329159Shselasky MLX4_ACCESS_REG_METHOD_MASK = 0x7f, 2844329159Shselasky MLX4_ACCESS_REG_LEN_MASK = 0x7ff 2845329159Shselasky}; 2846329159Shselasky 2847329159Shselaskystruct mlx4_access_reg { 2848329159Shselasky __be16 constant1; 2849329159Shselasky u8 status; 2850329159Shselasky u8 resrvd1; 2851329159Shselasky __be16 reg_id; 2852329159Shselasky u8 method; 2853329159Shselasky u8 constant2; 2854329159Shselasky __be32 resrvd2[2]; 2855329159Shselasky __be16 len_const; 2856329159Shselasky __be16 resrvd3; 2857329159Shselasky#define MLX4_ACCESS_REG_HEADER_SIZE (20) 2858329159Shselasky u8 reg_data[MLX4_MAILBOX_SIZE-MLX4_ACCESS_REG_HEADER_SIZE]; 2859329159Shselasky} __attribute__((__packed__)); 2860329159Shselasky 2861329159Shselasky/** 2862329159Shselasky * mlx4_ACCESS_REG - Generic access reg command. 2863329159Shselasky * @dev: mlx4_dev. 2864329159Shselasky * @reg_id: register ID to access. 2865329159Shselasky * @method: Access method Read/Write. 2866329159Shselasky * @reg_len: register length to Read/Write in bytes. 2867329159Shselasky * @reg_data: reg_data pointer to Read/Write From/To. 2868329159Shselasky * 2869329159Shselasky * Access ConnectX registers FW command. 2870329159Shselasky * Returns 0 on success and copies outbox mlx4_access_reg data 2871329159Shselasky * field into reg_data or a negative error code. 2872329159Shselasky */ 2873329159Shselaskystatic int mlx4_ACCESS_REG(struct mlx4_dev *dev, u16 reg_id, 2874329159Shselasky enum mlx4_access_reg_method method, 2875329159Shselasky u16 reg_len, void *reg_data) 2876329159Shselasky{ 2877329159Shselasky struct mlx4_cmd_mailbox *inbox, *outbox; 2878329159Shselasky struct mlx4_access_reg *inbuf, *outbuf; 2879329159Shselasky int err; 2880329159Shselasky 2881329159Shselasky inbox = mlx4_alloc_cmd_mailbox(dev); 2882329159Shselasky if (IS_ERR(inbox)) 2883329159Shselasky return PTR_ERR(inbox); 2884329159Shselasky 2885329159Shselasky outbox = mlx4_alloc_cmd_mailbox(dev); 2886329159Shselasky if (IS_ERR(outbox)) { 2887329159Shselasky mlx4_free_cmd_mailbox(dev, inbox); 2888329159Shselasky return PTR_ERR(outbox); 2889329159Shselasky } 2890329159Shselasky 2891329159Shselasky inbuf = inbox->buf; 2892329159Shselasky outbuf = outbox->buf; 2893329159Shselasky 2894329159Shselasky inbuf->constant1 = cpu_to_be16(0x1<<11 | 0x4); 2895329159Shselasky inbuf->constant2 = 0x1; 2896329159Shselasky inbuf->reg_id = cpu_to_be16(reg_id); 2897329159Shselasky inbuf->method = method & MLX4_ACCESS_REG_METHOD_MASK; 2898329159Shselasky 2899329159Shselasky reg_len = min(reg_len, (u16)(sizeof(inbuf->reg_data))); 2900329159Shselasky inbuf->len_const = 2901329159Shselasky cpu_to_be16(((reg_len/4 + 1) & MLX4_ACCESS_REG_LEN_MASK) | 2902329159Shselasky ((0x3) << 12)); 2903329159Shselasky 2904329159Shselasky memcpy(inbuf->reg_data, reg_data, reg_len); 2905329159Shselasky err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 0, 0, 2906329159Shselasky MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C, 2907329159Shselasky MLX4_CMD_WRAPPED); 2908329159Shselasky if (err) 2909329159Shselasky goto out; 2910329159Shselasky 2911329159Shselasky if (outbuf->status & MLX4_ACCESS_REG_STATUS_MASK) { 2912329159Shselasky err = outbuf->status & MLX4_ACCESS_REG_STATUS_MASK; 2913329159Shselasky mlx4_err(dev, 2914329159Shselasky "MLX4_CMD_ACCESS_REG(%x) returned REG status (%x)\n", 2915329159Shselasky reg_id, err); 2916329159Shselasky goto out; 2917329159Shselasky } 2918329159Shselasky 2919329159Shselasky memcpy(reg_data, outbuf->reg_data, reg_len); 2920329159Shselaskyout: 2921329159Shselasky mlx4_free_cmd_mailbox(dev, inbox); 2922329159Shselasky mlx4_free_cmd_mailbox(dev, outbox); 2923329159Shselasky return err; 2924329159Shselasky} 2925329159Shselasky 2926329159Shselasky/* ConnectX registers IDs */ 2927329159Shselaskyenum mlx4_reg_id { 2928329159Shselasky MLX4_REG_ID_PTYS = 0x5004, 2929329159Shselasky}; 2930329159Shselasky 2931329159Shselasky/** 2932329159Shselasky * mlx4_ACCESS_PTYS_REG - Access PTYs (Port Type and Speed) 2933329159Shselasky * register 2934329159Shselasky * @dev: mlx4_dev. 2935329159Shselasky * @method: Access method Read/Write. 2936329159Shselasky * @ptys_reg: PTYS register data pointer. 2937329159Shselasky * 2938329159Shselasky * Access ConnectX PTYS register, to Read/Write Port Type/Speed 2939329159Shselasky * configuration 2940329159Shselasky * Returns 0 on success or a negative error code. 2941329159Shselasky */ 2942329159Shselaskyint mlx4_ACCESS_PTYS_REG(struct mlx4_dev *dev, 2943329159Shselasky enum mlx4_access_reg_method method, 2944329159Shselasky struct mlx4_ptys_reg *ptys_reg) 2945329159Shselasky{ 2946329159Shselasky return mlx4_ACCESS_REG(dev, MLX4_REG_ID_PTYS, 2947329159Shselasky method, sizeof(*ptys_reg), ptys_reg); 2948329159Shselasky} 2949329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_ACCESS_PTYS_REG); 2950329159Shselasky 2951329159Shselaskyint mlx4_ACCESS_REG_wrapper(struct mlx4_dev *dev, int slave, 2952329159Shselasky struct mlx4_vhcr *vhcr, 2953329159Shselasky struct mlx4_cmd_mailbox *inbox, 2954329159Shselasky struct mlx4_cmd_mailbox *outbox, 2955329159Shselasky struct mlx4_cmd_info *cmd) 2956329159Shselasky{ 2957329159Shselasky struct mlx4_access_reg *inbuf = inbox->buf; 2958329159Shselasky u8 method = inbuf->method & MLX4_ACCESS_REG_METHOD_MASK; 2959329159Shselasky u16 reg_id = be16_to_cpu(inbuf->reg_id); 2960329159Shselasky 2961329159Shselasky if (slave != mlx4_master_func_num(dev) && 2962329159Shselasky method == MLX4_ACCESS_REG_WRITE) 2963329159Shselasky return -EPERM; 2964329159Shselasky 2965329159Shselasky if (reg_id == MLX4_REG_ID_PTYS) { 2966329159Shselasky struct mlx4_ptys_reg *ptys_reg = 2967329159Shselasky (struct mlx4_ptys_reg *)inbuf->reg_data; 2968329159Shselasky 2969329159Shselasky ptys_reg->local_port = 2970329159Shselasky mlx4_slave_convert_port(dev, slave, 2971329159Shselasky ptys_reg->local_port); 2972329159Shselasky } 2973329159Shselasky 2974329159Shselasky return mlx4_cmd_box(dev, inbox->dma, outbox->dma, vhcr->in_modifier, 2975329159Shselasky 0, MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C, 2976329159Shselasky MLX4_CMD_NATIVE); 2977329159Shselasky} 2978329159Shselasky 2979329159Shselaskystatic int mlx4_SET_PORT_phv_bit(struct mlx4_dev *dev, u8 port, u8 phv_bit) 2980329159Shselasky{ 2981329159Shselasky#define SET_PORT_GEN_PHV_VALID 0x10 2982329159Shselasky#define SET_PORT_GEN_PHV_EN 0x80 2983329159Shselasky 2984329159Shselasky struct mlx4_cmd_mailbox *mailbox; 2985329159Shselasky struct mlx4_set_port_general_context *context; 2986329159Shselasky u32 in_mod; 2987329159Shselasky int err; 2988329159Shselasky 2989329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 2990329159Shselasky if (IS_ERR(mailbox)) 2991329159Shselasky return PTR_ERR(mailbox); 2992329159Shselasky context = mailbox->buf; 2993329159Shselasky 2994329159Shselasky context->v_ignore_fcs |= SET_PORT_GEN_PHV_VALID; 2995329159Shselasky if (phv_bit) 2996329159Shselasky context->phv_en |= SET_PORT_GEN_PHV_EN; 2997329159Shselasky 2998329159Shselasky in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 2999329159Shselasky err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 3000329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 3001329159Shselasky MLX4_CMD_NATIVE); 3002329159Shselasky 3003329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 3004329159Shselasky return err; 3005329159Shselasky} 3006329159Shselasky 3007329159Shselaskyint get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv) 3008329159Shselasky{ 3009329159Shselasky int err; 3010329159Shselasky struct mlx4_func_cap func_cap; 3011329159Shselasky 3012329159Shselasky memset(&func_cap, 0, sizeof(func_cap)); 3013329159Shselasky err = mlx4_QUERY_FUNC_CAP(dev, port, &func_cap); 3014329159Shselasky if (!err) 3015329159Shselasky *phv = func_cap.flags0 & QUERY_FUNC_CAP_PHV_BIT; 3016329159Shselasky return err; 3017329159Shselasky} 3018329159ShselaskyEXPORT_SYMBOL(get_phv_bit); 3019329159Shselasky 3020329159Shselaskyint set_phv_bit(struct mlx4_dev *dev, u8 port, int new_val) 3021329159Shselasky{ 3022329159Shselasky int ret; 3023329159Shselasky 3024329159Shselasky if (mlx4_is_slave(dev)) 3025329159Shselasky return -EPERM; 3026329159Shselasky 3027329159Shselasky if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN && 3028329159Shselasky !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) { 3029329159Shselasky ret = mlx4_SET_PORT_phv_bit(dev, port, new_val); 3030329159Shselasky if (!ret) 3031329159Shselasky dev->caps.phv_bit[port] = new_val; 3032329159Shselasky return ret; 3033329159Shselasky } 3034329159Shselasky 3035329159Shselasky return -EOPNOTSUPP; 3036329159Shselasky} 3037329159ShselaskyEXPORT_SYMBOL(set_phv_bit); 3038329159Shselasky 3039329159Shselaskyvoid mlx4_replace_zero_macs(struct mlx4_dev *dev) 3040329159Shselasky{ 3041329159Shselasky int i; 3042329159Shselasky u8 mac_addr[ETH_ALEN]; 3043329159Shselasky 3044329159Shselasky dev->port_random_macs = 0; 3045329159Shselasky for (i = 1; i <= dev->caps.num_ports; ++i) 3046329159Shselasky if (!dev->caps.def_mac[i] && 3047329159Shselasky dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) { 3048329159Shselasky random_ether_addr(mac_addr); 3049329159Shselasky dev->port_random_macs |= 1 << i; 3050329159Shselasky dev->caps.def_mac[i] = mlx4_mac_to_u64(mac_addr); 3051329159Shselasky } 3052329159Shselasky} 3053329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_replace_zero_macs); 3054