1 /* 2 * Copyright (c) 2018, 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 "port.h" 34 35 /* speed in units of 1Mb */ 36 static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = { 37 [MLX5E_1000BASE_CX_SGMII] = 1000, 38 [MLX5E_1000BASE_KX] = 1000, 39 [MLX5E_10GBASE_CX4] = 10000, 40 [MLX5E_10GBASE_KX4] = 10000, 41 [MLX5E_10GBASE_KR] = 10000, 42 [MLX5E_20GBASE_KR2] = 20000, 43 [MLX5E_40GBASE_CR4] = 40000, 44 [MLX5E_40GBASE_KR4] = 40000, 45 [MLX5E_56GBASE_R4] = 56000, 46 [MLX5E_10GBASE_CR] = 10000, 47 [MLX5E_10GBASE_SR] = 10000, 48 [MLX5E_10GBASE_ER] = 10000, 49 [MLX5E_40GBASE_SR4] = 40000, 50 [MLX5E_40GBASE_LR4] = 40000, 51 [MLX5E_50GBASE_SR2] = 50000, 52 [MLX5E_100GBASE_CR4] = 100000, 53 [MLX5E_100GBASE_SR4] = 100000, 54 [MLX5E_100GBASE_KR4] = 100000, 55 [MLX5E_100GBASE_LR4] = 100000, 56 [MLX5E_100BASE_TX] = 100, 57 [MLX5E_1000BASE_T] = 1000, 58 [MLX5E_10GBASE_T] = 10000, 59 [MLX5E_25GBASE_CR] = 25000, 60 [MLX5E_25GBASE_KR] = 25000, 61 [MLX5E_25GBASE_SR] = 25000, 62 [MLX5E_50GBASE_CR2] = 50000, 63 [MLX5E_50GBASE_KR2] = 50000, 64 }; 65 66 u32 mlx5e_port_ptys2speed(u32 eth_proto_oper) 67 { 68 unsigned long temp = eth_proto_oper; 69 u32 speed = 0; 70 int i; 71 72 i = find_first_bit(&temp, MLX5E_LINK_MODES_NUMBER); 73 if (i < MLX5E_LINK_MODES_NUMBER) 74 speed = mlx5e_link_speed[i]; 75 76 return speed; 77 } 78 79 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 80 { 81 u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {}; 82 u32 eth_proto_oper; 83 int err; 84 85 err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); 86 if (err) 87 return err; 88 89 eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 90 *speed = mlx5e_port_ptys2speed(eth_proto_oper); 91 if (!(*speed)) { 92 mlx5_core_warn(mdev, "cannot get port speed\n"); 93 err = -EINVAL; 94 } 95 96 return err; 97 } 98 99 int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 100 { 101 u32 max_speed = 0; 102 u32 proto_cap; 103 int err; 104 int i; 105 106 err = mlx5_query_port_proto_cap(mdev, &proto_cap, MLX5_PTYS_EN); 107 if (err) 108 return err; 109 110 for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) 111 if (proto_cap & MLX5E_PROT_MASK(i)) 112 max_speed = max(max_speed, mlx5e_link_speed[i]); 113 114 *speed = max_speed; 115 return 0; 116 } 117 118 u32 mlx5e_port_speed2linkmodes(u32 speed) 119 { 120 u32 link_modes = 0; 121 int i; 122 123 for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { 124 if (mlx5e_link_speed[i] == speed) 125 link_modes |= MLX5E_PROT_MASK(i); 126 } 127 128 return link_modes; 129 } 130 131 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out) 132 { 133 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 134 void *in; 135 int err; 136 137 in = kzalloc(sz, GFP_KERNEL); 138 if (!in) 139 return -ENOMEM; 140 141 MLX5_SET(pbmc_reg, in, local_port, 1); 142 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0); 143 144 kfree(in); 145 return err; 146 } 147 148 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in) 149 { 150 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 151 void *out; 152 int err; 153 154 out = kzalloc(sz, GFP_KERNEL); 155 if (!out) 156 return -ENOMEM; 157 158 MLX5_SET(pbmc_reg, in, local_port, 1); 159 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1); 160 161 kfree(out); 162 return err; 163 } 164 165 /* buffer[i]: buffer that priority i mapped to */ 166 int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 167 { 168 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 169 u32 prio_x_buff; 170 void *out; 171 void *in; 172 int prio; 173 int err; 174 175 in = kzalloc(sz, GFP_KERNEL); 176 out = kzalloc(sz, GFP_KERNEL); 177 if (!in || !out) { 178 err = -ENOMEM; 179 goto out; 180 } 181 182 MLX5_SET(pptb_reg, in, local_port, 1); 183 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 184 if (err) 185 goto out; 186 187 prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff); 188 for (prio = 0; prio < 8; prio++) { 189 buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF; 190 mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]); 191 } 192 out: 193 kfree(in); 194 kfree(out); 195 return err; 196 } 197 198 int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 199 { 200 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 201 u32 prio_x_buff; 202 void *out; 203 void *in; 204 int prio; 205 int err; 206 207 in = kzalloc(sz, GFP_KERNEL); 208 out = kzalloc(sz, GFP_KERNEL); 209 if (!in || !out) { 210 err = -ENOMEM; 211 goto out; 212 } 213 214 /* First query the pptb register */ 215 MLX5_SET(pptb_reg, in, local_port, 1); 216 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 217 if (err) 218 goto out; 219 220 memcpy(in, out, sz); 221 MLX5_SET(pptb_reg, in, local_port, 1); 222 223 /* Update the pm and prio_x_buff */ 224 MLX5_SET(pptb_reg, in, pm, 0xFF); 225 226 prio_x_buff = 0; 227 for (prio = 0; prio < 8; prio++) 228 prio_x_buff |= (buffer[prio] << (4 * prio)); 229 MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff); 230 231 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1); 232 233 out: 234 kfree(in); 235 kfree(out); 236 return err; 237 } 238