changeset 10615:4bb212e117c7

6786791 nge needs to have a new tx stall detection mechanism 6871807 nge driver should enable TFINT for tx_recylce
author Winson Wang - Sun Microsystems - Beijing China <Zhen.W@Sun.COM>
date Wed, 23 Sep 2009 09:09:49 +0800
parents 4f397871da47
children 3be00c4a6835
files usr/src/uts/common/io/nge/nge.h usr/src/uts/common/io/nge/nge_chip.c usr/src/uts/common/io/nge/nge_main.c usr/src/uts/common/io/nge/nge_tx.c
diffstat 4 files changed, 75 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/nge/nge.h	Tue Sep 22 17:11:54 2009 -0700
+++ b/usr/src/uts/common/io/nge/nge.h	Wed Sep 23 09:09:49 2009 +0800
@@ -147,8 +147,7 @@
 #define	VTAG_SIZE		4
 #endif
 
-#define	NGE_HALFTICK		268435456LL		/* 2**28 ns!	*/
-#define	NGE_CYCLIC_PERIOD	(4*NGE_HALFTICK)	/*    ~0.5s	*/
+#define	NGE_CYCLIC_PERIOD	(1000000000)
 
 #define	NGE_DEFAULT_MTU		1500
 #define	NGE_DEFAULT_SDU		1518
@@ -191,9 +190,12 @@
 #define	NGE_MAX_DMA_HDR		(4*1024)
 
 /* Used by interrupt moderation */
+#define	NGE_TFINT_DEFAULT	32
+#define	NGE_POLL_TUNE		80000
+#define	NGE_POLL_ENTER		10000
+#define	NGE_POLL_MAX		1280000
 #define	NGE_POLL_QUIET_TIME	100
 #define	NGE_POLL_BUSY_TIME	2
-#define	NGE_TX_N_INTR		128
 
 /*
  * NGE-specific ioctls ...
@@ -655,7 +657,7 @@
 	uint32_t (*rxd_check)(const void *, size_t *);
 
 	void (*txd_fill)(void *, const ddi_dma_cookie_t *, size_t,
-			uint32_t, boolean_t);
+			uint32_t, boolean_t, boolean_t);
 
 	uint32_t (*txd_check)(const void *);
 };
@@ -755,7 +757,8 @@
 	uint32_t		recv_count;
 	uint32_t		quiet_time;
 	uint32_t		busy_time;
-	uint32_t		stint_count;
+	uint64_t		tpkts_last;
+	uint32_t		tfint_threshold;
 	uint32_t		sw_intr_intv;
 	nge_mac_addr_t		cur_uni_addr;
 	uint32_t		rx_datahwm;
@@ -829,7 +832,6 @@
 	int			param_poll_busy_time;
 	int			param_rx_intr_hwater;
 	int			param_rx_intr_lwater;
-	int			param_tx_n_intr;
 } nge_t;
 
 extern const nge_ksindex_t nge_statistics[];
@@ -1044,7 +1046,7 @@
 extern uint32_t nge_sum_rxd_check(const void *, size_t *);
 
 extern void nge_sum_txd_fill(void *, const ddi_dma_cookie_t *,
-				size_t, uint32_t, boolean_t);
+				size_t, uint32_t, boolean_t, boolean_t);
 extern uint32_t nge_sum_txd_check(const void *);
 
 /*
@@ -1055,7 +1057,7 @@
 extern uint32_t nge_hot_rxd_check(const void *, size_t *);
 
 extern void nge_hot_txd_fill(void *, const ddi_dma_cookie_t *,
-				size_t, uint32_t, boolean_t);
+				size_t, uint32_t, boolean_t, boolean_t);
 extern uint32_t nge_hot_txd_check(const void *);
 
 #ifdef __cplusplus
--- a/usr/src/uts/common/io/nge/nge_chip.c	Tue Sep 22 17:11:54 2009 -0700
+++ b/usr/src/uts/common/io/nge/nge_chip.c	Wed Sep 23 09:09:49 2009 +0800
@@ -25,7 +25,8 @@
  */
 
 #include "nge.h"
