Index: c/src/libchip/network/sonic.c
===================================================================
--- c/src/libchip/network/sonic.c	(revision d8ff79366bb0f4646436e4c298e4f5505a51c007)
+++ c/src/libchip/network/sonic.c	(revision f1f42b454dc955624d7bb2d78c0c9718c814a24b)
@@ -24,4 +24,13 @@
  *
  *  $Id$
+ *
+ *  This driver was originally written and tested on a DY-4 DMV177,
+ *  which had a 100 Mhz PPC603e.
+ *
+ *  This driver also works with DP83934CVUL-20/25 MHz, tested on
+ *  Tharsys ERC32 VME board. 
+ *
+ *  Rehaul to fix lost interrupts and buffers, and to use to use 
+ *  interrupt-free transmission by Jiri, 22/03/1999.
  */
 
@@ -51,33 +60,4 @@
 
 void *set_vector(void *, unsigned32, unsigned32);
-
-/*
- * Debug levels
- *
- */
-
-#define SONIC_DEBUG_NONE                0x0000
-#define SONIC_DEBUG_ALL                 0xFFFF
-#define SONIC_DEBUG_PRINT_REGISTERS     0x0001
-#define SONIC_DEBUG_MEMORY              0x0002
-#define SONIC_DEBUG_MEMORY_ALLOCATE     0x0004
-#define SONIC_DEBUG_MEMORY_DESCRIPTORS  0x0008
-#define SONIC_DEBUG_FRAGMENTS           0x0008
-#define SONIC_DEBUG_CAM                 0x0010
-#define SONIC_DEBUG_DESCRIPTORS         0x0020
-#define SONIC_DEBUG_ERRORS              0x0040
-#define SONIC_DEBUG_DUMP_TX_MBUFS       0x0080
-#define SONIC_DEBUG_DUMP_RX_MBUFS       0x0100
-
-#define SONIC_DEBUG_DUMP_MBUFS \
-  (SONIC_DEBUG_DUMP_TX_MBUFS|SONIC_DEBUG_DUMP_RX_MBUFS)
-
-#define SONIC_DEBUG  (SONIC_DEBUG_ERRORS)
-
-/*
-  ((SONIC_DEBUG_ALL) & ~(SONIC_DEBUG_PRINT_REGISTERS|SONIC_DEBUG_DUMP_MBUFS))
-  ((SONIC_DEBUG_ALL) & ~(SONIC_DEBUG_DUMP_MBUFS))
-*/
-
 
 #if (SONIC_DEBUG & SONIC_DEBUG_DUMP_MBUFS)
@@ -202,5 +182,4 @@
   TransmitDescriptorPointer_t     tdaHead;  /* Last filled */
   TransmitDescriptorPointer_t     tdaTail;  /* Next to retire */
-  int                             tdaActiveCount;
 
   /*
@@ -300,4 +279,47 @@
 }
 
+void sonic_disable_interrupts(
+  struct sonic_softc *sc,
+  unsigned32  mask
+)
+{
+  void *rp = sc->sonic;
+  rtems_interrupt_level level;
+
+  rtems_interrupt_disable( level );
+  (*sc->write_register)(
+         rp,
+         SONIC_REG_IMR,
+         (*sc->read_register)(rp, SONIC_REG_IMR) & ~mask
+      );
+  rtems_interrupt_enable( level );
+}
+
+void sonic_clear_interrupts(
+  struct sonic_softc *sc,
+  unsigned32  mask
+)
+{
+  void *rp = sc->sonic;
+  rtems_interrupt_level level;
+
+  rtems_interrupt_disable( level );
+  (*sc->write_register)( rp, SONIC_REG_ISR, mask);
+  rtems_interrupt_enable( level );
+}
+
+void sonic_command(
+  struct sonic_softc *sc,
+  unsigned32  mask
+)
+{
+  void *rp = sc->sonic;
+  rtems_interrupt_level level;
+
+  rtems_interrupt_disable( level );
+  (*sc->write_register)( rp, SONIC_REG_CR, mask);
+  rtems_interrupt_enable( level );
+}
+
 /*
  * Allocate non-cacheable memory on a single 64k page.
@@ -335,5 +357,4 @@
 SONIC_STATIC void sonic_stop (struct sonic_softc *sc)
 {
-  void *rp = sc->sonic;
   struct ifnet *ifp = &sc->arpcom.ac_if;
 
@@ -343,5 +364,5 @@
    * Stop the transmitter and receiver.
    */
