svn commit: r212790 - in head/sys/mips/rmi: . dev/nlge

Jayachandran C. jchandra at FreeBSD.org
Fri Sep 17 10:28:10 UTC 2010


Author: jchandra
Date: Fri Sep 17 10:28:10 2010
New Revision: 212790
URL: http://svn.freebsd.org/changeset/base/212790

Log:
  Fixes for XLR network accelerator driver (nlge).
  
  - Process some tx done messages in the transmit path, to ensure that
    the XLR NA tx done FIFO does not overflow.
  - Add a message ring handler API to process atmost a given number of
    messages from a specified bucket mask. This will be used to process
    the tx done messages
  - Add a callout to restart transmit in the case transmit gets blocked.
  - Update enable_msgring_int() and disable_msgring_int(), remove unused
    args and make static.
  
  Obtained from:	Sriram Gorti (srgorti at netlogicmicro dot com)

Modified:
  head/sys/mips/rmi/dev/nlge/if_nlge.c
  head/sys/mips/rmi/dev/nlge/if_nlge.h
  head/sys/mips/rmi/fmn.c
  head/sys/mips/rmi/msgring.h

Modified: head/sys/mips/rmi/dev/nlge/if_nlge.c
==============================================================================
--- head/sys/mips/rmi/dev/nlge/if_nlge.c	Fri Sep 17 09:50:36 2010	(r212789)
+++ head/sys/mips/rmi/dev/nlge/if_nlge.c	Fri Sep 17 10:28:10 2010	(r212790)
@@ -207,6 +207,9 @@ static void 	release_tx_desc(vm_paddr_t 
 static int	send_fmn_msg_tx(struct nlge_softc *, struct msgrng_msg *,
     uint32_t n_entries);
 
+static void
+nl_tx_q_wakeup(void *addr);
+
 //#define DEBUG
 #ifdef DEBUG
 static int	mac_debug = 1;
@@ -424,6 +427,10 @@ nlna_attach(device_t dev)
 		    XLR_CACHELINE_SIZE, 0);
 	}
 
+	/* Other per NA s/w initialization */
+	callout_init(&sc->tx_thr, CALLOUT_MPSAFE);
+	callout_reset(&sc->tx_thr, hz, nl_tx_q_wakeup, sc);
+
 	/* Enable NA interrupts */
 	nlna_setup_intr(sc);
 
