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"