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
11struct lan966x_tc_policer {
12 /* kilobit per second */
13 u32 rate;
14 /* bytes */
15 u32 burst;
16};
17
18static 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
52static 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
71static 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, entry: 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
132int 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(dividend: act->police.rate_bytes_ps, divisor: 1000) * 8;
153 pol.burst = act->police.burst;
154
155 err = lan966x_police_add(port, pol: &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(dev: port->dev, stats: &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
181int 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
206void 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(dev: port->dev, stats: &new_stats);
214
215 flow_stats_update(flow_stats: stats,
216 bytes: new_stats.rx_bytes - old_stats->bytes,
217 pkts: new_stats.rx_packets - old_stats->pkts,
218 drops: new_stats.rx_dropped - old_stats->drops,
219 lastused: old_stats->lastused,
220 used_hw_stats: 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

source code of linux/drivers/net/ethernet/microchip/lan966x/lan966x_police.c