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 */
mlx5_access_reg(struct mlx5_core_dev * dev,void * data_in,int size_in,void * data_out,int size_out,u16 reg_id,int arg,int write,bool verbose)37 int 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 
70 out:
71 	kvfree(out);
72 	kvfree(in);
73 	return err;
74 }
75 EXPORT_SYMBOL_GPL(mlx5_access_reg);
76 
mlx5_core_access_reg(struct mlx5_core_dev * dev,void * data_in,int size_in,void * data_out,int size_out,u16 reg_id,int arg,int write)77 int 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 }
84 EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
85 
mlx5_query_pcam_reg(struct mlx5_core_dev * dev,u32 * pcam,u8 feature_group,u8 access_reg_group)86 int 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 
mlx5_query_mcam_reg(struct mlx5_core_dev * dev,u32 * mcam,u8 feature_group,u8 access_reg_group)98 int 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 
mlx5_query_qcam_reg(struct mlx5_core_dev * mdev,u32 * qcam,u8 feature_group,u8 access_reg_group)110 int 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 
122 struct 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 
mlx5_set_port_caps(struct mlx5_core_dev * dev,u8 port_num,u32 caps)132 int 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 }
144 EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
145 
mlx5_query_port_ptys(struct mlx5_core_dev * dev,u32 * ptys,int ptys_size,int proto_mask,u8 local_port,u8 plane_index)146 int 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 }
158 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
159 
mlx5_set_port_beacon(struct mlx5_core_dev * dev,u16 beacon_duration)160 int 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 
mlx5_query_ib_port_oper(struct mlx5_core_dev * dev,u16 * link_width_oper,u16 * proto_oper,u8 local_port,u8 plane_index)171 int 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 }
187 EXPORT_SYMBOL(mlx5_query_ib_port_oper);
188 
189 /* This function should be used after setting a port register only */
mlx5_toggle_port_link(struct mlx5_core_dev * dev)190 void 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 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
200 
mlx5_set_port_admin_status(struct mlx5_core_dev * dev,enum mlx5_port_status status)201 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
202 			       enum mlx5_port_status status)
203 {
204 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
205 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
206 
207 	MLX5_SET(paos_reg, in, local_port, 1);
208 	MLX5_SET(paos_reg, in, admin_status, status);
209 	MLX5_SET(paos_reg, in, ase, 1);
210 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
211 				    sizeof(out), MLX5_REG_PAOS, 0, 1);
212 }
213 EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
214 
mlx5_query_port_admin_status(struct mlx5_core_dev * dev,enum mlx5_port_status * status)215 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
216 				 enum mlx5_port_status *status)
217 {
218 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
219 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
220 	int err;
221 
222 	MLX5_SET(paos_reg, in, local_port, 1);
223 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
224 				   sizeof(out), MLX5_REG_PAOS, 0, 0);
225 	if (err)
226 		return err;
227 	*status = MLX5_GET(paos_reg, out, admin_status);
228 	return 0;
229 }
230 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
231 
mlx5_query_port_mtu(struct mlx5_core_dev * dev,u16 * admin_mtu,u16 * max_mtu,u16 * oper_mtu,u8 port)232 static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
233 				u16 *max_mtu, u16 *oper_mtu, u8 port)
234 {
235 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
236 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
237 
238 	MLX5_SET(pmtu_reg, in, local_port, port);
239 	mlx5_core_access_reg(dev, in, sizeof(in), out,
240 			     sizeof(out), MLX5_REG_PMTU, 0, 0);
241 
242 	if (max_mtu)
243 		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
244 	if (oper_mtu)
245 		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
246 	if (admin_mtu)
247 		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
248 }
249 
mlx5_set_port_mtu(struct mlx5_core_dev * dev,u16 mtu,u8 port)250 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
251 {
252 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
253 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
254 
255 	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
256 	MLX5_SET(pmtu_reg, in, local_port, port);
257 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
258 				   sizeof(out), MLX5_REG_PMTU, 0, 1);
259 }
260 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
261 
mlx5_query_port_max_mtu(struct mlx5_core_dev * dev,u16 * max_mtu,u8 port)262 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
263 			     u8 port)
264 {
265 	mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
266 }
267 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
268 
mlx5_query_port_oper_mtu(struct mlx5_core_dev * dev,u16 * oper_mtu,u8 port)269 void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
270 			      u8 port)
271 {
272 	mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
273 }
274 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
275 
mlx5_query_module_num(struct mlx5_core_dev * dev,int * module_num)276 int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
277 {
278 	u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
279 	u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
280 	int err;
281 
282 	MLX5_SET(pmlp_reg, in, local_port, 1);
283 	err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
284 				   MLX5_REG_PMLP, 0, 0);
285 	if (err)
286 		return err;
287 
288 	*module_num = MLX5_GET(lane_2_module_mapping,
289 			       MLX5_ADDR_OF(pmlp_reg, out, lane0_module_mapping),
290 			       module);
291 
292 	return 0;
293 }
294 
mlx5_query_module_id(struct mlx5_core_dev * dev,int module_num,u8 * module_id)295 static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num,
296 				u8 *module_id)
297 {
298 	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
299 	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
300 	int err, status;
301 	u8 *ptr;
302 
303 	MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW);
304 	MLX5_SET(mcia_reg, in, module, module_num);
305 	MLX5_SET(mcia_reg, in, device_address, 0);
306 	MLX5_SET(mcia_reg, in, page_number, 0);
307 	MLX5_SET(mcia_reg, in, size, 1);
308 	MLX5_SET(mcia_reg, in, l, 0);
309 
310 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
311 				   sizeof(out), MLX5_REG_MCIA, 0, 0);
312 	if (err)
313 		return err;
314 
315 	status = MLX5_GET(mcia_reg, out, status);
316 	if (status) {
317 		mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
318 			      status);
319 		return -EIO;
320 	}
321 	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
322 
323 	*module_id = ptr[0];
324 
325 	return 0;
326 }
327 
mlx5_qsfp_eeprom_page(u16 offset)328 static int mlx5_qsfp_eeprom_page(u16 offset)
329 {
330 	if (offset < MLX5_EEPROM_PAGE_LENGTH)
331 		/* Addresses between 0-255 - page 00 */
332 		return 0;
333 
334 	/* Addresses between 256 - 639 belongs to pages 01, 02 and 03
335 	 * For example, offset = 400 belongs to page 02:
336 	 * 1 + ((400 - 256)/128) = 2
337 	 */
338 	return 1 + ((offset - MLX5_EEPROM_PAGE_LENGTH) /
339 		    MLX5_EEPROM_HIGH_PAGE_LENGTH);
340 }
341 
mlx5_qsfp_eeprom_high_page_offset(int page_num)342 static int mlx5_qsfp_eeprom_high_page_offset(int page_num)
343 {
344 	if (!page_num) /* Page 0 always start from low page */
345 		return 0;
346 
347 	/* High page */
348 	return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH;
349 }
350 
mlx5_qsfp_eeprom_params_set(u16 * i2c_addr,int * page_num,u16 * offset)351 static void mlx5_qsfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
352 {
353 	*i2c_addr = MLX5_I2C_ADDR_LOW;
354 	*page_num = mlx5_qsfp_eeprom_page(*offset);
355 	*offset -=  mlx5_qsfp_eeprom_high_page_offset(*page_num);
356 }
357 
mlx5_sfp_eeprom_params_set(u16 * i2c_addr,int * page_num,u16 * offset)358 static void mlx5_sfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
359 {
360 	*i2c_addr = MLX5_I2C_ADDR_LOW;
361 	*page_num = 0;
362 
363 	if (*offset < MLX5_EEPROM_PAGE_LENGTH)
364 		return;
365 
366 	*i2c_addr = MLX5_I2C_ADDR_HIGH;
367 	*offset -= MLX5_EEPROM_PAGE_LENGTH;
368 }
369 
mlx5_mcia_max_bytes(struct mlx5_core_dev * dev)370 static int mlx5_mcia_max_bytes(struct mlx5_core_dev *dev)
371 {
372 	/* mcia supports either 12 dwords or 32 dwords */
373 	return (MLX5_CAP_MCAM_FEATURE(dev, mcia_32dwords) ? 32 : 12) * sizeof(u32);
374 }
375 
mlx5_query_mcia(struct mlx5_core_dev * dev,struct mlx5_module_eeprom_query_params * params,u8 * data)376 static int mlx5_query_mcia(struct mlx5_core_dev *dev,
377 			   struct mlx5_module_eeprom_query_params *params, u8 *data)
378 {
379 	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
380 	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
381 	int status, err;
382 	void *ptr;
383 	u16 size;
384 
385 	size = min_t(int, params->size, mlx5_mcia_max_bytes(dev));
386 
387 	MLX5_SET(mcia_reg, in, l, 0);
388 	MLX5_SET(mcia_reg, in, size, size);
389 	MLX5_SET(mcia_reg, in, module, params->module_number);
390 	MLX5_SET(mcia_reg, in, device_address, params->offset);
391 	MLX5_SET(mcia_reg, in, page_number, params->page);
392 	MLX5_SET(mcia_reg, in, i2c_device_address, params->i2c_address);
393 
394 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
395 				   sizeof(out), MLX5_REG_MCIA, 0, 0);
396 	if (err)
397 		return err;
398 
399 	status = MLX5_GET(mcia_reg, out, status);
400 	if (status) {
401 		mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
402 			      status);
403 		return -EIO;
404 	}
405 
406 	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
407 	memcpy(data, ptr, size);
408 
409 	return size;
410 }
411 
mlx5_query_module_eeprom(struct mlx5_core_dev * dev,u16 offset,u16 size,u8 * data)412 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
413 			     u16 offset, u16 size, u8 *data)
414 {
415 	struct mlx5_module_eeprom_query_params query = {0};
416 	u8 module_id;
417 	int err;
418 
419 	err = mlx5_query_module_num(dev, &query.module_number);
420 	if (err)
421 		return err;
422 
423 	err = mlx5_query_module_id(dev, query.module_number, &module_id);
424 	if (err)
425 		return err;
426 
427 	switch (module_id) {
428 	case MLX5_MODULE_ID_SFP:
429 		mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
430 		break;
431 	case MLX5_MODULE_ID_QSFP:
432 	case MLX5_MODULE_ID_QSFP_PLUS:
433 	case MLX5_MODULE_ID_QSFP28:
434 		mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
435 		break;
436 	default:
437 		mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
438 		return -EINVAL;
439 	}
440 
441 	if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
442 		/* Cross pages read, read until offset 256 in low page */
443 		size = MLX5_EEPROM_PAGE_LENGTH - offset;
444 
445 	query.size = size;
446 	query.offset = offset;
447 
448 	return mlx5_query_mcia(dev, &query, data);
449 }
450 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
451 
mlx5_query_module_eeprom_by_page(struct mlx5_core_dev * dev,struct mlx5_module_eeprom_query_params * params,u8 * data)452 int mlx5_query_module_eeprom_by_page(struct mlx5_core_dev *dev,
453 				     struct mlx5_module_eeprom_query_params *params,
454 				     u8 *data)
455 {
456 	int err;
457 
458 	err = mlx5_query_module_num(dev, &params->module_number);
459 	if (err)
460 		return err;
461 
462 	if (params->i2c_address != MLX5_I2C_ADDR_HIGH &&
463 	    params->i2c_address != MLX5_I2C_ADDR_LOW) {
464 		mlx5_core_err(dev, "I2C address not recognized: 0x%x\n", params->i2c_address);
465 		return -EINVAL;
466 	}
467 
468 	return mlx5_query_mcia(dev, params, data);
469 }
470 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom_by_page);
471 
mlx5_query_port_pvlc(struct mlx5_core_dev * dev,u32 * pvlc,int pvlc_size,u8 local_port)472 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
473 				int pvlc_size,  u8 local_port)
474 {
475 	u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
476 
477 	MLX5_SET(pvlc_reg, in, local_port, local_port);
478 	return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
479 				    pvlc_size, MLX5_REG_PVLC, 0, 0);
480 }
481 
mlx5_query_port_vl_hw_cap(struct mlx5_core_dev * dev,u8 * vl_hw_cap,u8 local_port)482 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
483 			      u8 *vl_hw_cap, u8 local_port)
484 {
485 	u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
486 	int err;
487 
488 	err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
489 	if (err)
490 		return err;
491 
492 	*vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
493 
494 	return 0;
495 }
496 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
497 
mlx5_query_pfcc_reg(struct mlx5_core_dev * dev,u32 * out,u32 out_size)498 static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out,
499 			       u32 out_size)
500 {
501 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
502 
503 	MLX5_SET(pfcc_reg, in, local_port, 1);
504 
505 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
506 				    out_size, MLX5_REG_PFCC, 0, 0);
507 }
508 
mlx5_set_port_pause(struct mlx5_core_dev * dev,u32 rx_pause,u32 tx_pause)509 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
510 {
511 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
512 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
513 
514 	MLX5_SET(pfcc_reg, in, local_port, 1);
515 	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
516 	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
517 
518 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
519 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
520 }
521 EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
522 
mlx5_query_port_pause(struct mlx5_core_dev * dev,u32 * rx_pause,u32 * tx_pause)523 int mlx5_query_port_pause(struct mlx5_core_dev *dev,
524 			  u32 *rx_pause, u32 *tx_pause)
525 {
526 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
527 	int err;
528 
529 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
530 	if (err)
531 		return err;
532 
533 	if (rx_pause)
534 		*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
535 
536 	if (tx_pause)
537 		*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
538 
539 	return 0;
540 }
541 EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
542 
mlx5_set_port_stall_watermark(struct mlx5_core_dev * dev,u16 stall_critical_watermark,u16 stall_minor_watermark)543 int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
544 				  u16 stall_critical_watermark,
545 				  u16 stall_minor_watermark)
546 {
547 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
548 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
549 
550 	MLX5_SET(pfcc_reg, in, local_port, 1);
551 	MLX5_SET(pfcc_reg, in, pptx_mask_n, 1);
552 	MLX5_SET(pfcc_reg, in, pprx_mask_n, 1);
553 	MLX5_SET(pfcc_reg, in, ppan_mask_n, 1);
554 	MLX5_SET(pfcc_reg, in, critical_stall_mask, 1);
555 	MLX5_SET(pfcc_reg, in, minor_stall_mask, 1);
556 	MLX5_SET(pfcc_reg, in, device_stall_critical_watermark,
557 		 stall_critical_watermark);
558 	MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark);
559 
560 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
561 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
562 }
563 
mlx5_query_port_stall_watermark(struct mlx5_core_dev * dev,u16 * stall_critical_watermark,u16 * stall_minor_watermark)564 int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
565 				    u16 *stall_critical_watermark,
566 				    u16 *stall_minor_watermark)
567 {
568 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
569 	int err;
570 
571 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
572 	if (err)
573 		return err;
574 
575 	if (stall_critical_watermark)
576 		*stall_critical_watermark = MLX5_GET(pfcc_reg, out,
577 						     device_stall_critical_watermark);
578 
579 	if (stall_minor_watermark)
580 		*stall_minor_watermark = MLX5_GET(pfcc_reg, out,
581 						  device_stall_minor_watermark);
582 
583 	return 0;
584 }
585 
mlx5_set_port_pfc(struct mlx5_core_dev * dev,u8 pfc_en_tx,u8 pfc_en_rx)586 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
587 {
588 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
589 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
590 
591 	MLX5_SET(pfcc_reg, in, local_port, 1);
592 	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
593 	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
594 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
595 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
596 
597 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
598 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
599 }
600 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
601 
mlx5_query_port_pfc(struct mlx5_core_dev * dev,u8 * pfc_en_tx,u8 * pfc_en_rx)602 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
603 {
604 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
605 	int err;
606 
607 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
608 	if (err)
609 		return err;
610 
611 	if (pfc_en_tx)
612 		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
613 
614 	if (pfc_en_rx)
615 		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
616 
617 	return 0;
618 }
619 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
620 
mlx5_max_tc(struct mlx5_core_dev * mdev)621 int mlx5_max_tc(struct mlx5_core_dev *mdev)
622 {
623 	u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
624 
625 	return num_tc - 1;
626 }
627 
mlx5_query_port_dcbx_param(struct mlx5_core_dev * mdev,u32 * out)628 int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
629 {
630 	u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
631 
632 	MLX5_SET(dcbx_param, in, port_number, 1);
633 
634 	return  mlx5_core_access_reg(mdev, in, sizeof(in), out,
635 				    sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
636 }
637 
mlx5_set_port_dcbx_param(struct mlx5_core_dev * mdev,u32 * in)638 int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
639 {
640 	u32 out[MLX5_ST_SZ_DW(dcbx_param)];
641 
642 	MLX5_SET(dcbx_param, in, port_number, 1);
643 
644 	return mlx5_core_access_reg(mdev, in, sizeof(out), out,
645 				    sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
646 }
647 
mlx5_set_port_prio_tc(struct mlx5_core_dev * mdev,u8 * prio_tc)648 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
649 {
650 	u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
651 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
652 	int err;
653 	int i;
654 
655 	for (i = 0; i < 8; i++) {
656 		if (prio_tc[i] > mlx5_max_tc(mdev))
657 			return -EINVAL;
658 
659 		MLX5_SET(qtct_reg, in, prio, i);
660 		MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
661 
662 		err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
663 					   sizeof(out), MLX5_REG_QTCT, 0, 1);
664 		if (err)
665 			return err;
666 	}
667 
668 	return 0;
669 }
670 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
671 
mlx5_query_port_prio_tc(struct mlx5_core_dev * mdev,u8 prio,u8 * tc)672 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
673 			    u8 prio, u8 *tc)
674 {
675 	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
676 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
677 	int err;
678 
679 	memset(in, 0, sizeof(in));
680 	memset(out, 0, sizeof(out));
681 
682 	MLX5_SET(qtct_reg, in, port_number, 1);
683 	MLX5_SET(qtct_reg, in, prio, prio);
684 
685 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
686 				   sizeof(out), MLX5_REG_QTCT, 0, 0);
687 	if (!err)
688 		*tc = MLX5_GET(qtct_reg, out, tclass);
689 
690 	return err;
691 }
692 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
693 
mlx5_set_port_qetcr_reg(struct mlx5_core_dev * mdev,u32 * in,int inlen)694 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
695 				   int inlen)
696 {
697 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
698 
699 	if (!MLX5_CAP_GEN(mdev, ets))
700 		return -EOPNOTSUPP;
701 
702 	return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
703 				    MLX5_REG_QETCR, 0, 1);
704 }
705 
mlx5_query_port_qetcr_reg(struct mlx5_core_dev * mdev,u32 * out,int outlen)706 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
707 				     int outlen)
708 {
709 	u32 in[MLX5_ST_SZ_DW(qetc_reg)];
710 
711 	if (!MLX5_CAP_GEN(mdev, ets))
712 		return -EOPNOTSUPP;
713 
714 	memset(in, 0, sizeof(in));
715 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
716 				    MLX5_REG_QETCR, 0, 0);
717 }
718 
mlx5_set_port_tc_group(struct mlx5_core_dev * mdev,u8 * tc_group)719 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
720 {
721 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
722 	int i;
723 
724 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
725 		MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
726 		MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
727 	}
728 
729 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
730 }
731 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
732 
mlx5_query_port_tc_group(struct mlx5_core_dev * mdev,u8 tc,u8 * tc_group)733 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
734 			     u8 tc, u8 *tc_group)
735 {
736 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
737 	void *ets_tcn_conf;
738 	int err;
739 
740 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
741 	if (err)
742 		return err;
743 
744 	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
745 				    tc_configuration[tc]);
746 
747 	*tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
748 			     group);
749 
750 	return 0;
751 }
752 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
753 
mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev * mdev,u8 * tc_bw)754 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
755 {
756 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
757 	int i;
758 
759 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
760 		MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
761 		MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
762 	}
763 
764 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
765 }
766 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
767 
mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev * mdev,u8 tc,u8 * bw_pct)768 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
769 				u8 tc, u8 *bw_pct)
770 {
771 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
772 	void *ets_tcn_conf;
773 	int err;
774 
775 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
776 	if (err)
777 		return err;
778 
779 	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
780 				    tc_configuration[tc]);
781 
782 	*bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
783 			   bw_allocation);
784 
785 	return 0;
786 }
787 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
788 
mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev * mdev,u8 * max_bw_value,u8 * max_bw_units)789 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
790 				    u8 *max_bw_value,
791 				    u8 *max_bw_units)
792 {
793 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
794 	void *ets_tcn_conf;
795 	int i;
796 
797 	MLX5_SET(qetc_reg, in, port_number, 1);
798 
799 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
800 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
801 
802 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
803 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
804 			 max_bw_units[i]);
805 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
806 			 max_bw_value[i]);
807 	}
808 
809 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
810 }
811 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
812 
mlx5_query_port_ets_rate_limit(struct mlx5_core_dev * mdev,u8 * max_bw_value,u8 * max_bw_units)813 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
814 				   u8 *max_bw_value,
815 				   u8 *max_bw_units)
816 {
817 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
818 	void *ets_tcn_conf;
819 	int err;
820 	int i;
821 
822 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
823 	if (err)
824 		return err;
825 
826 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
827 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
828 
829 		max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
830 					   max_bw_value);
831 		max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
832 					   max_bw_units);
833 	}
834 
835 	return 0;
836 }
837 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
838 
mlx5_set_port_wol(struct mlx5_core_dev * mdev,u8 wol_mode)839 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
840 {
841 	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {};
842 
843 	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
844 	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
845 	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
846 	return mlx5_cmd_exec_in(mdev, set_wol_rol, in);
847 }
848 EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
849 
mlx5_query_port_wol(struct mlx5_core_dev * mdev,u8 * wol_mode)850 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
851 {
852 	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {};
853 	u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {};
854 	int err;
855 
856 	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
857 	err = mlx5_cmd_exec_inout(mdev, query_wol_rol, in, out);
858 	if (!err)
859 		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
860 
861 	return err;
862 }
863 EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
864 
mlx5_query_ports_check(struct mlx5_core_dev * mdev,u32 * out,int outlen)865 int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen)
866 {
867 	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
868 
869 	MLX5_SET(pcmr_reg, in, local_port, 1);
870 	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
871 				    outlen, MLX5_REG_PCMR, 0, 0);
872 }
873 
mlx5_set_ports_check(struct mlx5_core_dev * mdev,u32 * in,int inlen)874 int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
875 {
876 	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
877 
878 	return mlx5_core_access_reg(mdev, in, inlen, out,
879 				    sizeof(out), MLX5_REG_PCMR, 0, 1);
880 }
881 
mlx5_set_port_fcs(struct mlx5_core_dev * mdev,u8 enable)882 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
883 {
884 	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
885 	int err;
886 
887 	err = mlx5_query_ports_check(mdev, in, sizeof(in));
888 	if (err)
889 		return err;
890 	MLX5_SET(pcmr_reg, in, local_port, 1);
891 	MLX5_SET(pcmr_reg, in, fcs_chk, enable);
892 	return mlx5_set_ports_check(mdev, in, sizeof(in));
893 }
894 
mlx5_query_port_fcs(struct mlx5_core_dev * mdev,bool * supported,bool * enabled)895 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
896 			 bool *enabled)
897 {
898 	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
899 	/* Default values for FW which do not support MLX5_REG_PCMR */
900 	*supported = false;
901 	*enabled = true;
902 
903 	if (!MLX5_CAP_GEN(mdev, ports_check))
904 		return;
905 
906 	if (mlx5_query_ports_check(mdev, out, sizeof(out)))
907 		return;
908 
909 	*supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
910 	*enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
911 }
912 
mlx5_query_mtpps(struct mlx5_core_dev * mdev,u32 * mtpps,u32 mtpps_size)913 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
914 {
915 	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
916 
917 	return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
918 				    mtpps_size, MLX5_REG_MTPPS, 0, 0);
919 }
920 
mlx5_set_mtpps(struct mlx5_core_dev * mdev,u32 * mtpps,u32 mtpps_size)921 int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
922 {
923 	u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
924 
925 	return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
926 				    sizeof(out), MLX5_REG_MTPPS, 0, 1);
927 }
928 
mlx5_query_mtppse(struct mlx5_core_dev * mdev,u8 pin,u8 * arm,u8 * mode)929 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
930 {
931 	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
932 	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
933 	int err = 0;
934 
935 	MLX5_SET(mtppse_reg, in, pin, pin);
936 
937 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
938 				   sizeof(out), MLX5_REG_MTPPSE, 0, 0);
939 	if (err)
940 		return err;
941 
942 	*arm = MLX5_GET(mtppse_reg, in, event_arm);
943 	*mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
944 
945 	return err;
946 }
947 
mlx5_set_mtppse(struct mlx5_core_dev * mdev,u8 pin,u8 arm,u8 mode)948 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
949 {
950 	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
951 	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
952 
953 	MLX5_SET(mtppse_reg, in, pin, pin);
954 	MLX5_SET(mtppse_reg, in, event_arm, arm);
955 	MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
956 
957 	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
958 				    sizeof(out), MLX5_REG_MTPPSE, 0, 1);
959 }
960 
mlx5_set_trust_state(struct mlx5_core_dev * mdev,u8 trust_state)961 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
962 {
963 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
964 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
965 	int err;
966 
967 	MLX5_SET(qpts_reg, in, local_port, 1);
968 	MLX5_SET(qpts_reg, in, trust_state, trust_state);
969 
970 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
971 				   sizeof(out), MLX5_REG_QPTS, 0, 1);
972 	return err;
973 }
974 
mlx5_query_trust_state(struct mlx5_core_dev * mdev,u8 * trust_state)975 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
976 {
977 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
978 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
979 	int err;
980 
981 	MLX5_SET(qpts_reg, in, local_port, 1);
982 
983 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
984 				   sizeof(out), MLX5_REG_QPTS, 0, 0);
985 	if (!err)
986 		*trust_state = MLX5_GET(qpts_reg, out, trust_state);
987 
988 	return err;
989 }
990 
mlx5_set_dscp2prio(struct mlx5_core_dev * mdev,u8 dscp,u8 prio)991 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio)
992 {
993 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
994 	void *qpdpm_dscp;
995 	void *out;
996 	void *in;
997 	int err;
998 
999 	in = kzalloc(sz, GFP_KERNEL);
1000 	out = kzalloc(sz, GFP_KERNEL);
1001 	if (!in || !out) {
1002 		err = -ENOMEM;
1003 		goto out;
1004 	}
1005 
1006 	MLX5_SET(qpdpm_reg, in, local_port, 1);
1007 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1008 	if (err)
1009 		goto out;
1010 
1011 	memcpy(in, out, sz);
1012 	MLX5_SET(qpdpm_reg, in, local_port, 1);
1013 
1014 	/* Update the corresponding dscp entry */
1015 	qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]);
1016 	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio);
1017 	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
1018 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
1019 
1020 out:
1021 	kfree(in);
1022 	kfree(out);
1023 	return err;
1024 }
1025 
1026 /* dscp2prio[i]: priority that dscp i mapped to */
1027 #define MLX5E_SUPPORTED_DSCP 64
mlx5_query_dscp2prio(struct mlx5_core_dev * mdev,u8 * dscp2prio)1028 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
1029 {
1030 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1031 	void *qpdpm_dscp;
1032 	void *out;
1033 	void *in;
1034 	int err;
1035 	int i;
1036 
1037 	in = kzalloc(sz, GFP_KERNEL);
1038 	out = kzalloc(sz, GFP_KERNEL);
1039 	if (!in || !out) {
1040 		err = -ENOMEM;
1041 		goto out;
1042 	}
1043 
1044 	MLX5_SET(qpdpm_reg, in, local_port, 1);
1045 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1046 	if (err)
1047 		goto out;
1048 
1049 	for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) {
1050 		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
1051 		dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
1052 	}
1053 
1054 out:
1055 	kfree(in);
1056 	kfree(out);
1057 	return err;
1058 }
1059 
1060 /* speed in units of 1Mb */
1061 static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = {
1062 	[MLX5E_1000BASE_CX_SGMII] = 1000,
1063 	[MLX5E_1000BASE_KX]       = 1000,
1064 	[MLX5E_10GBASE_CX4]       = 10000,
1065 	[MLX5E_10GBASE_KX4]       = 10000,
1066 	[MLX5E_10GBASE_KR]        = 10000,
1067 	[MLX5E_20GBASE_KR2]       = 20000,
1068 	[MLX5E_40GBASE_CR4]       = 40000,
1069 	[MLX5E_40GBASE_KR4]       = 40000,
1070 	[MLX5E_56GBASE_R4]        = 56000,
1071 	[MLX5E_10GBASE_CR]        = 10000,
1072 	[MLX5E_10GBASE_SR]        = 10000,
1073 	[MLX5E_10GBASE_ER]        = 10000,
1074 	[MLX5E_40GBASE_SR4]       = 40000,
1075 	[MLX5E_40GBASE_LR4]       = 40000,
1076 	[MLX5E_50GBASE_SR2]       = 50000,
1077 	[MLX5E_100GBASE_CR4]      = 100000,
1078 	[MLX5E_100GBASE_SR4]      = 100000,
1079 	[MLX5E_100GBASE_KR4]      = 100000,
1080 	[MLX5E_100GBASE_LR4]      = 100000,
1081 	[MLX5E_100BASE_TX]        = 100,
1082 	[MLX5E_1000BASE_T]        = 1000,
1083 	[MLX5E_10GBASE_T]         = 10000,
1084 	[MLX5E_25GBASE_CR]        = 25000,
1085 	[MLX5E_25GBASE_KR]        = 25000,
1086 	[MLX5E_25GBASE_SR]        = 25000,
1087 	[MLX5E_50GBASE_CR2]       = 50000,
1088 	[MLX5E_50GBASE_KR2]       = 50000,
1089 };
1090 
1091 static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = {
1092 	[MLX5E_SGMII_100M] = 100,
1093 	[MLX5E_1000BASE_X_SGMII] = 1000,
1094 	[MLX5E_5GBASE_R] = 5000,
1095 	[MLX5E_10GBASE_XFI_XAUI_1] = 10000,
1096 	[MLX5E_40GBASE_XLAUI_4_XLPPI_4] = 40000,
1097 	[MLX5E_25GAUI_1_25GBASE_CR_KR] = 25000,
1098 	[MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000,
1099 	[MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR] = 50000,
1100 	[MLX5E_CAUI_4_100GBASE_CR4_KR4] = 100000,
1101 	[MLX5E_100GAUI_2_100GBASE_CR2_KR2] = 100000,
1102 	[MLX5E_200GAUI_4_200GBASE_CR4_KR4] = 200000,
1103 	[MLX5E_400GAUI_8_400GBASE_CR8] = 400000,
1104 	[MLX5E_100GAUI_1_100GBASE_CR_KR] = 100000,
1105 	[MLX5E_200GAUI_2_200GBASE_CR2_KR2] = 200000,
1106 	[MLX5E_400GAUI_4_400GBASE_CR4_KR4] = 400000,
1107 	[MLX5E_800GAUI_8_800GBASE_CR8_KR8] = 800000,
1108 };
1109 
mlx5_port_query_eth_proto(struct mlx5_core_dev * dev,u8 port,bool ext,struct mlx5_port_eth_proto * eproto)1110 int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
1111 			      struct mlx5_port_eth_proto *eproto)
1112 {
1113 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
1114 	int err;
1115 
1116 	if (!eproto)
1117 		return -EINVAL;
1118 
1119 	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port, 0);
1120 	if (err)
1121 		return err;
1122 
1123 	eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
1124 					   eth_proto_capability);
1125 	eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
1126 	eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
1127 	return 0;
1128 }
1129 
mlx5_ptys_ext_supported(struct mlx5_core_dev * mdev)1130 bool mlx5_ptys_ext_supported(struct mlx5_core_dev *mdev)
1131 {
1132 	struct mlx5_port_eth_proto eproto;
1133 	int err;
1134 
1135 	if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet))
1136 		return true;
1137 
1138 	err = mlx5_port_query_eth_proto(mdev, 1, true, &eproto);
1139 	if (err)
1140 		return false;
1141 
1142 	return !!eproto.cap;
1143 }
1144 
mlx5e_port_get_speed_arr(struct mlx5_core_dev * mdev,const u32 ** arr,u32 * size,bool force_legacy)1145 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
1146 				     const u32 **arr, u32 *size,
1147 				     bool force_legacy)
1148 {
1149 	bool ext = force_legacy ? false : mlx5_ptys_ext_supported(mdev);
1150 
1151 	*size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
1152 		      ARRAY_SIZE(mlx5e_link_speed);
1153 	*arr  = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
1154 }
1155 
mlx5_port_ptys2speed(struct mlx5_core_dev * mdev,u32 eth_proto_oper,bool force_legacy)1156 u32 mlx5_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
1157 			 bool force_legacy)
1158 {
1159 	unsigned long temp = eth_proto_oper;
1160 	const u32 *table;
1161 	u32 speed = 0;
1162 	u32 max_size;
1163 	int i;
1164 
1165 	mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
1166 	i = find_first_bit(&temp, max_size);
1167 	if (i < max_size)
1168 		speed = table[i];
1169 	return speed;
1170 }
1171 
mlx5_port_speed2linkmodes(struct mlx5_core_dev * mdev,u32 speed,bool force_legacy)1172 u32 mlx5_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
1173 			      bool force_legacy)
1174 {
1175 	u32 link_modes = 0;
1176 	const u32 *table;
1177 	u32 max_size;
1178 	int i;
1179 
1180 	mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
1181 	for (i = 0; i < max_size; ++i) {
1182 		if (table[i] == speed)
1183 			link_modes |= MLX5E_PROT_MASK(i);
1184 	}
1185 	return link_modes;
1186 }
1187 
mlx5_port_max_linkspeed(struct mlx5_core_dev * mdev,u32 * speed)1188 int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
1189 {
1190 	struct mlx5_port_eth_proto eproto;
1191 	u32 max_speed = 0;
1192 	const u32 *table;
1193 	u32 max_size;
1194 	bool ext;
1195 	int err;
1196 	int i;
1197 
1198 	ext = mlx5_ptys_ext_supported(mdev);
1199 	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
1200 	if (err)
1201 		return err;
1202 
1203 	mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
1204 	for (i = 0; i < max_size; ++i)
1205 		if (eproto.cap & MLX5E_PROT_MASK(i))
1206 			max_speed = max(max_speed, table[i]);
1207 
1208 	*speed = max_speed;
1209 	return 0;
1210 }
1211 
mlx5_query_mpir_reg(struct mlx5_core_dev * dev,u32 * mpir)1212 int mlx5_query_mpir_reg(struct mlx5_core_dev *dev, u32 *mpir)
1213 {
1214 	u32 in[MLX5_ST_SZ_DW(mpir_reg)] = {};
1215 	int sz = MLX5_ST_SZ_BYTES(mpir_reg);
1216 
1217 	MLX5_SET(mpir_reg, in, local_port, 1);
1218 
1219 	return mlx5_core_access_reg(dev, in, sz, mpir, sz, MLX5_REG_MPIR, 0, 0);
1220 }
1221