$NetBSD: patch-az,v 1.1 2007/03/17 13:44:19 tsutsui Exp $

--- ic/i825x6.c.orig	2007-03-15 20:29:47.000000000 +0900
+++ ic/i825x6.c	2007-03-17 22:07:48.000000000 +0900
@@ -809,6 +809,9 @@
 	 | TME_I825X6_SCB_CUS_IDLE
 	 | TME_I825X6_SCB_RUS_IDLE);
     
+    /* clears the SCB command word": */
+    /* [this is done at end of this routine] */
+
     /* "The 82596 ... sends an interrupt to the CPU": */
     i825x6->tme_i825x6_callout_flags = TME_I825X6_CALLOUTS_RUNNING | TME_I825X6_CALLOUT_INT;
   }
@@ -1258,8 +1261,10 @@
     break;
 
   case TME_I825X6_CB_CMD_DUMP:
-  case TME_I825X6_CB_CMD_DIAGNOSE:
     abort();
+
+  case TME_I825X6_CB_CMD_DIAGNOSE:
+    break;
   }
   
   /* add to the callouts and return the current status: */
@@ -1898,7 +1903,7 @@
   tme_uint16_t c_b_ok_a;
   tme_uint16_t value16;
   tme_uint32_t value32;
-  int rc, err;
+  int rc, err, tot_length;
 
   /* recover our data structures: */
   i825x6 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private;
@@ -1919,7 +1924,7 @@
   tme_mutex_lock(&i825x6->tme_i825x6_mutex);
 
   /* assume that we will have no packet to transmit: */
-  rc = 0;
+  tot_length = 0;
 
   /* if we have a packet to transmit: */
   if ((i825x6->tme_i825x6_el_s_i_cmd
@@ -1934,10 +1939,10 @@
 #define CHUNKS_DMA_TX(addr, size)						\
       err = _tme_i825x6_chunks_dma_tx(i825x6, frame_chunks, (addr), (size));	\
       if (err != TME_OK) break;							\
-      rc += size
+      tot_length += size
 #define CHUNKS_MEM_TX(data, size)						\
       _tme_i825x6_chunks_mem_tx(frame_chunks, (data), (size));			\
-      rc += size
+      tot_length += size
 
       /* if AL-LOC is set to zero, add the Ethernet/802.3 MAC header: */
       if (i825x6->tme_i825x6_al_loc == 0) {
@@ -1973,7 +1978,7 @@
 	CHUNKS_DMA_TX(tb_address,
 		      (eof_size & TME_I82586_TBD_SIZE_MASK));
 
-	/* the next transmit buffer: */
+	/* get out if no next transmit buffer: */
 	if (eof_size & TME_I82586_TBD_EOF) {
 	  break;
 	}
@@ -2022,7 +2027,7 @@
   tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
 
   /* done: */
-  return (rc);
+  return (tot_length);
 }
 
 /* this makes a new Ethernet connection: */
--- host/bsd/bsd-bpf.c.orig2	2006-12-13 08:07:09.000000000 -0500
+++ host/bsd/bsd-bpf.c	2006-12-13 11:38:27.000000000 -0500
@@ -292,7 +292,7 @@
   struct tme_ethernet_connection *conn_eth;
   int callouts, later_callouts;
   unsigned int ctrl;
-  int rc;
+  int rc, status;
   tme_ethernet_fid_t frame_id;
   struct tme_ethernet_frame_chunk frame_chunk_buffer;
   tme_uint8_t frame[TME_ETHERNET_FRAME_MAX];
@@ -372,6 +372,9 @@
 		&frame_id,
 		&frame_chunk_buffer,
 		TME_ETHERNET_READ_NEXT)));
+
+      /* ensure don't get back bad length from i825x6 */
+      assert(rc <= sizeof(frame));
       
       /* lock the mutex: */
       tme_mutex_lock(&bpf->tme_bsd_bpf_mutex);
