3434
3535#include "cxgb4.h"
3636#include "t4_regs.h"
37+ #include "t4_tcb.h"
3738#include "l2t.h"
39+ #include "smt.h"
3840#include "t4fw_api.h"
3941#include "cxgb4_filter.h"
4042
@@ -311,7 +313,7 @@ static int del_filter_wr(struct adapter *adapter, int fidx)
311313int set_filter_wr (struct adapter * adapter , int fidx )
312314{
313315 struct filter_entry * f = & adapter -> tids .ftid_tab [fidx ];
314- struct fw_filter_wr * fwr ;
316+ struct fw_filter2_wr * fwr ;
315317 struct sk_buff * skb ;
316318
317319 skb = alloc_skb (sizeof (* fwr ), GFP_KERNEL );
@@ -332,6 +334,21 @@ int set_filter_wr(struct adapter *adapter, int fidx)
332334 }
333335 }
334336
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+
335352 fwr = __skb_put_zero (skb , sizeof (* fwr ));
336353
337354 /* 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)
342359 * filter specification structure but for now it's easiest to simply
343360 * put this fairly direct code in line ...
344361 */
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 ));
346366 fwr -> len16_pkd = htonl (FW_WR_LEN16_V (sizeof (* fwr ) / 16 ));
347367 fwr -> tid_to_iq =
348368 htonl (FW_FILTER_WR_TID_V (f -> tid ) |
@@ -357,7 +377,6 @@ int set_filter_wr(struct adapter *adapter, int fidx)
357377 FW_FILTER_WR_DIRSTEERHASH_V (f -> fs .dirsteerhash ) |
358378 FW_FILTER_WR_LPBK_V (f -> fs .action == FILTER_SWITCH ) |
359379 FW_FILTER_WR_DMAC_V (f -> fs .newdmac ) |
360- FW_FILTER_WR_SMAC_V (f -> fs .newsmac ) |
361380 FW_FILTER_WR_INSVLAN_V (f -> fs .newvlan == VLAN_INSERT ||
362381 f -> fs .newvlan == VLAN_REWRITE ) |
363382 FW_FILTER_WR_RMVLAN_V (f -> fs .newvlan == VLAN_REMOVE ||
@@ -404,8 +423,18 @@ int set_filter_wr(struct adapter *adapter, int fidx)
404423 fwr -> lpm = htons (f -> fs .mask .lport );
405424 fwr -> fp = htons (f -> fs .val .fport );
406425 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+ }
409438
410439 /* Mark the filter as "pending" and ship off the Filter Work Request.
411440 * 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)
463492 if (f -> l2t )
464493 cxgb4_l2t_release (f -> l2t );
465494
495+ if (f -> smt )
496+ cxgb4_smt_release (f -> smt );
497+
466498 /* The zeroing of the filter rule below clears the filter valid,
467499 * pending, locked flags, l2t pointer, etc. so it's all we need for
468500 * this operation.
@@ -757,6 +789,62 @@ int cxgb4_del_filter(struct net_device *dev, int filter_id)
757789 return ret ;
758790}
759791
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+
760848/* Handle a filter write/deletion reply. */
761849void filter_rpl (struct adapter * adap , const struct cpl_set_tcb_rpl * rpl )
762850{
@@ -795,19 +883,23 @@ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
795883 clear_filter (adap , f );
796884 if (ctx )
797885 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 ;
804886 } 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 ;
811903 }
812904 } else {
813905 /* Something went wrong. Issue a warning about the
0 commit comments