Index: sys/dev/cxgbe/adapter.h =================================================================== --- sys/dev/cxgbe/adapter.h +++ sys/dev/cxgbe/adapter.h @@ -1155,6 +1155,7 @@ int adapter_full_init(struct adapter *); int adapter_full_uninit(struct adapter *); uint64_t cxgbe_get_counter(struct ifnet *, ift_counter); +void cxgbe_snd_tag_init(struct cxgbe_snd_tag *, struct ifnet *, int); int vi_full_init(struct vi_info *); int vi_full_uninit(struct vi_info *); void vi_sysctls(struct vi_info *); @@ -1214,7 +1215,7 @@ void t4_register_shared_cpl_handler(int, cpl_handler_t, int); #ifdef RATELIMIT int ethofld_transmit(struct ifnet *, struct mbuf *); -void send_etid_flush_wr(struct cxgbe_snd_tag *); +void send_etid_flush_wr(struct cxgbe_rate_tag *); #endif /* t4_tracer.c */ @@ -1240,13 +1241,13 @@ #ifdef RATELIMIT void t4_init_etid_table(struct adapter *); void t4_free_etid_table(struct adapter *); -struct cxgbe_snd_tag *lookup_etid(struct adapter *, int); -int cxgbe_snd_tag_alloc(struct ifnet *, union if_snd_tag_alloc_params *, +struct cxgbe_rate_tag *lookup_etid(struct adapter *, int); +int cxgbe_rate_tag_alloc(struct ifnet *, union if_snd_tag_alloc_params *, struct m_snd_tag **); -int cxgbe_snd_tag_modify(struct m_snd_tag *, union if_snd_tag_modify_params *); -int cxgbe_snd_tag_query(struct m_snd_tag *, union if_snd_tag_query_params *); -void cxgbe_snd_tag_free(struct m_snd_tag *); -void cxgbe_snd_tag_free_locked(struct cxgbe_snd_tag *); +int cxgbe_rate_tag_modify(struct m_snd_tag *, union if_snd_tag_modify_params *); +int cxgbe_rate_tag_query(struct m_snd_tag *, union if_snd_tag_query_params *); +void cxgbe_rate_tag_free(struct m_snd_tag *); +void cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag *); void cxgbe_ratelimit_query(struct ifnet *, struct if_ratelimit_query_results *); #endif Index: sys/dev/cxgbe/offload.h =================================================================== --- sys/dev/cxgbe/offload.h +++ sys/dev/cxgbe/offload.h @@ -79,7 +79,7 @@ union aopen_entry *next; }; -/* cxgbe_snd_tag flags */ +/* cxgbe_rate_tag flags */ enum { EO_FLOWC_PENDING = (1 << 0), /* flowc needs to be sent */ EO_FLOWC_RPL_PENDING = (1 << 1), /* flowc credits due back */ @@ -89,6 +89,11 @@ struct cxgbe_snd_tag { struct m_snd_tag com; + int type; +}; + +struct cxgbe_rate_tag { + struct cxgbe_snd_tag com; struct adapter *adapter; u_int flags; struct mtx lock; @@ -114,8 +119,14 @@ return (__containerof(t, struct cxgbe_snd_tag, com)); } +static inline struct cxgbe_rate_tag * +mst_to_crt(struct m_snd_tag *t) +{ + return ((struct cxgbe_rate_tag *)mst_to_cst(t)); +} + union etid_entry { - struct cxgbe_snd_tag *cst; + struct cxgbe_rate_tag *cst; union etid_entry *next; }; Index: sys/dev/cxgbe/t4_main.c =================================================================== --- sys/dev/cxgbe/t4_main.c +++ sys/dev/cxgbe/t4_main.c @@ -230,6 +230,15 @@ static int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t); static int cxgbe_transmit(struct ifnet *, struct mbuf *); static void cxgbe_qflush(struct ifnet *); +#ifdef RATELIMIT +static int cxgbe_snd_tag_alloc(struct ifnet *, union if_snd_tag_alloc_params *, + struct m_snd_tag **); +static int cxgbe_snd_tag_modify(struct m_snd_tag *, + union if_snd_tag_modify_params *); +static int cxgbe_snd_tag_query(struct m_snd_tag *, + union if_snd_tag_query_params *); +static void cxgbe_snd_tag_free(struct m_snd_tag *); +#endif MALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4/T5 Ethernet driver and services"); @@ -2041,11 +2050,18 @@ struct port_info *pi = vi->pi; struct adapter *sc = pi->adapter; struct sge_txq *txq; +#ifdef RATELIMIT + struct cxgbe_snd_tag *cst; +#endif void *items[1]; int rc; M_ASSERTPKTHDR(m); MPASS(m->m_nextpkt == NULL); /* not quite ready for this yet */ +#ifdef RATELIMIT + if (m->m_pkthdr.csum_flags & CSUM_SND_TAG) + MPASS(m->m_pkthdr.snd_tag->ifp == ifp); +#endif if (__predict_false(pi->link_cfg.link_ok == false)) { m_freem(m); @@ -2060,8 +2076,9 @@ } #ifdef RATELIMIT if (m->m_pkthdr.csum_flags & CSUM_SND_TAG) { - MPASS(m->m_pkthdr.snd_tag->ifp == ifp); - return (ethofld_transmit(ifp, m)); + cst = mst_to_cst(m->m_pkthdr.snd_tag); + if (cst->type == IF_SND_TAG_TYPE_RATE_LIMIT) + return (ethofld_transmit(ifp, m)); } #endif @@ -2218,6 +2235,87 @@ return (if_get_counter_default(ifp, c)); } } + +#ifdef RATELIMIT +void +cxgbe_snd_tag_init(struct cxgbe_snd_tag *cst, struct ifnet *ifp, int type) +{ + + m_snd_tag_init(&cst->com, ifp); + cst->type = type; +} + +static int +cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, + struct m_snd_tag **pt) +{ + int error; + + switch (params->hdr.type) { +#ifdef RATELIMIT + case IF_SND_TAG_TYPE_RATE_LIMIT: + error = cxgbe_rate_tag_alloc(ifp, params, pt); + break; +#endif + default: + error = EOPNOTSUPP; + } + if (error == 0) + MPASS(mst_to_cst(*pt)->type == params->hdr.type); + return (error); +} + +static int +cxgbe_snd_tag_modify(struct m_snd_tag *mst, + union if_snd_tag_modify_params *params) +{ + struct cxgbe_snd_tag *cst; + + cst = mst_to_cst(mst); + switch (cst->type) { +#ifdef RATELIMIT + case IF_SND_TAG_TYPE_RATE_LIMIT: + return (cxgbe_rate_tag_modify(mst, params)); +#endif + default: + return (EOPNOTSUPP); + } +} + +static int +cxgbe_snd_tag_query(struct m_snd_tag *mst, + union if_snd_tag_query_params *params) +{ + struct cxgbe_snd_tag *cst; + + cst = mst_to_cst(mst); + switch (cst->type) { +#ifdef RATELIMIT + case IF_SND_TAG_TYPE_RATE_LIMIT: + return (cxgbe_rate_tag_query(mst, params)); +#endif + default: + return (EOPNOTSUPP); + } +} + +static void +cxgbe_snd_tag_free(struct m_snd_tag *mst) +{ + struct cxgbe_snd_tag *cst; + + cst = mst_to_cst(mst); + switch (cst->type) { +#ifdef RATELIMIT + case IF_SND_TAG_TYPE_RATE_LIMIT: + cxgbe_rate_tag_free(mst); + return; +#endif + default: + panic("shouldn't get here"); + } +} +#endif /* * The kernel picks a media from the list we had provided but we still validate Index: sys/dev/cxgbe/t4_sched.c =================================================================== --- sys/dev/cxgbe/t4_sched.c +++ sys/dev/cxgbe/t4_sched.c @@ -711,11 +711,11 @@ } /* etid services */ -static int alloc_etid(struct adapter *, struct cxgbe_snd_tag *); +static int alloc_etid(struct adapter *, struct cxgbe_rate_tag *); static void free_etid(struct adapter *, int); static int -alloc_etid(struct adapter *sc, struct cxgbe_snd_tag *cst) +alloc_etid(struct adapter *sc, struct cxgbe_rate_tag *cst) { struct tid_info *t = &sc->tids; int etid = -1; @@ -733,7 +733,7 @@ return (etid); } -struct cxgbe_snd_tag * +struct cxgbe_rate_tag * lookup_etid(struct adapter *sc, int etid) { struct tid_info *t = &sc->tids; @@ -755,17 +755,16 @@ } int -cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, +cxgbe_rate_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, struct m_snd_tag **pt) { int rc, schedcl; struct vi_info *vi = ifp->if_softc; struct port_info *pi = vi->pi; struct adapter *sc = pi->adapter; - struct cxgbe_snd_tag *cst; + struct cxgbe_rate_tag *cst; - if (params->hdr.type != IF_SND_TAG_TYPE_RATE_LIMIT) - return (ENOTSUP); + MPASS(params->hdr.type == IF_SND_TAG_TYPE_RATE_LIMIT); rc = t4_reserve_cl_rl_kbps(sc, pi->port_id, (params->rate_limit.max_rate * 8ULL / 1000), &schedcl); @@ -789,7 +788,7 @@ mtx_init(&cst->lock, "cst_lock", NULL, MTX_DEF); mbufq_init(&cst->pending_tx, INT_MAX); mbufq_init(&cst->pending_fwack, INT_MAX); - m_snd_tag_init(&cst->com, ifp); + cxgbe_snd_tag_init(&cst->com, ifp, IF_SND_TAG_TYPE_RATE_LIMIT); cst->flags |= EO_FLOWC_PENDING | EO_SND_TAG_REF; cst->adapter = sc; cst->port_id = pi->port_id; @@ -806,7 +805,7 @@ * Queues will be selected later when the connection flowid is available. */ - *pt = &cst->com; + *pt = &cst->com.com; return (0); } @@ -814,11 +813,11 @@ * Change in parameters, no change in ifp. */ int -cxgbe_snd_tag_modify(struct m_snd_tag *mst, +cxgbe_rate_tag_modify(struct m_snd_tag *mst, union if_snd_tag_modify_params *params) { int rc, schedcl; - struct cxgbe_snd_tag *cst = mst_to_cst(mst); + struct cxgbe_rate_tag *cst = mst_to_crt(mst); struct adapter *sc = cst->adapter; /* XXX: is schedcl -1 ok here? */ @@ -840,10 +839,10 @@ } int -cxgbe_snd_tag_query(struct m_snd_tag *mst, +cxgbe_rate_tag_query(struct m_snd_tag *mst, union if_snd_tag_query_params *params) { - struct cxgbe_snd_tag *cst = mst_to_cst(mst); + struct cxgbe_rate_tag *cst = mst_to_crt(mst); params->rate_limit.max_rate = cst->max_rate; @@ -858,7 +857,7 @@ * Unlocks cst and frees it. */ void -cxgbe_snd_tag_free_locked(struct cxgbe_snd_tag *cst) +cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag *cst) { struct adapter *sc = cst->adapter; @@ -879,9 +878,9 @@ } void -cxgbe_snd_tag_free(struct m_snd_tag *mst) +cxgbe_rate_tag_free(struct m_snd_tag *mst) { - struct cxgbe_snd_tag *cst = mst_to_cst(mst); + struct cxgbe_rate_tag *cst = mst_to_crt(mst); mtx_lock(&cst->lock); @@ -896,7 +895,7 @@ * credits for the etid otherwise. */ if (cst->tx_credits == cst->tx_total) { - cxgbe_snd_tag_free_locked(cst); + cxgbe_rate_tag_free_locked(cst); return; /* cst is gone. */ } send_etid_flush_wr(cst); Index: sys/dev/cxgbe/t4_sge.c =================================================================== --- sys/dev/cxgbe/t4_sge.c +++ sys/dev/cxgbe/t4_sge.c @@ -2307,10 +2307,10 @@ } static inline int -needs_eo(struct mbuf *m) +needs_eo(struct cxgbe_snd_tag *cst) { - return (m->m_pkthdr.csum_flags & CSUM_SND_TAG); + return (cst != NULL && cst->type == IF_SND_TAG_TYPE_RATE_LIMIT); } #endif @@ -2542,6 +2542,9 @@ #if defined(INET) || defined(INET6) struct tcphdr *tcp; #endif +#ifdef RATELIMIT + struct cxgbe_snd_tag *cst; +#endif uint16_t eh_type; uint8_t cflags; @@ -2562,6 +2565,12 @@ M_ASSERTPKTHDR(m0); MPASS(m0->m_pkthdr.len > 0); nsegs = count_mbuf_nsegs(m0, 0, &cflags); +#ifdef RATELIMIT + if (m0->m_pkthdr.csum_flags & CSUM_SND_TAG) + cst = mst_to_cst(m0->m_pkthdr.snd_tag); + else + cst = NULL; +#endif if (nsegs > (needs_tso(m0) ? TX_SGL_SEGS_TSO : TX_SGL_SEGS)) { if (defragged++ > 0 || (m = m_defrag(m0, M_NOWAIT)) == NULL) { rc = EFBIG; @@ -2595,16 +2604,17 @@ * checksumming is enabled. needs_l4_csum happens to check for all the * right things. */ - if (__predict_false(needs_eo(m0) && !needs_l4_csum(m0))) { + if (__predict_false(needs_eo(cst) && !needs_l4_csum(m0))) { m_snd_tag_rele(m0->m_pkthdr.snd_tag); m0->m_pkthdr.snd_tag = NULL; m0->m_pkthdr.csum_flags &= ~CSUM_SND_TAG; + cst = NULL; } #endif if (!needs_tso(m0) && #ifdef RATELIMIT - !needs_eo(m0) && + !needs_eo(cst) && #endif !(sc->flags & IS_VF && (needs_l3_csum(m0) || needs_l4_csum(m0)))) return (0); @@ -2666,7 +2676,7 @@ #endif } #ifdef RATELIMIT - if (needs_eo(m0)) { + if (needs_eo(cst)) { u_int immhdrs; /* EO WRs have the headers in the WR and not the GL. */ @@ -5723,7 +5733,7 @@ #define ETID_FLOWC_LEN16 (howmany(ETID_FLOWC_LEN, 16)) static int -send_etid_flowc_wr(struct cxgbe_snd_tag *cst, struct port_info *pi, +send_etid_flowc_wr(struct cxgbe_rate_tag *cst, struct port_info *pi, struct vi_info *vi) { struct wrq_cookie cookie; @@ -5769,7 +5779,7 @@ #define ETID_FLUSH_LEN16 (howmany(sizeof (struct fw_flowc_wr), 16)) void -send_etid_flush_wr(struct cxgbe_snd_tag *cst) +send_etid_flush_wr(struct cxgbe_rate_tag *cst) { struct fw_flowc_wr *flowc; struct wrq_cookie cookie; @@ -5795,7 +5805,7 @@ } static void -write_ethofld_wr(struct cxgbe_snd_tag *cst, struct fw_eth_tx_eo_wr *wr, +write_ethofld_wr(struct cxgbe_rate_tag *cst, struct fw_eth_tx_eo_wr *wr, struct mbuf *m0, int compl) { struct cpl_tx_pkt_core *cpl; @@ -5944,7 +5954,7 @@ } static void -ethofld_tx(struct cxgbe_snd_tag *cst) +ethofld_tx(struct cxgbe_rate_tag *cst) { struct mbuf *m; struct wrq_cookie cookie; @@ -5977,7 +5987,7 @@ cst->tx_credits -= next_credits; cst->tx_nocompl += next_credits; compl = cst->ncompl == 0 || cst->tx_nocompl >= cst->tx_total / 2; - ETHER_BPF_MTAP(cst->com.ifp, m); + ETHER_BPF_MTAP(cst->com.com.ifp, m); write_ethofld_wr(cst, wr, m, compl); commit_wrq_wr(cst->eo_txq, wr, &cookie); if (compl) { @@ -5989,7 +5999,7 @@ /* * Drop the mbuf's reference on the tag now rather * than waiting until m_freem(). This ensures that - * cxgbe_snd_tag_free gets called when the inp drops + * cxgbe_rate_tag_free gets called when the inp drops * its reference on the tag and there are no more * mbufs in the pending_tx queue and can flush any * pending requests. Otherwise if the last mbuf @@ -5998,7 +6008,7 @@ */ m->m_pkthdr.snd_tag = NULL; m->m_pkthdr.csum_flags &= ~CSUM_SND_TAG; - m_snd_tag_rele(&cst->com); + m_snd_tag_rele(&cst->com.com); mbufq_enqueue(&cst->pending_fwack, m); } @@ -6007,13 +6017,13 @@ int ethofld_transmit(struct ifnet *ifp, struct mbuf *m0) { - struct cxgbe_snd_tag *cst; + struct cxgbe_rate_tag *cst; int rc; MPASS(m0->m_nextpkt == NULL); MPASS(m0->m_pkthdr.csum_flags & CSUM_SND_TAG); MPASS(m0->m_pkthdr.snd_tag != NULL); - cst = mst_to_cst(m0->m_pkthdr.snd_tag); + cst = mst_to_crt(m0->m_pkthdr.snd_tag); mtx_lock(&cst->lock); MPASS(cst->flags & EO_SND_TAG_REF); @@ -6052,10 +6062,10 @@ * ethofld_tx() in case we are sending the final mbuf after * the inp was freed. */ - m_snd_tag_ref(&cst->com); + m_snd_tag_ref(&cst->com.com); ethofld_tx(cst); mtx_unlock(&cst->lock); - m_snd_tag_rele(&cst->com); + m_snd_tag_rele(&cst->com.com); return (0); done: @@ -6072,7 +6082,7 @@ const struct cpl_fw4_ack *cpl = (const void *)(rss + 1); struct mbuf *m; u_int etid = G_CPL_FW4_ACK_FLOWID(be32toh(OPCODE_TID(cpl))); - struct cxgbe_snd_tag *cst; + struct cxgbe_rate_tag *cst; uint8_t credits = cpl->credits; cst = lookup_etid(sc, etid); @@ -6104,7 +6114,7 @@ cst->flags &= ~EO_FLUSH_RPL_PENDING; cst->tx_credits += cpl->credits; - cxgbe_snd_tag_free_locked(cst); + cxgbe_rate_tag_free_locked(cst); return (0); /* cst is gone. */ } KASSERT(m != NULL, @@ -6126,12 +6136,12 @@ * As with ethofld_transmit(), hold an extra reference * so that the tag is stable across ethold_tx(). */ - m_snd_tag_ref(&cst->com); + m_snd_tag_ref(&cst->com.com); m = mbufq_first(&cst->pending_tx); if (m != NULL && cst->tx_credits >= mbuf_eo_len16(m)) ethofld_tx(cst); mtx_unlock(&cst->lock); - m_snd_tag_rele(&cst->com); + m_snd_tag_rele(&cst->com.com); } else { /* * There shouldn't be any pending packets if the tag