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