-  (*sc->write_register)( rp, SONIC_REG_CR, CR_HTX | CR_RXDIS );
+  sonic_command(sc, CR_HTX | CR_RXDIS );
 }
 
@@ -410,22 +431,23 @@
    * Packet received or receive buffer area exceeded?
    */
-  if ((imr & (IMR_PRXEN | IMR_RBAEEN)) &&
-      (isr & (ISR_PKTRX | ISR_RBAE))) {
+  if (imr & isr & (IMR_PRXEN | IMR_RBAEEN)) {
     imr &= ~(IMR_PRXEN | IMR_RBAEEN);
     sc->rxInterrupts++;
     rtems_event_send (sc->rxDaemonTid, INTERRUPT_EVENT);
+    (*sc->write_register)( rp, SONIC_REG_IMR, imr );
+    (*sc->write_register)( rp, SONIC_REG_ISR, isr & ISR_PKTRX );
   }
 
   /*
    * Packet started, transmitter done or transmitter error?
-   */
-  if ((imr & (IMR_PINTEN | IMR_PTXEN | IMR_TXEREN)) &&
-      (isr & (ISR_PINT | ISR_TXDN | ISR_TXER))) {
-    imr &= ~(IMR_PINTEN | IMR_PTXEN | IMR_TXEREN);
+   * TX interrupts only occur after an error or when all TDA's are
+   * exhausted and we are waiting for buffer to come free.
+   */
+  if (imr & isr & (IMR_PINTEN | IMR_TXEREN)) {
     sc->txInterrupts++;
     rtems_event_send (sc->txDaemonTid, INTERRUPT_EVENT);
-  }
-
-  (*sc->write_register)( rp, SONIC_REG_IMR, imr );
+    (*sc->write_register)( rp, SONIC_REG_ISR, ISR_PINT | ISR_TXDN | ISR_TXER );
+  }
+
 }
 
@@ -451,6 +473,5 @@
    * Repeat for all completed transmit descriptors.
    */
-  while ((sc->tdaActiveCount != 0)
-      && ((status = sc->tdaTail->status) != 0)) {
+  while ((status = sc->tdaTail->status) != 0) {
 
 #if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS)
@@ -491,5 +512,5 @@
 
         (*sc->write_register)( rp, SONIC_REG_CTDA, link );
-        (*sc->write_register)( rp, SONIC_REG_CR, CR_TXP );
+        sonic_command(sc, CR_TXP );
       }
     }
@@ -522,5 +543,4 @@
      *  Free the packet and reset a couple of fields
      */
-    sc->tdaActiveCount--;
     m = sc->tdaTail->mbufp;
     while ( m ) {
@@ -529,6 +549,9 @@
     }
 
+    /*
     sc->tdaTail->frag[0].frag_link = LSW(sc->tdaTail->link_pad);
     sc->tdaTail->frag_count        = 0;
+    */
+    sc->tdaTail->status        = 0;
 
     /*
@@ -548,5 +571,4 @@
 {
   struct sonic_softc *sc = ifp->if_softc;
-  void *rp = sc->sonic;
   struct mbuf *l = NULL;
   TransmitDescriptorPointer_t tdp;
@@ -554,55 +576,44 @@
   unsigned int packetSize;
   int i;
+  rtems_event_set events;
   static char padBuf[64];
 
   /* printf( "sonic_sendpacket %p\n", m ); */
