@@ -85,11 +85,46 @@ aq_rule_already_exists(struct aq_nic_s *aq_nic,
85
85
return false;
86
86
}
87
87
88
+ static int aq_check_approve_fl3l4 (struct aq_nic_s * aq_nic ,
89
+ struct aq_hw_rx_fltrs_s * rx_fltrs ,
90
+ struct ethtool_rx_flow_spec * fsp )
91
+ {
92
+ if (fsp -> location < AQ_RX_FIRST_LOC_FL3L4 ||
93
+ fsp -> location > AQ_RX_LAST_LOC_FL3L4 ) {
94
+ netdev_err (aq_nic -> ndev ,
95
+ "ethtool: location must be in range [%d, %d]" ,
96
+ AQ_RX_FIRST_LOC_FL3L4 ,
97
+ AQ_RX_LAST_LOC_FL3L4 );
98
+ return - EINVAL ;
99
+ }
100
+ if (rx_fltrs -> fl3l4 .is_ipv6 && rx_fltrs -> fl3l4 .active_ipv4 ) {
101
+ rx_fltrs -> fl3l4 .is_ipv6 = false;
102
+ netdev_err (aq_nic -> ndev ,
103
+ "ethtool: mixing ipv4 and ipv6 is not allowed" );
104
+ return - EINVAL ;
105
+ } else if (!rx_fltrs -> fl3l4 .is_ipv6 && rx_fltrs -> fl3l4 .active_ipv6 ) {
106
+ rx_fltrs -> fl3l4 .is_ipv6 = true;
107
+ netdev_err (aq_nic -> ndev ,
108
+ "ethtool: mixing ipv4 and ipv6 is not allowed" );
109
+ return - EINVAL ;
110
+ } else if (rx_fltrs -> fl3l4 .is_ipv6 &&
111
+ fsp -> location != AQ_RX_FIRST_LOC_FL3L4 + 4 &&
112
+ fsp -> location != AQ_RX_FIRST_LOC_FL3L4 ) {
113
+ netdev_err (aq_nic -> ndev ,
114
+ "ethtool: The specified location for ipv6 must be %d or %d" ,
115
+ AQ_RX_FIRST_LOC_FL3L4 , AQ_RX_FIRST_LOC_FL3L4 + 4 );
116
+ return - EINVAL ;
117
+ }
118
+
119
+ return 0 ;
120
+ }
121
+
88
122
static int __must_check
89
123
aq_check_filter (struct aq_nic_s * aq_nic ,
90
124
struct ethtool_rx_flow_spec * fsp )
91
125
{
92
126
int err = 0 ;
127
+ struct aq_hw_rx_fltrs_s * rx_fltrs = aq_get_hw_rx_fltrs (aq_nic );
93
128
94
129
if (fsp -> flow_type & FLOW_EXT ) {
95
130
err = - EOPNOTSUPP ;
@@ -103,14 +138,16 @@ aq_check_filter(struct aq_nic_s *aq_nic,
103
138
case SCTP_V4_FLOW :
104
139
case IPV4_FLOW :
105
140
case IP_USER_FLOW :
106
- err = - EOPNOTSUPP ;
141
+ rx_fltrs -> fl3l4 .is_ipv6 = false;
142
+ err = aq_check_approve_fl3l4 (aq_nic , rx_fltrs , fsp );
107
143
break ;
108
144
case TCP_V6_FLOW :
109
145
case UDP_V6_FLOW :
110
146
case SCTP_V6_FLOW :
111
147
case IPV6_FLOW :
112
148
case IPV6_USER_FLOW :
113
- err = - EOPNOTSUPP ;
149
+ rx_fltrs -> fl3l4 .is_ipv6 = true;
150
+ err = aq_check_approve_fl3l4 (aq_nic , rx_fltrs , fsp );
114
151
break ;
115
152
default :
116
153
netdev_err (aq_nic -> ndev ,
@@ -156,6 +193,11 @@ aq_rule_is_not_correct(struct aq_nic_s *aq_nic,
156
193
157
194
if (!aq_nic ) {
158
195
rule_is_not_correct = true;
196
+ } else if (fsp -> location > AQ_RX_MAX_RXNFC_LOC ) {
197
+ netdev_err (aq_nic -> ndev ,
198
+ "ethtool: The specified number %u rule is invalid\n" ,
199
+ fsp -> location );
200
+ rule_is_not_correct = true;
159
201
} else if (aq_check_filter (aq_nic , fsp )) {
160
202
rule_is_not_correct = true;
161
203
} else if (fsp -> ring_cookie != RX_CLS_FLOW_DISC ) {
@@ -187,6 +229,125 @@ aq_check_rule(struct aq_nic_s *aq_nic,
187
229
return err ;
188
230
}
189
231
232
+ static int aq_set_data_fl3l4 (struct aq_nic_s * aq_nic ,
233
+ struct aq_rx_filter * aq_rx_fltr ,
234
+ struct aq_rx_filter_l3l4 * data , bool add )
235
+ {
236
+ struct aq_hw_rx_fltrs_s * rx_fltrs = aq_get_hw_rx_fltrs (aq_nic );
237
+ const struct ethtool_rx_flow_spec * fsp = & aq_rx_fltr -> aq_fsp ;
238
+
239
+ memset (data , 0 , sizeof (* data ));
240
+
241
+ data -> is_ipv6 = rx_fltrs -> fl3l4 .is_ipv6 ;
242
+ data -> location = HW_ATL_GET_REG_LOCATION_FL3L4 (fsp -> location );
243
+
244
+ if (!add ) {
245
+ if (!data -> is_ipv6 )
246
+ rx_fltrs -> fl3l4 .active_ipv4 &= ~BIT (data -> location );
247
+ else
248
+ rx_fltrs -> fl3l4 .active_ipv6 &=
249
+ ~BIT ((data -> location ) / 4 );
250
+
251
+ return 0 ;
252
+ }
253
+
254
+ data -> cmd |= HW_ATL_RX_ENABLE_FLTR_L3L4 ;
255
+
256
+ switch (fsp -> flow_type ) {
257
+ case TCP_V4_FLOW :
258
+ case TCP_V6_FLOW :
259
+ data -> cmd |= HW_ATL_RX_ENABLE_CMP_PROT_L4 ;
260
+ break ;
261
+ case UDP_V4_FLOW :
262
+ case UDP_V6_FLOW :
263
+ data -> cmd |= HW_ATL_RX_UDP ;
264
+ data -> cmd |= HW_ATL_RX_ENABLE_CMP_PROT_L4 ;
265
+ break ;
266
+ case SCTP_V4_FLOW :
267
+ case SCTP_V6_FLOW :
268
+ data -> cmd |= HW_ATL_RX_SCTP ;
269
+ data -> cmd |= HW_ATL_RX_ENABLE_CMP_PROT_L4 ;
270
+ break ;
271
+ default :
272
+ break ;
273
+ }
274
+
275
+ if (!data -> is_ipv6 ) {
276
+ data -> ip_src [0 ] =
277
+ ntohl (fsp -> h_u .tcp_ip4_spec .ip4src );
278
+ data -> ip_dst [0 ] =
279
+ ntohl (fsp -> h_u .tcp_ip4_spec .ip4dst );
280
+ rx_fltrs -> fl3l4 .active_ipv4 |= BIT (data -> location );
281
+ } else {
282
+ int i ;
283
+
284
+ rx_fltrs -> fl3l4 .active_ipv6 |= BIT ((data -> location ) / 4 );
285
+ for (i = 0 ; i < HW_ATL_RX_CNT_REG_ADDR_IPV6 ; ++ i ) {
286
+ data -> ip_dst [i ] =
287
+ ntohl (fsp -> h_u .tcp_ip6_spec .ip6dst [i ]);
288
+ data -> ip_src [i ] =
289
+ ntohl (fsp -> h_u .tcp_ip6_spec .ip6src [i ]);
290
+ }
291
+ data -> cmd |= HW_ATL_RX_ENABLE_L3_IPV6 ;
292
+ }
293
+ if (fsp -> flow_type != IP_USER_FLOW &&
294
+ fsp -> flow_type != IPV6_USER_FLOW ) {
295
+ if (!data -> is_ipv6 ) {
296
+ data -> p_dst =
297
+ ntohs (fsp -> h_u .tcp_ip4_spec .pdst );
298
+ data -> p_src =
299
+ ntohs (fsp -> h_u .tcp_ip4_spec .psrc );
300
+ } else {
301
+ data -> p_dst =
302
+ ntohs (fsp -> h_u .tcp_ip6_spec .pdst );
303
+ data -> p_src =
304
+ ntohs (fsp -> h_u .tcp_ip6_spec .psrc );
305
+ }
306
+ }
307
+ if (data -> ip_src [0 ] && !data -> is_ipv6 )
308
+ data -> cmd |= HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3 ;
309
+ if (data -> ip_dst [0 ] && !data -> is_ipv6 )
310
+ data -> cmd |= HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3 ;
311
+ if (data -> p_dst )
312
+ data -> cmd |= HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 ;
313
+ if (data -> p_src )
314
+ data -> cmd |= HW_ATL_RX_ENABLE_CMP_SRC_PORT_L4 ;
315
+ if (fsp -> ring_cookie != RX_CLS_FLOW_DISC ) {
316
+ data -> cmd |= HW_ATL_RX_HOST << HW_ATL_RX_ACTION_FL3F4_SHIFT ;
317
+ data -> cmd |= fsp -> ring_cookie << HW_ATL_RX_QUEUE_FL3L4_SHIFT ;
318
+ data -> cmd |= HW_ATL_RX_ENABLE_QUEUE_L3L4 ;
319
+ } else {
320
+ data -> cmd |= HW_ATL_RX_DISCARD << HW_ATL_RX_ACTION_FL3F4_SHIFT ;
321
+ }
322
+
323
+ return 0 ;
324
+ }
325
+
326
+ static int aq_set_fl3l4 (struct aq_hw_s * aq_hw ,
327
+ const struct aq_hw_ops * aq_hw_ops ,
328
+ struct aq_rx_filter_l3l4 * data )
329
+ {
330
+ if (unlikely (!aq_hw_ops -> hw_filter_l3l4_set ))
331
+ return - EOPNOTSUPP ;
332
+
333
+ return aq_hw_ops -> hw_filter_l3l4_set (aq_hw , data );
334
+ }
335
+
336
+ static int aq_add_del_fl3l4 (struct aq_nic_s * aq_nic ,
337
+ struct aq_rx_filter * aq_rx_fltr , bool add )
338
+ {
339
+ const struct aq_hw_ops * aq_hw_ops = aq_nic -> aq_hw_ops ;
340
+ struct aq_hw_s * aq_hw = aq_nic -> aq_hw ;
341
+ struct aq_rx_filter_l3l4 data ;
342
+
343
+ if (unlikely (aq_rx_fltr -> aq_fsp .location < AQ_RX_FIRST_LOC_FL3L4 ||
344
+ aq_rx_fltr -> aq_fsp .location > AQ_RX_LAST_LOC_FL3L4 ||
345
+ aq_set_data_fl3l4 (aq_nic , aq_rx_fltr , & data , add )))
346
+ return - EINVAL ;
347
+
348
+ return aq_set_fl3l4 (aq_hw , aq_hw_ops , & data );
349
+ }
350
+
190
351
static int aq_add_del_rule (struct aq_nic_s * aq_nic ,
191
352
struct aq_rx_filter * aq_rx_fltr , bool add )
192
353
{
@@ -207,7 +368,8 @@ static int aq_add_del_rule(struct aq_nic_s *aq_nic,
207
368
case UDP_V6_FLOW :
208
369
case SCTP_V6_FLOW :
209
370
case IPV6_USER_FLOW :
210
- err = - EOPNOTSUPP ;
371
+ aq_rx_fltr -> type = aq_rx_filter_l3l4 ;
372
+ err = aq_add_del_fl3l4 (aq_nic , aq_rx_fltr , add );
211
373
break ;
212
374
default :
213
375
err = - EINVAL ;
0 commit comments