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 void lan966x_police_del(struct lan966x_port *port, u16 pol_idx)
53 {
54 	struct lan966x *lan966x = port->lan966x;
55 
56 	lan_wr(ANA_POL_MODE_DROP_ON_YELLOW_ENA_SET(0) |
57 	       ANA_POL_MODE_MARK_ALL_FRMS_RED_ENA_SET(0) |
58 	       ANA_POL_MODE_IPG_SIZE_SET(20) |
59 	       ANA_POL_MODE_FRM_MODE_SET(2) |
60 	       ANA_POL_MODE_OVERSHOOT_ENA_SET(1),
61 	       lan966x, ANA_POL_MODE(pol_idx));
62 
63 	lan_wr(ANA_POL_PIR_STATE_PIR_LVL_SET(0),
64 	       lan966x, ANA_POL_PIR_STATE(pol_idx));
65 
66 	lan_wr(ANA_POL_PIR_CFG_PIR_RATE_SET(GENMASK(14, 0)) |
67 	       ANA_POL_PIR_CFG_PIR_BURST_SET(0),
68 	       lan966x, ANA_POL_PIR_CFG(pol_idx));
69 }
70 
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)71 static int lan966x_police_validate(struct lan966x_port *port,
72 				   const struct flow_action *action,
73 				   const struct flow_action_entry *act,
74 				   unsigned long police_id,
75 				   bool ingress,
76 				   struct netlink_ext_ack *extack)
77 {
78 	if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
79 		NL_SET_ERR_MSG_MOD(extack,
80 				   "Offload not supported when exceed action is not drop");
81 		return -EOPNOTSUPP;
82 	}
83 
84 	if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
85 	    act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
86 		NL_SET_ERR_MSG_MOD(extack,
87 				   "Offload not supported when conform action is not pipe or ok");
88 		return -EOPNOTSUPP;
89 	}
90 
91 	if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
92 	    !flow_action_is_last_entry(action, act)) {
93 		NL_SET_ERR_MSG_MOD(extack,
94 				   "Offload not supported when conform action is ok, but action is not last");
95 		return -EOPNOTSUPP;
96 	}
97 
98 	if (act->police.peakrate_bytes_ps ||
99 	    act->police.avrate || act->police.overhead) {
100 		NL_SET_ERR_MSG_MOD(extack,
101 				   "Offload not supported when peakrate/avrate/overhead is configured");
102 		return -EOPNOTSUPP;
103 	}
104 
105 	if (act->police.rate_pkt_ps) {
106 		NL_SET_ERR_MSG_MOD(extack,
107 				   "QoS offload not support packets per second");
108 		return -EOPNOTSUPP;
109 	}
110 
111 	if (!ingress) {
112 		NL_SET_ERR_MSG_MOD(extack,
113 				   "Policer is not supported on egress");
114 		return -EOPNOTSUPP;
115 	}
116 
117 	if (port->tc.ingress_shared_block) {
118 		NL_SET_ERR_MSG_MOD(extack,
119 				   "Policer is not supported on shared ingress blocks");
120 		return -EOPNOTSUPP;
121 	}
122 
123 	if (port->tc.police_id && port->tc.police_id != police_id) {
124 		NL_SET_ERR_MSG_MOD(extack,
125 				   "Only one policer per port is supported");
126 		return -EEXIST;
127 	}
128 
129 	return 0;
130 }
131 
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)132 int lan966x_police_port_add(struct lan966x_port *port,
133 			    struct flow_action *action,
134 			    struct flow_action_entry *act,
135 			    unsigned long police_id,
136 			    bool ingress,
137 			    struct netlink_ext_ack *extack)
138 {
139 	struct lan966x *lan966x = port->lan966x;
140 	struct rtnl_link_stats64 new_stats;
141 	struct lan966x_tc_policer pol;
142 	struct flow_stats *old_stats;
143 	int err;
144 
145 	err = lan966x_police_validate(port, action, act, police_id, ingress,
146 				      extack);
147 	if (err)
148 		return err;
149 
150 	memset(&pol, 0, sizeof(pol));
151 
152 	pol.rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
153 	pol.burst = act->police.burst;
154 
155 	err = lan966x_police_add(port, &pol, POL_IDX_PORT + port->chip_port);
156 	if (err) {
157 		NL_SET_ERR_MSG_MOD(extack,
158 				   "Failed to add policer to port");
159 		return err;
160 	}
161 
162 	lan_rmw(ANA_POL_CFG_PORT_POL_ENA_SET(1) |
163 		ANA_POL_CFG_POL_ORDER_SET(POL_ORDER),
164 		ANA_POL_CFG_PORT_POL_ENA |
165 		ANA_POL_CFG_POL_ORDER,
166 		lan966x, ANA_POL_CFG(port->chip_port));
167 
168 	port->tc.police_id = police_id;
169 
170 	/* Setup initial stats */
171 	old_stats = &port->tc.police_stat;
172 	lan966x_stats_get(port->dev, &new_stats);
173 	old_stats->bytes = new_stats.rx_bytes;
174 	old_stats->pkts = new_stats.rx_packets;
175 	old_stats->drops = new_stats.rx_dropped;
176 	old_stats->lastused = jiffies;
177 
178 	return 0;
179 }
180 
lan966x_police_port_del(struct lan966x_port * port,unsigned long police_id,struct netlink_ext_ack * extack)181 int lan966x_police_port_del(struct lan966x_port *port,
182 			    unsigned long police_id,
183 			    struct netlink_ext_ack *extack)
184 {
185 	struct lan966x *lan966x = port->lan966x;
186 
187 	if (port->tc.police_id != police_id) {
188 		NL_SET_ERR_MSG_MOD(extack,
189 				   "Invalid policer id");
190 		return -EINVAL;
191 	}
192 
193 	lan966x_police_del(port, POL_IDX_PORT + port->chip_port);
194 
195 	lan_rmw(ANA_POL_CFG_PORT_POL_ENA_SET(0) |
196 		ANA_POL_CFG_POL_ORDER_SET(POL_ORDER),
197 		ANA_POL_CFG_PORT_POL_ENA |
198 		ANA_POL_CFG_POL_ORDER,
199 		lan966x, ANA_POL_CFG(port->chip_port));
200 
201 	port->tc.police_id = 0;
202 
203 	return 0;
204 }
205 
lan966x_police_port_stats(struct lan966x_port * port,struct flow_stats * stats)206 void lan966x_police_port_stats(struct lan966x_port *port,
207 			       struct flow_stats *stats)
208 {
209 	struct rtnl_link_stats64 new_stats;
210 	struct flow_stats *old_stats;
211 
212 	old_stats = &port->tc.police_stat;
213 	lan966x_stats_get(port->dev, &new_stats);
214 
215 	flow_stats_update(stats,
216 			  new_stats.rx_bytes - old_stats->bytes,
217 			  new_stats.rx_packets - old_stats->pkts,
218 			  new_stats.rx_dropped - old_stats->drops,
219 			  old_stats->lastused,
220 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
221 
222 	old_stats->bytes = new_stats.rx_bytes;
223 	old_stats->pkts = new_stats.rx_packets;
224 	old_stats->drops = new_stats.rx_dropped;
225 	old_stats->lastused = jiffies;
226 }
227