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 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
37 			 int size_in, void *data_out, int size_out,
38 			 u16 reg_id, int arg, int write)
39 {
40 	int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
41 	int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
42 	int err = -ENOMEM;
43 	u32 *out = NULL;
44 	u32 *in = NULL;
45 	void *data;
46 
47 	in = kvzalloc(inlen, GFP_KERNEL);
48 	out = kvzalloc(outlen, GFP_KERNEL);
49 	if (!in || !out)
50 		goto out;
51 
52 	data = MLX5_ADDR_OF(access_register_in, in, register_data);
53 	memcpy(data, data_in, size_in);
54 
55 	MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
56 	MLX5_SET(access_register_in, in, op_mod, !write);
57 	MLX5_SET(access_register_in, in, argument, arg);
58 	MLX5_SET(access_register_in, in, register_id, reg_id);
59 
60 	err = mlx5_cmd_exec(dev, in, inlen, out, outlen);
61 	if (err)
62 		goto out;
63 
64 	data = MLX5_ADDR_OF(access_register_out, out, register_data);
65 	memcpy(data_out, data, size_out);
66 
67 out:
68 	kvfree(out);
69 	kvfree(in);
70 	return err;
71 }
72 EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
73 
74 int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
75 			u8 access_reg_group)
76 {
77 	u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {0};
78 	int sz = MLX5_ST_SZ_BYTES(pcam_reg);
79 
80 	MLX5_SET(pcam_reg, in, feature_group, feature_group);
81 	MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
82 
83 	return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
84 }
85 
86 int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
87 			u8 access_reg_group)
88 {
89 	u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {0};
90 	int sz = MLX5_ST_SZ_BYTES(mcam_reg);
91 
92 	MLX5_SET(mcam_reg, in, feature_group, feature_group);
93 	MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
94 
95 	return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
96 }
97 
98 int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
99 			u8 feature_group, u8 access_reg_group)
100 {
101 	u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {};
102 	int sz = MLX5_ST_SZ_BYTES(qcam_reg);
103 
104 	MLX5_SET(qcam_reg, in, feature_group, feature_group);
105 	MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group);
106 
107 	return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0);
108 }
109 
110 struct mlx5_reg_pcap {
111 	u8			rsvd0;
112 	u8			port_num;
113 	u8			rsvd1[2];
114 	__be32			caps_127_96;
115 	__be32			caps_95_64;
116 	__be32			caps_63_32;
117 	__be32			caps_31_0;
118 };
119 
120 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
121 {
122 	struct mlx5_reg_pcap in;
123 	struct mlx5_reg_pcap out;
124 
125 	memset(&in, 0, sizeof(in));
126 	in.caps_127_96 = cpu_to_be32(caps);
127 	in.port_num = port_num;
128 
129 	return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
130 				    sizeof(out), MLX5_REG_PCAP, 0, 1);
131 }
132 EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
133 
134 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
135 			 int ptys_size, int proto_mask, u8 local_port)
136 {
137 	u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
138 
139 	MLX5_SET(ptys_reg, in, local_port, local_port);
140 	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
141 	return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
142 				    ptys_size, MLX5_REG_PTYS, 0, 0);
143 }
144 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
145 
146 int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
147 {
148 	u32 in[MLX5_ST_SZ_DW(mlcr_reg)]  = {0};
149 	u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
150 
151 	MLX5_SET(mlcr_reg, in, local_port, 1);
152 	MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
153 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
154 				    sizeof(out), MLX5_REG_MLCR, 0, 1);
155 }
156 
157 int mlx5_query_ib_port_oper(struct mlx5_core_dev *dev, u16 *link_width_oper,
158 			    u16 *proto_oper, u8 local_port)
159 {
160 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
161 	int err;
162 
163 	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB,
164 				   local_port);
165 	if (err)
166 		return err;
167 
168 	*link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
169 	*proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
170 
171 	return 0;
172 }
173 EXPORT_SYMBOL(mlx5_query_ib_port_oper);
174 
175 /* This function should be used after setting a port register only */
176 void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
177 {
178 	enum mlx5_port_status ps;
179 
180 	mlx5_query_port_admin_status(dev, &ps);
181 	mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
182 	if (ps == MLX5_PORT_UP)
183 		mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
184 }
185 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
186 
187 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
188 			       enum mlx5_port_status status)
189 {
190 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
191 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
192 
193 	MLX5_SET(paos_reg, in, local_port, 1);
194 	MLX5_SET(paos_reg, in, admin_status, status);
195 	MLX5_SET(paos_reg, in, ase, 1);
196 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
197 				    sizeof(out), MLX5_REG_PAOS, 0, 1);
198 }
199 EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
200 
201 int mlx5_query_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 	int err;
207 
208 	MLX5_SET(paos_reg, in, local_port, 1);
209 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
210 				   sizeof(out), MLX5_REG_PAOS, 0, 0);
211 	if (err)
212 		return err;
213 	*status = MLX5_GET(paos_reg, out, admin_status);
214 	return 0;
215 }
216 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
217 
218 static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
219 				u16 *max_mtu, u16 *oper_mtu, u8 port)
220 {
221 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
222 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
223 
224 	MLX5_SET(pmtu_reg, in, local_port, port);
225 	mlx5_core_access_reg(dev, in, sizeof(in), out,
226 			     sizeof(out), MLX5_REG_PMTU, 0, 0);
227 
228 	if (max_mtu)
229 		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
230 	if (oper_mtu)
231 		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
232 	if (admin_mtu)
233 		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
234 }
235 
236 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
237 {
238 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
239 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
240 
241 	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
242 	MLX5_SET(pmtu_reg, in, local_port, port);
243 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
244 				   sizeof(out), MLX5_REG_PMTU, 0, 1);
245 }
246 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
247 
248 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
249 			     u8 port)
250 {
251 	mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
252 }
253 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
254 
255 void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
256 			      u8 port)
257 {
258 	mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
259 }
260 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
261 
262 static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
263 {
264 	u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
265 	u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
266 	int module_mapping;
267 	int err;
268 
269 	MLX5_SET(pmlp_reg, in, local_port, 1);
270 	err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
271 				   MLX5_REG_PMLP, 0, 0);
272 	if (err)
273 		return err;
274 
275 	module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
276 	*module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
277 
278 	return 0;
279 }
280 
281 static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num,
282 				u8 *module_id)
283 {
284 	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
285 	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
286 	int err, status;
287 	u8 *ptr;
288 
289 	MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW);
290 	MLX5_SET(mcia_reg, in, module, module_num);
291 	MLX5_SET(mcia_reg, in, device_address, 0);
292 	MLX5_SET(mcia_reg, in, page_number, 0);
293 	MLX5_SET(mcia_reg, in, size, 1);
294 	MLX5_SET(mcia_reg, in, l, 0);
295 
296 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
297 				   sizeof(out), MLX5_REG_MCIA, 0, 0);
298 	if (err)
299 		return err;
300 
301 	status = MLX5_GET(mcia_reg, out, status);
302 	if (status) {
303 		mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
304 			      status);
305 		return -EIO;
306 	}
307 	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
308 
309 	*module_id = ptr[0];
310 
311 	return 0;
312 }
313 
314 static int mlx5_qsfp_eeprom_page(u16 offset)
315 {
316 	if (offset < MLX5_EEPROM_PAGE_LENGTH)
317 		/* Addresses between 0-255 - page 00 */
318 		return 0;
319 
320 	/* Addresses between 256 - 639 belongs to pages 01, 02 and 03
321 	 * For example, offset = 400 belongs to page 02:
322 	 * 1 + ((400 - 256)/128) = 2
323 	 */
324 	return 1 + ((offset - MLX5_EEPROM_PAGE_LENGTH) /
325 		    MLX5_EEPROM_HIGH_PAGE_LENGTH);
326 }
327 
328 static int mlx5_qsfp_eeprom_high_page_offset(int page_num)
329 {
330 	if (!page_num) /* Page 0 always start from low page */
331 		return 0;
332 
333 	/* High page */
334 	return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH;
335 }
336 
337 static void mlx5_qsfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
338 {
339 	*i2c_addr = MLX5_I2C_ADDR_LOW;
340 	*page_num = mlx5_qsfp_eeprom_page(*offset);
341 	*offset -=  mlx5_qsfp_eeprom_high_page_offset(*page_num);
342 }
343 
344 static void mlx5_sfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
345 {
346 	*i2c_addr = MLX5_I2C_ADDR_LOW;
347 	*page_num = 0;
348 
349 	if (*offset < MLX5_EEPROM_PAGE_LENGTH)
350 		return;
351 
352 	*i2c_addr = MLX5_I2C_ADDR_HIGH;
353 	*offset -= MLX5_EEPROM_PAGE_LENGTH;
354 }
355 
356 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
357 			     u16 offset, u16 size, u8 *data)
358 {
359 	int module_num, status, err, page_num = 0;
360 	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
361 	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
362 	u16 i2c_addr = 0;
363 	u8 module_id;
364 	void *ptr;
365 
366 	err = mlx5_query_module_num(dev, &module_num);
367 	if (err)
368 		return err;
369 
370 	err = mlx5_query_module_id(dev, module_num, &module_id);
371 	if (err)
372 		return err;
373 
374 	switch (module_id) {
375 	case MLX5_MODULE_ID_SFP:
376 		mlx5_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
377 		break;
378 	case MLX5_MODULE_ID_QSFP:
379 	case MLX5_MODULE_ID_QSFP_PLUS:
380 	case MLX5_MODULE_ID_QSFP28:
381 		mlx5_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
382 		break;
383 	default:
384 		mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
385 		return -EINVAL;
386 	}
387 
388 	if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
389 		/* Cross pages read, read until offset 256 in low page */
390 		size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
391 
392 	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
393 
394 	MLX5_SET(mcia_reg, in, l, 0);
395 	MLX5_SET(mcia_reg, in, module, module_num);
396 	MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
397 	MLX5_SET(mcia_reg, in, page_number, page_num);
398 	MLX5_SET(mcia_reg, in, device_address, offset);
399 	MLX5_SET(mcia_reg, in, size, size);
400 
401 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
402 				   sizeof(out), MLX5_REG_MCIA, 0, 0);
403 	if (err)
404 		return err;
405 
406 	status = MLX5_GET(mcia_reg, out, status);
407 	if (status) {
408 		mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
409 			      status);
410 		return -EIO;
411 	}
412 
413 	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
414 	memcpy(data, ptr, size);
415 
416 	return size;
417 }
418 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
419 
420 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
421 				int pvlc_size,  u8 local_port)
422 {
423 	u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
424 
425 	MLX5_SET(pvlc_reg, in, local_port, local_port);
426 	return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
427 				    pvlc_size, MLX5_REG_PVLC, 0, 0);
428 }
429 
430 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
431 			      u8 *vl_hw_cap, u8 local_port)
432 {
433 	u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
434 	int err;
435 
436 	err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
437 	if (err)
438 		return err;
439 
440 	*vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
441 
442 	return 0;
443 }
444 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
445 
446 int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
447 			     u8 port_num, void *out, size_t sz)
448 {
449 	u32 *in;
450 	int err;
451 
452 	in  = kvzalloc(sz, GFP_KERNEL);
453 	if (!in) {
454 		err = -ENOMEM;
455 		return err;
456 	}
457 
458 	MLX5_SET(ppcnt_reg, in, local_port, port_num);
459 
460 	MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP);
461 	err = mlx5_core_access_reg(dev, in, sz, out,
462 				   sz, MLX5_REG_PPCNT, 0, 0);
463 
464 	kvfree(in);
465 	return err;
466 }
467 EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt);
468 
469 static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out,
470 			       u32 out_size)
471 {
472 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
473 
474 	MLX5_SET(pfcc_reg, in, local_port, 1);
475 
476 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
477 				    out_size, MLX5_REG_PFCC, 0, 0);
478 }
479 
480 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
481 {
482 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
483 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
484 
485 	MLX5_SET(pfcc_reg, in, local_port, 1);
486 	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
487 	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
488 
489 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
490 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
491 }
492 EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
493 
494 int mlx5_query_port_pause(struct mlx5_core_dev *dev,
495 			  u32 *rx_pause, u32 *tx_pause)
496 {
497 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
498 	int err;
499 
500 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
501 	if (err)
502 		return err;
503 
504 	if (rx_pause)
505 		*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
506 
507 	if (tx_pause)
508 		*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
509 
510 	return 0;
511 }
512 EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
513 
514 int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
515 				  u16 stall_critical_watermark,
516 				  u16 stall_minor_watermark)
517 {
518 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
519 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
520 
521 	MLX5_SET(pfcc_reg, in, local_port, 1);
522 	MLX5_SET(pfcc_reg, in, pptx_mask_n, 1);
523 	MLX5_SET(pfcc_reg, in, pprx_mask_n, 1);
524 	MLX5_SET(pfcc_reg, in, ppan_mask_n, 1);
525 	MLX5_SET(pfcc_reg, in, critical_stall_mask, 1);
526 	MLX5_SET(pfcc_reg, in, minor_stall_mask, 1);
527 	MLX5_SET(pfcc_reg, in, device_stall_critical_watermark,
528 		 stall_critical_watermark);
529 	MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark);
530 
531 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
532 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
533 }
534 
535 int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
536 				    u16 *stall_critical_watermark,
537 				    u16 *stall_minor_watermark)
538 {
539 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
540 	int err;
541 
542 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
543 	if (err)
544 		return err;
545 
546 	if (stall_critical_watermark)
547 		*stall_critical_watermark = MLX5_GET(pfcc_reg, out,
548 						     device_stall_critical_watermark);
549 
550 	if (stall_minor_watermark)
551 		*stall_minor_watermark = MLX5_GET(pfcc_reg, out,
552 						  device_stall_minor_watermark);
553 
554 	return 0;
555 }
556 
557 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
558 {
559 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
560 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
561 
562 	MLX5_SET(pfcc_reg, in, local_port, 1);
563 	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
564 	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
565 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
566 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
567 
568 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
569 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
570 }
571 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
572 
573 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
574 {
575 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
576 	int err;
577 
578 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
579 	if (err)
580 		return err;
581 
582 	if (pfc_en_tx)
583 		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
584 
585 	if (pfc_en_rx)
586 		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
587 
588 	return 0;
589 }
590 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
591 
592 int mlx5_max_tc(struct mlx5_core_dev *mdev)
593 {
594 	u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
595 
596 	return num_tc - 1;
597 }
598 
599 int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
600 {
601 	u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
602 
603 	MLX5_SET(dcbx_param, in, port_number, 1);
604 
605 	return  mlx5_core_access_reg(mdev, in, sizeof(in), out,
606 				    sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
607 }
608 
609 int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
610 {
611 	u32 out[MLX5_ST_SZ_DW(dcbx_param)];
612 
613 	MLX5_SET(dcbx_param, in, port_number, 1);
614 
615 	return mlx5_core_access_reg(mdev, in, sizeof(out), out,
616 				    sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
617 }
618 
619 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
620 {
621 	u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
622 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
623 	int err;
624 	int i;
625 
626 	for (i = 0; i < 8; i++) {
627 		if (prio_tc[i] > mlx5_max_tc(mdev))
628 			return -EINVAL;
629 
630 		MLX5_SET(qtct_reg, in, prio, i);
631 		MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
632 
633 		err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
634 					   sizeof(out), MLX5_REG_QTCT, 0, 1);
635 		if (err)
636 			return err;
637 	}
638 
639 	return 0;
640 }
641 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
642 
643 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
644 			    u8 prio, u8 *tc)
645 {
646 	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
647 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
648 	int err;
649 
650 	memset(in, 0, sizeof(in));
651 	memset(out, 0, sizeof(out));
652 
653 	MLX5_SET(qtct_reg, in, port_number, 1);
654 	MLX5_SET(qtct_reg, in, prio, prio);
655 
656 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
657 				   sizeof(out), MLX5_REG_QTCT, 0, 0);
658 	if (!err)
659 		*tc = MLX5_GET(qtct_reg, out, tclass);
660 
661 	return err;
662 }
663 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
664 
665 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
666 				   int inlen)
667 {
668 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
669 
670 	if (!MLX5_CAP_GEN(mdev, ets))
671 		return -EOPNOTSUPP;
672 
673 	return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
674 				    MLX5_REG_QETCR, 0, 1);
675 }
676 
677 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
678 				     int outlen)
679 {
680 	u32 in[MLX5_ST_SZ_DW(qetc_reg)];
681 
682 	if (!MLX5_CAP_GEN(mdev, ets))
683 		return -EOPNOTSUPP;
684 
685 	memset(in, 0, sizeof(in));
686 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
687 				    MLX5_REG_QETCR, 0, 0);
688 }
689 
690 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
691 {
692 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
693 	int i;
694 
695 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
696 		MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
697 		MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
698 	}
699 
700 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
701 }
702 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
703 
704 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
705 			     u8 tc, u8 *tc_group)
706 {
707 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
708 	void *ets_tcn_conf;
709 	int err;
710 
711 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
712 	if (err)
713 		return err;
714 
715 	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
716 				    tc_configuration[tc]);
717 
718 	*tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
719 			     group);
720 
721 	return 0;
722 }
723 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
724 
725 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
726 {
727 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
728 	int i;
729 
730 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
731 		MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
732 		MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
733 	}
734 
735 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
736 }
737 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
738 
739 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
740 				u8 tc, u8 *bw_pct)
741 {
742 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
743 	void *ets_tcn_conf;
744 	int err;
745 
746 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
747 	if (err)
748 		return err;
749 
750 	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
751 				    tc_configuration[tc]);
752 
753 	*bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
754 			   bw_allocation);
755 
756 	return 0;
757 }
758 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
759 
760 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
761 				    u8 *max_bw_value,
762 				    u8 *max_bw_units)
763 {
764 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
765 	void *ets_tcn_conf;
766 	int i;
767 
768 	MLX5_SET(qetc_reg, in, port_number, 1);
769 
770 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
771 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
772 
773 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
774 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
775 			 max_bw_units[i]);
776 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
777 			 max_bw_value[i]);
778 	}
779 
780 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
781 }
782 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
783 
784 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
785 				   u8 *max_bw_value,
786 				   u8 *max_bw_units)
787 {
788 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
789 	void *ets_tcn_conf;
790 	int err;
791 	int i;
792 
793 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
794 	if (err)
795 		return err;
796 
797 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
798 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
799 
800 		max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
801 					   max_bw_value);
802 		max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
803 					   max_bw_units);
804 	}
805 
806 	return 0;
807 }
808 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
809 
810 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
811 {
812 	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {};
813 
814 	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
815 	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
816 	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
817 	return mlx5_cmd_exec_in(mdev, set_wol_rol, in);
818 }
819 EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
820 
821 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
822 {
823 	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {};
824 	u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {};
825 	int err;
826 
827 	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
828 	err = mlx5_cmd_exec_inout(mdev, query_wol_rol, in, out);
829 	if (!err)
830 		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
831 
832 	return err;
833 }
834 EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
835 
836 int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen)
837 {
838 	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
839 
840 	MLX5_SET(pcmr_reg, in, local_port, 1);
841 	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
842 				    outlen, MLX5_REG_PCMR, 0, 0);
843 }
844 
845 int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
846 {
847 	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
848 
849 	return mlx5_core_access_reg(mdev, in, inlen, out,
850 				    sizeof(out), MLX5_REG_PCMR, 0, 1);
851 }
852 
853 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
854 {
855 	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
856 	int err;
857 
858 	err = mlx5_query_ports_check(mdev, in, sizeof(in));
859 	if (err)
860 		return err;
861 	MLX5_SET(pcmr_reg, in, local_port, 1);
862 	MLX5_SET(pcmr_reg, in, fcs_chk, enable);
863 	return mlx5_set_ports_check(mdev, in, sizeof(in));
864 }
865 
866 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
867 			 bool *enabled)
868 {
869 	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
870 	/* Default values for FW which do not support MLX5_REG_PCMR */
871 	*supported = false;
872 	*enabled = true;
873 
874 	if (!MLX5_CAP_GEN(mdev, ports_check))
875 		return;
876 
877 	if (mlx5_query_ports_check(mdev, out, sizeof(out)))
878 		return;
879 
880 	*supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
881 	*enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
882 }
883 
884 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
885 {
886 	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
887 
888 	return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
889 				    mtpps_size, MLX5_REG_MTPPS, 0, 0);
890 }
891 
892 int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
893 {
894 	u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
895 
896 	return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
897 				    sizeof(out), MLX5_REG_MTPPS, 0, 1);
898 }
899 
900 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
901 {
902 	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
903 	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
904 	int err = 0;
905 
906 	MLX5_SET(mtppse_reg, in, pin, pin);
907 
908 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
909 				   sizeof(out), MLX5_REG_MTPPSE, 0, 0);
910 	if (err)
911 		return err;
912 
913 	*arm = MLX5_GET(mtppse_reg, in, event_arm);
914 	*mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
915 
916 	return err;
917 }
918 
919 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
920 {
921 	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
922 	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
923 
924 	MLX5_SET(mtppse_reg, in, pin, pin);
925 	MLX5_SET(mtppse_reg, in, event_arm, arm);
926 	MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
927 
928 	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
929 				    sizeof(out), MLX5_REG_MTPPSE, 0, 1);
930 }
931 
932 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
933 {
934 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
935 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
936 	int err;
937 
938 	MLX5_SET(qpts_reg, in, local_port, 1);
939 	MLX5_SET(qpts_reg, in, trust_state, trust_state);
940 
941 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
942 				   sizeof(out), MLX5_REG_QPTS, 0, 1);
943 	return err;
944 }
945 
946 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
947 {
948 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
949 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
950 	int err;
951 
952 	MLX5_SET(qpts_reg, in, local_port, 1);
953 
954 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
955 				   sizeof(out), MLX5_REG_QPTS, 0, 0);
956 	if (!err)
957 		*trust_state = MLX5_GET(qpts_reg, out, trust_state);
958 
959 	return err;
960 }
961 
962 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio)
963 {
964 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
965 	void *qpdpm_dscp;
966 	void *out;
967 	void *in;
968 	int err;
969 
970 	in = kzalloc(sz, GFP_KERNEL);
971 	out = kzalloc(sz, GFP_KERNEL);
972 	if (!in || !out) {
973 		err = -ENOMEM;
974 		goto out;
975 	}
976 
977 	MLX5_SET(qpdpm_reg, in, local_port, 1);
978 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
979 	if (err)
980 		goto out;
981 
982 	memcpy(in, out, sz);
983 	MLX5_SET(qpdpm_reg, in, local_port, 1);
984 
985 	/* Update the corresponding dscp entry */
986 	qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]);
987 	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio);
988 	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
989 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
990 
991 out:
992 	kfree(in);
993 	kfree(out);
994 	return err;
995 }
996 
997 /* dscp2prio[i]: priority that dscp i mapped to */
998 #define MLX5E_SUPPORTED_DSCP 64
999 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
1000 {
1001 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1002 	void *qpdpm_dscp;
1003 	void *out;
1004 	void *in;
1005 	int err;
1006 	int i;
1007 
1008 	in = kzalloc(sz, GFP_KERNEL);
1009 	out = kzalloc(sz, GFP_KERNEL);
1010 	if (!in || !out) {
1011 		err = -ENOMEM;
1012 		goto out;
1013 	}
1014 
1015 	MLX5_SET(qpdpm_reg, in, local_port, 1);
1016 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1017 	if (err)
1018 		goto out;
1019 
1020 	for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) {
1021 		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
1022 		dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
1023 	}
1024 
1025 out:
1026 	kfree(in);
1027 	kfree(out);
1028 	return err;
1029 }
1030