196f17e07SNogah Frankel /*
296f17e07SNogah Frankel  * drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
396f17e07SNogah Frankel  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
496f17e07SNogah Frankel  * Copyright (c) 2017 Nogah Frankel <nogahf@mellanox.com>
596f17e07SNogah Frankel  *
696f17e07SNogah Frankel  * Redistribution and use in source and binary forms, with or without
796f17e07SNogah Frankel  * modification, are permitted provided that the following conditions are met:
896f17e07SNogah Frankel  *
996f17e07SNogah Frankel  * 1. Redistributions of source code must retain the above copyright
1096f17e07SNogah Frankel  *    notice, this list of conditions and the following disclaimer.
1196f17e07SNogah Frankel  * 2. Redistributions in binary form must reproduce the above copyright
1296f17e07SNogah Frankel  *    notice, this list of conditions and the following disclaimer in the
1396f17e07SNogah Frankel  *    documentation and/or other materials provided with the distribution.
1496f17e07SNogah Frankel  * 3. Neither the names of the copyright holders nor the names of its
1596f17e07SNogah Frankel  *    contributors may be used to endorse or promote products derived from
1696f17e07SNogah Frankel  *    this software without specific prior written permission.
1796f17e07SNogah Frankel  *
1896f17e07SNogah Frankel  * Alternatively, this software may be distributed under the terms of the
1996f17e07SNogah Frankel  * GNU General Public License ("GPL") version 2 as published by the Free
2096f17e07SNogah Frankel  * Software Foundation.
2196f17e07SNogah Frankel  *
2296f17e07SNogah Frankel  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2396f17e07SNogah Frankel  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2496f17e07SNogah Frankel  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2596f17e07SNogah Frankel  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2696f17e07SNogah Frankel  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2796f17e07SNogah Frankel  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2896f17e07SNogah Frankel  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2996f17e07SNogah Frankel  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3096f17e07SNogah Frankel  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3196f17e07SNogah Frankel  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3296f17e07SNogah Frankel  * POSSIBILITY OF SUCH DAMAGE.
3396f17e07SNogah Frankel  */
3496f17e07SNogah Frankel 
3596f17e07SNogah Frankel #include <linux/kernel.h>
3696f17e07SNogah Frankel #include <linux/errno.h>
3796f17e07SNogah Frankel #include <linux/netdevice.h>
3896f17e07SNogah Frankel #include <net/pkt_cls.h>
39861fb829SNogah Frankel #include <net/red.h>
4096f17e07SNogah Frankel 
4196f17e07SNogah Frankel #include "spectrum.h"
4296f17e07SNogah Frankel #include "reg.h"
4396f17e07SNogah Frankel 
44371b437aSNogah Frankel enum mlxsw_sp_qdisc_type {
45371b437aSNogah Frankel 	MLXSW_SP_QDISC_NO_QDISC,
46371b437aSNogah Frankel 	MLXSW_SP_QDISC_RED,
47371b437aSNogah Frankel };
48371b437aSNogah Frankel 
49371b437aSNogah Frankel struct mlxsw_sp_qdisc {
50371b437aSNogah Frankel 	u32 handle;
51371b437aSNogah Frankel 	enum mlxsw_sp_qdisc_type type;
52371b437aSNogah Frankel 	struct red_stats xstats_base;
53371b437aSNogah Frankel 	union {
54371b437aSNogah Frankel 		struct {
55371b437aSNogah Frankel 			u64 tail_drop_base;
56371b437aSNogah Frankel 			u64 ecn_base;
57371b437aSNogah Frankel 			u64 wred_drop_base;
58371b437aSNogah Frankel 		} red;
59371b437aSNogah Frankel 	} xstats;
60371b437aSNogah Frankel 	u64 tx_bytes;
61371b437aSNogah Frankel 	u64 tx_packets;
62371b437aSNogah Frankel 	u64 drops;
63371b437aSNogah Frankel 	u64 overlimits;
64371b437aSNogah Frankel };
65371b437aSNogah Frankel 
6696f17e07SNogah Frankel static int
6796f17e07SNogah Frankel mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port,
6896f17e07SNogah Frankel 				  int tclass_num, u32 min, u32 max,
6996f17e07SNogah Frankel 				  u32 probability, bool is_ecn)
7096f17e07SNogah Frankel {
7196f17e07SNogah Frankel 	char cwtp_cmd[max_t(u8, MLXSW_REG_CWTP_LEN, MLXSW_REG_CWTPM_LEN)];
7296f17e07SNogah Frankel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
7396f17e07SNogah Frankel 	int err;
7496f17e07SNogah Frankel 
7596f17e07SNogah Frankel 	mlxsw_reg_cwtp_pack(cwtp_cmd, mlxsw_sp_port->local_port, tclass_num);
7696f17e07SNogah Frankel 	mlxsw_reg_cwtp_profile_pack(cwtp_cmd, MLXSW_REG_CWTP_DEFAULT_PROFILE,
7796f17e07SNogah Frankel 				    roundup(min, MLXSW_REG_CWTP_MIN_VALUE),
7896f17e07SNogah Frankel 				    roundup(max, MLXSW_REG_CWTP_MIN_VALUE),
7996f17e07SNogah Frankel 				    probability);
8096f17e07SNogah Frankel 
8196f17e07SNogah Frankel 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtp), cwtp_cmd);
8296f17e07SNogah Frankel 	if (err)
8396f17e07SNogah Frankel 		return err;
8496f17e07SNogah Frankel 
8596f17e07SNogah Frankel 	mlxsw_reg_cwtpm_pack(cwtp_cmd, mlxsw_sp_port->local_port, tclass_num,
8696f17e07SNogah Frankel 			     MLXSW_REG_CWTP_DEFAULT_PROFILE, true, is_ecn);
8796f17e07SNogah Frankel 
8896f17e07SNogah Frankel 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtp_cmd);
8996f17e07SNogah Frankel }
9096f17e07SNogah Frankel 
9196f17e07SNogah Frankel static int
9296f17e07SNogah Frankel mlxsw_sp_tclass_congestion_disable(struct mlxsw_sp_port *mlxsw_sp_port,
9396f17e07SNogah Frankel 				   int tclass_num)
9496f17e07SNogah Frankel {
9596f17e07SNogah Frankel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
9696f17e07SNogah Frankel 	char cwtpm_cmd[MLXSW_REG_CWTPM_LEN];
9796f17e07SNogah Frankel 
9896f17e07SNogah Frankel 	mlxsw_reg_cwtpm_pack(cwtpm_cmd, mlxsw_sp_port->local_port, tclass_num,
9996f17e07SNogah Frankel 			     MLXSW_REG_CWTPM_RESET_PROFILE, false, false);
10096f17e07SNogah Frankel 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtpm_cmd);
10196f17e07SNogah Frankel }
10296f17e07SNogah Frankel 
103861fb829SNogah Frankel static void
104861fb829SNogah Frankel mlxsw_sp_setup_tc_qdisc_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
105861fb829SNogah Frankel 				    struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
106861fb829SNogah Frankel 				    int tclass_num)
107861fb829SNogah Frankel {
108861fb829SNogah Frankel 	struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base;
109861fb829SNogah Frankel 	struct mlxsw_sp_port_xstats *xstats;
1103670756fSNogah Frankel 	struct rtnl_link_stats64 *stats;
111861fb829SNogah Frankel 
112861fb829SNogah Frankel 	xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
1133670756fSNogah Frankel 	stats = &mlxsw_sp_port->periodic_hw_stats.stats;
1143670756fSNogah Frankel 
1153670756fSNogah Frankel 	mlxsw_sp_qdisc->tx_packets = stats->tx_packets;
1163670756fSNogah Frankel 	mlxsw_sp_qdisc->tx_bytes = stats->tx_bytes;
117861fb829SNogah Frankel 
118861fb829SNogah Frankel 	switch (mlxsw_sp_qdisc->type) {
119861fb829SNogah Frankel 	case MLXSW_SP_QDISC_RED:
120861fb829SNogah Frankel 		xstats_base->prob_mark = xstats->ecn;
121861fb829SNogah Frankel 		xstats_base->prob_drop = xstats->wred_drop[tclass_num];
122861fb829SNogah Frankel 		xstats_base->pdrop = xstats->tail_drop[tclass_num];
1233670756fSNogah Frankel 
1243670756fSNogah Frankel 		mlxsw_sp_qdisc->overlimits = xstats_base->prob_drop +
1253670756fSNogah Frankel 					     xstats_base->prob_mark;
1263670756fSNogah Frankel 		mlxsw_sp_qdisc->drops = xstats_base->prob_drop +
1273670756fSNogah Frankel 					xstats_base->pdrop;
128861fb829SNogah Frankel 		break;
129861fb829SNogah Frankel 	default:
130861fb829SNogah Frankel 		break;
131861fb829SNogah Frankel 	}
132861fb829SNogah Frankel }
133861fb829SNogah Frankel 
13496f17e07SNogah Frankel static int
13596f17e07SNogah Frankel mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
13696f17e07SNogah Frankel 			   struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
13796f17e07SNogah Frankel 			   int tclass_num)
13896f17e07SNogah Frankel {
13996f17e07SNogah Frankel 	int err;
14096f17e07SNogah Frankel 
14196f17e07SNogah Frankel 	if (mlxsw_sp_qdisc->handle != handle)
14296f17e07SNogah Frankel 		return 0;
14396f17e07SNogah Frankel 
14496f17e07SNogah Frankel 	err = mlxsw_sp_tclass_congestion_disable(mlxsw_sp_port, tclass_num);
14596f17e07SNogah Frankel 	mlxsw_sp_qdisc->handle = TC_H_UNSPEC;
14696f17e07SNogah Frankel 	mlxsw_sp_qdisc->type = MLXSW_SP_QDISC_NO_QDISC;
14796f17e07SNogah Frankel 
14896f17e07SNogah Frankel 	return err;
14996f17e07SNogah Frankel }
15096f17e07SNogah Frankel 
15196f17e07SNogah Frankel static int
15296f17e07SNogah Frankel mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
15396f17e07SNogah Frankel 			   struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
15496f17e07SNogah Frankel 			   int tclass_num,
15596f17e07SNogah Frankel 			   struct tc_red_qopt_offload_params *p)
15696f17e07SNogah Frankel {
15796f17e07SNogah Frankel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
15896f17e07SNogah Frankel 	u32 min, max;
15996f17e07SNogah Frankel 	u64 prob;
16096f17e07SNogah Frankel 	int err = 0;
16196f17e07SNogah Frankel 
16296f17e07SNogah Frankel 	if (p->min > p->max) {
16396f17e07SNogah Frankel 		dev_err(mlxsw_sp->bus_info->dev,
16496f17e07SNogah Frankel 			"spectrum: RED: min %u is bigger then max %u\n", p->min,
16596f17e07SNogah Frankel 			p->max);
16696f17e07SNogah Frankel 		goto err_bad_param;
16796f17e07SNogah Frankel 	}
16896f17e07SNogah Frankel 	if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) {
16996f17e07SNogah Frankel 		dev_err(mlxsw_sp->bus_info->dev,
17096f17e07SNogah Frankel 			"spectrum: RED: max value %u is too big\n", p->max);
17196f17e07SNogah Frankel 		goto err_bad_param;
17296f17e07SNogah Frankel 	}
17396f17e07SNogah Frankel 	if (p->min == 0 || p->max == 0) {
17496f17e07SNogah Frankel 		dev_err(mlxsw_sp->bus_info->dev,
17596f17e07SNogah Frankel 			"spectrum: RED: 0 value is illegal for min and max\n");
17696f17e07SNogah Frankel 		goto err_bad_param;
17796f17e07SNogah Frankel 	}
17896f17e07SNogah Frankel 
17996f17e07SNogah Frankel 	/* calculate probability in percentage */
18096f17e07SNogah Frankel 	prob = p->probability;
18196f17e07SNogah Frankel 	prob *= 100;
18296f17e07SNogah Frankel 	prob = DIV_ROUND_UP(prob, 1 << 16);
18396f17e07SNogah Frankel 	prob = DIV_ROUND_UP(prob, 1 << 16);
18496f17e07SNogah Frankel 	min = mlxsw_sp_bytes_cells(mlxsw_sp, p->min);
18596f17e07SNogah Frankel 	max = mlxsw_sp_bytes_cells(mlxsw_sp, p->max);
18696f17e07SNogah Frankel 	err = mlxsw_sp_tclass_congestion_enable(mlxsw_sp_port, tclass_num, min,
18796f17e07SNogah Frankel 						max, prob, p->is_ecn);
18896f17e07SNogah Frankel 	if (err)
18996f17e07SNogah Frankel 		goto err_config;
19096f17e07SNogah Frankel 
19196f17e07SNogah Frankel 	mlxsw_sp_qdisc->type = MLXSW_SP_QDISC_RED;
192861fb829SNogah Frankel 	if (mlxsw_sp_qdisc->handle != handle)
193861fb829SNogah Frankel 		mlxsw_sp_setup_tc_qdisc_clean_stats(mlxsw_sp_port,
194861fb829SNogah Frankel 						    mlxsw_sp_qdisc,
195861fb829SNogah Frankel 						    tclass_num);
196861fb829SNogah Frankel 
19796f17e07SNogah Frankel 	mlxsw_sp_qdisc->handle = handle;
19896f17e07SNogah Frankel 	return 0;
19996f17e07SNogah Frankel 
20096f17e07SNogah Frankel err_bad_param:
20196f17e07SNogah Frankel 	err = -EINVAL;
20296f17e07SNogah Frankel err_config:
20396f17e07SNogah Frankel 	mlxsw_sp_qdisc_red_destroy(mlxsw_sp_port, mlxsw_sp_qdisc->handle,
20496f17e07SNogah Frankel 				   mlxsw_sp_qdisc, tclass_num);
20596f17e07SNogah Frankel 	return err;
20696f17e07SNogah Frankel }
20796f17e07SNogah Frankel 
208861fb829SNogah Frankel static int
209861fb829SNogah Frankel mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
210861fb829SNogah Frankel 			      struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
211861fb829SNogah Frankel 			      int tclass_num, struct red_stats *res)
212861fb829SNogah Frankel {
213861fb829SNogah Frankel 	struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base;
214861fb829SNogah Frankel 	struct mlxsw_sp_port_xstats *xstats;
215861fb829SNogah Frankel 
216861fb829SNogah Frankel 	if (mlxsw_sp_qdisc->handle != handle ||
217861fb829SNogah Frankel 	    mlxsw_sp_qdisc->type != MLXSW_SP_QDISC_RED)
218861fb829SNogah Frankel 		return -EOPNOTSUPP;
219861fb829SNogah Frankel 
220861fb829SNogah Frankel 	xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
221861fb829SNogah Frankel 
222861fb829SNogah Frankel 	res->prob_drop = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
223861fb829SNogah Frankel 	res->prob_mark = xstats->ecn - xstats_base->prob_mark;
224861fb829SNogah Frankel 	res->pdrop = xstats->tail_drop[tclass_num] - xstats_base->pdrop;
225861fb829SNogah Frankel 	return 0;
226861fb829SNogah Frankel }
227861fb829SNogah Frankel 
2283670756fSNogah Frankel static int
2293670756fSNogah Frankel mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
2303670756fSNogah Frankel 			     struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
2313670756fSNogah Frankel 			     int tclass_num,
2323670756fSNogah Frankel 			     struct tc_red_qopt_offload_stats *res)
2333670756fSNogah Frankel {
2343670756fSNogah Frankel 	u64 tx_bytes, tx_packets, overlimits, drops;
2353670756fSNogah Frankel 	struct mlxsw_sp_port_xstats *xstats;
2363670756fSNogah Frankel 	struct rtnl_link_stats64 *stats;
2373670756fSNogah Frankel 
2383670756fSNogah Frankel 	if (mlxsw_sp_qdisc->handle != handle ||
2393670756fSNogah Frankel 	    mlxsw_sp_qdisc->type != MLXSW_SP_QDISC_RED)
2403670756fSNogah Frankel 		return -EOPNOTSUPP;
2413670756fSNogah Frankel 
2423670756fSNogah Frankel 	xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
2433670756fSNogah Frankel 	stats = &mlxsw_sp_port->periodic_hw_stats.stats;
2443670756fSNogah Frankel 
2453670756fSNogah Frankel 	tx_bytes = stats->tx_bytes - mlxsw_sp_qdisc->tx_bytes;
2463670756fSNogah Frankel 	tx_packets = stats->tx_packets - mlxsw_sp_qdisc->tx_packets;
2473670756fSNogah Frankel 	overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
2483670756fSNogah Frankel 		     mlxsw_sp_qdisc->overlimits;
2493670756fSNogah Frankel 	drops = xstats->wred_drop[tclass_num] + xstats->tail_drop[tclass_num] -
2503670756fSNogah Frankel 		mlxsw_sp_qdisc->drops;
2513670756fSNogah Frankel 
2523670756fSNogah Frankel 	_bstats_update(res->bstats, tx_bytes, tx_packets);
2533670756fSNogah Frankel 	res->qstats->overlimits += overlimits;
2543670756fSNogah Frankel 	res->qstats->drops += drops;
2553670756fSNogah Frankel 	res->qstats->backlog += mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
2563670756fSNogah Frankel 						xstats->backlog[tclass_num]);
2573670756fSNogah Frankel 
2583670756fSNogah Frankel 	mlxsw_sp_qdisc->drops +=  drops;
2593670756fSNogah Frankel 	mlxsw_sp_qdisc->overlimits += overlimits;
2603670756fSNogah Frankel 	mlxsw_sp_qdisc->tx_bytes += tx_bytes;
2613670756fSNogah Frankel 	mlxsw_sp_qdisc->tx_packets += tx_packets;
2623670756fSNogah Frankel 	return 0;
2633670756fSNogah Frankel }
2643670756fSNogah Frankel 
26596f17e07SNogah Frankel #define MLXSW_SP_PORT_DEFAULT_TCLASS 0
26696f17e07SNogah Frankel 
26796f17e07SNogah Frankel int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
26896f17e07SNogah Frankel 			  struct tc_red_qopt_offload *p)
26996f17e07SNogah Frankel {
27096f17e07SNogah Frankel 	struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
27196f17e07SNogah Frankel 	int tclass_num;
27296f17e07SNogah Frankel 
27396f17e07SNogah Frankel 	if (p->parent != TC_H_ROOT)
27496f17e07SNogah Frankel 		return -EOPNOTSUPP;
27596f17e07SNogah Frankel 
276371b437aSNogah Frankel 	mlxsw_sp_qdisc = mlxsw_sp_port->root_qdisc;
27796f17e07SNogah Frankel 	tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS;
27896f17e07SNogah Frankel 
27996f17e07SNogah Frankel 	switch (p->command) {
28096f17e07SNogah Frankel 	case TC_RED_REPLACE:
28196f17e07SNogah Frankel 		return mlxsw_sp_qdisc_red_replace(mlxsw_sp_port, p->handle,
28296f17e07SNogah Frankel 						  mlxsw_sp_qdisc, tclass_num,
28396f17e07SNogah Frankel 						  &p->set);
28496f17e07SNogah Frankel 	case TC_RED_DESTROY:
28596f17e07SNogah Frankel 		return mlxsw_sp_qdisc_red_destroy(mlxsw_sp_port, p->handle,
28696f17e07SNogah Frankel 						  mlxsw_sp_qdisc, tclass_num);
287861fb829SNogah Frankel 	case TC_RED_XSTATS:
288861fb829SNogah Frankel 		return mlxsw_sp_qdisc_get_red_xstats(mlxsw_sp_port, p->handle,
289861fb829SNogah Frankel 						     mlxsw_sp_qdisc, tclass_num,
290861fb829SNogah Frankel 						     p->xstats);
2913670756fSNogah Frankel 	case TC_RED_STATS:
2923670756fSNogah Frankel 		return mlxsw_sp_qdisc_get_red_stats(mlxsw_sp_port, p->handle,
2933670756fSNogah Frankel 						    mlxsw_sp_qdisc, tclass_num,
2943670756fSNogah Frankel 						    &p->stats);
29596f17e07SNogah Frankel 	default:
29696f17e07SNogah Frankel 		return -EOPNOTSUPP;
29796f17e07SNogah Frankel 	}
29896f17e07SNogah Frankel }
299371b437aSNogah Frankel 
300371b437aSNogah Frankel int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port)
301371b437aSNogah Frankel {
302371b437aSNogah Frankel 	mlxsw_sp_port->root_qdisc = kzalloc(sizeof(*mlxsw_sp_port->root_qdisc),
303371b437aSNogah Frankel 					    GFP_KERNEL);
304371b437aSNogah Frankel 	if (!mlxsw_sp_port->root_qdisc)
305371b437aSNogah Frankel 		return -ENOMEM;
306371b437aSNogah Frankel 
307371b437aSNogah Frankel 	return 0;
308371b437aSNogah Frankel }
309371b437aSNogah Frankel 
310371b437aSNogah Frankel void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
311371b437aSNogah Frankel {
312371b437aSNogah Frankel 	kfree(mlxsw_sp_port->root_qdisc);
313371b437aSNogah Frankel }
314