diff --git a/drivers/net/nfp/nfdk/nfp_nfdk.h b/drivers/net/nfp/nfdk/nfp_nfdk.h
index 9af9176eb7..c39501990a 100644
--- a/drivers/net/nfp/nfdk/nfp_nfdk.h
+++ b/drivers/net/nfp/nfdk/nfp_nfdk.h
@@ -9,22 +9,27 @@
 #define NFDK_TX_DESC_PER_SIMPLE_PKT     2
 #define NFDK_TX_DESC_GATHER_MAX         17
 
-#define NFDK_TX_MAX_DATA_PER_HEAD       0x00001000
-#define NFDK_TX_MAX_DATA_PER_DESC       0x00004000
-#define NFDK_TX_MAX_DATA_PER_BLOCK      0x00010000
+#define NFDK_TX_MAX_DATA_PER_HEAD       0x00001000    /* 4K */
+#define NFDK_TX_MAX_DATA_PER_DESC       0x00004000    /* 16K */
+#define NFDK_TX_MAX_DATA_PER_BLOCK      0x00010000    /* 64K */
 
+/* The mask of 'dma_len_xx' of address descriptor */
 #define NFDK_DESC_TX_DMA_LEN_HEAD       0x0FFF        /* [0,11] */
 #define NFDK_DESC_TX_DMA_LEN            0x3FFF        /* [0,13] */
 #define NFDK_DESC_TX_TYPE_HEAD          0xF000        /* [12,15] */
 
+/* The mask of upper 4 bit of first address descriptor */
+#define NFDK_DESC_TX_TYPE_HEAD          0xF000        /* [12,15] */
+
+/* The value of upper 4 bit of first address descriptor */
 #define NFDK_DESC_TX_TYPE_GATHER        1
 #define NFDK_DESC_TX_TYPE_TSO           2
 #define NFDK_DESC_TX_TYPE_SIMPLE        8
 
-/* TX descriptor format */
+/* The 'end of chain' flag of address descriptor */
 #define NFDK_DESC_TX_EOP                RTE_BIT32(14)
 
-/* Flags in the host TX descriptor */
+/* Flags in the host metadata descriptor */
 #define NFDK_DESC_TX_CHAIN_META         RTE_BIT32(3)
 #define NFDK_DESC_TX_ENCAP              RTE_BIT32(2)
 #define NFDK_DESC_TX_L4_CSUM            RTE_BIT32(1)
@@ -40,14 +45,73 @@
 /* Convenience macro for wrapping descriptor index on ring size */
 #define D_IDX(ring, idx)               ((idx) & ((ring)->tx_count - 1))
 