@@ -380,7 +383,11 @@
       if (rc > 0) {
 
 	/* do the write: */
-	tme_thread_write(bpf->tme_bsd_bpf_fd, frame, rc);
+	status = tme_thread_write(bpf->tme_bsd_bpf_fd, frame, rc);
+
+        /* assert if write failed.  also assert if we wrote less bytes
+           than we commanded */
+        assert (status == rc);
 
 	/* mark that we need to loop to callout to read more frames: */
 	bpf->tme_bsd_bpf_callout_flags |= TME_BSD_BPF_CALLOUT_READ;
--- machine/sun/sun-obie.c.orig	2005-02-17 07:37:25.000000000 -0500
+++ machine/sun/sun-obie.c	2006-12-19 05:34:13.000000000 -0500
@@ -78,7 +78,6 @@
 #define TME_SUN_OBIE_CALLOUT_RUNNING	TME_BIT(0)
 #define TME_SUN_OBIE_CALLOUTS_MASK	(-2)
 #define  TME_SUN_OBIE_CALLOUT_SIGNALS	TME_BIT(1)
-#define	 TME_SUN_OBIE_CALLOUT_INT	TME_BIT(2)
 
 /* structures: */
 
@@ -106,8 +105,15 @@
   /* the callout flags: */
   int tme_sun_obie_callout_flags;
 
-  /* if our interrupt line is currently asserted: */
-  int tme_sun_obie_int_asserted;
+  /* the obie CSR interrupt enable bit has been set since powerup */
+  int csr_ie_has_been_set;
+
+  /* the i825x6 interrupt is currently active to the obie */
+  int i825x6_interrupt_is_active;
+
+  /* the obie interrupt (forward of the i825x6 interrupt) is currently active
+     to the bus */
+  int obie_interrupt_is_active;
 
   /* it's easiest to just model the board registers as a chunk of memory: */
   tme_uint8_t tme_sun_obie_regs[TME_SUN_OBIE_SIZ_REGS];
@@ -137,17 +143,67 @@
 static const struct tme_bus_signals _tme_sun_obie_bus_signals_generic = TME_BUS_SIGNALS_GENERIC;
 static const struct tme_bus_signals _tme_sun_obie_bus_signals_i825x6 = TME_BUS_SIGNALS_I825X6;
 
+
+/* TME originally never set or cleared TME_SUN_OBIE_CSR_INTR in the obie CSR.
+ * This worked fine for running NetBSD inside the emulator, as the NetBSD ie0
+ * driver never checked that bit.  But SunOS 4.1.1 does.
+ * Following is the logic that makes NetBSD and SunOS work inside the
+ * emulator (and therefore is likely close to the logic of the actual OBIE
+ * hardware: The Sun-2 MultiBus Ethernet Controller, part 501-1004).
+ *
+ *  When i825x6 chip asserts/deasserts an interrupt to OBIE:
+ *     1) set or clear TME_SUN_OBIE_CSR_INTR as appropriate
+ *           and, if the TME_SUN_OBIE_IE (interrupt enable) has ever been set:
+ *     2) pass along signal to main bus.
+ *
+ * Note:
+ *  When correcting the TME code to work with SunOS, I originally only
+ *  forwarded the interrupt when IE was active, but SunOS fails five minutes
+ *  after bootup (complaining about level 3 interrupt) with this arrangement.
+ *
+ *  So the actual use of the IE bit remains a mystery.  It is likely sufficient
+ *  to ignore the IE bit and always pass along the i825x6 interrupt to the main
+ *  bus.   But the current "has been set" IE logic allows NetBSD and SunOS to
+ *  fully run ethernet correctly inside the emulator, and that's good enough
+ *  for me.  ART
+ */
+
+static void
+_possibly_set_csr_intr_bit(struct tme_sun_obie *sun_obie)
+{
+  tme_uint16_t csr;
+
+  csr = TME_SUN_OBIE_CSR_GET(sun_obie);
+  sun_obie->csr_ie_has_been_set |=
+                ((csr & TME_SUN_OBIE_CSR_IE) == TME_SUN_OBIE_CSR_IE);
+
+  /* if a change in interrupt status */
+  if (sun_obie->obie_interrupt_is_active != sun_obie->i825x6_interrupt_is_active) {
+
+    /* transition to assert */
+    if (!sun_obie->obie_interrupt_is_active) {
+      csr = (csr | TME_SUN_OBIE_CSR_INTR);
+    }
+
+    /* transition to deassert */
+    else {
+      csr = (csr & ~TME_SUN_OBIE_CSR_INTR);
+    }
+
+    TME_SUN_OBIE_CSR_PUT(sun_obie, csr);
+    sun_obie->obie_interrupt_is_active = sun_obie->i825x6_interrupt_is_active;
+  }
+}
+
 /* the sun_obie callout function.  it must be called with the mutex locked: */
 static void
 _tme_sun_obie_callout(struct tme_sun_obie *sun_obie, int new_callouts)
 {
   struct tme_bus_connection *conn_i825x6;
-  struct tme_bus_connection *conn_bus;
   tme_uint16_t csr, csr_diff;
   unsigned int signal, level;
   int callouts, later_callouts;
   int rc;
-  int int_asserted;
   
   /* add in any new callouts: */
   sun_obie->tme_sun_obie_callout_flags |= new_callouts;
@@ -176,6 +232,8 @@
 
       /* get the current CSR value: */
       csr = TME_SUN_OBIE_CSR_GET(sun_obie);
+      sun_obie->csr_ie_has_been_set |=
+                    ((csr & TME_SUN_OBIE_CSR_IE) == TME_SUN_OBIE_CSR_IE);
 
       /* get the next signal to call out to the i825x6: */
       csr_diff = ((csr
@@ -230,7 +288,10 @@
 		 (conn_i825x6,
 		  signal | level))
 	      : TME_OK);
-	
+
+        /* possibly update status of INTR bit in CSR */
+        _possibly_set_csr_intr_bit(sun_obie);
+
 	/* lock the mutex: */
 	tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
       
@@ -254,55 +315,6 @@
 	}
       }
     }