@@ -655,15 +662,23 @@ nlge_msgring_handler(int bucket, int siz
 	}
 
 	if (ctrl == CTRL_REG_FREE || ctrl == CTRL_JUMBO_FREE) {
-		if (is_p2p) {
-			release_tx_desc(phys_addr);
-		} else {
-			m_freem((struct mbuf *)(uintptr_t)phys_addr);
-		}
-
 		ifp = sc->nlge_if;
-		if (ifp->if_drv_flags & IFF_DRV_OACTIVE){
-			ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+		if (!tx_error) {
+			if (is_p2p) {
+				release_tx_desc(phys_addr);
+			} else {
+				m_freem((struct mbuf *)(uintptr_t)phys_addr);
+			}
+			NLGE_LOCK(sc);
+			if (ifp->if_drv_flags & IFF_DRV_OACTIVE){
+				ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+				callout_reset(&na_sc->tx_thr, hz,
+				    nl_tx_q_wakeup, na_sc);
+			}
+			NLGE_UNLOCK(sc);
+		} else {
+			printf("ERROR: Tx fb error (%d) on port %d\n", tx_error,
+			    port);
 		}
 		atomic_incr_long((tx_error) ? &ifp->if_oerrors: &ifp->if_opackets);
 	} else if (ctrl == CTRL_SNGL || ctrl == CTRL_START) {
@@ -687,7 +702,24 @@ nlge_start(struct ifnet *ifp)
 	nlge_start_locked(ifp, sc);
 	//NLGE_UNLOCK(sc);
 }
-	
+
+static void
+nl_tx_q_wakeup(void *addr)
+{
+	struct nlna_softc *na_sc;
+	struct nlge_softc *sc;
+	int i;
+
+	na_sc = (struct nlna_softc *) addr;
+	for (i = 0; i < XLR_MAX_MACS; i++) { 
+		sc = na_sc->child_sc[i];
+		if (sc == NULL)
+			continue;
+		nlge_start_locked(sc->nlge_if, sc);
+	}
+	callout_reset(&na_sc->tx_thr, 5 * hz, nl_tx_q_wakeup, na_sc);
+}
+
 static void
 nlge_start_locked(struct ifnet *ifp, struct nlge_softc *sc)
 {
@@ -696,20 +728,30 @@ nlge_start_locked(struct ifnet *ifp, str
 	struct nlge_tx_desc 	*tx_desc;
 	uint64_t		fr_stid;
 	uint32_t		cpu;	
-	uint32_t		n_entries;	
+	uint32_t		n_entries;
 	uint32_t		tid;
 	int 			ret;
-	int 			sent;
 
 	cpu = xlr_core_id();	
 	tid = xlr_thr_id();
-	fr_stid = cpu * 8 + tid + 4;
+	/* H/w threads [0, 2] --> bucket 6 and [1, 3] --> bucket 7 */
+	fr_stid = cpu * 8 + 6 + (tid % 2); 
 
 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
 		return;
 	}
 
 	do {
+		/*
+		 * First, remove some freeback messages before transmitting
+		 * any new packets. However, cap the number of messages
+		 * drained to permit this thread to continue with its
+		 * transmission.
+		 *
+		 * Mask for buckets {6, 7} is 0xc0
+		 */
+		xlr_msgring_handler(0xc0, 4);
+
 		/* Grab a packet off the queue. */
 		IF_DEQUEUE(&ifp->if_snd, m);
 		if (m == NULL) {
@@ -721,8 +763,8 @@ nlge_start_locked(struct ifnet *ifp, str
 		if (ret) {
 			goto fail;
 		}
-		sent = send_fmn_msg_tx(sc, &msg, n_entries);
-		if (sent != 0) {
+		ret = send_fmn_msg_tx(sc, &msg, n_entries);
+		if (ret != 0) {
 			goto fail;
 		}
 	} while(1);
@@ -734,20 +776,10 @@ fail:
 		uma_zfree(nl_tx_desc_zone, tx_desc);
 	}
 	if (m != NULL) {
-		/*
-		 * TBD: It is observed that only when both of the statements
-		 * below are not enabled, traffic continues till the end.
-		 * Otherwise, the port locks up in the middle and never
-		 * recovers from it. The current theory for this behavior
-		 * is that the queue is full and the upper layer is neither
-		 * able to add to it not invoke nlge_start to drian the
-		 * queue. The driver may have to do something in addition
-		 * to reset'ing the OACTIVE bit when a trasnmit free-back
-		 * is received.
-		 */
-		//ifp->if_drv_flags |= IFF_DRV_OACTIVE;
-		//IF_PREPEND(&ifp->if_snd, m);
-		m_freem(m);
+		NLGE_LOCK(sc);
+		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+		NLGE_UNLOCK(sc);
+		IF_PREPEND(&ifp->if_snd, m);
 		atomic_incr_long(&ifp->if_iqdrops);
 	}
 	return;
@@ -1020,7 +1052,7 @@ nlna_submit_rx_free_desc(struct nlna_sof
 			msgrng_flags = msgrng_access_enable();
 			ret = message_send(1, code, stid, &msg);
 			msgrng_restore(msgrng_flags);
-			KASSERT(n++ < 100000, ("Too many credit fails\n"));
+			KASSERT(n++ < 100000, ("Too many credit fails in rx path\n"));
 		} while (ret != 0);
 	}
 }
@@ -1942,9 +1974,14 @@ send_fmn_msg_tx(struct nlge_softc *sc, s
 		ret = message_send(n_entries, MSGRNG_CODE_MAC,
 		    sc->tx_bucket_id, msg);
 		msgrng_restore(msgrng_flags);
-		KASSERT(i++ < 100000, ("Too many credit fails\n"));
-	} while (ret != 0);
-	return (0);
+		if (ret == 0)
+			return (0);
+		i++;
+	} while (i < 100000);
+
+	KASSERT(i < 100000, ("Too many credit fails in tx path\n"));
+
+	return (1);
 }
 
 static void