+/*
+ * A full TX descriptor consists of one or more address descriptors,
+ * followed by a TX metadata descriptor, and finally a TSO descriptor for
+ * TSO packets.
+ *
+ * --> Header address descriptor:
+ * Bit    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+ * -----\ 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * Word  +-+-+---+-----------------------+-------------------------------+
+ *    0  |S|E| TP|     dma_len_12        |         dma_addr_hi           |
+ *       +-+-+---+-----------------------+-------------------------------+
+ *    1  |                          dma_addr_lo                          |
+ *       +---------------------------------------------------------------+
+ *
+ * --> Subsequent address descriptor(s):
+ * Bit    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+ * -----\ 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * Word  +-+-+---------------------------+-------------------------------+
+ *    0  |S|E|         dma_len_14        |          dma_addr_hi          |
+ *       +-+-+---------------------------+-------------------------------+
+ *    1  |                          dma_addr_lo                          |
+ *       +---------------------------------------------------------------+
+ *
+ * S - Simple Packet descriptor
+ * TP - Type of descriptor
+ * E - End of chain
+ * dma_len - length of the host memory in bytes -1
+ * dma_addr_hi - bits [47:32] of host memory address
+ * dma_addr_lo - bits [31:0] of host memory address
+ *
+ * --> metadata descriptor
+ * Bit     3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+ * -----\  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * Word   +-------+-----------------------+---------------------+---+-----+
+ *    0   |  ZERO |   Rsvd (64b support)  |       TBD meta      | MT| CSUM|
+ *        +-------+-----------------------+---------------------+---+-----+
+ *    1   |                           TBD meta                            |
+ *        +---------------------------------------------------------------+
+ *
+ * --> TSO descriptor
+ * The following is only present if TP above indicates LSO:
+ * Bit    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+ * -----\ 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * Word  +---------------+---------------+---+---------------------------+
+ *    0  | total_segments|   header_len  |sp0|          mss              |
+ *       +---------------+---------------+---+---------------------------+
+ *    1  |               sp1             |       L4      |      L3       |
+ *       +---------------------------------------------------------------+
+ *
+ * total_segments - LSO: Total number of segments
+ * header_len - LSO: length of the LSO header in bytes
+ * sp0 - Spare Bits (ZERO)
+ * mss - LSO: TCP MSS, maximum segment size of TCP payload
+ * sp1 - Spare Bits (ZERO)
+ * L4 - Layer 4 data
+ * L3 - Layer 3 data
+ */
 struct nfp_net_nfdk_tx_desc {
 	union {
+		/* Address descriptor */
 		struct {
 			uint16_t dma_addr_hi;  /* High bits of host buf address */
 			uint16_t dma_len_type; /* Length to DMA for this desc */
 			uint32_t dma_addr_lo;  /* Low 32bit of host buf addr */
 		};
 
+		/* TSO descriptor */
 		struct {
 			uint16_t mss;          /* MSS to be used for LSO */
 			uint8_t lso_hdrlen;    /* LSO, TCP payload offset */
@@ -57,6 +121,7 @@ struct nfp_net_nfdk_tx_desc {
 			uint16_t lso_meta_res; /* Rsvd bits in TSO metadata */
 		};
 
+		/* Metadata descriptor */
 		struct {
 			uint8_t flags;         /* TX Flags, see @NFDK_DESC_TX_* */
 			uint8_t reserved[7];   /* meta byte placeholder */
diff --git a/drivers/net/nfp/nfdk/nfp_nfdk_dp.c b/drivers/net/nfp/nfdk/nfp_nfdk_dp.c
index 013f369b55..12233393fc 100644
--- a/drivers/net/nfp/nfdk/nfp_nfdk_dp.c
+++ b/drivers/net/nfp/nfdk/nfp_nfdk_dp.c
@@ -14,25 +14,46 @@
 #include "../nfpcore/nfp_rtsym.h"
 #include "nfp_nfdk.h"
 
-static inline int
-nfp_net_nfdk_headlen_to_segs(unsigned int headlen)
+static inline uint16_t
+nfp_net_nfdk_headlen_to_segs(uint16_t headlen)
 {
+	/* First descriptor fits less data, so adjust for that */
 	return DIV_ROUND_UP(headlen +
 			NFDK_TX_MAX_DATA_PER_DESC -
 			NFDK_TX_MAX_DATA_PER_HEAD,
 			NFDK_TX_MAX_DATA_PER_DESC);
 }
 
+static inline void
+nfp_net_nfdk_tx_close_block(struct nfp_net_txq *txq,
+		uint32_t nop_slots)
+{
+	uint32_t i;
+	uint32_t wr_p;
+
+	wr_p = txq->wr_p;
+	memset(&txq->ktxds[wr_p], 0, nop_slots * sizeof(struct nfp_net_nfdk_tx_desc));
+
+	for (i = wr_p; i < nop_slots + wr_p; i++) {
+		if (txq->txbufs[i].mbuf != NULL) {
+			rte_pktmbuf_free_seg(txq->txbufs[i].mbuf);
+			txq->txbufs[i].mbuf = NULL;
+		}
+	}
+
+	txq->data_pending = 0;
+	txq->wr_p = D_IDX(txq, wr_p + nop_slots);
+}
+
 static int
 nfp_net_nfdk_tx_maybe_close_block(struct nfp_net_txq *txq,
 		struct rte_mbuf *pkt)
 {
-	uint32_t i;
-	uint32_t wr_p;
 	uint16_t n_descs;
 	uint32_t nop_slots;
 	struct rte_mbuf *pkt_temp;
 
+	/* Count address descriptor */
 	pkt_temp = pkt;
 	n_descs = nfp_net_nfdk_headlen_to_segs(pkt_temp->data_len);
 	while (pkt_temp->next != NULL) {
@@ -43,9 +64,12 @@ nfp_net_nfdk_tx_maybe_close_block(struct nfp_net_txq *txq,
 	if (unlikely(n_descs > NFDK_TX_DESC_GATHER_MAX))
 		return -EINVAL;
 
-	if ((pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0)
+	/* Count TSO descriptor */
+	if ((txq->hw->cap & NFP_NET_CFG_CTRL_LSO_ANY) != 0 &&
+			(pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0)
 		n_descs++;
 
+	/* Don't count metadata descriptor, for the round down to work out */
 	if (round_down(txq->wr_p, NFDK_TX_DESC_BLOCK_CNT) !=
 			round_down(txq->wr_p + n_descs, NFDK_TX_DESC_BLOCK_CNT))
 		goto close_block;
@@ -56,18 +80,8 @@ nfp_net_nfdk_tx_maybe_close_block(struct nfp_net_txq *txq,
 	return 0;
 
 close_block:
-	wr_p = txq->wr_p;
-	nop_slots = D_BLOCK_CPL(wr_p);
-
-	memset(&txq->ktxds[wr_p], 0, nop_slots * sizeof(struct nfp_net_nfdk_tx_desc));
-	for (i = wr_p; i < nop_slots + wr_p; i++) {
-		if (txq->txbufs[i].mbuf) {
-			rte_pktmbuf_free_seg(txq->txbufs[i].mbuf);
-			txq->txbufs[i].mbuf = NULL;
-		}
-	}
-	txq->data_pending = 0;
-	txq->wr_p = D_IDX(txq, txq->wr_p + nop_slots);
+	nop_slots = D_BLOCK_CPL(txq->wr_p);
+	nfp_net_nfdk_tx_close_block(txq, nop_slots);
 
 	return nop_slots;
 }
