1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include "lan966x_main.h"
4 
5 /* 0-8 : 9 port policers */
6 #define POL_IDX_PORT	0
7 
8 /* Policer order: Serial (QoS -> Port -> VCAP) */
9 #define POL_ORDER	0x1d3
10 
11 struct lan966x_tc_policer {
12 	/* kilobit per second */
13 	u32 rate;
14 	/* bytes */
15 	u32 burst;
16 };
17 
lan966x_police_add(struct lan966x_port * port,struct lan966x_tc_policer * pol,u16 pol_idx)18 static int lan966x_police_add(struct lan966x_port *port,
19 			      struct lan966x_tc_policer *pol,
20 			      u16 pol_idx)
21 {
22 	struct lan966x *lan966x = port->lan966x;
23 
24 	/* Rate unit is 33 1/3 kpps */
25 	pol->rate = DIV_ROUND_UP(pol->rate * 3, 100);
26 	/* Avoid zero burst size */
27 	pol->burst = pol->burst ?: 1;
28 	/* Unit is 4kB */
29 	pol->burst = DIV_ROUND_UP(pol->burst, 4096);
30 
31 	if (pol->rate > GENMASK(15, 0) ||
32 	    pol->burst > GENMASK(6, 0))
33 		return -EINVAL;
34 
35 	lan_wr(ANA_POL_MODE_DROP_ON_YELLOW_ENA_SET(0) |
36 	       ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA_SET(0) |
37 	       ANA_POL_MODE_IPG_SIZE_SET(20) |
38 	       ANA_POL_MODE_FRM_MODE_SET(1) |
39 	       ANA_POL_MODE_OVERSHOOT_ENA_SET(1),
40 	       lan966x, ANA_POL_MODE(pol_idx));
41 
42 	lan_wr(ANA_POL_PIR_STATE_PIR_LVL_SET(0),
43 	       lan966x, ANA_POL_PIR_STATE(pol_idx));
44 
45 	lan_wr(ANA_POL_PIR_CFG_PIR_RATE_SET(pol->rate) |
46 	       ANA_POL_PIR_CFG_PIR_BURST_SET(pol->burst),
47 	       lan966x, ANA_POL_PIR_CFG(pol_idx));
48 
49 	return 0;
50 }
51 
lan966x_police_del(struct lan966x_port * port,u16 pol_idx)52 static int lan966x_police_del(struct lan966x_port *port,
53 			      u16 pol_idx)
54 {
55 	struct lan966x *lan966x = port->lan966x;
56 
57 	lan_wr(ANA_POL_MODE_DROP_ON_YELLOW_ENA_SET(0) |
58 	       ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA_SET(0) |
59 	       ANA_POL_MODE_IPG_SIZE_SET(20) |
60 	       ANA_POL_MODE_FRM_MODE_SET(2) |
61 	       ANA_POL_MODE_OVERSHOOT_ENA_SET(1),
62 	       lan966x, ANA_POL_MODE(pol_idx));
63 
64 	lan_wr(ANA_POL_PIR_STATE_PIR_LVL_SET(0),
65 	       lan966x, ANA_POL_PIR_STATE(pol_idx));
66 
67 	lan_wr(ANA_POL_PIR_CFG_PIR_RATE_SET(GENMASK(14, 0)) |
68 	       ANA_POL_PIR_CFG_PIR_BURST_SET(0),
69 	       lan966x, ANA_POL_PIR_CFG(pol_idx));
70 
71 	return 0;
72 }
73 
lan966x_police_validate(struct lan966x_port * port,const struct flow_action * action,const struct flow_action_entry * act,unsigned long police_id,bool ingress,struct netlink_ext_ack * extack)74 static int lan966x_police_validate(struct lan966x_port *port,
75 				   const struct flow_action *action,
76 				   const struct flow_action_entry *act,
77 				   unsigned long police_id,
78 				   bool ingress,
79 				   struct netlink_ext_ack *extack)
80 {
81 	if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
82 		NL_SET_ERR_MSG_MOD(extack,
83 				   "Offload not supported when exceed action is not drop");
84 		return -EOPNOTSUPP;
85 	}
86 
87 	if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
88 	    act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
89 		NL_SET_ERR_MSG_MOD(extack,
90 				   "Offload not supported when conform action is not pipe or ok");
91 		return -EOPNOTSUPP;
92 	}
93 
94 	if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
95 	    !flow_action_is_last_entry(action, act)) {
96 		NL_SET_ERR_MSG_MOD(extack,
97 				   "Offload not supported when conform action is ok, but action is not last");
98 		return -EOPNOTSUPP;
99 	}
100 
101 	if (act->police.peakrate_bytes_ps ||
102 	    act->police.avrate || act->police.overhead) {
103 		NL_SET_ERR_MSG_MOD(extack,
104 				   "Offload not supported when peakrate/avrate/overhead is configured");
105 		return -EOPNOTSUPP;
106 	}
107 
108 	if (act->police.rate_pkt_ps) {
109 		NL_SET_ERR_MSG_MOD(extack,
110 				   "QoS offload not support packets per second");
111 		return -EOPNOTSUPP;
112 	}
113 
114 	if (!ingress) {
115 		NL_SET_ERR_MSG_MOD(extack,
116 				   "Policer is not supported on egress");
117 		return -EOPNOTSUPP;
118 	}
119 
120 	if (port->tc.ingress_shared_block) {
121 		NL_SET_ERR_MSG_MOD(extack,
122 				   "Policer is not supported on shared ingress blocks");
123 		return -EOPNOTSUPP;
124 	}
125 
126 	if (port->tc.police_id && port->tc.police_id != police_id) {
127 		NL_SET_ERR_MSG_MOD(extack,
128 				   "Only one policer per port is supported");
129 		return -EEXIST;
130 	}
131 
132 	return 0;
133 }
134 
lan966x_police_port_add(struct lan966x_port * port,struct flow_action * action,struct flow_action_entry * act,unsigned long police_id,bool ingress,struct netlink_ext_ack * extack)135 int lan966x_police_port_add(struct lan966x_port *port,
136 			    struct flow_action *action,
137 			    struct flow_action_entry *act,
138 			    unsigned long police_id,
139 			    bool ingress,
140 			    struct netlink_ext_ack *extack)
141 {
142 	struct lan966x *lan966x = port->lan966x;
143 	struct rtnl_link_stats64 new_stats;
144 	struct lan966x_tc_policer pol;
145 	struct flow_stats *old_stats;
146 	int err;
147 
148 	err = lan966x_police_validate(port, action, act, police_id, ingress,
149 				      extack);
150 	if (err)
151 		return err;
152 
153 	memset(&pol, 0, sizeof(pol));
154 
155 	pol.rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
156 	pol.burst = act->police.burst;
157 
158 	err = lan966x_police_add(port, &pol, POL_IDX_PORT + port->chip_port);
159 	if (err) {
160 		NL_SET_ERR_MSG_MOD(extack,
161 				   "Failed to add policer to port");
162 		return err;
163 	}
164 
165 	lan_rmw(ANA_POL_CFG_PORT_POL_ENA_SET(1) |
166 		ANA_POL_CFG_POL_ORDER_SET(POL_ORDER),
167 		ANA_POL_CFG_PORT_POL_ENA |
168 		ANA_POL_CFG_POL_ORDER,
169 		lan966x, ANA_POL_CFG(port->chip_port));
170 
171 	port->tc.police_id = police_id;
172 
173 	/* Setup initial stats */
174 	old_stats = &port->tc.police_stat;
175 	lan966x_stats_get(port->dev, &new_stats);
176 	old_stats->bytes = new_stats.rx_bytes;
177 	old_stats->pkts = new_stats.rx_packets;
178 	old_stats->drops = new_stats.rx_dropped;
179 	old_stats->lastused = jiffies;
180 
181 	return 0;
182 }
183 
lan966x_police_port_del(struct lan966x_port * port,unsigned long police_id,struct netlink_ext_ack * extack)184 int lan966x_police_port_del(struct lan966x_port *port,
185 			    unsigned long police_id,
186 			    struct netlink_ext_ack *extack)
187 {
188 	struct lan966x *lan966x = port->lan966x;
189 	int err;
190 
191 	if (port->tc.police_id != police_id) {
192 		NL_SET_ERR_MSG_MOD(extack,
193 				   "Invalid policer id");
194 		return -EINVAL;
195 	}
196 
197 	err = lan966x_police_del(port, POL_IDX_PORT + port->chip_port);
198 	if (err) {
199 		NL_SET_ERR_MSG_MOD(extack,
200 				   "Failed to add policer to port");
201 		return err;
202 	}
203 
204 	lan_rmw(ANA_POL_CFG_PORT_POL_ENA_SET(0) |
205 		ANA_POL_CFG_POL_ORDER_SET(POL_ORDER),
206 		ANA_POL_CFG_PORT_POL_ENA |
207 		ANA_POL_CFG_POL_ORDER,
208 		lan966x, ANA_POL_CFG(port->chip_port));
209 
210 	port->tc.police_id = 0;
211 
212 	return 0;
213 }
214 
lan966x_police_port_stats(struct lan966x_port * port,struct flow_stats * stats)215 void lan966x_police_port_stats(struct lan966x_port *port,
216 			       struct flow_stats *stats)
217 {
218 	struct rtnl_link_stats64 new_stats;
219 	struct flow_stats *old_stats;
220 
221 	old_stats = &port->tc.police_stat;
222 	lan966x_stats_get(port->dev, &new_stats);
223 
224 	flow_stats_update(stats,
225 			  new_stats.rx_bytes - old_stats->bytes,
226 			  new_stats.rx_packets - old_stats->pkts,
227 			  new_stats.rx_dropped - old_stats->drops,
228 			  old_stats->lastused,
229 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
230 
231 	old_stats->bytes = new_stats.rx_bytes;
232 	old_stats->pkts = new_stats.rx_packets;
233 	old_stats->drops = new_stats.rx_dropped;
234 	old_stats->lastused = jiffies;
235 }
236