-static uint32_t	nge_watchdog_count	= 1 << 29;
+static uint32_t	nge_watchdog_count	= 1 << 5;
+static uint32_t	nge_watchdog_check	= 1 << 3;
 extern boolean_t nge_enable_msi;
 static void nge_sync_mac_modes(nge_t *);
 
@@ -1302,12 +1303,12 @@
 	intr_mask.mask_bits.reint = NGE_SET;
 	intr_mask.mask_bits.rcint = NGE_SET;
 	intr_mask.mask_bits.miss = NGE_SET;
-	intr_mask.mask_bits.teint = NGE_CLEAR;
-	intr_mask.mask_bits.tcint = NGE_SET;
+	intr_mask.mask_bits.teint = NGE_SET;
+	intr_mask.mask_bits.tcint = NGE_CLEAR;
 	intr_mask.mask_bits.stint = NGE_CLEAR;
 	intr_mask.mask_bits.mint = NGE_CLEAR;
 	intr_mask.mask_bits.rfint = NGE_CLEAR;
-	intr_mask.mask_bits.tfint = NGE_CLEAR;
+	intr_mask.mask_bits.tfint = NGE_SET;
 	intr_mask.mask_bits.feint = NGE_SET;
 	intr_mask.mask_bits.resv10 = NGE_CLEAR;
 	intr_mask.mask_bits.resv11 = NGE_CLEAR;
