175 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Microchip Sparx5 Switch driver3 *4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.5 */6 7#include <net/pkt_cls.h>8#include <net/pkt_sched.h>9 10#include "sparx5_tc.h"11#include "sparx5_main.h"12#include "sparx5_qos.h"13 14/* tc block handling */15static LIST_HEAD(sparx5_block_cb_list);16 17static int sparx5_tc_block_cb(enum tc_setup_type type,18 void *type_data,19 void *cb_priv, bool ingress)20{21 struct net_device *ndev = cb_priv;22 23 switch (type) {24 case TC_SETUP_CLSMATCHALL:25 return sparx5_tc_matchall(ndev, type_data, ingress);26 case TC_SETUP_CLSFLOWER:27 return sparx5_tc_flower(ndev, type_data, ingress);28 default:29 return -EOPNOTSUPP;30 }31}32 33static int sparx5_tc_block_cb_ingress(enum tc_setup_type type,34 void *type_data,35 void *cb_priv)36{37 return sparx5_tc_block_cb(type, type_data, cb_priv, true);38}39 40static int sparx5_tc_block_cb_egress(enum tc_setup_type type,41 void *type_data,42 void *cb_priv)43{44 return sparx5_tc_block_cb(type, type_data, cb_priv, false);45}46 47static int sparx5_tc_setup_block(struct net_device *ndev,48 struct flow_block_offload *fbo)49{50 flow_setup_cb_t *cb;51 52 if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)53 cb = sparx5_tc_block_cb_ingress;54 else if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)55 cb = sparx5_tc_block_cb_egress;56 else57 return -EOPNOTSUPP;58 59 return flow_block_cb_setup_simple(fbo, &sparx5_block_cb_list,60 cb, ndev, ndev, false);61}62 63static void sparx5_tc_get_layer_and_idx(u32 parent, u32 portno, u32 *layer,64 u32 *idx)65{66 if (parent == TC_H_ROOT) {67 *layer = 2;68 *idx = portno;69 } else {70 u32 queue = TC_H_MIN(parent) - 1;71 *layer = 0;72 *idx = SPX5_HSCH_L0_GET_IDX(portno, queue);73 }74}75 76static int sparx5_tc_setup_qdisc_mqprio(struct net_device *ndev,77 struct tc_mqprio_qopt_offload *m)78{79 m->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;80 81 if (m->qopt.num_tc == 0)82 return sparx5_tc_mqprio_del(ndev);83 else84 return sparx5_tc_mqprio_add(ndev, m->qopt.num_tc);85}86 87static int sparx5_tc_setup_qdisc_tbf(struct net_device *ndev,88 struct tc_tbf_qopt_offload *qopt)89{90 struct sparx5_port *port = netdev_priv(ndev);91 u32 layer, se_idx;92 93 sparx5_tc_get_layer_and_idx(qopt->parent, port->portno, &layer,94 &se_idx);95 96 switch (qopt->command) {97 case TC_TBF_REPLACE:98 return sparx5_tc_tbf_add(port, &qopt->replace_params, layer,99 se_idx);100 case TC_TBF_DESTROY:101 return sparx5_tc_tbf_del(port, layer, se_idx);102 case TC_TBF_STATS:103 return -EOPNOTSUPP;104 default:105 return -EOPNOTSUPP;106 }107 108 return -EOPNOTSUPP;109}110 111static int sparx5_tc_setup_qdisc_ets(struct net_device *ndev,112 struct tc_ets_qopt_offload *qopt)113{114 struct tc_ets_qopt_offload_replace_params *params =115 &qopt->replace_params;116 struct sparx5_port *port = netdev_priv(ndev);117 int i;118 119 /* Only allow ets on ports */120 if (qopt->parent != TC_H_ROOT)121 return -EOPNOTSUPP;122 123 switch (qopt->command) {124 case TC_ETS_REPLACE:125 126 /* We support eight priorities */127 if (params->bands != SPX5_PRIOS)128 return -EOPNOTSUPP;129 130 /* Sanity checks */131 for (i = 0; i < SPX5_PRIOS; ++i) {132 /* Priority map is *always* reverse e.g: 7 6 5 .. 0 */133 if (params->priomap[i] != (7 - i))134 return -EOPNOTSUPP;135 /* Throw an error if we receive zero weights by tc */136 if (params->quanta[i] && params->weights[i] == 0) {137 pr_err("Invalid ets configuration; band %d has weight zero",138 i);139 return -EINVAL;140 }141 }142 143 return sparx5_tc_ets_add(port, params);144 case TC_ETS_DESTROY:145 146 return sparx5_tc_ets_del(port);147 case TC_ETS_GRAFT:148 return -EOPNOTSUPP;149 150 default:151 return -EOPNOTSUPP;152 }153 154 return -EOPNOTSUPP;155}156 157int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type,158 void *type_data)159{160 switch (type) {161 case TC_SETUP_BLOCK:162 return sparx5_tc_setup_block(ndev, type_data);163 case TC_SETUP_QDISC_MQPRIO:164 return sparx5_tc_setup_qdisc_mqprio(ndev, type_data);165 case TC_SETUP_QDISC_TBF:166 return sparx5_tc_setup_qdisc_tbf(ndev, type_data);167 case TC_SETUP_QDISC_ETS:168 return sparx5_tc_setup_qdisc_ets(ndev, type_data);169 default:170 return -EOPNOTSUPP;171 }172 173 return 0;174}175