summaryrefslogtreecommitdiffstats
path: root/sys/mips/rmi
diff options
context:
space:
mode:
authorjchandra <jchandra@FreeBSD.org>2010-09-17 10:28:10 +0000
committerjchandra <jchandra@FreeBSD.org>2010-09-17 10:28:10 +0000
commitb87e4d6669f1ce72b815d534824efb7657aee725 (patch)
tree565e2e12fd7d832f82266f347ef3515600159da1 /sys/mips/rmi
parenteffc08cc6c7d97fab3424610eacade38dba594d2 (diff)
downloadFreeBSD-src-b87e4d6669f1ce72b815d534824efb7657aee725.zip
FreeBSD-src-b87e4d6669f1ce72b815d534824efb7657aee725.tar.gz
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)
Diffstat (limited to 'sys/mips/rmi')
-rw-r--r--sys/mips/rmi/dev/nlge/if_nlge.c101
-rw-r--r--sys/mips/rmi/dev/nlge/if_nlge.h1
-rw-r--r--sys/mips/rmi/fmn.c54
-rw-r--r--sys/mips/rmi/msgring.h7
4 files changed, 104 insertions, 59 deletions
diff --git a/sys/mips/rmi/dev/nlge/if_nlge.c b/sys/mips/rmi/dev/nlge/if_nlge.c
index 1a217c0..46d9286 100644
--- a/sys/mips/rmi/dev/nlge/if_nlge.c
+++ b/sys/mips/rmi/dev/nlge/if_nlge.c
@@ -207,6 +207,9 @@ static void release_tx_desc(vm_paddr_t phy_addr);
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 size, int code, int stid,
}
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, struct nlge_softc *sc)
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, struct nlge_softc *sc)
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_softc *sc, uint32_t n_desc)
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, struct msgrng_msg *msg,
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
diff --git a/sys/mips/rmi/dev/nlge/if_nlge.h b/sys/mips/rmi/dev/nlge/if_nlge.h
index 0347071..39450fb 100644
--- a/sys/mips/rmi/dev/nlge/if_nlge.h
+++ b/sys/mips/rmi/dev/nlge/if_nlge.h
@@ -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;
diff --git a/sys/mips/rmi/fmn.c b/sys/mips/rmi/fmn.c
index f10d3ff..f55f39f 100644
--- a/sys/mips/rmi/fmn.c
+++ b/sys/mips/rmi/fmn.c
@@ -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);
diff --git a/sys/mips/rmi/msgring.h b/sys/mips/rmi/msgring.h
index ae3d9d4..c55d0de 100644
--- a/sys/mips/rmi/msgring.h
+++ b/sys/mips/rmi/msgring.h
@@ -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
OpenPOWER on IntegriCloud