@@ -1635,6 +1636,8 @@
 nge_factotum_stall_check(nge_t *ngep)
 {
 	uint32_t dogval;
+	send_ring_t *srp;
+	srp = ngep->send;
 	/*
 	 * Specific check for Tx stall ...
 	 *
@@ -1649,23 +1652,21 @@
 	 * All of which should ensure that we don't get into a state
 	 * where packets are left pending indefinitely!
 	 */
+	if (ngep->watchdog == 0 &&
+	    srp->tx_free < srp->desc.nslots)
+		ngep->watchdog = 1;
 	dogval = nge_atomic_shl32(&ngep->watchdog, 1);
-	if (dogval < nge_watchdog_count) {
-		ngep->stall_cknum = 0;
-	} else {
-		ngep->stall_cknum++;
-	}
-	if (ngep->stall_cknum < 16) {
+	if (dogval >= nge_watchdog_check)
+		nge_tx_recycle(ngep, B_FALSE);
+	if (dogval < nge_watchdog_count)
 		return (B_FALSE);
-	} else {
-		ngep->stall_cknum = 0;
+	else {
 		ngep->statistics.sw_statistics.tx_stall++;
 		return (B_TRUE);
 	}
 }
 
 
-
 /*
  * The factotum is woken up when there's something to do that we'd rather
  * not do from inside a hardware interrupt handler or high-level cyclic.
@@ -1748,12 +1749,8 @@
 	if (pintr_src->int_bits.miss)
 		ngep->statistics.sw_statistics.rx_nobuffer++;
 
-	btx = (pintr_src->int_bits.teint | pintr_src->int_bits.tcint)
+	btx = (pintr_src->int_bits.teint | pintr_src->int_bits.tfint)
 	    != 0 ? B_TRUE : B_FALSE;
-	if (pintr_src->int_bits.stint && ngep->poll)
-		ngep->stint_count ++;
-	if (ngep->poll && (ngep->stint_count % ngep->param_tx_n_intr == 0))
-		btx = B_TRUE;
 	if (btx)
 		nge_tx_recycle(ngep, B_TRUE);
 	if (brx)
@@ -1768,8 +1765,6 @@
 				    ngep->param_poll_quiet_time) {
 					ngep->poll = B_FALSE;
 					ngep->quiet_time = 0;
-					ngep->stint_count = 0;
-					nge_tx_recycle(ngep, B_TRUE);
 				}
 			} else
 				ngep->quiet_time = 0;
@@ -1837,9 +1832,6 @@
 		intr_mask.mask_val = nge_reg_get32(ngep, NGE_INTR_MASK);
 		intr_mask.mask_bits.stint = NGE_SET;
 		intr_mask.mask_bits.rcint = NGE_CLEAR;
-		intr_mask.mask_bits.reint = NGE_CLEAR;
-		intr_mask.mask_bits.tcint = NGE_CLEAR;
-		intr_mask.mask_bits.teint = NGE_CLEAR;
 		nge_reg_put32(ngep, NGE_INTR_MASK, intr_mask.mask_val);
 		ngep->ch_intr_mode = B_TRUE;
 	} else if ((ngep->ch_intr_mode) && (!ngep->poll)) {
--- a/usr/src/uts/common/io/nge/nge_main.c	Tue Sep 22 17:11:54 2009 -0700
+++ b/usr/src/uts/common/io/nge/nge_main.c	Wed Sep 23 09:09:49 2009 +0800
@@ -211,7 +211,6 @@
 	{"_poll_busy_time", MAC_PROP_PERM_RW},
 	{"_rx_intr_hwater", MAC_PROP_PERM_RW},
 	{"_rx_intr_lwater", MAC_PROP_PERM_RW},
-	{"_tx_n_intr", MAC_PROP_PERM_RW}
 };
 
 #define	NGE_MAX_PRIV_PROPS \
@@ -2044,21 +2043,6 @@
 		}
 		return (err);
 	}
-	if (strcmp(pr_name, "_tx_n_intr") == 0) {
-		if (pr_val == NULL) {
-			err = EINVAL;
-			return (err);
-		}
-		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
-		if (result < 1 || result > 10000) {
-			err = EINVAL;
-		} else {
-			ngep->param_tx_n_intr = (uint32_t)result;
-			goto reprogram;
-		}
-		return (err);
-	}
-
 	err = ENOTSUP;
 	return (err);
 
@@ -2118,12 +2102,6 @@
 		err = 0;
 		goto done;
 	}
-	if (strcmp(pr_name, "_tx_n_intr") == 0) {
-		value = (is_default ? NGE_TX_N_INTR :
-		    ngep->param_tx_n_intr);
-		err = 0;
-		goto done;
-	}
 
 done:
 	if (err == 0) {
@@ -2190,6 +2168,19 @@
 	mutex_exit(ngep->softlock);
 }
 
+void
+nge_interrupt_optimize(nge_t *ngep)
+{
+	uint32_t tx_pkts;
+	tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last;
+	ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count;
+	if ((tx_pkts > NGE_POLL_TUNE) &&
+	    (tx_pkts <= NGE_POLL_MAX))
+		ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER);
+	else
+		ngep->tfint_threshold = NGE_TFINT_DEFAULT;
+}
+
 /*
  * High-level cyclic handler
  *
@@ -2209,6 +2200,7 @@
 		return;
 
 	case NGE_CHIP_RUNNING:
+		nge_interrupt_optimize(ngep);
 		break;
 
 	case NGE_CHIP_FAULT:
@@ -2461,6 +2453,9 @@
 	 */
 	ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
 	ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
+	ngep->tfint_threshold = NGE_TFINT_DEFAULT;
+	ngep->poll = B_FALSE;
+	ngep->ch_intr_mode = B_FALSE;
 
 	/*
 	 * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
@@ -2470,11 +2465,6 @@
 	ngep->param_rx_intr_hwater = 1;
 	ngep->param_rx_intr_lwater = 8;
 
-	/*
-	 * param_tx_n_intr: Per N tx packets to do tx recycle in poll mode.
-	 * Bounds: min 1, max 10000.
-	 */
-	ngep->param_tx_n_intr = NGE_TX_N_INTR;
 
 	infop = (chip_info_t *)&ngep->chipinfo;
 	nge_chip_cfg_init(ngep, infop, B_FALSE);
--- a/usr/src/uts/common/io/nge/nge_tx.c	Tue Sep 22 17:11:54 2009 -0700
+++ b/usr/src/uts/common/io/nge/nge_tx.c	Wed Sep 23 09:09:49 2009 +0800
@@ -80,6 +80,12 @@
 
 		NGE_TXSWD_RECYCLE(ssbdp);
 	}
+	if (ngep->nge_mac_state == NGE_MAC_STARTED &&
+	    ngep->resched_needed == 1) {
+			ngep->resched_needed = 0;
+			mac_tx_update(ngep->mh);
+	}
+
 }
 
 static size_t
@@ -178,8 +184,13 @@
 	used = nslots - free - used;
 
 	ASSERT(slot == NEXT_INDEX(next, free, nslots));
