added intermediate driver for connecting lance ethernet to sun3 obio
diff --git a/machine/sun/Makefile.am b/machine/sun/Makefile.am
index ba80a5c..2255c01 100644
--- a/machine/sun/Makefile.am
+++ b/machine/sun/Makefile.am
@@ -12,7 +12,8 @@
sun-cgsix.c \
sun-fb.c sun-fb.h \
sun-si.c \
- sun-obie.c
+ sun-obie.c \
+ sun-oble.c
libtme_machine_sun_la_LDFLAGS = -version-info 0:0:0
libtme_machine_sun_la_LIBADD = $(top_builddir)/libtme/libtme.la \
$(top_builddir)/generic/libtme-generic.la
diff --git a/machine/sun/Makefile.in b/machine/sun/Makefile.in
index 2fc51d1..f1e4f9e 100644
--- a/machine/sun/Makefile.in
+++ b/machine/sun/Makefile.in
@@ -77,7 +77,8 @@
libtme_machine_sun_la_DEPENDENCIES = $(top_builddir)/libtme/libtme.la \
$(top_builddir)/generic/libtme-generic.la
am_libtme_machine_sun_la_OBJECTS = sun-mmu.lo sun-bwtwo.lo \
- sun-cgtwo.lo sun-cgsix.lo sun-fb.lo sun-si.lo sun-obie.lo
+ sun-cgtwo.lo sun-cgsix.lo sun-fb.lo sun-si.lo sun-obie.lo \
+ sun-oble.lo
libtme_machine_sun_la_OBJECTS = $(am_libtme_machine_sun_la_OBJECTS)
libtme_machine_sun_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -250,7 +251,8 @@
sun-cgsix.c \
sun-fb.c sun-fb.h \
sun-si.c \
- sun-obie.c
+ sun-obie.c \
+ sun-oble.c
libtme_machine_sun_la_LDFLAGS = -version-info 0:0:0
libtme_machine_sun_la_LIBADD = $(top_builddir)/libtme/libtme.la \
@@ -374,6 +376,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-fb.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-mmu.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-obie.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-oble.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-si.Plo@am__quote@
.c.o:
diff --git a/machine/sun/sun-oble.c b/machine/sun/sun-oble.c
new file mode 100644
index 0000000..5942200
--- /dev/null
+++ b/machine/sun/sun-oble.c
@@ -0,0 +1,490 @@
+/* $Id:$ */
+
+/* machine/sun/sun-oble.c - classic Sun onboard Lance Ethernet implementation: */
+
+/*
+ * Copyright (c) 2012 Thomas Bogendoerfer
+ * All rights reserved.
+ *
+ * Based on sun-obie.c, Copyright (c) 2004 Matt Fredette
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Matt Fredette.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tme/common.h>
+_TME_RCSID("$Id$");
+
+/* includes: */
+#include <tme/element.h>
+#undef TME_BUS_VERSION
+#define TME_BUS_VERSION TME_X_VERSION(0, 0)
+#include <tme/generic/bus.h>
+#include <tme/machine/sun.h>
+
+/* macros: */
+
+/* register offsets and sizes: */
+#define TME_SUN_OBLE_REG_CSR (0)
+#define TME_SUN_OBLE_SIZ_CSR (4)
+
+/* structures: */
+
+/* the card: */
+struct tme_sun_oble {
+
+ /* backpointer to our element: */
+ struct tme_element *tme_sun_oble_element;
+
+ /* the mutex protecting the card: */
+ tme_mutex_t tme_sun_oble_mutex;
+
+ /* the bus connection for the card's registers: */
+ struct tme_bus_connection *tme_sun_oble_conn_regs;
+
+ /* the bus connection for the card's memory: */
+ struct tme_bus_connection *tme_sun_oble_conn_memory;
+
+ /* the bus connection for the card's am7990 chip: */
+ struct tme_bus_connection *tme_sun_oble_conn_am7990;
+};
+
+/* a sun_oble internal bus connection: */
+struct tme_sun_oble_connection {
+
+ /* the external bus connection: */
+ struct tme_bus_connection tme_sun_oble_connection;
+
+ /* this is nonzero if a TME_CONNECTION_BUS_GENERIC chip connection
+ is for the registers: */
+ tme_uint8_t tme_sun_oble_connection_regs;
+};
+
+/* globals: */
+
+/* our bus signals sets: */
+static const struct tme_bus_signals _tme_sun_oble_bus_signals_generic = TME_BUS_SIGNALS_GENERIC;
+
+/* the sun_oble bus signal handler: */
+static int
+_tme_sun_oble_bus_signal(struct tme_bus_connection *conn_bus,
+ unsigned int signal)
+{
+ struct tme_bus_connection *conn_out_bus;
+ struct tme_sun_oble *sun_oble;
+ int rc;
+
+ /* return now if this is not a generic bus signal: */
+ if (TME_BUS_SIGNAL_INDEX(signal)
+ > _tme_sun_oble_bus_signals_generic.tme_bus_signals_count) {
+ return (TME_OK);
+ }
+
+ /* recover our data structures: */
+ sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+
+ /* if this bus signal is from the am7990: */
+ if (conn_bus->tme_bus_connection.tme_connection_other
+ == &sun_oble->tme_sun_oble_conn_am7990->tme_bus_connection) {
+
+ /* this must be the unspecified interrupt signal: */
+ assert (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_INT_UNSPEC);
+
+ /* get outgoing bus connection: */
+ conn_out_bus = sun_oble->tme_sun_oble_conn_regs;
+
+ }
+
+ /* otherwise, this bus signal must be from obio: */
+ else {
+ assert (conn_bus->tme_bus_connection.tme_connection_other
+ == &sun_oble->tme_sun_oble_conn_regs->tme_bus_connection);
+
+ conn_out_bus = sun_oble->tme_sun_oble_conn_am7990;
+ }
+
+ /* call out the bus interrupt signal edge: */
+ rc = (conn_out_bus != NULL
+ ? ((*conn_out_bus->tme_bus_signal)
+ (conn_out_bus, signal))
+ : TME_OK);
+
+ return (rc);
+}
+
+/* the sun_oble bus signals adder for the am7990: */
+static int
+_tme_sun_oble_bus_signals_add(struct tme_bus_connection *conn_bus,
+ struct tme_bus_signals *bus_signals_caller)
+{
+ const struct tme_bus_signals *bus_signals;
+ tme_uint32_t signal_first;
+
+ /* we only support the generic: */
+ switch (bus_signals_caller->tme_bus_signals_id) {
+ case TME_BUS_SIGNALS_ID_GENERIC:
+ bus_signals = &_tme_sun_oble_bus_signals_generic;
+ signal_first = _tme_sun_oble_bus_signals_generic.tme_bus_signals_first;
+ break;
+ default:
+ return (ENOENT);
+ }
+
+ /* XXX we should check versions here: */
+ *bus_signals_caller = *bus_signals;
+ bus_signals_caller->tme_bus_signals_first = signal_first;
+ return (TME_OK);
+}
+
+/* the sun_oble TLB adder for the Am7990: */
+static int
+_tme_sun_oble_tlb_set_add(struct tme_bus_connection *conn_bus,
+ struct tme_bus_tlb_set_info *tlb_set_info)
+{
+ struct tme_sun_oble *sun_oble;
+
+ /* recover our data structures: */
+ sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+
+ /* pass the am7990 request through to the mainbus: */
+ conn_bus = sun_oble->tme_sun_oble_conn_memory;
+ return (conn_bus != NULL
+ ? (*conn_bus->tme_bus_tlb_set_add)(conn_bus,
+ tlb_set_info)
+ : ENXIO);
+}
+
+/* the sun_oble TLB filler for the memory: */
+static int
+_tme_sun_oble_tlb_fill(struct tme_bus_connection *conn_bus,
+ struct tme_bus_tlb *tlb,
+ tme_bus_addr_t address,
+ unsigned int cycles)
+{
+ struct tme_sun_oble *sun_oble;
+
+ /* the address must be within range: */
+ assert(address <= 0xffffff);
+
+ /* recover our data structures: */
+ sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+
+ /* pass the am7990's request through to the mainbus: */
+ conn_bus = sun_oble->tme_sun_oble_conn_memory;
+ return (conn_bus != NULL
+ ? (*conn_bus->tme_bus_tlb_fill)(conn_bus,
+ tlb,
+ address,
+ cycles)
+ : ENXIO);
+}
+
+/* the sun_oble TLB filler for the board registers: */
+static int
+_tme_sun_oble_tlb_fill_regs(struct tme_bus_connection *conn_bus,
+ struct tme_bus_tlb *tlb,
+ tme_bus_addr_t address, unsigned int cycles)
+{
+ struct tme_sun_oble *sun_oble;
+ struct tme_bus_connection *conn_am7990;
+ struct tme_bus_tlb tlb_mapping;
+ int rc;
+
+ /* the address must be within range: */
+ assert(address < TME_SUN_OBLE_SIZ_CSR);
+
+ /* recover our data structures: */
+ sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+ conn_am7990 = sun_oble->tme_sun_oble_conn_am7990;
+
+ /* call the Am7990 TLB fill function: */
+ rc = (conn_am7990 != NULL
+ ? (*conn_am7990->tme_bus_tlb_fill)(conn_am7990, tlb,
+ address, cycles)
+ : EINVAL);
+
+ /* if that succeeded: */
+ if (rc == TME_OK) {
+ /* create the mapping TLB entry: */
+ tlb_mapping.tme_bus_tlb_addr_first = TME_SUN_OBLE_REG_CSR;
+ tlb_mapping.tme_bus_tlb_addr_last = TME_SUN_OBLE_SIZ_CSR - 1;
+ tlb_mapping.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
+
+ /* map the filled TLB entry: */
+ tme_bus_tlb_map(tlb, 0, &tlb_mapping, 0);
+ }
+ return (rc);
+}
+
+/* this scores a new connection: */
+static int
+_tme_sun_oble_connection_score(struct tme_connection *conn, unsigned int *_score)
+{
+ struct tme_sun_oble *sun_oble;
+ struct tme_sun_oble_connection *conn_sun_oble;
+
+ /* both sides must be generic bus connections: */
+ assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
+ assert(conn->tme_connection_other->tme_connection_type
+ == conn->tme_connection_type);
+
+ /* recover our data structures: */
+ sun_oble = conn->tme_connection_element->tme_element_private;
+ conn_sun_oble = (struct tme_sun_oble_connection *)conn;
+
+ /* this is a generic bus connection, so just score it nonzero and
+ return. note that there's no good way to differentiate a
+ connection to a bus from a connection to just another chip, so we
+ always return a nonzero score here: */
+ *_score = 1;
+ return (TME_OK);
+}
+
+/* this makes a new connection: */
+static int
+_tme_sun_oble_connection_make(struct tme_connection *conn, unsigned int state)
+{
+ struct tme_sun_oble *sun_oble;
+ struct tme_sun_oble_connection *conn_sun_oble;
+ struct tme_bus_connection *conn_bus;
+
+ /* both sides must be generic bus connections: */
+ assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
+ assert(conn->tme_connection_other->tme_connection_type
+ == conn->tme_connection_type);
+
+ /* recover our data structures: */
+ sun_oble = conn->tme_connection_element->tme_element_private;
+ conn_sun_oble = (struct tme_sun_oble_connection *)conn;
+ conn_bus = &conn_sun_oble->tme_sun_oble_connection;
+
+ /* we're always set up to answer calls across the connection, so we
+ only have to do work when the connection has gone full, namely
+ taking the other side of the connection: */
+ if (state == TME_CONNECTION_FULL) {
+
+ /* lock our mutex: */
+ tme_mutex_lock(&sun_oble->tme_sun_oble_mutex);
+
+ /* save our connection: */
+ if (conn_bus->tme_bus_signals_add != NULL) {
+ sun_oble->tme_sun_oble_conn_am7990 = (struct tme_bus_connection *) conn->tme_connection_other;
+ }
+ else if (conn_sun_oble->tme_sun_oble_connection_regs) {
+ sun_oble->tme_sun_oble_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other;
+ }
+ else {
+ sun_oble->tme_sun_oble_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other;
+ }
+
+ /* unlock our mutex: */
+ tme_mutex_unlock(&sun_oble->tme_sun_oble_mutex);
+ }
+
+ return (TME_OK);
+}
+
+/* this breaks a connection: */
+static int
+_tme_sun_oble_connection_break(struct tme_connection *conn, unsigned int state)
+{
+ abort();
+}
+
+/* this makes a new connection side for a sun_oble: */
+static int
+_tme_sun_oble_connections_new(struct tme_element *element,
+ const char * const *args,
+ struct tme_connection **_conns,
+ char **_output)
+{
+ struct tme_sun_oble *sun_oble;
+ struct tme_sun_oble_connection *conn_sun_oble;
+ struct tme_bus_connection *conn_bus;
+ struct tme_connection *conn;
+ unsigned int am7990;
+ tme_uint8_t regs;
+ int usage;
+ int rc;
+
+ /* recover our data structure: */
+ sun_oble = (struct tme_sun_oble *) element->tme_element_private;
+
+ /* we don't bother locking the mutex simply to check if connections
+ already exist: */
+
+ /* check our arguments: */
+ usage = FALSE;
+ rc = 0;
+ am7990 = FALSE;
+ regs = FALSE;
+
+ /* if this connection is for the registers: */
+ if (TME_ARG_IS(args[1], "csr")) {
+
+ /* if we already have a register connection, complain: */
+ if (sun_oble->tme_sun_oble_conn_regs != NULL) {
+ rc = EEXIST;
+ }
+
+ /* otherwise, make the new connection: */
+ else {
+ regs = TRUE;
+ }
+ }
+
+ /* else, if this connection is for the memory: */
+ else if (TME_ARG_IS(args[1], "memory")) {
+
+ /* if we already have a memory connection, complain: */
+ if (sun_oble->tme_sun_oble_conn_memory != NULL) {
+ rc = EEXIST;
+ }
+ }
+
+ /* else, the connection must be for the am7990: */
+ else if (args[1] == NULL) {
+
+ /* if we already have an am7990 connection, complain: */
+ if (sun_oble->tme_sun_oble_conn_am7990 != NULL) {
+ rc = EEXIST;
+ }
+
+ /* otherwise, make the new conection: */
+ else {
+ am7990 = TRUE;
+ }
+ }
+
+ /* otherwise, this is a bad argument: */
+ else {
+ tme_output_append_error(_output,
+ "%s %s, ",
+ args[1],
+ _("unexpected"));
+ usage = TRUE;
+ }
+
+ if (usage) {
+ tme_output_append_error(_output,
+ "%s %s [ csr | memory ]",
+ _("usage:"),
+ args[0]);
+ rc = EINVAL;
+ }
+
+ if (rc) {
+ return (rc);
+ }
+
+ /* make a new connection: */
+ conn_sun_oble = tme_new0(struct tme_sun_oble_connection, 1);
+ conn_bus = &conn_sun_oble->tme_sun_oble_connection;
+ conn = &conn_bus->tme_bus_connection;
+
+ /* fill in the generic connection: */
+ conn->tme_connection_next = *_conns;
+ conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
+ conn->tme_connection_score = _tme_sun_oble_connection_score;
+ conn->tme_connection_make = _tme_sun_oble_connection_make;
+ conn->tme_connection_break = _tme_sun_oble_connection_break;
+
+ /* fill in the generic bus connection: */
+ conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0;
+ conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL;
+ if (am7990) {
+ conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0xffffff;
+ conn_bus->tme_bus_signals_add = _tme_sun_oble_bus_signals_add;
+ conn_bus->tme_bus_signal = _tme_sun_oble_bus_signal;
+ conn_bus->tme_bus_tlb_set_add = _tme_sun_oble_tlb_set_add;
+ conn_bus->tme_bus_tlb_fill = _tme_sun_oble_tlb_fill;
+ }
+ else if (regs) {
+ conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_OBLE_SIZ_CSR - 1;
+ conn_bus->tme_bus_signal = _tme_sun_oble_bus_signal;
+ conn_bus->tme_bus_tlb_fill = _tme_sun_oble_tlb_fill_regs;
+ }
+ else {
+ conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0;
+ }
+
+ /* fill in the internal information: */
+ conn_sun_oble->tme_sun_oble_connection_regs = regs;
+
+ /* return the connection side possibility: */
+ *_conns = conn;
+ return (TME_OK);
+}
+
+/* the new sun_oble function: */
+int
+tme_sun_oble(struct tme_element *element, const char * const *args, char **_output)
+{
+ struct tme_sun_oble *sun_oble;
+ int arg_i;
+ int usage;
+
+ /* check our arguments: */
+ usage = 0;
+ arg_i = 1;
+ for (;;) {
+
+ /* if we ran out of arguments: */
+ if (args[arg_i] == NULL) {
+
+ break;
+ }
+
+ /* otherwise this is a bad argument: */
+ else {
+ tme_output_append_error(_output,
+ "%s %s, ",
+ args[arg_i],
+ _("unexpected"));
+ usage = TRUE;
+ break;
+ }
+ }
+
+ if (usage) {
+ tme_output_append_error(_output,
+ "%s %s",
+ _("usage:"),
+ args[0]);
+ return (EINVAL);
+ }
+
+ /* start the sun_oble structure: */
+ sun_oble = tme_new0(struct tme_sun_oble, 1);
+ sun_oble->tme_sun_oble_element = element;
+ tme_mutex_init(&sun_oble->tme_sun_oble_mutex);
+
+ /* fill the element: */
+ element->tme_element_private = sun_oble;
+ element->tme_element_connections_new = _tme_sun_oble_connections_new;
+
+ return (TME_OK);
+}
diff --git a/machine/sun3/sun3-mainbus.c b/machine/sun3/sun3-mainbus.c
index 292f3d4..1812e09 100644
--- a/machine/sun3/sun3-mainbus.c
+++ b/machine/sun3/sun3-mainbus.c
@@ -810,6 +810,11 @@
return (tme_sun_obie(element, args, _output));
}
+/* this creates a new Sun-3 oble: */
+TME_ELEMENT_SUB_NEW_DECL(tme_machine_sun3,oble) {
+ return (tme_sun_oble(element, args, _output));
+}
+
/* this creates a new Sun-3 bwtwo: */
TME_ELEMENT_SUB_NEW_DECL(tme_machine_sun3,bwtwo) {
return (tme_sun_bwtwo(element, args, _output));
diff --git a/tme/machine/sun.h b/tme/machine/sun.h
index 3ea4b35..f2c416f 100644
--- a/tme/machine/sun.h
+++ b/tme/machine/sun.h
@@ -162,6 +162,9 @@
/* onboard Intel Ethernet support: */
int tme_sun_obie _TME_P((struct tme_element *, _tme_const char * _tme_const *, char **));
+/* onboard Lance Ethernet support: */
+int tme_sun_oble _TME_P((struct tme_element *, _tme_const char * _tme_const *, char **));
+
/* bwtwo support: */
int tme_sun_bwtwo _TME_P((struct tme_element *, _tme_const char * _tme_const *, char **));