-  /*
-   * Free up transmit descriptors.
-   */
-  sonic_retire_tda (sc);
-
-  /*
-   * Wait for transmit descriptor to become available.
-   */
-  if (sc->tdaActiveCount == sc->tdaCount) {
+
+
+  /*
+   * Wait for transmit descriptor to become available. Only retire TDA's
+   * if there are no more free buffers to minimize TX latency. Retire TDA'a
+   * on the way out.
+   */
+
+  while (sc->tdaHead->next->status != 0) {
+  
+  /*
+   * Free up transmit descriptors
+   */
+    sonic_retire_tda (sc);
+
+    if (sc->tdaHead->next->status == 0) 
+      break;
+
 #if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
-    puts( "Wait for more TDAs" );
-#endif
-
-    /*
-     * Clear old events.
-     */
-    (*sc->write_register)( rp, SONIC_REG_ISR, ISR_PINT | ISR_TXDN | ISR_TXER );
-
-    /*
-     * Wait for transmit descriptor to become available.
-     * Note that the transmit descriptors are checked
-     * *before* * entering the wait loop -- this catches
-     * the possibility that a transmit descriptor became
-     * available between the `if' the started this block,
-     * and the clearing of the interrupt status register.
-     */
-    sonic_retire_tda (sc);
-    while (sc->tdaActiveCount == sc->tdaCount) {
-      rtems_event_set events;
-
-#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
-      printf("blocking until TDAs are available\n");
+    printf("blocking until TDAs are available\n");
 #endif
       /*
-       * Enable transmitter interrupts.
+       * Enable PINT interrupts.
+    sonic_clear_interrupts( sc, ISR_PINT );
+    sonic_enable_interrupts( sc, IMR_PINTEN );
        */
-      sonic_enable_interrupts( sc, (IMR_PINTEN | IMR_PTXEN | IMR_TXEREN) );
 
       /*
-       * Wait for interrupt
+       * Wait for PINT TX interrupt. Every fourth TX buffer will raise PINT.
        */
-      rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+    rtems_bsdnet_event_receive (INTERRUPT_EVENT,
             RTEMS_WAIT|RTEMS_EVENT_ANY,
             RTEMS_NO_TIMEOUT,
             &events);
-      (*sc->write_register)( rp, SONIC_REG_ISR, ISR_PINT | ISR_TXDN | ISR_TXER );
-      sonic_retire_tda (sc);
-    }
+    sonic_disable_interrupts( sc, IMR_PINTEN );
+    sonic_retire_tda (sc);
   }
 
@@ -686,10 +697,14 @@
   if ( sc->tdaHead->frag_count )
     *sc->tdaHead->linkp &= ~TDA_LINK_EOL;
-  sc->tdaActiveCount++;
   sc->tdaHead = tdp;
 
-/* XXX not in KA9Q */
-  sonic_enable_interrupts( sc, (IMR_PINTEN | IMR_PTXEN | IMR_TXEREN) );
-  (*sc->write_register)( rp, SONIC_REG_CR, CR_TXP );
+  /* Start transmission */
+
+  sonic_command(sc, CR_TXP );
+
+  /*
+   * Free up transmit descriptors on the way out.
+   */
+  sonic_retire_tda (sc);
 }
 
@@ -837,12 +852,7 @@
        * Restart reception
        */
-      (*sc->write_register)( rp, SONIC_REG_ISR, ISR_RBAE );
-      (*sc->write_register)( rp, SONIC_REG_CR, CR_RXEN );
+      sonic_clear_interrupts( sc, ISR_RBAE );
+      sonic_command( sc, CR_RXEN );
     }
-
-    /*
-     * Clear old packet-received events.
-     */
-    (*sc->write_register)( rp, SONIC_REG_ISR, ISR_PKTRX );
 
     /*
@@ -934,5 +944,10 @@
 #if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS)
       sonic_print_rx_descriptor( rdp );
-#endif
+      if ((LSW(rdp->mbufp->m_data) != rdp->pkt_lsw)
+       || (MSW(rdp->mbufp->m_data) != rdp->pkt_msw))
+        printf ("SONIC RDA/RRA %p, %08x\n",rdp->mbufp->m_data,(rdp->pkt_msw << 16) | 
+	(rdp->pkt_lsw & 0x0ffff));
+#endif
+      rdp->byte_count &= 0x0ffff;    /* ERC32 pollutes msb of byte_count */
       m = rdp->mbufp;
       m->m_len = m->m_pkthdr.len = rdp->byte_count -
@@ -942,4 +957,8 @@
       m->m_data += sizeof(struct ether_header);
   
+#ifdef CPU_U32_FIX
+      ipalign(m);	/* Align packet on 32-bit boundary */
+#endif
+
 #if (SONIC_DEBUG & SONIC_DEBUG_DUMP_RX_MBUFS)
       Dump_Buffer( (void *) eh, sizeof(struct ether_header) );
@@ -948,5 +967,11 @@
 
       /* printf( "ether_input %p\n", m ); */
+      /*
+      printf( "pkt %p, seq %04x, mbuf %p, m_data %p\n", rdp, rdp->seq_no, m, m->m_data );
+      printf( "%u, %u\n", ((int*)m->m_data)[6], ((int*)m->m_data)[7]);
+      */
       ether_input (ifp, eh, m);
+      /*
+      */
 
       /*
@@ -996,5 +1021,5 @@
        */
       if ((*sc->read_register)( rp, SONIC_REG_ISR ) & ISR_RBE)
