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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to