Modified: head/sys/mips/rmi/dev/nlge/if_nlge.h
==============================================================================
--- head/sys/mips/rmi/dev/nlge/if_nlge.h	Fri Sep 17 09:50:36 2010	(r212789)
+++ head/sys/mips/rmi/dev/nlge/if_nlge.h	Fri Sep 17 10:28:10 2010	(r212790)
@@ -1110,6 +1110,7 @@ struct nlna_softc {
         int		mac_type;
         xlr_reg_t	*base;
 
+	struct callout 	tx_thr;
 	struct fr_desc *frin_spill;
 	struct fr_desc *frout_spill;
 	union rx_tx_desc *class_0_spill;

Modified: head/sys/mips/rmi/fmn.c
==============================================================================
--- head/sys/mips/rmi/fmn.c	Fri Sep 17 09:50:36 2010	(r212789)
+++ head/sys/mips/rmi/fmn.c	Fri Sep 17 10:28:10 2010	(r212790)
@@ -60,11 +60,6 @@ __FBSDID("$FreeBSD$");
 #include <mips/rmi/pic.h>
 #include <mips/rmi/board.h>
 
-void 
-disable_msgring_int(void *arg);
-void 
-enable_msgring_int(void *arg);
-
 /* definitions */
 struct tx_stn_handler {
 	void (*action) (int, int, int, int, struct msgrng_msg *, void *);
@@ -101,14 +96,12 @@ do { \
 static struct mtx msgrng_lock;
 static int msgring_int_enabled;
 static int msgring_pop_num_buckets;
-static uint32_t msgring_pop_bucket_mask;
+static uint8_t msgring_pop_bucket_mask;
 static int msgring_int_type;
 static int msgring_watermark_count;
 static uint32_t msgring_thread_mask;
 uint32_t msgrng_msg_cycles = 0;
 
-void xlr_msgring_handler(struct trapframe *);
-
 void 
 xlr_msgring_cpu_init(void)
 {
@@ -174,28 +167,34 @@ xlr_msgring_config(void)
 	msgring_thread_mask = 0x01;
 }
 
-void 
-xlr_msgring_handler(struct trapframe *tf)
+/*
+ * Drain out max_messages for the buckets set in the bucket mask. 
+ * Use max_messages = 0 to drain out all messages.
+ */
+uint32_t
+xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages)
 {
-	unsigned long mflags;
 	int bucket = 0;
 	int size = 0, code = 0, rx_stid = 0, tx_stid = 0;
 	struct msgrng_msg msg;
-	unsigned int bucket_empty_bm = 0;
+	uint8_t bucket_empty_bm = 0;
 	unsigned int status = 0;
+	unsigned long mflags;
+	uint32_t  n_msgs;
 
+	n_msgs = 0;
 	mflags = msgrng_access_enable();
-
 	/* First Drain all the high priority messages */
 	for (;;) {
-		bucket_empty_bm = (msgrng_read_status() >> 24) & msgring_pop_bucket_mask;
+		bucket_empty_bm = (msgrng_read_status() >> 24) & bucket_mask;
 
 		/* all buckets empty, break */
-		if (bucket_empty_bm == msgring_pop_bucket_mask)
+		if (bucket_empty_bm == bucket_mask)
 			break;
 
 		for (bucket = 0; bucket < msgring_pop_num_buckets; bucket++) {
-			if ((bucket_empty_bm & (1 << bucket)) /* empty */ )
+			if (!((1 << bucket) & bucket_mask)        /* bucket not in mask */
+			    || (bucket_empty_bm & (1 << bucket))) /* empty */
 				continue;
 
 			status = message_receive(bucket, &size, &code, &rx_stid, &msg);
@@ -203,6 +202,7 @@ xlr_msgring_handler(struct trapframe *tf
 				continue;
 
 			tx_stid = xlr_board_info.msgmap[rx_stid];
+			n_msgs++;
 
 			if (!tx_stn_handlers[tx_stid].action) {
 				printf("[%s]: No Handler for message from stn_id=%d, bucket=%d, "
@@ -215,13 +215,19 @@ xlr_msgring_handler(struct trapframe *tf
 				    &msg, tx_stn_handlers[tx_stid].dev_id);
 				mflags = msgrng_access_enable();
 			}
+			if (max_messages > 0 && n_msgs >= max_messages)
+				goto done;
 		}
 	}
+
+done:
 	msgrng_restore(mflags);
+
+	return (n_msgs);
 }
 
-void 
-enable_msgring_int(void *arg)
+static void 
+enable_msgring_int(void)
 {
 	uint32_t config, mflags;
 
@@ -232,8 +238,8 @@ enable_msgring_int(void *arg)
 	msgrng_restore(mflags);
 }
 
-void 
-disable_msgring_int(void *arg)
+static void 
+disable_msgring_int(void)
 {
 	uint32_t config, mflags;
 
@@ -259,7 +265,7 @@ msgring_process_fast_intr(void *arg)
 	 * Interrupt thread will enable the interrupts after processing all
 	 * messages
 	 */
-	disable_msgring_int(NULL);
+	disable_msgring_int();
 	atomic_store_rel_int(&it->i_pending, 1);
 	thread_lock(td);
 	if (TD_AWAITING_INTR(td)) {
@@ -291,7 +297,7 @@ msgring_process(void *arg)
 
 	atomic_store_rel_ptr((volatile uintptr_t *)&msgring_ithreads[ithd->i_core],
 	     (uintptr_t)arg);
-	enable_msgring_int(NULL);
+	enable_msgring_int();
 	
 	while (1) {
 		while (ithd->i_pending) {
@@ -300,9 +306,9 @@ msgring_process(void *arg)
 			 * make sure that this write posts before any of the
 			 * memory or device accesses in the handlers.
 			 */
-			xlr_msgring_handler(NULL);
+			xlr_msgring_handler(msgring_pop_bucket_mask, 0);
 			atomic_store_rel_int(&ithd->i_pending, 0);
-			enable_msgring_int(NULL);
+			enable_msgring_int();
 		}
 		if (!ithd->i_pending) {
 			thread_lock(td);

Modified: head/sys/mips/rmi/msgring.h
==============================================================================
--- head/sys/mips/rmi/msgring.h	Fri Sep 17 09:50:36 2010	(r212789)
+++ head/sys/mips/rmi/msgring.h	Fri Sep 17 10:28:10 2010	(r212790)
@@ -386,10 +386,11 @@ enum {
 	MAX_TX_STNS
 };
 
-extern int register_msgring_handler(int major,
+int register_msgring_handler(int major,
     void (*action) (int, int, int, int, struct msgrng_msg *, void *),
     void *dev_id);
-extern void xlr_msgring_cpu_init(void);
-extern void xlr_msgring_config(void);
+uint32_t xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages);
+void xlr_msgring_cpu_init(void);
+void xlr_msgring_config(void);
 
 #endif


More information about the svn-src-head mailing list