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 default: 73 return -EOPNOTSUPP; 74 } 75 } 76 77 static int lan966x_tc_block_cb_ingress(enum tc_setup_type type, 78 void *type_data, void *cb_priv) 79 { 80 return lan966x_tc_block_cb(type, type_data, cb_priv, true); 81 } 82 83 static int lan966x_tc_block_cb_egress(enum tc_setup_type type, 84 void *type_data, void *cb_priv) 85 { 86 return lan966x_tc_block_cb(type, type_data, cb_priv, false); 87 } 88 89 static int lan966x_tc_setup_block(struct lan966x_port *port, 90 struct flow_block_offload *f) 91 { 92 flow_setup_cb_t *cb; 93 bool ingress; 94 95 if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) { 96 cb = lan966x_tc_block_cb_ingress; 97 port->tc.ingress_shared_block = f->block_shared; 98 ingress = true; 99 } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) { 100 cb = lan966x_tc_block_cb_egress; 101 ingress = false; 102 } else { 103 return -EOPNOTSUPP; 104 } 105 106 return flow_block_cb_setup_simple(f, &lan966x_tc_block_cb_list, 107 cb, port, port, ingress); 108 } 109 110 int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type, 111 void *type_data) 112 { 113 struct lan966x_port *port = netdev_priv(dev); 114 115 switch (type) { 116 case TC_SETUP_QDISC_MQPRIO: 117 return lan966x_tc_setup_qdisc_mqprio(port, type_data); 118 case TC_SETUP_QDISC_TAPRIO: 119 return lan966x_tc_setup_qdisc_taprio(port, type_data); 120 case TC_SETUP_QDISC_TBF: 121 return lan966x_tc_setup_qdisc_tbf(port, type_data); 122 case TC_SETUP_QDISC_CBS: 123 return lan966x_tc_setup_qdisc_cbs(port, type_data); 124 case TC_SETUP_QDISC_ETS: 125 return lan966x_tc_setup_qdisc_ets(port, type_data); 126 case TC_SETUP_BLOCK: 127 return lan966x_tc_setup_block(port, type_data); 128 default: 129 return -EOPNOTSUPP; 130 } 131 132 return 0; 133 } 134