+	if (used == 0) {
+		ngep->watchdog = 0;
+		mutex_exit(srp->tc_lock);
+		return;
+	}
 
-	if (used > srp->tx_hwmark)
+	if (used > srp->tx_hwmark && ngep->resched_needed == 0)
 		used = srp->tx_hwmark;
 
 	nge_tx_desc_sync(ngep, slot, used, DDI_DMA_SYNC_FORKERNEL);
@@ -224,6 +235,11 @@
 	 * we're not about to free more places than were claimed!
 	 */
 
+	if (free == 0) {
+		mutex_exit(srp->tc_lock);
+		return;
+	}
+
 	mutex_enter(srp->tx_lock);
 
 	srp->tx_free += free;
@@ -317,7 +333,8 @@
 		 * counter may not get reset on a partial reclaim; but the
 		 * large trigger threshold makes false positives unlikely
 		 */
-		ngep->watchdog ++;
+		if (ngep->watchdog == 0)
+			ngep->watchdog = 1;
 
 		mode_cntl.mode_val = nge_reg_get32(ngep, NGE_MODE_CNTL);
 		mode_cntl.mode_bits.txdm = NGE_SET;
@@ -343,6 +360,7 @@
 	mblk_t *bp;
 	void *hw_sbd_p;
 	sw_tx_sbd_t *ssbdp;
+	boolean_t tfint;
 
 	hcksum_retrieve(mp, NULL, NULL, NULL, NULL,
 	    NULL, NULL, &flags);
@@ -361,6 +379,7 @@
 	 * This is the point of no return!
 	 */
 
+	tfint = ((start_index % ngep->tfint_threshold) == 0);
 	bp = mp;
 	totlen = 0;
 	ssbdp = &srp->sw_sbds[start_index];
@@ -384,7 +403,7 @@
 	hw_sbd_p = DMA_VPTR(ssbdp->desc);
 
 	ngep->desc_attr.txd_fill(hw_sbd_p, &ssbdp->pbuf.cookie, totlen,
-	    flags, B_TRUE);
+	    flags, B_TRUE, tfint);
 	nge_tx_desc_sync(ngep, start_index, bds, DDI_DMA_SYNC_FORDEV);
 
 	ssbdp->flags = CONTROLER_OWN;
@@ -427,6 +446,7 @@
 	nge_dmah_node_t	*dmer;
 	nge_dmah_list_t dmah_list;
 	ddi_dma_cookie_t cookie[NGE_MAX_COOKIES * NGE_MAP_FRAGS];
+	boolean_t tfint;
 
 	srp = ngep->send;
 	nslots = srp->desc.nslots;
@@ -522,16 +542,18 @@
 	for (i = slot - 1, j = end_index; start_index - j != 0;
 	    j = PREV(j, nslots), --i)	{
 
+		tfint = ((j % ngep->tfint_threshold) == 0);
 		hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
 		ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i,
-		    cookie[i].dmac_size, 0, end);
+		    cookie[i].dmac_size, 0, end, tfint);
 
 		end = B_FALSE;
 	}
 
 	hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
+	tfint = ((j % ngep->tfint_threshold) == 0);
 	ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i, cookie[i].dmac_size,
-	    flags, end);
+	    flags, end, tfint);
 
 	nge_tx_desc_sync(ngep, start_index, slot, DDI_DMA_SYNC_FORDEV);
 
@@ -710,7 +732,7 @@
 
 void
 nge_hot_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
-	size_t length, uint32_t sum_flag, boolean_t end)
+	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
 {
 	hot_tx_bd * hw_sbd_p = hwdesc;
 
@@ -736,6 +758,8 @@
 	/*
 	 * indicating the end of BDs
 	 */
+	if (tfint)
+		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
 	if (end)
 		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;
 
@@ -747,7 +771,7 @@
 
 void
 nge_sum_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
-	size_t length, uint32_t sum_flag, boolean_t end)
+	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
 {
 	sum_tx_bd * hw_sbd_p = hwdesc;
 
@@ -772,6 +796,8 @@
 	/*
 	 * indicating the end of BDs
 	 */
+	if (tfint)
+		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
 	if (end)
 		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;