-        (*sc->write_register)( rp, SONIC_REG_ISR, ISR_RBE );
+      sonic_clear_interrupts( sc, ISR_RBE );
     }
     else {
@@ -1017,10 +1042,12 @@
 
     /*
-     * Move to next receive descriptor
-     */
-
+     * Move to next receive descriptor and update EOL
+     */
+
+    rdp->link |= RDA_LINK_EOL;
     rdp->in_use = RDA_FREE;
+    sc->rdp_last->link &= ~RDA_LINK_EOL;
+    sc->rdp_last = rdp;
     rdp = rdp->next;
-    rdp->link &= ~RDA_LINK_EOL;
 
   }
@@ -1059,5 +1086,5 @@
    */
 
-  if ( (*sc->read_register)( rp, SONIC_REG_SR ) < SONIC_REVISION_C ) {
+  if ( (*sc->read_register)( rp, SONIC_REG_SR ) <= SONIC_REVISION_B ) {
     rtems_fatal_error_occurred( 0x0BADF00D );  /* don't eat this part :) */
   }
@@ -1071,5 +1098,4 @@
    */
 
-  sc->tdaActiveCount = 0;
   sc->tdaTail = sonic_allocate(sc->tdaCount * sizeof *tdp);
 #if (SONIC_DEBUG & SONIC_DEBUG_MEMORY)
@@ -1088,13 +1114,14 @@
 
 /* XXX not used by the BSD drivers
+    tdp->frag[0].frag_link = LSW(tdp + 1);
 */
-    if (i & 1)
+    if (i & 3)
       tdp->pkt_config = TDA_CONFIG_PINT;
 
-    tdp->frag_count        = 0;
-    tdp->frag[0].frag_link = LSW(tdp + 1);
-    tdp->link_pad          = LSW(tdp + 1) | TDA_LINK_EOL;
-    tdp->linkp             = &((tdp + 1)->frag[0].frag_link);
-    tdp->next              = (TransmitDescriptor_t *)(tdp + 1);
+    tdp->status 	= 0;
+    tdp->frag_count     = 0;
+    tdp->link_pad       = LSW(tdp + 1) | TDA_LINK_EOL;
+    tdp->linkp          = &((tdp + 1)->frag[0].frag_link);
+    tdp->next           = (TransmitDescriptor_t *)(tdp + 1);
 #if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS)
     sonic_print_tx_descriptor( tdp );
@@ -1143,5 +1170,5 @@
   ordp->next   = sc->rda;
   ordp->link   = LSW(sc->rda) | RDA_LINK_EOL;
-  sc->rdp_last = rdp;
+  sc->rdp_last = ordp;
  
   /*
@@ -1320,5 +1347,4 @@
         (*sc->read_register)( rp, SONIC_REG_CAP0 ),
         (*sc->read_register)( rp, SONIC_REG_CE ));
-#endif
 
   (*sc->write_register)( rp, SONIC_REG_CEP, 0 );  /* Select first entry in CAM */
@@ -1337,4 +1363,5 @@
     rtems_panic ("SONIC LCAM");
   }
+#endif
 
   (*sc->write_register)(rp, SONIC_REG_CR, /* CR_TXP | */CR_RXEN | CR_STP);
@@ -1387,6 +1414,6 @@
      * Start driver tasks
      */
+    sc->rxDaemonTid = rtems_bsdnet_newproc ("SNrx", 4096, sonic_rxDaemon, sc);
     sc->txDaemonTid = rtems_bsdnet_newproc ("SNtx", 4096, sonic_txDaemon, sc);
-    sc->rxDaemonTid = rtems_bsdnet_newproc ("SNrx", 4096, sonic_rxDaemon, sc);
   }
 
@@ -1409,9 +1436,6 @@
    * Enable receiver and transmitter
    */
-  /* (*sc->write_register)( rp, SONIC_REG_IMR, 0 ); */
-  sonic_enable_interrupts( sc,
-        (IMR_PINTEN | IMR_PTXEN | IMR_TXEREN) | (IMR_PRXEN | IMR_RBAEEN) );
-
-  (*sc->write_register)(rp, SONIC_REG_CR, /* CR_TXP | */ CR_RXEN);
+  sonic_enable_interrupts( sc, IMR_TXEREN | (IMR_PRXEN | IMR_RBAEEN) );
+  sonic_command( sc, CR_RXEN );
 }
 
