aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuy Nguyen <huyn@mellanox.com>2017-09-28 16:33:50 -0400
committerSaeed Mahameed <saeedm@mellanox.com>2017-10-26 03:47:27 -0400
commitbe0f161ef141e4df368aa3f417a1c2ab9c362e75 (patch)
tree72e160e5ba28cb3c2aa1b33dfd085acde2ba213b
parent3c37745ec614ff048d5dce38f976804b05d307ee (diff)
net/mlx5e: DCBNL, Implement tc with ets type and zero bandwidth
Previously, tc with ets type and zero bandwidth is not accepted by driver. This behavior does not follow the IEEE802.1qaz spec. If there are tcs with ets type and zero bandwidth, these tcs are assigned to the lowest priority tc_group #0. We equally distribute 100% bw of the tc_group #0 to these zero bandwidth ets tcs. Also, the non zero bandwidth ets tcs are assigned to tc_group #1. If there is no zero bandwidth ets tc, the non zero bandwidth ets tcs are assigned to tc_group #0. Fixes: cdcf11212b22 ("net/mlx5e: Validate BW weight values of ETS") Signed-off-by: Huy Nguyen <huyn@mellanox.com> Reviewed-by: Parav Pandit <parav@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c113
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/port.c21
-rw-r--r--include/linux/mlx5/port.h2
3 files changed, 106 insertions, 30 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
index c1d384fca4dc..51c4cc00a186 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
@@ -41,6 +41,11 @@
41#define MLX5E_CEE_STATE_UP 1 41#define MLX5E_CEE_STATE_UP 1
42#define MLX5E_CEE_STATE_DOWN 0 42#define MLX5E_CEE_STATE_DOWN 0
43 43
44enum {
45 MLX5E_VENDOR_TC_GROUP_NUM = 7,
46 MLX5E_LOWEST_PRIO_GROUP = 0,
47};
48
44/* If dcbx mode is non-host set the dcbx mode to host. 49/* If dcbx mode is non-host set the dcbx mode to host.
45 */ 50 */
46static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv, 51static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv,
@@ -85,6 +90,9 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
85{ 90{
86 struct mlx5e_priv *priv = netdev_priv(netdev); 91 struct mlx5e_priv *priv = netdev_priv(netdev);
87 struct mlx5_core_dev *mdev = priv->mdev; 92 struct mlx5_core_dev *mdev = priv->mdev;
93 u8 tc_group[IEEE_8021QAZ_MAX_TCS];
94 bool is_tc_group_6_exist = false;
95 bool is_zero_bw_ets_tc = false;
88 int err = 0; 96 int err = 0;
89 int i; 97 int i;
90 98
@@ -96,37 +104,64 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
96 err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]); 104 err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]);
97 if (err) 105 if (err)
98 return err; 106 return err;
99 }
100 107
101 for (i = 0; i < ets->ets_cap; i++) { 108 err = mlx5_query_port_tc_group(mdev, i, &tc_group[i]);
109 if (err)
110 return err;
111
102 err = mlx5_query_port_tc_bw_alloc(mdev, i, &ets->tc_tx_bw[i]); 112 err = mlx5_query_port_tc_bw_alloc(mdev, i, &ets->tc_tx_bw[i]);
103 if (err) 113 if (err)
104 return err; 114 return err;
115
116 if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC &&
117 tc_group[i] == (MLX5E_LOWEST_PRIO_GROUP + 1))
118 is_zero_bw_ets_tc = true;
119
120 if (tc_group[i] == (MLX5E_VENDOR_TC_GROUP_NUM - 1))
121 is_tc_group_6_exist = true;
122 }
123
124 /* Report 0% ets tc if exits*/
125 if (is_zero_bw_ets_tc) {
126 for (i = 0; i < ets->ets_cap; i++)
127 if (tc_group[i] == MLX5E_LOWEST_PRIO_GROUP)
128 ets->tc_tx_bw[i] = 0;
129 }
130
131 /* Update tc_tsa based on fw setting*/
132 for (i = 0; i < ets->ets_cap; i++) {
105 if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC) 133 if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC)
106 priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; 134 priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS;
135 else if (tc_group[i] == MLX5E_VENDOR_TC_GROUP_NUM &&
136 !is_tc_group_6_exist)
137 priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;
107 } 138 }
108
109 memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa)); 139 memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa));
110 140
111 return err; 141 return err;
112} 142}
113 143
114enum {
115 MLX5E_VENDOR_TC_GROUP_NUM = 7,
116 MLX5E_ETS_TC_GROUP_NUM = 0,
117};
118
119static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) 144static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc)
120{ 145{
121 bool any_tc_mapped_to_ets = false; 146 bool any_tc_mapped_to_ets = false;
147 bool ets_zero_bw = false;
122 int strict_group; 148 int strict_group;
123 int i; 149 int i;
124 150
125 for (i = 0; i <= max_tc; i++) 151 for (i = 0; i <= max_tc; i++) {
126 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) 152 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) {
127 any_tc_mapped_to_ets = true; 153 any_tc_mapped_to_ets = true;
154 if (!ets->tc_tx_bw[i])
155 ets_zero_bw = true;
156 }
157 }
128 158
129 strict_group = any_tc_mapped_to_ets ? 1 : 0; 159 /* strict group has higher priority than ets group */
160 strict_group = MLX5E_LOWEST_PRIO_GROUP;
161 if (any_tc_mapped_to_ets)
162 strict_group++;
163 if (ets_zero_bw)
164 strict_group++;
130 165
131 for (i = 0; i <= max_tc; i++) { 166 for (i = 0; i <= max_tc; i++) {
132 switch (ets->tc_tsa[i]) { 167 switch (ets->tc_tsa[i]) {
@@ -137,7 +172,9 @@ static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc)
137 tc_group[i] = strict_group++; 172 tc_group[i] = strict_group++;
138 break; 173 break;
139 case IEEE_8021QAZ_TSA_ETS: 174 case IEEE_8021QAZ_TSA_ETS:
140 tc_group[i] = MLX5E_ETS_TC_GROUP_NUM; 175 tc_group[i] = MLX5E_LOWEST_PRIO_GROUP;
176 if (ets->tc_tx_bw[i] && ets_zero_bw)
177 tc_group[i] = MLX5E_LOWEST_PRIO_GROUP + 1;
141 break; 178 break;
142 } 179 }
143 } 180 }
@@ -146,9 +183,23 @@ static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc)
146static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, 183static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw,
147 u8 *tc_group, int max_tc) 184 u8 *tc_group, int max_tc)
148{ 185{
186 int bw_for_ets_zero_bw_tc = 0;
187 int last_ets_zero_bw_tc = -1;
188 int num_ets_zero_bw = 0;
149 int i; 189 int i;
150 190
151 for (i = 0; i <= max_tc; i++) { 191 for (i = 0; i <= max_tc; i++) {
192 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS &&
193 !ets->tc_tx_bw[i]) {
194 num_ets_zero_bw++;
195 last_ets_zero_bw_tc = i;
196 }
197 }
198
199 if (num_ets_zero_bw)
200 bw_for_ets_zero_bw_tc = MLX5E_MAX_BW_ALLOC / num_ets_zero_bw;
201
202 for (i = 0; i <= max_tc; i++) {
152 switch (ets->tc_tsa[i]) { 203 switch (ets->tc_tsa[i]) {
153 case IEEE_8021QAZ_TSA_VENDOR: 204 case IEEE_8021QAZ_TSA_VENDOR:
154 tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; 205 tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
@@ -157,12 +208,26 @@ static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw,
157 tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; 208 tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
158 break; 209 break;
159 case IEEE_8021QAZ_TSA_ETS: 210 case IEEE_8021QAZ_TSA_ETS:
160 tc_tx_bw[i] = ets->tc_tx_bw[i]; 211 tc_tx_bw[i] = ets->tc_tx_bw[i] ?
212 ets->tc_tx_bw[i] :
213 bw_for_ets_zero_bw_tc;
161 break; 214 break;
162 } 215 }
163 } 216 }
217
218 /* Make sure the total bw for ets zero bw group is 100% */
219 if (last_ets_zero_bw_tc != -1)
220 tc_tx_bw[last_ets_zero_bw_tc] +=
221 MLX5E_MAX_BW_ALLOC % num_ets_zero_bw;
164} 222}
165 223
224/* If there are ETS BW 0,
225 * Set ETS group # to 1 for all ETS non zero BW tcs. Their sum must be 100%.
226 * Set group #0 to all the ETS BW 0 tcs and
227 * equally splits the 100% BW between them
228 * Report both group #0 and #1 as ETS type.
229 * All the tcs in group #0 will be reported with 0% BW.
230 */
166int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets) 231int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets)
167{ 232{
168 struct mlx5_core_dev *mdev = priv->mdev; 233 struct mlx5_core_dev *mdev = priv->mdev;
@@ -188,7 +253,6 @@ int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets)
188 return err; 253 return err;
189 254
190 memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa)); 255 memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa));
191
192 return err; 256 return err;
193} 257}
194 258
@@ -209,17 +273,9 @@ static int mlx5e_dbcnl_validate_ets(struct net_device *netdev,
209 } 273 }
210 274
211 /* Validate Bandwidth Sum */ 275 /* Validate Bandwidth Sum */
212 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 276 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
213 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { 277 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS)
214 if (!ets->tc_tx_bw[i]) {
215 netdev_err(netdev,
216 "Failed to validate ETS: BW 0 is illegal\n");
217 return -EINVAL;
218 }
219
220 bw_sum += ets->tc_tx_bw[i]; 278 bw_sum += ets->tc_tx_bw[i];
221 }
222 }
223 279
224 if (bw_sum != 0 && bw_sum != 100) { 280 if (bw_sum != 0 && bw_sum != 100) {
225 netdev_err(netdev, 281 netdev_err(netdev,
@@ -533,8 +589,7 @@ static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev,
533static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev, 589static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev,
534 int pgid, u8 *bw_pct) 590 int pgid, u8 *bw_pct)
535{ 591{
536 struct mlx5e_priv *priv = netdev_priv(netdev); 592 struct ieee_ets ets;
537 struct mlx5_core_dev *mdev = priv->mdev;
538 593
539 if (pgid >= CEE_DCBX_MAX_PGS) { 594 if (pgid >= CEE_DCBX_MAX_PGS) {
540 netdev_err(netdev, 595 netdev_err(netdev,
@@ -542,8 +597,8 @@ static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev,
542 return; 597 return;
543 } 598 }
544 599
545 if (mlx5_query_port_tc_bw_alloc(mdev, pgid, bw_pct)) 600 mlx5e_dcbnl_ieee_getets(netdev, &ets);
546 *bw_pct = 0; 601 *bw_pct = ets.tc_tx_bw[pgid];
547} 602}
548 603
549static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev, 604static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev,
@@ -739,8 +794,6 @@ static void mlx5e_ets_init(struct mlx5e_priv *priv)
739 ets.prio_tc[i] = i; 794 ets.prio_tc[i] = i;
740 } 795 }
741 796
742 memcpy(priv->dcbx.tc_tsa, ets.tc_tsa, sizeof(ets.tc_tsa));
743
744 /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */ 797 /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */
745 ets.prio_tc[0] = 1; 798 ets.prio_tc[0] = 1;
746 ets.prio_tc[1] = 0; 799 ets.prio_tc[1] = 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
index 1975d4388d4f..e07061f565d6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -677,6 +677,27 @@ int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
677} 677}
678EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); 678EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
679 679
680int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
681 u8 tc, u8 *tc_group)
682{
683 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
684 void *ets_tcn_conf;
685 int err;
686
687 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
688 if (err)
689 return err;
690
691 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
692 tc_configuration[tc]);
693
694 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
695 group);
696
697 return 0;
698}
699EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
700
680int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw) 701int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
681{ 702{
682 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; 703 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
diff --git a/include/linux/mlx5/port.h b/include/linux/mlx5/port.h
index c57d4b7de3a8..c59af8ab753a 100644
--- a/include/linux/mlx5/port.h
+++ b/include/linux/mlx5/port.h
@@ -157,6 +157,8 @@ int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc);
157int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev, 157int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
158 u8 prio, u8 *tc); 158 u8 prio, u8 *tc);
159int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group); 159int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group);
160int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
161 u8 tc, u8 *tc_group);
160int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw); 162int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw);
161int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, 163int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
162 u8 tc, u8 *bw_pct); 164 u8 tc, u8 *bw_pct);