0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/mlx5/port.h>
0034 #include "mlx5_core.h"
0035
0036
0037 int mlx5_access_reg(struct mlx5_core_dev *dev, void *data_in, int size_in,
0038 void *data_out, int size_out, u16 reg_id, int arg,
0039 int write, bool verbose)
0040 {
0041 int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
0042 int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
0043 int err = -ENOMEM;
0044 u32 *out = NULL;
0045 u32 *in = NULL;
0046 void *data;
0047
0048 in = kvzalloc(inlen, GFP_KERNEL);
0049 out = kvzalloc(outlen, GFP_KERNEL);
0050 if (!in || !out)
0051 goto out;
0052
0053 data = MLX5_ADDR_OF(access_register_in, in, register_data);
0054 memcpy(data, data_in, size_in);
0055
0056 MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
0057 MLX5_SET(access_register_in, in, op_mod, !write);
0058 MLX5_SET(access_register_in, in, argument, arg);
0059 MLX5_SET(access_register_in, in, register_id, reg_id);
0060
0061 err = mlx5_cmd_do(dev, in, inlen, out, outlen);
0062 if (verbose)
0063 err = mlx5_cmd_check(dev, err, in, out);
0064 if (err)
0065 goto out;
0066
0067 data = MLX5_ADDR_OF(access_register_out, out, register_data);
0068 memcpy(data_out, data, size_out);
0069
0070 out:
0071 kvfree(out);
0072 kvfree(in);
0073 return err;
0074 }
0075 EXPORT_SYMBOL_GPL(mlx5_access_reg);
0076
0077 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
0078 int size_in, void *data_out, int size_out,
0079 u16 reg_id, int arg, int write)
0080 {
0081 return mlx5_access_reg(dev, data_in, size_in, data_out, size_out,
0082 reg_id, arg, write, true);
0083 }
0084 EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
0085
0086 int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
0087 u8 access_reg_group)
0088 {
0089 u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {0};
0090 int sz = MLX5_ST_SZ_BYTES(pcam_reg);
0091
0092 MLX5_SET(pcam_reg, in, feature_group, feature_group);
0093 MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
0094
0095 return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
0096 }
0097
0098 int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
0099 u8 access_reg_group)
0100 {
0101 u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {0};
0102 int sz = MLX5_ST_SZ_BYTES(mcam_reg);
0103
0104 MLX5_SET(mcam_reg, in, feature_group, feature_group);
0105 MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
0106
0107 return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
0108 }
0109
0110 int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
0111 u8 feature_group, u8 access_reg_group)
0112 {
0113 u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {};
0114 int sz = MLX5_ST_SZ_BYTES(qcam_reg);
0115
0116 MLX5_SET(qcam_reg, in, feature_group, feature_group);
0117 MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group);
0118
0119 return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0);
0120 }
0121
0122 struct mlx5_reg_pcap {
0123 u8 rsvd0;
0124 u8 port_num;
0125 u8 rsvd1[2];
0126 __be32 caps_127_96;
0127 __be32 caps_95_64;
0128 __be32 caps_63_32;
0129 __be32 caps_31_0;
0130 };
0131
0132 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
0133 {
0134 struct mlx5_reg_pcap in;
0135 struct mlx5_reg_pcap out;
0136
0137 memset(&in, 0, sizeof(in));
0138 in.caps_127_96 = cpu_to_be32(caps);
0139 in.port_num = port_num;
0140
0141 return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
0142 sizeof(out), MLX5_REG_PCAP, 0, 1);
0143 }
0144 EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
0145
0146 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
0147 int ptys_size, int proto_mask, u8 local_port)
0148 {
0149 u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
0150
0151 MLX5_SET(ptys_reg, in, local_port, local_port);
0152 MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
0153 return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
0154 ptys_size, MLX5_REG_PTYS, 0, 0);
0155 }
0156 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
0157
0158 int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
0159 {
0160 u32 in[MLX5_ST_SZ_DW(mlcr_reg)] = {0};
0161 u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
0162
0163 MLX5_SET(mlcr_reg, in, local_port, 1);
0164 MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
0165 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0166 sizeof(out), MLX5_REG_MLCR, 0, 1);
0167 }
0168
0169 int mlx5_query_ib_port_oper(struct mlx5_core_dev *dev, u16 *link_width_oper,
0170 u16 *proto_oper, u8 local_port)
0171 {
0172 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
0173 int err;
0174
0175 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB,
0176 local_port);
0177 if (err)
0178 return err;
0179
0180 *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
0181 *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
0182
0183 return 0;
0184 }
0185 EXPORT_SYMBOL(mlx5_query_ib_port_oper);
0186
0187
0188 void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
0189 {
0190 enum mlx5_port_status ps;
0191
0192 mlx5_query_port_admin_status(dev, &ps);
0193 mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
0194 if (ps == MLX5_PORT_UP)
0195 mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
0196 }
0197 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
0198
0199 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
0200 enum mlx5_port_status status)
0201 {
0202 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
0203 u32 out[MLX5_ST_SZ_DW(paos_reg)];
0204
0205 MLX5_SET(paos_reg, in, local_port, 1);
0206 MLX5_SET(paos_reg, in, admin_status, status);
0207 MLX5_SET(paos_reg, in, ase, 1);
0208 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0209 sizeof(out), MLX5_REG_PAOS, 0, 1);
0210 }
0211 EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
0212
0213 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
0214 enum mlx5_port_status *status)
0215 {
0216 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
0217 u32 out[MLX5_ST_SZ_DW(paos_reg)];
0218 int err;
0219
0220 MLX5_SET(paos_reg, in, local_port, 1);
0221 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0222 sizeof(out), MLX5_REG_PAOS, 0, 0);
0223 if (err)
0224 return err;
0225 *status = MLX5_GET(paos_reg, out, admin_status);
0226 return 0;
0227 }
0228 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
0229
0230 static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
0231 u16 *max_mtu, u16 *oper_mtu, u8 port)
0232 {
0233 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
0234 u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
0235
0236 MLX5_SET(pmtu_reg, in, local_port, port);
0237 mlx5_core_access_reg(dev, in, sizeof(in), out,
0238 sizeof(out), MLX5_REG_PMTU, 0, 0);
0239
0240 if (max_mtu)
0241 *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu);
0242 if (oper_mtu)
0243 *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
0244 if (admin_mtu)
0245 *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
0246 }
0247
0248 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
0249 {
0250 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
0251 u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
0252
0253 MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
0254 MLX5_SET(pmtu_reg, in, local_port, port);
0255 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0256 sizeof(out), MLX5_REG_PMTU, 0, 1);
0257 }
0258 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
0259
0260 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
0261 u8 port)
0262 {
0263 mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
0264 }
0265 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
0266
0267 void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
0268 u8 port)
0269 {
0270 mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
0271 }
0272 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
0273
0274 static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
0275 {
0276 u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
0277 u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
0278 int err;
0279
0280 MLX5_SET(pmlp_reg, in, local_port, 1);
0281 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
0282 MLX5_REG_PMLP, 0, 0);
0283 if (err)
0284 return err;
0285
0286 *module_num = MLX5_GET(lane_2_module_mapping,
0287 MLX5_ADDR_OF(pmlp_reg, out, lane0_module_mapping),
0288 module);
0289
0290 return 0;
0291 }
0292
0293 static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num,
0294 u8 *module_id)
0295 {
0296 u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
0297 u32 out[MLX5_ST_SZ_DW(mcia_reg)];
0298 int err, status;
0299 u8 *ptr;
0300
0301 MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW);
0302 MLX5_SET(mcia_reg, in, module, module_num);
0303 MLX5_SET(mcia_reg, in, device_address, 0);
0304 MLX5_SET(mcia_reg, in, page_number, 0);
0305 MLX5_SET(mcia_reg, in, size, 1);
0306 MLX5_SET(mcia_reg, in, l, 0);
0307
0308 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0309 sizeof(out), MLX5_REG_MCIA, 0, 0);
0310 if (err)
0311 return err;
0312
0313 status = MLX5_GET(mcia_reg, out, status);
0314 if (status) {
0315 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
0316 status);
0317 return -EIO;
0318 }
0319 ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
0320
0321 *module_id = ptr[0];
0322
0323 return 0;
0324 }
0325
0326 static int mlx5_qsfp_eeprom_page(u16 offset)
0327 {
0328 if (offset < MLX5_EEPROM_PAGE_LENGTH)
0329
0330 return 0;
0331
0332
0333
0334
0335
0336 return 1 + ((offset - MLX5_EEPROM_PAGE_LENGTH) /
0337 MLX5_EEPROM_HIGH_PAGE_LENGTH);
0338 }
0339
0340 static int mlx5_qsfp_eeprom_high_page_offset(int page_num)
0341 {
0342 if (!page_num)
0343 return 0;
0344
0345
0346 return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH;
0347 }
0348
0349 static void mlx5_qsfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
0350 {
0351 *i2c_addr = MLX5_I2C_ADDR_LOW;
0352 *page_num = mlx5_qsfp_eeprom_page(*offset);
0353 *offset -= mlx5_qsfp_eeprom_high_page_offset(*page_num);
0354 }
0355
0356 static void mlx5_sfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
0357 {
0358 *i2c_addr = MLX5_I2C_ADDR_LOW;
0359 *page_num = 0;
0360
0361 if (*offset < MLX5_EEPROM_PAGE_LENGTH)
0362 return;
0363
0364 *i2c_addr = MLX5_I2C_ADDR_HIGH;
0365 *offset -= MLX5_EEPROM_PAGE_LENGTH;
0366 }
0367
0368 static int mlx5_mcia_max_bytes(struct mlx5_core_dev *dev)
0369 {
0370
0371 return (MLX5_CAP_MCAM_FEATURE(dev, mcia_32dwords) ? 32 : 12) * sizeof(u32);
0372 }
0373
0374 static int mlx5_query_mcia(struct mlx5_core_dev *dev,
0375 struct mlx5_module_eeprom_query_params *params, u8 *data)
0376 {
0377 u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
0378 u32 out[MLX5_ST_SZ_DW(mcia_reg)];
0379 int status, err;
0380 void *ptr;
0381 u16 size;
0382
0383 size = min_t(int, params->size, mlx5_mcia_max_bytes(dev));
0384
0385 MLX5_SET(mcia_reg, in, l, 0);
0386 MLX5_SET(mcia_reg, in, size, size);
0387 MLX5_SET(mcia_reg, in, module, params->module_number);
0388 MLX5_SET(mcia_reg, in, device_address, params->offset);
0389 MLX5_SET(mcia_reg, in, page_number, params->page);
0390 MLX5_SET(mcia_reg, in, i2c_device_address, params->i2c_address);
0391
0392 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0393 sizeof(out), MLX5_REG_MCIA, 0, 0);
0394 if (err)
0395 return err;
0396
0397 status = MLX5_GET(mcia_reg, out, status);
0398 if (status) {
0399 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
0400 status);
0401 return -EIO;
0402 }
0403
0404 ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
0405 memcpy(data, ptr, size);
0406
0407 return size;
0408 }
0409
0410 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
0411 u16 offset, u16 size, u8 *data)
0412 {
0413 struct mlx5_module_eeprom_query_params query = {0};
0414 u8 module_id;
0415 int err;
0416
0417 err = mlx5_query_module_num(dev, &query.module_number);
0418 if (err)
0419 return err;
0420
0421 err = mlx5_query_module_id(dev, query.module_number, &module_id);
0422 if (err)
0423 return err;
0424
0425 switch (module_id) {
0426 case MLX5_MODULE_ID_SFP:
0427 mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
0428 break;
0429 case MLX5_MODULE_ID_QSFP:
0430 case MLX5_MODULE_ID_QSFP_PLUS:
0431 case MLX5_MODULE_ID_QSFP28:
0432 mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
0433 break;
0434 default:
0435 mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
0436 return -EINVAL;
0437 }
0438
0439 if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
0440
0441 size = MLX5_EEPROM_PAGE_LENGTH - offset;
0442
0443 query.size = size;
0444 query.offset = offset;
0445
0446 return mlx5_query_mcia(dev, &query, data);
0447 }
0448 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
0449
0450 int mlx5_query_module_eeprom_by_page(struct mlx5_core_dev *dev,
0451 struct mlx5_module_eeprom_query_params *params,
0452 u8 *data)
0453 {
0454 int err;
0455
0456 err = mlx5_query_module_num(dev, ¶ms->module_number);
0457 if (err)
0458 return err;
0459
0460 if (params->i2c_address != MLX5_I2C_ADDR_HIGH &&
0461 params->i2c_address != MLX5_I2C_ADDR_LOW) {
0462 mlx5_core_err(dev, "I2C address not recognized: 0x%x\n", params->i2c_address);
0463 return -EINVAL;
0464 }
0465
0466 return mlx5_query_mcia(dev, params, data);
0467 }
0468 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom_by_page);
0469
0470 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
0471 int pvlc_size, u8 local_port)
0472 {
0473 u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
0474
0475 MLX5_SET(pvlc_reg, in, local_port, local_port);
0476 return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
0477 pvlc_size, MLX5_REG_PVLC, 0, 0);
0478 }
0479
0480 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
0481 u8 *vl_hw_cap, u8 local_port)
0482 {
0483 u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
0484 int err;
0485
0486 err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
0487 if (err)
0488 return err;
0489
0490 *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
0491
0492 return 0;
0493 }
0494 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
0495
0496 int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
0497 u8 port_num, void *out, size_t sz)
0498 {
0499 u32 *in;
0500 int err;
0501
0502 in = kvzalloc(sz, GFP_KERNEL);
0503 if (!in) {
0504 err = -ENOMEM;
0505 return err;
0506 }
0507
0508 MLX5_SET(ppcnt_reg, in, local_port, port_num);
0509
0510 MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP);
0511 err = mlx5_core_access_reg(dev, in, sz, out,
0512 sz, MLX5_REG_PPCNT, 0, 0);
0513
0514 kvfree(in);
0515 return err;
0516 }
0517 EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt);
0518
0519 static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out,
0520 u32 out_size)
0521 {
0522 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
0523
0524 MLX5_SET(pfcc_reg, in, local_port, 1);
0525
0526 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0527 out_size, MLX5_REG_PFCC, 0, 0);
0528 }
0529
0530 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
0531 {
0532 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
0533 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
0534
0535 MLX5_SET(pfcc_reg, in, local_port, 1);
0536 MLX5_SET(pfcc_reg, in, pptx, tx_pause);
0537 MLX5_SET(pfcc_reg, in, pprx, rx_pause);
0538
0539 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0540 sizeof(out), MLX5_REG_PFCC, 0, 1);
0541 }
0542 EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
0543
0544 int mlx5_query_port_pause(struct mlx5_core_dev *dev,
0545 u32 *rx_pause, u32 *tx_pause)
0546 {
0547 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
0548 int err;
0549
0550 err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
0551 if (err)
0552 return err;
0553
0554 if (rx_pause)
0555 *rx_pause = MLX5_GET(pfcc_reg, out, pprx);
0556
0557 if (tx_pause)
0558 *tx_pause = MLX5_GET(pfcc_reg, out, pptx);
0559
0560 return 0;
0561 }
0562 EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
0563
0564 int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
0565 u16 stall_critical_watermark,
0566 u16 stall_minor_watermark)
0567 {
0568 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
0569 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
0570
0571 MLX5_SET(pfcc_reg, in, local_port, 1);
0572 MLX5_SET(pfcc_reg, in, pptx_mask_n, 1);
0573 MLX5_SET(pfcc_reg, in, pprx_mask_n, 1);
0574 MLX5_SET(pfcc_reg, in, ppan_mask_n, 1);
0575 MLX5_SET(pfcc_reg, in, critical_stall_mask, 1);
0576 MLX5_SET(pfcc_reg, in, minor_stall_mask, 1);
0577 MLX5_SET(pfcc_reg, in, device_stall_critical_watermark,
0578 stall_critical_watermark);
0579 MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark);
0580
0581 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0582 sizeof(out), MLX5_REG_PFCC, 0, 1);
0583 }
0584
0585 int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
0586 u16 *stall_critical_watermark,
0587 u16 *stall_minor_watermark)
0588 {
0589 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
0590 int err;
0591
0592 err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
0593 if (err)
0594 return err;
0595
0596 if (stall_critical_watermark)
0597 *stall_critical_watermark = MLX5_GET(pfcc_reg, out,
0598 device_stall_critical_watermark);
0599
0600 if (stall_minor_watermark)
0601 *stall_minor_watermark = MLX5_GET(pfcc_reg, out,
0602 device_stall_minor_watermark);
0603
0604 return 0;
0605 }
0606
0607 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
0608 {
0609 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
0610 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
0611
0612 MLX5_SET(pfcc_reg, in, local_port, 1);
0613 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
0614 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
0615 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
0616 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
0617
0618 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0619 sizeof(out), MLX5_REG_PFCC, 0, 1);
0620 }
0621 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
0622
0623 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
0624 {
0625 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
0626 int err;
0627
0628 err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
0629 if (err)
0630 return err;
0631
0632 if (pfc_en_tx)
0633 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
0634
0635 if (pfc_en_rx)
0636 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
0637
0638 return 0;
0639 }
0640 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
0641
0642 int mlx5_max_tc(struct mlx5_core_dev *mdev)
0643 {
0644 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
0645
0646 return num_tc - 1;
0647 }
0648
0649 int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
0650 {
0651 u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
0652
0653 MLX5_SET(dcbx_param, in, port_number, 1);
0654
0655 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
0656 sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
0657 }
0658
0659 int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
0660 {
0661 u32 out[MLX5_ST_SZ_DW(dcbx_param)];
0662
0663 MLX5_SET(dcbx_param, in, port_number, 1);
0664
0665 return mlx5_core_access_reg(mdev, in, sizeof(out), out,
0666 sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
0667 }
0668
0669 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
0670 {
0671 u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
0672 u32 out[MLX5_ST_SZ_DW(qtct_reg)];
0673 int err;
0674 int i;
0675
0676 for (i = 0; i < 8; i++) {
0677 if (prio_tc[i] > mlx5_max_tc(mdev))
0678 return -EINVAL;
0679
0680 MLX5_SET(qtct_reg, in, prio, i);
0681 MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
0682
0683 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
0684 sizeof(out), MLX5_REG_QTCT, 0, 1);
0685 if (err)
0686 return err;
0687 }
0688
0689 return 0;
0690 }
0691 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
0692
0693 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
0694 u8 prio, u8 *tc)
0695 {
0696 u32 in[MLX5_ST_SZ_DW(qtct_reg)];
0697 u32 out[MLX5_ST_SZ_DW(qtct_reg)];
0698 int err;
0699
0700 memset(in, 0, sizeof(in));
0701 memset(out, 0, sizeof(out));
0702
0703 MLX5_SET(qtct_reg, in, port_number, 1);
0704 MLX5_SET(qtct_reg, in, prio, prio);
0705
0706 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
0707 sizeof(out), MLX5_REG_QTCT, 0, 0);
0708 if (!err)
0709 *tc = MLX5_GET(qtct_reg, out, tclass);
0710
0711 return err;
0712 }
0713 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
0714
0715 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
0716 int inlen)
0717 {
0718 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
0719
0720 if (!MLX5_CAP_GEN(mdev, ets))
0721 return -EOPNOTSUPP;
0722
0723 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
0724 MLX5_REG_QETCR, 0, 1);
0725 }
0726
0727 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
0728 int outlen)
0729 {
0730 u32 in[MLX5_ST_SZ_DW(qetc_reg)];
0731
0732 if (!MLX5_CAP_GEN(mdev, ets))
0733 return -EOPNOTSUPP;
0734
0735 memset(in, 0, sizeof(in));
0736 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
0737 MLX5_REG_QETCR, 0, 0);
0738 }
0739
0740 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
0741 {
0742 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
0743 int i;
0744
0745 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
0746 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
0747 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
0748 }
0749
0750 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
0751 }
0752 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
0753
0754 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
0755 u8 tc, u8 *tc_group)
0756 {
0757 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
0758 void *ets_tcn_conf;
0759 int err;
0760
0761 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
0762 if (err)
0763 return err;
0764
0765 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
0766 tc_configuration[tc]);
0767
0768 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
0769 group);
0770
0771 return 0;
0772 }
0773 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
0774
0775 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
0776 {
0777 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
0778 int i;
0779
0780 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
0781 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
0782 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
0783 }
0784
0785 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
0786 }
0787 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
0788
0789 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
0790 u8 tc, u8 *bw_pct)
0791 {
0792 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
0793 void *ets_tcn_conf;
0794 int err;
0795
0796 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
0797 if (err)
0798 return err;
0799
0800 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
0801 tc_configuration[tc]);
0802
0803 *bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
0804 bw_allocation);
0805
0806 return 0;
0807 }
0808 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
0809
0810 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
0811 u8 *max_bw_value,
0812 u8 *max_bw_units)
0813 {
0814 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
0815 void *ets_tcn_conf;
0816 int i;
0817
0818 MLX5_SET(qetc_reg, in, port_number, 1);
0819
0820 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
0821 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
0822
0823 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
0824 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
0825 max_bw_units[i]);
0826 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
0827 max_bw_value[i]);
0828 }
0829
0830 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
0831 }
0832 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
0833
0834 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
0835 u8 *max_bw_value,
0836 u8 *max_bw_units)
0837 {
0838 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
0839 void *ets_tcn_conf;
0840 int err;
0841 int i;
0842
0843 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
0844 if (err)
0845 return err;
0846
0847 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
0848 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
0849
0850 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
0851 max_bw_value);
0852 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
0853 max_bw_units);
0854 }
0855
0856 return 0;
0857 }
0858 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
0859
0860 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
0861 {
0862 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {};
0863
0864 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
0865 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
0866 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
0867 return mlx5_cmd_exec_in(mdev, set_wol_rol, in);
0868 }
0869 EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
0870
0871 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
0872 {
0873 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {};
0874 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {};
0875 int err;
0876
0877 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
0878 err = mlx5_cmd_exec_inout(mdev, query_wol_rol, in, out);
0879 if (!err)
0880 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
0881
0882 return err;
0883 }
0884 EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
0885
0886 int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen)
0887 {
0888 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
0889
0890 MLX5_SET(pcmr_reg, in, local_port, 1);
0891 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
0892 outlen, MLX5_REG_PCMR, 0, 0);
0893 }
0894
0895 int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
0896 {
0897 u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
0898
0899 return mlx5_core_access_reg(mdev, in, inlen, out,
0900 sizeof(out), MLX5_REG_PCMR, 0, 1);
0901 }
0902
0903 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
0904 {
0905 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
0906 int err;
0907
0908 err = mlx5_query_ports_check(mdev, in, sizeof(in));
0909 if (err)
0910 return err;
0911 MLX5_SET(pcmr_reg, in, local_port, 1);
0912 MLX5_SET(pcmr_reg, in, fcs_chk, enable);
0913 return mlx5_set_ports_check(mdev, in, sizeof(in));
0914 }
0915
0916 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
0917 bool *enabled)
0918 {
0919 u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
0920
0921 *supported = false;
0922 *enabled = true;
0923
0924 if (!MLX5_CAP_GEN(mdev, ports_check))
0925 return;
0926
0927 if (mlx5_query_ports_check(mdev, out, sizeof(out)))
0928 return;
0929
0930 *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
0931 *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
0932 }
0933
0934 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
0935 {
0936 u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
0937
0938 return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
0939 mtpps_size, MLX5_REG_MTPPS, 0, 0);
0940 }
0941
0942 int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
0943 {
0944 u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
0945
0946 return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
0947 sizeof(out), MLX5_REG_MTPPS, 0, 1);
0948 }
0949
0950 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
0951 {
0952 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
0953 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
0954 int err = 0;
0955
0956 MLX5_SET(mtppse_reg, in, pin, pin);
0957
0958 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
0959 sizeof(out), MLX5_REG_MTPPSE, 0, 0);
0960 if (err)
0961 return err;
0962
0963 *arm = MLX5_GET(mtppse_reg, in, event_arm);
0964 *mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
0965
0966 return err;
0967 }
0968
0969 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
0970 {
0971 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
0972 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
0973
0974 MLX5_SET(mtppse_reg, in, pin, pin);
0975 MLX5_SET(mtppse_reg, in, event_arm, arm);
0976 MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
0977
0978 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
0979 sizeof(out), MLX5_REG_MTPPSE, 0, 1);
0980 }
0981
0982 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
0983 {
0984 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
0985 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
0986 int err;
0987
0988 MLX5_SET(qpts_reg, in, local_port, 1);
0989 MLX5_SET(qpts_reg, in, trust_state, trust_state);
0990
0991 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
0992 sizeof(out), MLX5_REG_QPTS, 0, 1);
0993 return err;
0994 }
0995
0996 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
0997 {
0998 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
0999 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
1000 int err;
1001
1002 MLX5_SET(qpts_reg, in, local_port, 1);
1003
1004 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
1005 sizeof(out), MLX5_REG_QPTS, 0, 0);
1006 if (!err)
1007 *trust_state = MLX5_GET(qpts_reg, out, trust_state);
1008
1009 return err;
1010 }
1011
1012 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio)
1013 {
1014 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1015 void *qpdpm_dscp;
1016 void *out;
1017 void *in;
1018 int err;
1019
1020 in = kzalloc(sz, GFP_KERNEL);
1021 out = kzalloc(sz, GFP_KERNEL);
1022 if (!in || !out) {
1023 err = -ENOMEM;
1024 goto out;
1025 }
1026
1027 MLX5_SET(qpdpm_reg, in, local_port, 1);
1028 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1029 if (err)
1030 goto out;
1031
1032 memcpy(in, out, sz);
1033 MLX5_SET(qpdpm_reg, in, local_port, 1);
1034
1035
1036 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]);
1037 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio);
1038 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
1039 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
1040
1041 out:
1042 kfree(in);
1043 kfree(out);
1044 return err;
1045 }
1046
1047
1048 #define MLX5E_SUPPORTED_DSCP 64
1049 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
1050 {
1051 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1052 void *qpdpm_dscp;
1053 void *out;
1054 void *in;
1055 int err;
1056 int i;
1057
1058 in = kzalloc(sz, GFP_KERNEL);
1059 out = kzalloc(sz, GFP_KERNEL);
1060 if (!in || !out) {
1061 err = -ENOMEM;
1062 goto out;
1063 }
1064
1065 MLX5_SET(qpdpm_reg, in, local_port, 1);
1066 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1067 if (err)
1068 goto out;
1069
1070 for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) {
1071 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
1072 dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
1073 }
1074
1075 out:
1076 kfree(in);
1077 kfree(out);
1078 return err;
1079 }