-
-    /* if we need to call out a possible change to our interrupt
-       signal: */
-    if (callouts & TME_SUN_OBIE_CALLOUT_INT) {
-
-      /* get the current CSR value: */
-      csr = TME_SUN_OBIE_CSR_GET(sun_obie);
-
-      /* see if the interrupt signal should be asserted or negated: */
-      int_asserted = ((csr & (TME_SUN_OBIE_CSR_IE
-			      | TME_SUN_OBIE_CSR_INTR))
-		      == (TME_SUN_OBIE_CSR_IE
-			  | TME_SUN_OBIE_CSR_INTR));
-
-      /* if the interrupt signal doesn't already have the right state: */
-      if (!int_asserted != !sun_obie->tme_sun_obie_int_asserted) {
-
-	/* get our bus connection: */
-	conn_bus = sun_obie->tme_sun_obie_conn_regs;
-	
-	/* unlock our mutex: */
-	tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
-	
-	/* call out the bus interrupt signal edge: */
-	rc = (conn_bus != NULL
-	      ? ((*conn_bus->tme_bus_signal)
-		 (conn_bus,
-		  TME_BUS_SIGNAL_INT_UNSPEC
-		  | (int_asserted
-		     ? TME_BUS_SIGNAL_LEVEL_ASSERTED
-		     : TME_BUS_SIGNAL_LEVEL_NEGATED)))
-	      : TME_OK);
-
-	/* lock our mutex: */
-	tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
-	
-	/* if this callout was successful, note the new state of the
-	   interrupt signal: */
-	if (rc == TME_OK) {
-	  sun_obie->tme_sun_obie_int_asserted = int_asserted;
-	}
-
-	/* otherwise, remember that at some later time this callout
-	   should be attempted again: */
-	else {
-	  later_callouts |= TME_SUN_OBIE_CALLOUT_INT;
-	}
-      }
-    }
   }
   
   /* put in any later callouts, and clear that callouts are running: */
@@ -321,6 +333,9 @@
   /* recover our data structure: */
   sun_obie = (struct tme_sun_obie *) _sun_obie;
 
+  /* possibly update status of INTR bit in CSR */
+  _possibly_set_csr_intr_bit(sun_obie);
+
   /* assume we won't need any new callouts: */
   new_callouts = 0;
 
@@ -329,6 +344,8 @@
 
   /* get the previous CSR value: */
   csr_old = TME_SUN_OBIE_CSR_GET(sun_obie);
+  sun_obie->csr_ie_has_been_set |=
+                ((csr_old & TME_SUN_OBIE_CSR_IE) == TME_SUN_OBIE_CSR_IE);
 
   /* run the cycle: */
   tme_bus_cycle_xfer_memory(cycle_init, 
@@ -354,12 +371,6 @@
     new_callouts |= TME_SUN_OBIE_CALLOUT_SIGNALS;
   }
   
-  /* if this is an interrupt mask change, possibly call out an
-     interrupt signal change to the bus: */
-  if (csr_diff & TME_SUN_OBIE_CSR_IE) {
-    new_callouts |= TME_SUN_OBIE_CALLOUT_INT;
-  }
-  
 #ifndef TME_NO_LOG
   if (csr_new != sun_obie->tme_sun_obie_last_log_csr) {
     sun_obie->tme_sun_obie_last_log_csr = csr_new;
@@ -397,6 +408,15 @@
   /* recover our data structures: */
   sun_obie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
 
+  /* save this information so we'll know it later */
+  sun_obie->i825x6_interrupt_is_active =
+    ((signal & TME_BUS_SIGNAL_LEVEL_ASSERTED) == TME_BUS_SIGNAL_LEVEL_ASSERTED);
+
+  /* return now if interrupt enable has never been set in CSR */
+  if (!sun_obie->csr_ie_has_been_set) {
+    return (TME_OK);
+  }
+
   /* pass the i825x6's signal through to the obio bus: */
   conn_bus = sun_obie->tme_sun_obie_conn_regs;
   return (conn_bus != NULL
--- ic/i825x6reg.h.orig	2006-12-13 08:27:48.000000000 -0500
+++ ic/i825x6reg.h	2006-12-13 08:28:27.000000000 -0500
@@ -156,7 +156,7 @@
 /* the i82586 and 32-bit segmented i82586 Transmit Buffer: */
 #define TME_I82586_TBD_EOF_SIZE		(0)
 #define  TME_I82586_TBD_EOF		 (0x8000)
-#define  TME_I82586_TBD_SIZE_MASK	 (0x7fff)
+#define  TME_I82586_TBD_SIZE_MASK	 (0x3fff)
 #define TME_I82586_TBD_TBD_OFFSET	(2)
 #define TME_I82586_TBD_TB_ADDRESS	(4)
 
