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