File Index
Files and directories
Sign in
FILE

port.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/port.c C
   1/*
   2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include <linux/mlx5/port.h>
  34#include "mlx5_core.h"
  35
  36/* calling with verbose false will not print error to log */
  37int mlx5_access_reg(struct mlx5_core_dev *dev, void *data_in, int size_in,
  38		    void *data_out, int size_out, u16 reg_id, int arg,
  39		    int write, bool verbose)
  40{
  41	int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
  42	int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
  43	int err = -ENOMEM;
  44	u32 *out = NULL;
  45	u32 *in = NULL;
  46	void *data;
  47
  48	in = kvzalloc(inlen, GFP_KERNEL);
  49	out = kvzalloc(outlen, GFP_KERNEL);
  50	if (!in || !out)
  51		goto out;
  52
  53	data = MLX5_ADDR_OF(access_register_in, in, register_data);
  54	memcpy(data, data_in, size_in);
  55
  56	MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
  57	MLX5_SET(access_register_in, in, op_mod, !write);
  58	MLX5_SET(access_register_in, in, argument, arg);
  59	MLX5_SET(access_register_in, in, register_id, reg_id);
  60
  61	err = mlx5_cmd_do(dev, in, inlen, out, outlen);
  62	if (verbose)
  63		err = mlx5_cmd_check(dev, err, in, out);
  64	if (err)
  65		goto out;
  66
  67	data = MLX5_ADDR_OF(access_register_out, out, register_data);
  68	memcpy(data_out, data, size_out);
  69
  70out:
  71	kvfree(out);
  72	kvfree(in);
  73	return err;
  74}
  75EXPORT_SYMBOL_GPL(mlx5_access_reg);
  76
  77int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
  78			 int size_in, void *data_out, int size_out,
  79			 u16 reg_id, int arg, int write)
  80{
  81	return mlx5_access_reg(dev, data_in, size_in, data_out, size_out,
  82			       reg_id, arg, write, true);
  83}
  84EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
  85
  86int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
  87			u8 access_reg_group)
  88{
  89	u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {0};
  90	int sz = MLX5_ST_SZ_BYTES(pcam_reg);
  91
  92	MLX5_SET(pcam_reg, in, feature_group, feature_group);
  93	MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
  94
  95	return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
  96}
  97
  98int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
  99			u8 access_reg_group)
 100{
 101	u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {0};
 102	int sz = MLX5_ST_SZ_BYTES(mcam_reg);
 103
 104	MLX5_SET(mcam_reg, in, feature_group, feature_group);
 105	MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
 106
 107	return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
 108}
 109
 110int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
 111			u8 feature_group, u8 access_reg_group)
 112{
 113	u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {};
 114	int sz = MLX5_ST_SZ_BYTES(qcam_reg);
 115
 116	MLX5_SET(qcam_reg, in, feature_group, feature_group);
 117	MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group);
 118
 119	return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0);
 120}
 121
 122struct mlx5_reg_pcap {
 123	u8			rsvd0;
 124	u8			port_num;
 125	u8			rsvd1[2];
 126	__be32			caps_127_96;
 127	__be32			caps_95_64;
 128	__be32			caps_63_32;
 129	__be32			caps_31_0;
 130};
 131
 132int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
 133{
 134	struct mlx5_reg_pcap in;
 135	struct mlx5_reg_pcap out;
 136
 137	memset(&in, 0, sizeof(in));
 138	in.caps_127_96 = cpu_to_be32(caps);
 139	in.port_num = port_num;
 140
 141	return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
 142				    sizeof(out), MLX5_REG_PCAP, 0, 1);
 143}
 144EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
 145
 146int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
 147			 int ptys_size, int proto_mask,
 148			 u8 local_port, u8 plane_index)
 149{
 150	u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
 151
 152	MLX5_SET(ptys_reg, in, local_port, local_port);
 153	MLX5_SET(ptys_reg, in, plane_ind, plane_index);
 154	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
 155	return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
 156				    ptys_size, MLX5_REG_PTYS, 0, 0);
 157}
 158EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
 159
 160int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
 161{
 162	u32 in[MLX5_ST_SZ_DW(mlcr_reg)]  = {0};
 163	u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
 164
 165	MLX5_SET(mlcr_reg, in, local_port, 1);
 166	MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
 167	return mlx5_core_access_reg(dev, in, sizeof(in), out,
 168				    sizeof(out), MLX5_REG_MLCR, 0, 1);
 169}
 170
 171int mlx5_query_ib_port_oper(struct mlx5_core_dev *dev, u16 *link_width_oper,
 172			    u16 *proto_oper, u8 local_port, u8 plane_index)
 173{
 174	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 175	int err;
 176
 177	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB,
 178				   local_port, plane_index);
 179	if (err)
 180		return err;
 181
 182	*link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
 183	*proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
 184
 185	return 0;
 186}
 187EXPORT_SYMBOL(mlx5_query_ib_port_oper);
 188
 189/* This function should be used after setting a port register only */
 190void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
 191{
 192	enum mlx5_port_status ps;
 193
 194	mlx5_query_port_admin_status(dev, &ps);
 195	mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
 196	if (ps == MLX5_PORT_UP)
 197		mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
 198}
 199
 200int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
 201			       enum mlx5_port_status status)
 202{
 203	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
 204	u32 out[MLX5_ST_SZ_DW(paos_reg)];
 205
 206	MLX5_SET(paos_reg, in, local_port, 1);
 207	MLX5_SET(paos_reg, in, admin_status, status);
 208	MLX5_SET(paos_reg, in, ase, 1);
 209	return mlx5_core_access_reg(dev, in, sizeof(in), out,
 210				    sizeof(out), MLX5_REG_PAOS, 0, 1);
 211}
 212
 213int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
 214				 enum mlx5_port_status *status)
 215{
 216	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
 217	u32 out[MLX5_ST_SZ_DW(paos_reg)];
 218	int err;
 219
 220	MLX5_SET(paos_reg, in, local_port, 1);
 221	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 222				   sizeof(out), MLX5_REG_PAOS, 0, 0);
 223	if (err)
 224		return err;
 225	*status = MLX5_GET(paos_reg, out, admin_status);
 226	return 0;
 227}
 228
 229static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
 230				u16 *max_mtu, u16 *oper_mtu, u8 port)
 231{
 232	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
 233	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
 234
 235	MLX5_SET(pmtu_reg, in, local_port, port);
 236	mlx5_core_access_reg(dev, in, sizeof(in), out,
 237			     sizeof(out), MLX5_REG_PMTU, 0, 0);
 238
 239	if (max_mtu)
 240		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
 241	if (oper_mtu)
 242		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
 243	if (admin_mtu)
 244		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
 245}
 246
 247int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
 248{
 249	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
 250	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
 251
 252	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
 253	MLX5_SET(pmtu_reg, in, local_port, port);
 254	return mlx5_core_access_reg(dev, in, sizeof(in), out,
 255				   sizeof(out), MLX5_REG_PMTU, 0, 1);
 256}
 257
 258void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
 259			     u8 port)
 260{
 261	mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
 262}
 263EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
 264
 265void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
 266			      u8 port)
 267{
 268	mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
 269}
 270EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
 271
 272int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
 273{
 274	u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
 275	u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
 276	int err;
 277
 278	MLX5_SET(pmlp_reg, in, local_port, 1);
 279	err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
 280				   MLX5_REG_PMLP, 0, 0);
 281	if (err)
 282		return err;
 283
 284	*module_num = MLX5_GET(lane_2_module_mapping,
 285			       MLX5_ADDR_OF(pmlp_reg, out, lane0_module_mapping),
 286			       module);
 287
 288	return 0;
 289}
 290
 291static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num,
 292				u8 *module_id, u8 *status)
 293{
 294	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
 295	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
 296	int err;
 297	u8 *ptr;
 298
 299	MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW);
 300	MLX5_SET(mcia_reg, in, module, module_num);
 301	MLX5_SET(mcia_reg, in, device_address, 0);
 302	MLX5_SET(mcia_reg, in, page_number, 0);
 303	MLX5_SET(mcia_reg, in, size, 1);
 304	MLX5_SET(mcia_reg, in, l, 0);
 305
 306	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 307				   sizeof(out), MLX5_REG_MCIA, 0, 0);
 308	if (err)
 309		return err;
 310
 311	if (MLX5_GET(mcia_reg, out, status)) {
 312		if (status)
 313			*status = MLX5_GET(mcia_reg, out, status);
 314		return -EIO;
 315	}
 316
 317	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
 318
 319	*module_id = ptr[0];
 320
 321	return 0;
 322}
 323
 324static int mlx5_qsfp_eeprom_page(u16 offset)
 325{
 326	if (offset < MLX5_EEPROM_PAGE_LENGTH)
 327		/* Addresses between 0-255 - page 00 */
 328		return 0;
 329
 330	/* Addresses between 256 - 639 belongs to pages 01, 02 and 03
 331	 * For example, offset = 400 belongs to page 02:
 332	 * 1 + ((400 - 256)/128) = 2
 333	 */
 334	return 1 + ((offset - MLX5_EEPROM_PAGE_LENGTH) /
 335		    MLX5_EEPROM_HIGH_PAGE_LENGTH);
 336}
 337
 338static int mlx5_qsfp_eeprom_high_page_offset(int page_num)
 339{
 340	if (!page_num) /* Page 0 always start from low page */
 341		return 0;
 342
 343	/* High page */
 344	return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH;
 345}
 346
 347static void mlx5_qsfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
 348{
 349	*i2c_addr = MLX5_I2C_ADDR_LOW;
 350	*page_num = mlx5_qsfp_eeprom_page(*offset);
 351	*offset -=  mlx5_qsfp_eeprom_high_page_offset(*page_num);
 352}
 353
 354static void mlx5_sfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
 355{
 356	*i2c_addr = MLX5_I2C_ADDR_LOW;
 357	*page_num = 0;
 358
 359	if (*offset < MLX5_EEPROM_PAGE_LENGTH)
 360		return;
 361
 362	*i2c_addr = MLX5_I2C_ADDR_HIGH;
 363	*offset -= MLX5_EEPROM_PAGE_LENGTH;
 364}
 365
 366static int mlx5_mcia_max_bytes(struct mlx5_core_dev *dev)
 367{
 368	/* mcia supports either 12 dwords or 32 dwords */
 369	return (MLX5_CAP_MCAM_FEATURE(dev, mcia_32dwords) ? 32 : 12) * sizeof(u32);
 370}
 371
 372static int mlx5_query_mcia(struct mlx5_core_dev *dev,
 373			   struct mlx5_module_eeprom_query_params *params,
 374			   u8 *data, u8 *status)
 375{
 376	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
 377	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
 378	void *ptr;
 379	u16 size;
 380	int err;
 381
 382	size = min_t(int, params->size, mlx5_mcia_max_bytes(dev));
 383
 384	MLX5_SET(mcia_reg, in, l, 0);
 385	MLX5_SET(mcia_reg, in, size, size);
 386	MLX5_SET(mcia_reg, in, module, params->module_number);
 387	MLX5_SET(mcia_reg, in, device_address, params->offset);
 388	MLX5_SET(mcia_reg, in, page_number, params->page);
 389	MLX5_SET(mcia_reg, in, i2c_device_address, params->i2c_address);
 390
 391	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 392				   sizeof(out), MLX5_REG_MCIA, 0, 0);
 393	if (err)
 394		return err;
 395
 396	if (MLX5_GET(mcia_reg, out, status)) {
 397		if (status)
 398			*status = MLX5_GET(mcia_reg, out, status);
 399		return -EIO;
 400	}
 401
 402	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
 403	memcpy(data, ptr, size);
 404
 405	return size;
 406}
 407
 408int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
 409			     u16 offset, u16 size, u8 *data, u8 *status)
 410{
 411	struct mlx5_module_eeprom_query_params query = {0};
 412	u8 module_id;
 413	int err;
 414
 415	err = mlx5_query_module_num(dev, &query.module_number);
 416	if (err)
 417		return err;
 418
 419	err = mlx5_query_module_id(dev, query.module_number, &module_id,
 420				   status);
 421	if (err)
 422		return err;
 423
 424	switch (module_id) {
 425	case MLX5_MODULE_ID_SFP:
 426		mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
 427		break;
 428	case MLX5_MODULE_ID_QSFP:
 429	case MLX5_MODULE_ID_QSFP_PLUS:
 430	case MLX5_MODULE_ID_QSFP28:
 431		mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
 432		break;
 433	default:
 434		mlx5_core_dbg(dev, "Module ID not recognized: 0x%x\n",
 435			      module_id);
 436		return -EINVAL;
 437	}
 438
 439	if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
 440		/* Cross pages read, read until offset 256 in low page */
 441		size = MLX5_EEPROM_PAGE_LENGTH - offset;
 442
 443	query.size = size;
 444	query.offset = offset;
 445
 446	return mlx5_query_mcia(dev, &query, data, status);
 447}
 448
 449int mlx5_query_module_eeprom_by_page(struct mlx5_core_dev *dev,
 450				     struct mlx5_module_eeprom_query_params *params,
 451				     u8 *data, u8 *status)
 452{
 453	int err;
 454
 455	err = mlx5_query_module_num(dev, &params->module_number);
 456	if (err)
 457		return err;
 458
 459	if (params->i2c_address != MLX5_I2C_ADDR_HIGH &&
 460	    params->i2c_address != MLX5_I2C_ADDR_LOW) {
 461		mlx5_core_err(dev, "I2C address not recognized: 0x%x\n", params->i2c_address);
 462		return -EINVAL;
 463	}
 464
 465	return mlx5_query_mcia(dev, params, data, status);
 466}
 467
 468static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
 469				int pvlc_size,  u8 local_port)
 470{
 471	u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
 472
 473	MLX5_SET(pvlc_reg, in, local_port, local_port);
 474	return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
 475				    pvlc_size, MLX5_REG_PVLC, 0, 0);
 476}
 477
 478int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
 479			      u8 *vl_hw_cap, u8 local_port)
 480{
 481	u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
 482	int err;
 483
 484	err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
 485	if (err)
 486		return err;
 487
 488	*vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
 489
 490	return 0;
 491}
 492EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
 493
 494static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out,
 495			       u32 out_size)
 496{
 497	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 498
 499	MLX5_SET(pfcc_reg, in, local_port, 1);
 500
 501	return mlx5_core_access_reg(dev, in, sizeof(in), out,
 502				    out_size, MLX5_REG_PFCC, 0, 0);
 503}
 504
 505int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
 506{
 507	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 508	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 509
 510	MLX5_SET(pfcc_reg, in, local_port, 1);
 511	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
 512	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
 513
 514	return mlx5_core_access_reg(dev, in, sizeof(in), out,
 515				    sizeof(out), MLX5_REG_PFCC, 0, 1);
 516}
 517
 518int mlx5_query_port_pause(struct mlx5_core_dev *dev,
 519			  u32 *rx_pause, u32 *tx_pause)
 520{
 521	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 522	int err;
 523
 524	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
 525	if (err)
 526		return err;
 527
 528	if (rx_pause)
 529		*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
 530
 531	if (tx_pause)
 532		*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
 533
 534	return 0;
 535}
 536
 537int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
 538				  u16 stall_critical_watermark,
 539				  u16 stall_minor_watermark)
 540{
 541	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 542	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 543
 544	MLX5_SET(pfcc_reg, in, local_port, 1);
 545	MLX5_SET(pfcc_reg, in, pptx_mask_n, 1);
 546	MLX5_SET(pfcc_reg, in, pprx_mask_n, 1);
 547	MLX5_SET(pfcc_reg, in, ppan_mask_n, 1);
 548	MLX5_SET(pfcc_reg, in, critical_stall_mask, 1);
 549	MLX5_SET(pfcc_reg, in, minor_stall_mask, 1);
 550	MLX5_SET(pfcc_reg, in, device_stall_critical_watermark,
 551		 stall_critical_watermark);
 552	MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark);
 553
 554	return mlx5_core_access_reg(dev, in, sizeof(in), out,
 555				    sizeof(out), MLX5_REG_PFCC, 0, 1);
 556}
 557
 558int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
 559				    u16 *stall_critical_watermark,
 560				    u16 *stall_minor_watermark)
 561{
 562	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 563	int err;
 564
 565	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
 566	if (err)
 567		return err;
 568
 569	if (stall_critical_watermark)
 570		*stall_critical_watermark = MLX5_GET(pfcc_reg, out,
 571						     device_stall_critical_watermark);
 572
 573	if (stall_minor_watermark)
 574		*stall_minor_watermark = MLX5_GET(pfcc_reg, out,
 575						  device_stall_minor_watermark);
 576
 577	return 0;
 578}
 579
 580int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
 581{
 582	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 583	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 584
 585	MLX5_SET(pfcc_reg, in, local_port, 1);
 586	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
 587	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
 588	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
 589	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
 590
 591	return mlx5_core_access_reg(dev, in, sizeof(in), out,
 592				    sizeof(out), MLX5_REG_PFCC, 0, 1);
 593}
 594
 595int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
 596{
 597	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 598	int err;
 599
 600	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
 601	if (err)
 602		return err;
 603
 604	if (pfc_en_tx)
 605		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
 606
 607	if (pfc_en_rx)
 608		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
 609
 610	return 0;
 611}
 612
 613int mlx5_max_tc(struct mlx5_core_dev *mdev)
 614{
 615	u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
 616
 617	return num_tc - 1;
 618}
 619
 620int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
 621{
 622	u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
 623
 624	MLX5_SET(dcbx_param, in, port_number, 1);
 625
 626	return  mlx5_core_access_reg(mdev, in, sizeof(in), out,
 627				    sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
 628}
 629
 630int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
 631{
 632	u32 out[MLX5_ST_SZ_DW(dcbx_param)];
 633
 634	MLX5_SET(dcbx_param, in, port_number, 1);
 635
 636	return mlx5_core_access_reg(mdev, in, sizeof(out), out,
 637				    sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
 638}
 639
 640int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
 641{
 642	u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
 643	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 644	int err;
 645	int i;
 646
 647	for (i = 0; i < 8; i++) {
 648		if (prio_tc[i] > mlx5_max_tc(mdev))
 649			return -EINVAL;
 650
 651		MLX5_SET(qtct_reg, in, prio, i);
 652		MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
 653
 654		err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 655					   sizeof(out), MLX5_REG_QTCT, 0, 1);
 656		if (err)
 657			return err;
 658	}
 659
 660	return 0;
 661}
 662
 663int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
 664			    u8 prio, u8 *tc)
 665{
 666	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
 667	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 668	int err;
 669
 670	memset(in, 0, sizeof(in));
 671	memset(out, 0, sizeof(out));
 672
 673	MLX5_SET(qtct_reg, in, port_number, 1);
 674	MLX5_SET(qtct_reg, in, prio, prio);
 675
 676	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 677				   sizeof(out), MLX5_REG_QTCT, 0, 0);
 678	if (!err)
 679		*tc = MLX5_GET(qtct_reg, out, tclass);
 680
 681	return err;
 682}
 683
 684static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
 685				   int inlen)
 686{
 687	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 688
 689	if (!MLX5_CAP_GEN(mdev, ets))
 690		return -EOPNOTSUPP;
 691
 692	return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
 693				    MLX5_REG_QETCR, 0, 1);
 694}
 695
 696static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
 697				     int outlen)
 698{
 699	u32 in[MLX5_ST_SZ_DW(qetc_reg)];
 700
 701	if (!MLX5_CAP_GEN(mdev, ets))
 702		return -EOPNOTSUPP;
 703
 704	memset(in, 0, sizeof(in));
 705	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
 706				    MLX5_REG_QETCR, 0, 0);
 707}
 708
 709int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
 710{
 711	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
 712	int i;
 713
 714	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 715		MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
 716		MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
 717	}
 718
 719	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 720}
 721
 722int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
 723			     u8 tc, u8 *tc_group)
 724{
 725	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 726	void *ets_tcn_conf;
 727	int err;
 728
 729	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
 730	if (err)
 731		return err;
 732
 733	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
 734				    tc_configuration[tc]);
 735
 736	*tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 737			     group);
 738
 739	return 0;
 740}
 741
 742int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
 743{
 744	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
 745	int i;
 746
 747	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 748		MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
 749		MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
 750	}
 751
 752	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 753}
 754
 755int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
 756				u8 tc, u8 *bw_pct)
 757{
 758	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 759	void *ets_tcn_conf;
 760	int err;
 761
 762	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
 763	if (err)
 764		return err;
 765
 766	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
 767				    tc_configuration[tc]);
 768
 769	*bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 770			   bw_allocation);
 771
 772	return 0;
 773}
 774
 775int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
 776				    u8 *max_bw_value,
 777				    u8 *max_bw_units)
 778{
 779	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
 780	void *ets_tcn_conf;
 781	int i;
 782
 783	MLX5_SET(qetc_reg, in, port_number, 1);
 784
 785	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 786		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
 787
 788		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
 789		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
 790			 max_bw_units[i]);
 791		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
 792			 max_bw_value[i]);
 793	}
 794
 795	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 796}
 797
 798int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
 799				   u8 *max_bw_value,
 800				   u8 *max_bw_units)
 801{
 802	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 803	void *ets_tcn_conf;
 804	int err;
 805	int i;
 806
 807	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
 808	if (err)
 809		return err;
 810
 811	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 812		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
 813
 814		max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 815					   max_bw_value);
 816		max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 817					   max_bw_units);
 818	}
 819
 820	return 0;
 821}
 822
 823int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
 824{
 825	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {};
 826
 827	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
 828	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
 829	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
 830	return mlx5_cmd_exec_in(mdev, set_wol_rol, in);
 831}
 832
 833int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
 834{
 835	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {};
 836	u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {};
 837	int err;
 838
 839	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
 840	err = mlx5_cmd_exec_inout(mdev, query_wol_rol, in, out);
 841	if (!err)
 842		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
 843
 844	return err;
 845}
 846
 847int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen)
 848{
 849	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
 850
 851	MLX5_SET(pcmr_reg, in, local_port, 1);
 852	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
 853				    outlen, MLX5_REG_PCMR, 0, 0);
 854}
 855
 856int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
 857{
 858	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
 859
 860	return mlx5_core_access_reg(mdev, in, inlen, out,
 861				    sizeof(out), MLX5_REG_PCMR, 0, 1);
 862}
 863
 864int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
 865{
 866	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
 867	int err;
 868
 869	err = mlx5_query_ports_check(mdev, in, sizeof(in));
 870	if (err)
 871		return err;
 872	MLX5_SET(pcmr_reg, in, local_port, 1);
 873	MLX5_SET(pcmr_reg, in, fcs_chk, enable);
 874	return mlx5_set_ports_check(mdev, in, sizeof(in));
 875}
 876
 877void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
 878			 bool *enabled)
 879{
 880	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
 881	/* Default values for FW which do not support MLX5_REG_PCMR */
 882	*supported = false;
 883	*enabled = true;
 884
 885	if (!MLX5_CAP_GEN(mdev, ports_check))
 886		return;
 887
 888	if (mlx5_query_ports_check(mdev, out, sizeof(out)))
 889		return;
 890
 891	*supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
 892	*enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
 893}
 894
 895int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
 896{
 897	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
 898
 899	return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
 900				    mtpps_size, MLX5_REG_MTPPS, 0, 0);
 901}
 902
 903int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
 904{
 905	u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
 906
 907	return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
 908				    sizeof(out), MLX5_REG_MTPPS, 0, 1);
 909}
 910
 911int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
 912{
 913	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 914	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 915	int err = 0;
 916
 917	MLX5_SET(mtppse_reg, in, pin, pin);
 918
 919	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 920				   sizeof(out), MLX5_REG_MTPPSE, 0, 0);
 921	if (err)
 922		return err;
 923
 924	*arm = MLX5_GET(mtppse_reg, in, event_arm);
 925	*mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
 926
 927	return err;
 928}
 929
 930int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
 931{
 932	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 933	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 934
 935	MLX5_SET(mtppse_reg, in, pin, pin);
 936	MLX5_SET(mtppse_reg, in, event_arm, arm);
 937	MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
 938
 939	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
 940				    sizeof(out), MLX5_REG_MTPPSE, 0, 1);
 941}
 942
 943int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
 944{
 945	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
 946	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
 947	int err;
 948
 949	MLX5_SET(qpts_reg, in, local_port, 1);
 950	MLX5_SET(qpts_reg, in, trust_state, trust_state);
 951
 952	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 953				   sizeof(out), MLX5_REG_QPTS, 0, 1);
 954	return err;
 955}
 956
 957int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
 958{
 959	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
 960	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
 961	int err;
 962
 963	MLX5_SET(qpts_reg, in, local_port, 1);
 964
 965	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 966				   sizeof(out), MLX5_REG_QPTS, 0, 0);
 967	if (!err)
 968		*trust_state = MLX5_GET(qpts_reg, out, trust_state);
 969
 970	return err;
 971}
 972
 973int mlx5_query_port_buffer_ownership(struct mlx5_core_dev *mdev,
 974				     u8 *buffer_ownership)
 975{
 976	u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {};
 977	int err;
 978
 979	if (!MLX5_CAP_PCAM_FEATURE(mdev, buffer_ownership)) {
 980		*buffer_ownership = MLX5_BUF_OWNERSHIP_UNKNOWN;
 981		return 0;
 982	}
 983
 984	err = mlx5_query_pfcc_reg(mdev, out, sizeof(out));
 985	if (err)
 986		return err;
 987
 988	*buffer_ownership = MLX5_GET(pfcc_reg, out, buf_ownership);
 989
 990	return 0;
 991}
 992
 993int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio)
 994{
 995	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
 996	void *qpdpm_dscp;
 997	void *out;
 998	void *in;
 999	int err;
1000
1001	in = kzalloc(sz, GFP_KERNEL);
1002	out = kzalloc(sz, GFP_KERNEL);
1003	if (!in || !out) {
1004		err = -ENOMEM;
1005		goto out;
1006	}
1007
1008	MLX5_SET(qpdpm_reg, in, local_port, 1);
1009	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1010	if (err)
1011		goto out;
1012
1013	memcpy(in, out, sz);
1014	MLX5_SET(qpdpm_reg, in, local_port, 1);
1015
1016	/* Update the corresponding dscp entry */
1017	qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]);
1018	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio);
1019	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
1020	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
1021
1022out:
1023	kfree(in);
1024	kfree(out);
1025	return err;
1026}
1027
1028/* dscp2prio[i]: priority that dscp i mapped to */
1029#define MLX5E_SUPPORTED_DSCP 64
1030int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
1031{
1032	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1033	void *qpdpm_dscp;
1034	void *out;
1035	void *in;
1036	int err;
1037	int i;
1038
1039	in = kzalloc(sz, GFP_KERNEL);
1040	out = kzalloc(sz, GFP_KERNEL);
1041	if (!in || !out) {
1042		err = -ENOMEM;
1043		goto out;
1044	}
1045
1046	MLX5_SET(qpdpm_reg, in, local_port, 1);
1047	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1048	if (err)
1049		goto out;
1050
1051	for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) {
1052		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
1053		dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
1054	}
1055
1056out:
1057	kfree(in);
1058	kfree(out);
1059	return err;
1060}
1061
1062/* speed in units of 1Mb */
1063static const struct mlx5_link_info mlx5e_link_info[MLX5E_LINK_MODES_NUMBER] = {
1064	[MLX5E_1000BASE_CX_SGMII]	= {.speed = 1000, .lanes = 1},
1065	[MLX5E_1000BASE_KX]		= {.speed = 1000, .lanes = 1},
1066	[MLX5E_10GBASE_CX4]		= {.speed = 10000, .lanes = 4},
1067	[MLX5E_10GBASE_KX4]		= {.speed = 10000, .lanes = 4},
1068	[MLX5E_10GBASE_KR]		= {.speed = 10000, .lanes = 1},
1069	[MLX5E_20GBASE_KR2]		= {.speed = 20000, .lanes = 2},
1070	[MLX5E_40GBASE_CR4]		= {.speed = 40000, .lanes = 4},
1071	[MLX5E_40GBASE_KR4]		= {.speed = 40000, .lanes = 4},
1072	[MLX5E_56GBASE_R4]		= {.speed = 56000, .lanes = 4},
1073	[MLX5E_10GBASE_CR]		= {.speed = 10000, .lanes = 1},
1074	[MLX5E_10GBASE_SR]		= {.speed = 10000, .lanes = 1},
1075	[MLX5E_10GBASE_ER]		= {.speed = 10000, .lanes = 1},
1076	[MLX5E_40GBASE_SR4]		= {.speed = 40000, .lanes = 4},
1077	[MLX5E_40GBASE_LR4]		= {.speed = 40000, .lanes = 4},
1078	[MLX5E_50GBASE_SR2]		= {.speed = 50000, .lanes = 2},
1079	[MLX5E_100GBASE_CR4]		= {.speed = 100000, .lanes = 4},
1080	[MLX5E_100GBASE_SR4]		= {.speed = 100000, .lanes = 4},
1081	[MLX5E_100GBASE_KR4]		= {.speed = 100000, .lanes = 4},
1082	[MLX5E_100GBASE_LR4]		= {.speed = 100000, .lanes = 4},
1083	[MLX5E_100BASE_TX]		= {.speed = 100, .lanes = 1},
1084	[MLX5E_1000BASE_T]		= {.speed = 1000, .lanes = 1},
1085	[MLX5E_10GBASE_T]		= {.speed = 10000, .lanes = 1},
1086	[MLX5E_25GBASE_CR]		= {.speed = 25000, .lanes = 1},
1087	[MLX5E_25GBASE_KR]		= {.speed = 25000, .lanes = 1},
1088	[MLX5E_25GBASE_SR]		= {.speed = 25000, .lanes = 1},
1089	[MLX5E_50GBASE_CR2]		= {.speed = 50000, .lanes = 2},
1090	[MLX5E_50GBASE_KR2]		= {.speed = 50000, .lanes = 2},
1091};
1092
1093static const struct mlx5_link_info
1094mlx5e_ext_link_info[MLX5E_EXT_LINK_MODES_NUMBER] = {
1095	[MLX5E_SGMII_100M]			= {.speed = 100, .lanes = 1},
1096	[MLX5E_1000BASE_X_SGMII]		= {.speed = 1000, .lanes = 1},
1097	[MLX5E_5GBASE_R]			= {.speed = 5000, .lanes = 1},
1098	[MLX5E_10GBASE_XFI_XAUI_1]		= {.speed = 10000, .lanes = 1},
1099	[MLX5E_40GBASE_XLAUI_4_XLPPI_4]		= {.speed = 40000, .lanes = 4},
1100	[MLX5E_25GAUI_1_25GBASE_CR_KR]		= {.speed = 25000, .lanes = 1},
1101	[MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2]	= {.speed = 50000, .lanes = 2},
1102	[MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR]	= {.speed = 50000, .lanes = 1},
1103	[MLX5E_CAUI_4_100GBASE_CR4_KR4]		= {.speed = 100000, .lanes = 4},
1104	[MLX5E_100GAUI_2_100GBASE_CR2_KR2]	= {.speed = 100000, .lanes = 2},
1105	[MLX5E_200GAUI_4_200GBASE_CR4_KR4]	= {.speed = 200000, .lanes = 4},
1106	[MLX5E_400GAUI_8_400GBASE_CR8]		= {.speed = 400000, .lanes = 8},
1107	[MLX5E_100GAUI_1_100GBASE_CR_KR]	= {.speed = 100000, .lanes = 1},
1108	[MLX5E_200GAUI_2_200GBASE_CR2_KR2]	= {.speed = 200000, .lanes = 2},
1109	[MLX5E_400GAUI_4_400GBASE_CR4_KR4]	= {.speed = 400000, .lanes = 4},
1110	[MLX5E_800GAUI_8_800GBASE_CR8_KR8]	= {.speed = 800000, .lanes = 8},
1111	[MLX5E_200GAUI_1_200GBASE_CR1_KR1]	= {.speed = 200000, .lanes = 1},
1112	[MLX5E_400GAUI_2_400GBASE_CR2_KR2]	= {.speed = 400000, .lanes = 2},
1113	[MLX5E_800GAUI_4_800GBASE_CR4_KR4]	= {.speed = 800000, .lanes = 4},
1114	[MLX5E_1600TAUI_8_1600TBASE_CR8_KR8]	= {.speed = 1600000, .lanes = 8},
1115};
1116
1117int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
1118			      struct mlx5_port_eth_proto *eproto)
1119{
1120	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
1121	int err;
1122
1123	if (!eproto)
1124		return -EINVAL;
1125
1126	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port, 0);
1127	if (err)
1128		return err;
1129
1130	eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
1131					   eth_proto_capability);
1132	eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
1133	eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
1134	return 0;
1135}
1136
1137bool mlx5_ptys_ext_supported(struct mlx5_core_dev *mdev)
1138{
1139	struct mlx5_port_eth_proto eproto;
1140	int err;
1141
1142	if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet))
1143		return true;
1144
1145	err = mlx5_port_query_eth_proto(mdev, 1, true, &eproto);
1146	if (err)
1147		return false;
1148
1149	return !!eproto.cap;
1150}
1151
1152static void mlx5e_port_get_link_mode_info_arr(struct mlx5_core_dev *mdev,
1153					      const struct mlx5_link_info **arr,
1154					      u32 *size,
1155					      bool force_legacy)
1156{
1157	bool ext = force_legacy ? false : mlx5_ptys_ext_supported(mdev);
1158
1159	*size = ext ? ARRAY_SIZE(mlx5e_ext_link_info) :
1160		      ARRAY_SIZE(mlx5e_link_info);
1161	*arr  = ext ? mlx5e_ext_link_info : mlx5e_link_info;
1162}
1163
1164const struct mlx5_link_info *mlx5_port_ptys2info(struct mlx5_core_dev *mdev,
1165						 u32 eth_proto_oper,
1166						 bool force_legacy)
1167{
1168	unsigned long temp = eth_proto_oper;
1169	const struct mlx5_link_info *table;
1170	u32 max_size;
1171	int i;
1172
1173	mlx5e_port_get_link_mode_info_arr(mdev, &table, &max_size,
1174					  force_legacy);
1175	i = find_first_bit(&temp, max_size);
1176
1177	/* mlx5e_link_info has holes. Check speed
1178	 * is not zero as indication of one.
1179	 */
1180	if (i < max_size && table[i].speed)
1181		return &table[i];
1182
1183	return NULL;
1184}
1185
1186u32 mlx5_port_info2linkmodes(struct mlx5_core_dev *mdev,
1187			     struct mlx5_link_info *info,
1188			     bool force_legacy)
1189{
1190	const struct mlx5_link_info *table;
1191	u32 link_modes = 0;
1192	u32 max_size;
1193	int i;
1194
1195	mlx5e_port_get_link_mode_info_arr(mdev, &table, &max_size,
1196					  force_legacy);
1197	for (i = 0; i < max_size; ++i) {
1198		if (table[i].speed == info->speed) {
1199			if (!info->lanes || table[i].lanes == info->lanes)
1200				link_modes |= MLX5E_PROT_MASK(i);
1201		}
1202	}
1203	return link_modes;
1204}
1205
1206int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
1207{
1208	const struct mlx5_link_info *table;
1209	struct mlx5_port_eth_proto eproto;
1210	u32 max_speed = 0;
1211	u32 max_size;
1212	bool ext;
1213	int err;
1214	int i;
1215
1216	ext = mlx5_ptys_ext_supported(mdev);
1217	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
1218	if (err)
1219		return err;
1220
1221	mlx5e_port_get_link_mode_info_arr(mdev, &table, &max_size, false);
1222	for (i = 0; i < max_size; ++i)
1223		if (eproto.cap & MLX5E_PROT_MASK(i))
1224			max_speed = max(max_speed, table[i].speed);
1225
1226	*speed = max_speed;
1227	return 0;
1228}
1229
1230int mlx5_query_mpir_reg(struct mlx5_core_dev *dev, u32 *mpir)
1231{
1232	u32 in[MLX5_ST_SZ_DW(mpir_reg)] = {};
1233	int sz = MLX5_ST_SZ_BYTES(mpir_reg);
1234
1235	MLX5_SET(mpir_reg, in, local_port, 1);
1236
1237	return mlx5_core_access_reg(dev, in, sz, mpir, sz, MLX5_REG_MPIR, 0, 0);
1238}
~/ Read-only file preview.