1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include <net/pkt_cls.h> 4 5 #include "lan966x_main.h" 6 7 static LIST_HEAD(lan966x_tc_block_cb_list); 8 9 static int lan966x_tc_setup_qdisc_mqprio(struct lan966x_port *port, 10 struct tc_mqprio_qopt_offload *mqprio) 11 { 12 u8 num_tc = mqprio->qopt.num_tc; 13 14 mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS; 15 16 return num_tc ? lan966x_mqprio_add(port, num_tc) : 17 lan966x_mqprio_del(port); 18 } 19 20 static int lan966x_tc_setup_qdisc_taprio(struct lan966x_port *port, 21 struct tc_taprio_qopt_offload *taprio) 22 { 23 return taprio->enable ? lan966x_taprio_add(port, taprio) : 24 lan966x_taprio_del(port); 25 } 26 27 static int lan966x_tc_setup_qdisc_tbf(struct lan966x_port *port, 28 struct tc_tbf_qopt_offload *qopt) 29 { 30 switch (qopt->command) { 31 case TC_TBF_REPLACE: 32 return lan966x_tbf_add(port, qopt); 33 case TC_TBF_DESTROY: 34 return lan966x_tbf_del(port, qopt); 35 default: 36 return -EOPNOTSUPP; 37 } 38 39 return -EOPNOTSUPP; 40 } 41 42 static int lan966x_tc_setup_qdisc_cbs(struct lan966x_port *port, 43 struct tc_cbs_qopt_offload *qopt) 44 { 45 return qopt->enable ? lan966x_cbs_add(port, qopt) : 46 lan966x_cbs_del(port, qopt); 47 } 48 49 static int lan966x_tc_setup_qdisc_ets(struct lan966x_port *port, 50 struct tc_ets_qopt_offload *qopt) 51 { 52 switch (qopt->command) { 53 case TC_ETS_REPLACE: 54 return lan966x_ets_add(port, qopt); 55 case TC_ETS_DESTROY: 56 return lan966x_ets_del(port, qopt); 57 default: 58 return -EOPNOTSUPP; 59 }; 60 61 return -EOPNOTSUPP; 62 } 63 64 static int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data, 65 void *cb_priv, bool ingress) 66 { 67 struct lan966x_port *port = cb_priv; 68 69 switch (type) { 70 case TC_SETUP_CLSMATCHALL: 71 return lan966x_tc_matchall(port, type_data, ingress); 72 case TC_SETUP_CLSFLOWER: 73 return lan966x_tc_flower(port, type_data); 74 default: 75 return -EOPNOTSUPP; 76 } 77 } 78 79 static int lan966x_tc_block_cb_ingress(enum tc_setup_type type, 80 void *type_data, void *cb_priv) 81 { 82 return lan966x_tc_block_cb(type, type_data, cb_priv, true); 83 } 84 85 static int lan966x_tc_block_cb_egress(enum tc_setup_type type, 86 void *type_data, void *cb_priv) 87 { 88 return lan966x_tc_block_cb(type, type_data, cb_priv, false); 89 } 90 91 static int lan966x_tc_setup_block(struct lan966x_port *port, 92 struct flow_block_offload *f) 93 { 94 flow_setup_cb_t *cb; 95 bool ingress; 96 97 if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) { 98 cb = lan966x_tc_block_cb_ingress; 99 port->tc.ingress_shared_block = f->block_shared; 100 ingress = true; 101 } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) { 102 cb = lan966x_tc_block_cb_egress; 103 ingress = false; 104 } else { 105 return -EOPNOTSUPP; 106 } 107 108 return flow_block_cb_setup_simple(f, &lan966x_tc_block_cb_list, 109 cb, port, port, ingress); 110 } 111 112 int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type, 113 void *type_data) 114 { 115 struct lan966x_port *port = netdev_priv(dev); 116 117 switch (type) { 118 case TC_SETUP_QDISC_MQPRIO: 119 return lan966x_tc_setup_qdisc_mqprio(port, type_data); 120 case TC_SETUP_QDISC_TAPRIO: 121 return lan966x_tc_setup_qdisc_taprio(port, type_data); 122 case TC_SETUP_QDISC_TBF: 123 return lan966x_tc_setup_qdisc_tbf(port, type_data); 124 case TC_SETUP_QDISC_CBS: 125 return lan966x_tc_setup_qdisc_cbs(port, type_data); 126 case TC_SETUP_QDISC_ETS: 127 return lan966x_tc_setup_qdisc_ets(port, type_data); 128 case TC_SETUP_BLOCK: 129 return lan966x_tc_setup_block(port, type_data); 130 default: 131 return -EOPNOTSUPP; 132 } 133 134 return 0; 135 } 136