diff options
author | Navdeep Parhar <np@FreeBSD.org> | 2018-05-31 21:56:57 +0000 |
---|---|---|
committer | Navdeep Parhar <np@FreeBSD.org> | 2018-05-31 21:56:57 +0000 |
commit | 2c87bdc7065bd3000ff66dcb56be8712ec7020bb (patch) | |
tree | 6dd261f0a2a415474a59409aaeb9d44e4a417020 /sys/dev | |
parent | a6bc59f203405b00f03cb62d079fded00996f4e0 (diff) | |
download | src-2c87bdc7065bd3000ff66dcb56be8712ec7020bb.tar.gz src-2c87bdc7065bd3000ff66dcb56be8712ec7020bb.zip |
cxgbe(4): Add support for SMAC-rewriting filters.
Submitted by: Krishnamraju Eraparaju @ Chelsio
Sponsored by: Chelsio Communications
Notes
Notes:
svn path=/head/; revision=334452
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/cxgbe/t4_filter.c | 143 |
1 files changed, 90 insertions, 53 deletions
diff --git a/sys/dev/cxgbe/t4_filter.c b/sys/dev/cxgbe/t4_filter.c index 6b259290b4ce..efd487a2b3de 100644 --- a/sys/dev/cxgbe/t4_filter.c +++ b/sys/dev/cxgbe/t4_filter.c @@ -50,14 +50,15 @@ __FBSDID("$FreeBSD$"); #include "common/t4_regs_values.h" #include "common/t4_tcb.h" #include "t4_l2t.h" +#include "t4_smt.h" struct filter_entry { uint32_t valid:1; /* filter allocated and valid */ uint32_t locked:1; /* filter is administratively locked or busy */ uint32_t pending:1; /* filter action is pending firmware reply */ - uint32_t smtidx:8; /* Source MAC Table index for smac */ int tid; /* tid of the filter TCB */ struct l2t_entry *l2te; /* L2 table entry for DMAC rewrite */ + struct smt_entry *smt; /* SMT entry for SMAC rewrite */ struct t4_filter_specification fs; }; @@ -65,7 +66,7 @@ struct filter_entry { static void free_filter_resources(struct filter_entry *); static int get_hashfilter(struct adapter *, struct t4_filter *); static int set_hashfilter(struct adapter *, struct t4_filter *, uint64_t, - struct l2t_entry *); + struct l2t_entry *, struct smt_entry *); static int del_hashfilter(struct adapter *, struct t4_filter *); static int configure_hashfilter_tcb(struct adapter *, struct filter_entry *); @@ -321,7 +322,7 @@ get_filter(struct adapter *sc, struct t4_filter *t) MPASS(f->tid == sc->tids.ftid_base + i); t->idx = i; t->l2tidx = f->l2te ? f->l2te->idx : 0; - t->smtidx = f->smtidx; + t->smtidx = f->smt ? f->smt->idx : 0; if (f->fs.hitcnts) t->hits = get_filter_hits(sc, f->tid); else @@ -338,7 +339,8 @@ done: } static int -set_tcamfilter(struct adapter *sc, struct t4_filter *t, struct l2t_entry *l2te) +set_tcamfilter(struct adapter *sc, struct t4_filter *t, struct l2t_entry *l2te, + struct smt_entry *smt) { struct filter_entry *f; struct fw_filter2_wr *fwr; @@ -383,6 +385,8 @@ set_tcamfilter(struct adapter *sc, struct t4_filter *t, struct l2t_entry *l2te) if (rc != 0) { if (l2te) t4_l2t_release(l2te); + if (smt) + t4_smt_release(smt); return (rc); } @@ -393,6 +397,7 @@ set_tcamfilter(struct adapter *sc, struct t4_filter *t, struct l2t_entry *l2te) f->tid = sc->tids.ftid_base + t->idx; f->fs = t->fs; f->l2te = l2te; + f->smt = smt; if (t->fs.val.pfvf_vld || t->fs.val.ovlan_vld) vnic_vld = 1; @@ -468,10 +473,8 @@ set_tcamfilter(struct adapter *sc, struct t4_filter *t, struct l2t_entry *l2te) fwr->lpm = htobe16(f->fs.mask.dport); fwr->fp = htobe16(f->fs.val.sport); fwr->fpm = htobe16(f->fs.mask.sport); - if (f->fs.newsmac) { - /* XXX: need to use SMT idx instead */ - bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); - } + /* sma = 0 tells the fw to use SMAC_SEL for source MAC address */ + bzero(fwr->sma, sizeof (fwr->sma)); if (sc->params.filter2_wr_support) { fwr->filter_type_swapmac = V_FW_FILTER2_WR_SWAPMAC(f->fs.swapmac); @@ -585,6 +588,7 @@ set_filter(struct adapter *sc, struct t4_filter *t) { struct tid_info *ti = &sc->tids; struct l2t_entry *l2te; + struct smt_entry *smt; uint64_t ftuple; int rc; @@ -690,22 +694,36 @@ done: l2te = t4_l2t_alloc_switching(sc->l2t); if (__predict_false(l2te == NULL)) return (EAGAIN); - if (t4_l2t_set_switching(sc, l2te, t->fs.vlan, t->fs.eport, - t->fs.dmac)) { + rc = t4_l2t_set_switching(sc, l2te, t->fs.vlan, t->fs.eport, + t->fs.dmac); + if (rc) { t4_l2t_release(l2te); return (ENOMEM); } } + smt = NULL; if (t->fs.newsmac) { - /* XXX: alloc SMT */ - return (ENOTSUP); + /* This filter needs an SMT entry; allocate one. */ + smt = t4_smt_alloc_switching(sc->smt, t->fs.smac); + if (__predict_false(smt == NULL)) { + if (l2te != NULL) + t4_l2t_release(l2te); + return (EAGAIN); + } + rc = t4_smt_set_switching(sc, smt, 0x0, t->fs.smac); + if (rc) { + t4_smt_release(smt); + if (l2te != NULL) + t4_l2t_release(l2te); + return (rc); + } } if (t->fs.hash) - return (set_hashfilter(sc, t, ftuple, l2te)); + return (set_hashfilter(sc, t, ftuple, l2te, smt)); else - return (set_tcamfilter(sc, t, l2te)); + return (set_tcamfilter(sc, t, l2te, smt)); } @@ -799,6 +817,45 @@ free_filter_resources(struct filter_entry *f) t4_l2t_release(f->l2te); f->l2te = NULL; } + if (f->smt) { + t4_smt_release(f->smt); + f->smt = NULL; + } +} + +static int +set_tcb_field(struct adapter *sc, u_int tid, uint16_t word, uint64_t mask, + uint64_t val, int no_reply) +{ + struct wrq_cookie cookie; + struct cpl_set_tcb_field *req; + + req = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*req), 16), &cookie); + if (req == NULL) + return (ENOMEM); + bzero(req, sizeof(*req)); + INIT_TP_WR_MIT_CPL(req, CPL_SET_TCB_FIELD, tid); + if (no_reply == 0) { + req->reply_ctrl = htobe16(V_QUEUENO(sc->sge.fwq.abs_id) | + V_NO_REPLY(0)); + } else + req->reply_ctrl = htobe16(V_NO_REPLY(1)); + req->word_cookie = htobe16(V_WORD(word) | V_COOKIE(CPL_COOKIE_HASHFILTER)); + req->mask = htobe64(mask); + req->val = htobe64(val); + commit_wrq_wr(&sc->sge.mgmtq, req, &cookie); + + return (0); +} + +/* Set one of the t_flags bits in the TCB. */ +static inline int +set_tcb_tflag(struct adapter *sc, int tid, u_int bit_pos, u_int val, + u_int no_reply) +{ + + return (set_tcb_field(sc, tid, W_TCB_T_FLAGS, 1ULL << bit_pos, + (uint64_t)val << bit_pos, no_reply)); } int @@ -826,7 +883,14 @@ t4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) case FW_FILTER_WR_FLT_ADDED: /* set-filter succeeded */ f->valid = 1; - f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; + if (f->fs.newsmac) { + MPASS(f->smt != NULL); + set_tcb_tflag(sc, f->tid, S_TF_CCTRL_CWR, 1, 1); + set_tcb_field(sc, f->tid, W_TCB_SMAC_SEL, + V_TCB_SMAC_SEL(M_TCB_SMAC_SEL), + V_TCB_SMAC_SEL(f->smt->idx), 1); + /* XXX: wait for reply to TCB update before !pending */ + } break; case FW_FILTER_WR_FLT_DELETED: /* del-filter succeeded */ @@ -995,7 +1059,7 @@ get_hashfilter(struct adapter *sc, struct t4_filter *t) if (f != NULL && f->valid) { t->idx = i; t->l2tidx = f->l2te ? f->l2te->idx : 0; - t->smtidx = f->smtidx; + t->smtidx = f->smt ? f->smt->idx : 0; if (f->fs.hitcnts) t->hits = get_filter_hits(sc, t->idx); else @@ -1126,7 +1190,7 @@ act_open_cpl_len16(struct adapter *sc, int isipv6) static int set_hashfilter(struct adapter *sc, struct t4_filter *t, uint64_t ftuple, - struct l2t_entry *l2te) + struct l2t_entry *l2te, struct smt_entry *smt) { void *wr; struct wrq_cookie cookie; @@ -1150,16 +1214,21 @@ set_hashfilter(struct adapter *sc, struct t4_filter *t, uint64_t ftuple, if (__predict_false(f == NULL)) { if (l2te) t4_l2t_release(l2te); + if (smt) + t4_smt_release(smt); rc = ENOMEM; goto done; } f->fs = t->fs; f->l2te = l2te; + f->smt = smt; atid = alloc_atid(sc, f); if (__predict_false(atid) == -1) { if (l2te) t4_l2t_release(l2te); + if (smt) + t4_smt_release(smt); free(f, M_CXGBE); rc = EAGAIN; goto done; @@ -1172,6 +1241,8 @@ set_hashfilter(struct adapter *sc, struct t4_filter *t, uint64_t ftuple, free_atid(sc, atid); if (l2te) t4_l2t_release(l2te); + if (smt) + t4_smt_release(smt); free(f, M_CXGBE); rc = ENOMEM; goto done; @@ -1396,41 +1467,6 @@ done: return (rc); } -static int -set_tcb_field(struct adapter *sc, u_int tid, uint16_t word, uint64_t mask, - uint64_t val, int no_reply) -{ - struct wrq_cookie cookie; - struct cpl_set_tcb_field *req; - - req = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*req), 16), &cookie); - if (req == NULL) - return (ENOMEM); - bzero(req, sizeof(*req)); - INIT_TP_WR_MIT_CPL(req, CPL_SET_TCB_FIELD, tid); - if (no_reply == 0) { - req->reply_ctrl = htobe16(V_QUEUENO(sc->sge.fwq.abs_id) | - V_NO_REPLY(0)); - } else - req->reply_ctrl = htobe16(V_NO_REPLY(1)); - req->word_cookie = htobe16(V_WORD(word) | V_COOKIE(CPL_COOKIE_HASHFILTER)); - req->mask = htobe64(mask); - req->val = htobe64(val); - commit_wrq_wr(&sc->sge.mgmtq, req, &cookie); - - return (0); -} - -/* Set one of the t_flags bits in the TCB. */ -static inline int -set_tcb_tflag(struct adapter *sc, int tid, u_int bit_pos, u_int val, - u_int no_reply) -{ - - return (set_tcb_field(sc, tid, W_TCB_T_FLAGS, 1ULL << bit_pos, - (uint64_t)val << bit_pos, no_reply)); -} - #define WORD_MASK 0xffffffff static void set_nat_params(struct adapter *sc, struct filter_entry *f, const bool dip, @@ -1525,9 +1561,10 @@ configure_hashfilter_tcb(struct adapter *sc, struct filter_entry *f) } if (f->fs.newsmac) { + MPASS(f->smt != NULL); set_tcb_tflag(sc, f->tid, S_TF_CCTRL_CWR, 1, 1); set_tcb_field(sc, f->tid, W_TCB_SMAC_SEL, - V_TCB_SMAC_SEL(M_TCB_SMAC_SEL), V_TCB_SMAC_SEL(f->smtidx), + V_TCB_SMAC_SEL(M_TCB_SMAC_SEL), V_TCB_SMAC_SEL(f->smt->idx), 1); updated++; } |