34
34
35
35
#include "cxgb4.h"
36
36
#include "t4_regs.h"
37
+ #include "t4_tcb.h"
37
38
#include "l2t.h"
39
+ #include "smt.h"
38
40
#include "t4fw_api.h"
39
41
#include "cxgb4_filter.h"
40
42
@@ -311,7 +313,7 @@ static int del_filter_wr(struct adapter *adapter, int fidx)
311
313
int set_filter_wr (struct adapter * adapter , int fidx )
312
314
{
313
315
struct filter_entry * f = & adapter -> tids .ftid_tab [fidx ];
314
- struct fw_filter_wr * fwr ;
316
+ struct fw_filter2_wr * fwr ;
315
317
struct sk_buff * skb ;
316
318
317
319
skb = alloc_skb (sizeof (* fwr ), GFP_KERNEL );
@@ -332,6 +334,21 @@ int set_filter_wr(struct adapter *adapter, int fidx)
332
334
}
333
335
}
334
336
337
+ /* If the new filter requires loopback Source MAC rewriting then
338
+ * we need to allocate a SMT entry for the filter.
339
+ */
340
+ if (f -> fs .newsmac ) {
341
+ f -> smt = cxgb4_smt_alloc_switching (f -> dev , f -> fs .smac );
342
+ if (!f -> smt ) {
343
+ if (f -> l2t ) {
344
+ cxgb4_l2t_release (f -> l2t );
345
+ f -> l2t = NULL ;
346
+ }
347
+ kfree_skb (skb );
348
+ return - ENOMEM ;
349
+ }
350
+ }
351
+
335
352
fwr = __skb_put_zero (skb , sizeof (* fwr ));
336
353
337
354
/* It would be nice to put most of the following in t4_hw.c but most
@@ -342,7 +359,10 @@ int set_filter_wr(struct adapter *adapter, int fidx)
342
359
* filter specification structure but for now it's easiest to simply
343
360
* put this fairly direct code in line ...
344
361
*/
345
- fwr -> op_pkd = htonl (FW_WR_OP_V (FW_FILTER_WR ));
362
+ if (adapter -> params .filter2_wr_support )
363
+ fwr -> op_pkd = htonl (FW_WR_OP_V (FW_FILTER2_WR ));
364
+ else
365
+ fwr -> op_pkd = htonl (FW_WR_OP_V (FW_FILTER_WR ));
346
366
fwr -> len16_pkd = htonl (FW_WR_LEN16_V (sizeof (* fwr ) / 16 ));
347
367
fwr -> tid_to_iq =
348
368
htonl (FW_FILTER_WR_TID_V (f -> tid ) |
@@ -357,7 +377,6 @@ int set_filter_wr(struct adapter *adapter, int fidx)
357
377
FW_FILTER_WR_DIRSTEERHASH_V (f -> fs .dirsteerhash ) |
358
378
FW_FILTER_WR_LPBK_V (f -> fs .action == FILTER_SWITCH ) |
359
379
FW_FILTER_WR_DMAC_V (f -> fs .newdmac ) |
360
- FW_FILTER_WR_SMAC_V (f -> fs .newsmac ) |
361
380
FW_FILTER_WR_INSVLAN_V (f -> fs .newvlan == VLAN_INSERT ||
362
381
f -> fs .newvlan == VLAN_REWRITE ) |
363
382
FW_FILTER_WR_RMVLAN_V (f -> fs .newvlan == VLAN_REMOVE ||
@@ -404,8 +423,18 @@ int set_filter_wr(struct adapter *adapter, int fidx)
404
423
fwr -> lpm = htons (f -> fs .mask .lport );
405
424
fwr -> fp = htons (f -> fs .val .fport );
406
425
fwr -> fpm = htons (f -> fs .mask .fport );
407
- if (f -> fs .newsmac )
408
- memcpy (fwr -> sma , f -> fs .smac , sizeof (fwr -> sma ));
426
+
427
+ if (adapter -> params .filter2_wr_support ) {
428
+ fwr -> natmode_to_ulp_type =
429
+ FW_FILTER2_WR_ULP_TYPE_V (f -> fs .nat_mode ?
430
+ ULP_MODE_TCPDDP :
431
+ ULP_MODE_NONE ) |
432
+ FW_FILTER2_WR_NATMODE_V (f -> fs .nat_mode );
433
+ memcpy (fwr -> newlip , f -> fs .nat_lip , sizeof (fwr -> newlip ));
434
+ memcpy (fwr -> newfip , f -> fs .nat_fip , sizeof (fwr -> newfip ));
435
+ fwr -> newlport = htons (f -> fs .nat_lport );
436
+ fwr -> newfport = htons (f -> fs .nat_fport );
437
+ }
409
438
410
439
/* Mark the filter as "pending" and ship off the Filter Work Request.
411
440
* When we get the Work Request Reply we'll clear the pending status.
@@ -463,6 +492,9 @@ void clear_filter(struct adapter *adap, struct filter_entry *f)
463
492
if (f -> l2t )
464
493
cxgb4_l2t_release (f -> l2t );
465
494
495
+ if (f -> smt )
496
+ cxgb4_smt_release (f -> smt );
497
+
466
498
/* The zeroing of the filter rule below clears the filter valid,
467
499
* pending, locked flags, l2t pointer, etc. so it's all we need for
468
500
* this operation.
@@ -757,6 +789,62 @@ int cxgb4_del_filter(struct net_device *dev, int filter_id)
757
789
return ret ;
758
790
}
759
791
792
+ static int set_tcb_field (struct adapter * adap , struct filter_entry * f ,
793
+ unsigned int ftid , u16 word , u64 mask , u64 val ,
794
+ int no_reply )
795
+ {
796
+ struct cpl_set_tcb_field * req ;
797
+ struct sk_buff * skb ;
798
+
799
+ skb = alloc_skb (sizeof (struct cpl_set_tcb_field ), GFP_ATOMIC );
800
+ if (!skb )
801
+ return - ENOMEM ;
802
+
803
+ req = (struct cpl_set_tcb_field * )__skb_put (skb , sizeof (* req ));
804
+ memset (req , 0 , sizeof (* req ));
805
+ INIT_TP_WR_CPL (req , CPL_SET_TCB_FIELD , ftid );
806
+ req -> reply_ctrl = htons (REPLY_CHAN_V (0 ) |
807
+ QUEUENO_V (adap -> sge .fw_evtq .abs_id ) |
808
+ NO_REPLY_V (no_reply ));
809
+ req -> word_cookie = htons (TCB_WORD_V (word ) | TCB_COOKIE_V (ftid ));
810
+ req -> mask = cpu_to_be64 (mask );
811
+ req -> val = cpu_to_be64 (val );
812
+ set_wr_txq (skb , CPL_PRIORITY_CONTROL , f -> fs .val .iport & 0x3 );
813
+ t4_ofld_send (adap , skb );
814
+ return 0 ;
815
+ }
816
+
817
+ /* Set one of the t_flags bits in the TCB.
818
+ */
819
+ static int set_tcb_tflag (struct adapter * adap , struct filter_entry * f ,
820
+ unsigned int ftid , unsigned int bit_pos ,
821
+ unsigned int val , int no_reply )
822
+ {
823
+ return set_tcb_field (adap , f , ftid , TCB_T_FLAGS_W , 1ULL << bit_pos ,
824
+ (unsigned long long )val << bit_pos , no_reply );
825
+ }
826
+
827
+ static int configure_filter_smac (struct adapter * adap , struct filter_entry * f )
828
+ {
829
+ int err ;
830
+
831
+ /* do a set-tcb for smac-sel and CWR bit.. */
832
+ err = set_tcb_tflag (adap , f , f -> tid , TF_CCTRL_CWR_S , 1 , 1 );
833
+ if (err )
834
+ goto smac_err ;
835
+
836
+ err = set_tcb_field (adap , f , f -> tid , TCB_SMAC_SEL_W ,
837
+ TCB_SMAC_SEL_V (TCB_SMAC_SEL_M ),
838
+ TCB_SMAC_SEL_V (f -> smt -> idx ), 1 );
839
+ if (!err )
840
+ return 0 ;
841
+
842
+ smac_err :
843
+ dev_err (adap -> pdev_dev , "filter %u smac config failed with error %u\n" ,
844
+ f -> tid , err );
845
+ return err ;
846
+ }
847
+
760
848
/* Handle a filter write/deletion reply. */
761
849
void filter_rpl (struct adapter * adap , const struct cpl_set_tcb_rpl * rpl )
762
850
{
@@ -795,19 +883,23 @@ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
795
883
clear_filter (adap , f );
796
884
if (ctx )
797
885
ctx -> result = 0 ;
798
- } else if (ret == FW_FILTER_WR_SMT_TBL_FULL ) {
799
- dev_err (adap -> pdev_dev , "filter %u setup failed due to full SMT\n" ,
800
- idx );
801
- clear_filter (adap , f );
802
- if (ctx )
803
- ctx -> result = - ENOMEM ;
804
886
} else if (ret == FW_FILTER_WR_FLT_ADDED ) {
805
- f -> smtidx = (be64_to_cpu (rpl -> oldval ) >> 24 ) & 0xff ;
806
- f -> pending = 0 ; /* asynchronous setup completed */
807
- f -> valid = 1 ;
808
- if (ctx ) {
809
- ctx -> result = 0 ;
810
- ctx -> tid = idx ;
887
+ int err = 0 ;
888
+
889
+ if (f -> fs .newsmac )
890
+ err = configure_filter_smac (adap , f );
891
+
892
+ if (!err ) {
893
+ f -> pending = 0 ; /* async setup completed */
894
+ f -> valid = 1 ;
895
+ if (ctx ) {
896
+ ctx -> result = 0 ;
897
+ ctx -> tid = idx ;
898
+ }
899
+ } else {
900
+ clear_filter (adap , f );
901
+ if (ctx )
902
+ ctx -> result = err ;
811
903
}
812
904
} else {
813
905
/* Something went wrong. Issue a warning about the
0 commit comments