FreeBSD/sys/dev/cxgb/cxgb_sge.c
/**
 *	write_wr_hdr_sgl - write a WR header and, optionally, SGL
 *	@ndesc: number of Tx descriptors spanned by the SGL
 *	@txd: first Tx descriptor to be written
 *	@txqs: txq state (generation and producer index)
 *	@txq: the SGE Tx queue
 *	@sgl: the SGL
 *	@flits: number of flits to the start of the SGL in the first descriptor
 *	@sgl_flits: the SGL size in flits
 *	@wr_hi: top 32 bits of WR header based on WR type (big endian)
 *	@wr_lo: low 32 bits of WR header based on WR type (big endian)
 *
 *	Write a work request header and an associated SGL.  If the SGL is
 *	small enough to fit into one Tx descriptor it has already been written
 *	and we just need to write the WR header.  Otherwise we distribute the
 *	SGL across the number of descriptors it spans.
 */


Write a work request header and an associated SGL.  If the SGL is
small enough to fit into one Tx descriptor it has already been written
and we just need to write the WR header.  Otherwise we distribute the
SGL across the number of descriptors it spans.
Write a work request header and an associated SGL . If the SGL is small enough to fit into one Tx descriptor it has already been written and we just need to write the WR header . Otherwise we distribute the SGL across the number of descriptors it spans .
static void
write_wr_hdr_sgl(unsigned int ndesc, struct tx_desc *txd, struct txq_state *txqs,
    const struct sge_txq *txq, const struct sg_ent *sgl, unsigned int flits,
    unsigned int sgl_flits, unsigned int wr_hi, unsigned int wr_lo)
{
	struct work_request_hdr *wrp = (struct work_request_hdr *)txd;
	struct tx_sw_desc *txsd = &txq->sdesc[txqs->pidx];
	if (__predict_true(ndesc == 1)) {
		set_wr_hdr(wrp, htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
		    V_WR_SGLSFLT(flits)) | wr_hi,
		    htonl(V_WR_LEN(flits + sgl_flits) | V_WR_GEN(txqs->gen)) |
		    wr_lo);
		wr_gen2(txd, txqs->gen);
	} else {
		unsigned int ogen = txqs->gen;
		const uint64_t *fp = (const uint64_t *)sgl;
		struct work_request_hdr *wp = wrp;
		wrp->wrh_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) |
		    V_WR_SGLSFLT(flits)) | wr_hi;
		while (sgl_flits) {
			unsigned int avail = WR_FLITS - flits;
			if (avail > sgl_flits)
				avail = sgl_flits;
			memcpy(&txd->flit[flits], fp, avail * sizeof(*fp));
			sgl_flits -= avail;
			ndesc--;
			if (!sgl_flits)
				break;
			fp += avail;
			txd++;
			txsd++;
			if (++txqs->pidx == txq->size) {
				txqs->pidx = 0;
				txqs->gen ^= 1;
				txd = txq->desc;
				txsd = txq->sdesc;
			}
			wrp = (struct work_request_hdr *)txd;
			wrp->wrh_hi = htonl(V_WR_DATATYPE(1) |
			    V_WR_SGLSFLT(1)) | wr_hi;
			wrp->wrh_lo = htonl(V_WR_LEN(min(WR_FLITS,
				    sgl_flits + 1)) |
			    V_WR_GEN(txqs->gen)) | wr_lo;
			wr_gen2(txd, txqs->gen);
			flits = 1;
		}
		wrp->wrh_hi |= htonl(F_WR_EOP);
		wmb();
		wp->wrh_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
		wr_gen2((struct tx_desc *)wp, ogen);
	}
}
static void write_wr_hdr_sgl ( unsigned int ndesc , struct tx_desc * txd , struct txq_state * txqs , const struct sge_txq * txq , const struct sg_ent * sgl , unsigned int flits , unsigned int sgl_flits , unsigned int wr_hi , unsigned int wr_lo ) { struct work_request_hdr * wrp = ( struct work_request_hdr * ) txd ; struct tx_sw_desc * txsd = & txq -> sdesc [ txqs -> pidx ] ; if ( __predict_true ( ndesc == 1 ) ) { set_wr_hdr ( wrp , htonl ( F_WR_SOP | F_WR_EOP | V_WR_DATATYPE ( 1 ) | V_WR_SGLSFLT ( flits ) ) | wr_hi , htonl ( V_WR_LEN ( flits + sgl_flits ) | V_WR_GEN ( txqs -> gen ) ) | wr_lo ) ; wr_gen2 ( txd , txqs -> gen ) ; } else { unsigned int ogen = txqs -> gen ; const uint64_t * fp = ( const uint64_t * ) sgl ; struct work_request_hdr * wp = wrp ; wrp -> wrh_hi = htonl ( F_WR_SOP | V_WR_DATATYPE ( 1 ) | V_WR_SGLSFLT ( flits ) ) | wr_hi ; while ( sgl_flits ) { unsigned int avail = WR_FLITS - flits ; if ( avail > sgl_flits ) avail = sgl_flits ; memcpy ( & txd -> flit [ flits ] , fp , avail * sizeof ( * fp ) ) ; sgl_flits -= avail ; ndesc -- ; if ( ! sgl_flits ) break ; fp += avail ; txd ++ ; txsd ++ ; if ( ++ txqs -> pidx == txq -> size ) { txqs -> pidx = 0 ; txqs -> gen ^= 1 ; txd = txq -> desc ; txsd = txq -> sdesc ; } wrp = ( struct work_request_hdr * ) txd ; wrp -> wrh_hi = htonl ( V_WR_DATATYPE ( 1 ) | V_WR_SGLSFLT ( 1 ) ) | wr_hi ; wrp -> wrh_lo = htonl ( V_WR_LEN ( min ( WR_FLITS , sgl_flits + 1 ) ) | V_WR_GEN ( txqs -> gen ) ) | wr_lo ; wr_gen2 ( txd , txqs -> gen ) ; flits = 1 ; } wrp -> wrh_hi |= htonl ( F_WR_EOP ) ; wmb ( ) ; wp -> wrh_lo = htonl ( V_WR_LEN ( WR_FLITS ) | V_WR_GEN ( ogen ) ) | wr_lo ; wr_gen2 ( ( struct tx_desc * ) wp , ogen ) ; } }
write_wr_hdr_sgl - write a WR header and, optionally, SGL
      @ndesc: number of Tx descriptors spanned by the SGL
      @txd: first Tx descriptor to be written
      @txqs: txq state (generation and producer index)
      @txq: the SGE Tx queue
      @sgl: the SGL
      @flits: number of flits to the start of the SGL in the first descriptor
      @sgl_flits: the SGL size in flits
      @wr_hi: top 32 bits of WR header based on WR type (big endian)
      @wr_lo: low 32 bits of WR header based on WR type (big endian)
write_wr_hdr_sgl - write a WR header and optionally SGL @ndesc : number of Tx descriptors spanned by the SGL @txd : first Tx descriptor to be written @txqs : txq state ( generation and producer index ) @txq : the SGE Tx queue @sgl : the SGL @flits : number of flits to the start of the SGL in the first descriptor @sgl_flits : the SGL size in flits @wr_hi : top 32 bits of WR header based on WR type ( big endian ) @wr_lo : low 32 bits of WR header based on WR type ( big endian )
/*
			 * when the head of the mbuf chain
			 * is freed all clusters will be freed
			 * with it
			 */