]> Zhao Yanbai Git Server - minix.git/commitdiff
Added fxp driver for the Intel Pro/100 series ethernet cards
authorPhilip Homburg <philip@cs.vu.nl>
Thu, 19 May 2005 13:27:05 +0000 (13:27 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Thu, 19 May 2005 13:27:05 +0000 (13:27 +0000)
Print PC in hex for easier debugging.

13 files changed:
drivers/Makefile
drivers/fxp/Makefile [new file with mode: 0644]
drivers/fxp/fxp.c [new file with mode: 0644]
drivers/fxp/fxp.h [new file with mode: 0644]
drivers/fxp/mii.c [new file with mode: 0644]
drivers/fxp/mii.h [new file with mode: 0644]
drivers/libpci/pci.h
include/minix/com.h
include/minix/config.h
kernel/exception.c
kernel/sendmask.h
kernel/table.c
tools/Makefile

index e7a515b8fd567f3a1cccc4ed814273066e2e538e..b9eb9d784bc690a76d6552f57daf3dc27e53fe7d 100644 (file)
@@ -22,4 +22,5 @@ all install clean:
        cd ./floppy && $(MAKE) $@
        cd ./printer && $(MAKE) $@
        cd ./rtl8139 && $(MAKE) $@
+       cd ./fxp && $(MAKE) $@
 
diff --git a/drivers/fxp/Makefile b/drivers/fxp/Makefile
new file mode 100644 (file)
index 0000000..16093d3
--- /dev/null
@@ -0,0 +1,47 @@
+# Makefile for Intel Pro/100 driver (FXP)
+DRIVER = fxp
+
+# directories
+u = /usr
+i = $u/include
+s = $i/sys
+m = $i/minix
+b = $i/ibm
+d = $u/src/drivers
+
+# programs, flags, etc.
+CC =   exec cc
+CFLAGS = -I$i
+LDFLAGS = -i 
+LIBS = -lsys -lutils -ltimers
+
+OBJ = fxp.o mii.o
+LIBPCI = $d/libpci/pci.o $d/libpci/pci_table.o
+
+# build local binary
+all build:     $(DRIVER)
+$(DRIVER):     $(OBJ) $(LIBPCI)
+       $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBPCI) $(LIBS)
+       install -S 64w $(DRIVER)
+
+$(LIBPCI): 
+       cd $d/libpci && $(MAKE) 
+
+# install with other drivers
+install:       /usr/sbin/drivers/$(DRIVER)
+/usr/sbin/drivers/$(DRIVER):   $(DRIVER)
+       install -o root -cs $? $@
+
+# clean up local files
+clean:
+       rm -f *.o *.bak $(DRIVER)
+
+# Dependencies
+a =    $d/drivers.h $b/interrupt.h $b/bios.h \
+       $i/ansi.h $i/string.h $i/limits.h $i/stddef.h $i/errno.h \
+       $m/config.h $m/type.h $m/com.h $m/callnr.h $m/const.h $s/types.h \
+       $m/syslib.h $s/types.h \
+       $m/utils.h $m/serverassert.h $m/devio.h
+
+fxp.o: $a
+
diff --git a/drivers/fxp/fxp.c b/drivers/fxp/fxp.c
new file mode 100644 (file)
index 0000000..e3748d5
--- /dev/null
@@ -0,0 +1,2483 @@
+/*
+ * fxp.c
+ *
+ * This file contains an ethernet device driver for Intel 82557, 82558, 
+ * 82559, 82550, and 82562 fast ethernet controllers.
+ *
+ * The valid messages and their parameters are:
+ *
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
+ * |------------+----------+---------+----------+---------+---------|
+ * | HARDINT   |          |         |          |         |         |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_READ   | port nr  | proc nr | count    |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_READV  | port nr  | proc nr | count    |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_INIT   | port nr  | proc nr | mode     |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_GETSTAT        | port nr  | proc nr |          |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_STOP   | port_nr  |         |          |         |         |
+ * |------------|----------|---------|----------|---------|---------|
+ *
+ * The messages sent are:
+ *
+ *   m-type       DL_PORT    DL_PROC   DL_COUNT   DL_STAT   DL_CLCK
+ * |-------------+----------+---------+----------+---------+---------|
+ * |DL_TASK_REPLY| port nr  | proc nr | rd-count | err|stat| clock   |
+ * |-------------+----------+---------+----------+---------+---------|
+ *
+ *   m_type       m3_i1     m3_i2       m3_ca1
+ * |-------------+---------+-----------+---------------|
+ * |DL_INIT_REPLY| port nr | last port | ethernet addr |
+ * |-------------+---------+-----------+---------------|
+ *
+ * Created:    Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
+ */
+
+#include "../drivers.h"
+
+#include <stdlib.h>
+#include <net/hton.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+
+#include <timers.h>
+
+#define tmra_ut                        timer_t
+#define tmra_inittimer(tp)     tmr_inittimer(tp)
+#define Proc_number(p)         proc_number(p)
+#define debug                  0
+#define RAND_UPDATE            /**/
+#define printW()               ((void)0)
+#define vm_1phys2bus(p)                (p)
+
+#if ENABLE_FXP
+#if !ENABLE_PCI
+#error PCI support not enabled
+#endif
+
+#include "assert.h"
+#include "../libpci/pci.h"
+#include "fxp.h"
+#include "mii.h"
+
+/* Number of receive buffers */
+#define N_RX_BUF       40
+
+/* Number of transmit buffers */
+#define N_TX_BUF       4
+
+/* I/O vectors are handled IOVEC_NR entries at a time. */
+#define IOVEC_NR       16
+
+/* Configuration */
+#define FXP_ENVVAR     "FXPETH"
+
+struct pcitab
+{
+       u16_t vid;
+       u16_t did;
+       int checkclass;
+};
+
+PRIVATE struct pcitab pcitab_fxp[]=
+{
+       { 0x8086, 0x1229, 0 },          /* Intel 82557, etc. */
+       { 0x8086, 0x2449, 0 },          /* Intel 82801BA/BAM/CA/CAM */
+
+       { 0x0000, 0x0000, 0 }
+};
+
+#define FXP_PORT_NR    1               /* Minix */
+
+typedef int irq_hook_t;
+
+/* Translate a pointer to a field in a structure to a pointer to the structure
+ * itself.  So it translates '&struct_ptr->field' back to 'struct_ptr'.
+ */
+#define structof(type, field, ptr) \
+       ((type *) (((char *) (ptr)) - offsetof(type, field)))
+
+#define panic(m,n) server_panic("FXP",(m),(n))
+#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
+
+static timer_t *fxp_timers= NULL;
+static clock_t fxp_next_timeout= 0;
+
+static void micro_delay(unsigned long usecs);
+
+/* ignore interrupt for the moment */
+#define interrupt(x)   0
+
+char buffer[70*1024];
+
+typedef struct fxp
+{
+       port_t fxp_base_port;
+       int fxp_mode;
+       int fxp_got_int;
+       int fxp_send_int;
+       int fxp_flags;
+       int fxp_client;
+       int fxp_features;               /* Needed? */
+       int fxp_irq;
+       int fxp_type;                   /* What kind of hardware */
+       int fxp_ee_addrlen;             /* #EEPROM address bits */
+       int fxp_tx_alive;
+       int fxp_need_reset;
+
+       /* Rx */
+       vir_bytes fxp_read_s;
+       int fxp_rx_nbuf;
+       int fxp_rx_bufsize;
+       struct rfd *fxp_rx_buf;
+       phys_bytes fxp_rx_busaddr;
+       int fxp_rx_head;
+       int fxp_rx_need_restart;
+       int fxp_need_conf;              /* Re-configure after draining send
+                                        * queue
+                                        */
+
+       /* Tx */
+       int fxp_tx_nbuf;
+       int fxp_tx_bufsize;
+       struct tx *fxp_tx_buf;
+       phys_bytes fxp_tx_busaddr;
+       int fxp_tx_idle;
+       int fxp_tx_head;
+       int fxp_tx_tail;
+       int fxp_tx_threshold;
+
+       /* Link status */
+       int fxp_report_link;
+       int fxp_link_up;
+       int fxp_mii_busy;
+       u16_t fxp_mii_scr;
+
+       /* PCI related */
+       int fxp_seen;                   /* TRUE iff device available */
+       u8_t fxp_pcibus;        
+       u8_t fxp_pcidev;        
+       u8_t fxp_pcifunc;       
+
+       /* 'large' items */
+       irq_hook_t fxp_hook;
+       ether_addr_t fxp_address;
+       message fxp_rx_mess;
+       message fxp_tx_mess;
+       struct sc fxp_stat;
+       u8_t fxp_conf_bytes[CC_BYTES_NR];
+       char fxp_name[sizeof("fxp#n")];
+       iovec_t fxp_iovec[IOVEC_NR];
+}
+fxp_t;
+
+/* fxp_mode */
+#define FM_DISABLED    0x0
+#define FM_ENABLED     0x1
+
+/* fxp_flags */
+#define FF_EMPTY       0x000
+#define FF_PACK_SENT   0x001
+#define FF_PACK_RECV   0x002
+#define FF_SEND_AVAIL  0x004
+#define FF_READING     0x010
+#define FF_PROMISC     0x040
+#define FF_MULTI       0x080
+#define FF_BROAD       0x100
+#define FF_ENABLED     0x200
+
+/* fxp_features */
+#define FFE_NONE       0x0
+
+/* fxp_type */
+#define FT_UNKNOWN     0x0
+#define FT_82557       0x1
+#define FT_82558A      0x2
+#define FT_82559       0x4
+
+static fxp_t fxp_table[FXP_PORT_NR];
+
+static int fxp_tasknr= ANY;
+static u16_t eth_ign_proto;
+static tmra_ut fxp_watchdog;
+
+#define fxp_inb(port, offset)  (do_inb((port) + (offset)))
+#define fxp_inw(port, offset)  (do_inw((port) + (offset)))
+#define fxp_inl(port, offset)  (do_inl((port) + (offset)))
+#define fxp_outb(port, offset, value)  (do_outb((port) + (offset), (value)))
+#define fxp_outw(port, offset, value)  (do_outw((port) + (offset), (value)))
+#define fxp_outl(port, offset, value)  (do_outl((port) + (offset), (value)))
+
+_PROTOTYPE( static void fxp_init, (message *mp)                                );
+_PROTOTYPE( static void fxp_pci_conf, (void)                           );
+_PROTOTYPE( static int fxp_probe, (fxp_t *fp)                          );
+_PROTOTYPE( static void fxp_conf_hw, (fxp_t *fp)                       );
+_PROTOTYPE( static void fxp_init_hw, (fxp_t *fp)                       );
+_PROTOTYPE( static void fxp_init_buf, (fxp_t *fp)                      );
+_PROTOTYPE( static void fxp_reset_hw, (fxp_t *fp)                      );
+_PROTOTYPE( static void fxp_confaddr, (fxp_t *fp)                      );
+_PROTOTYPE( static void fxp_rec_mode, (fxp_t *fp)                      );
+_PROTOTYPE( static void fxp_writev, (message *mp, int from_int,
+                                                       int vectored)   );
+_PROTOTYPE( static void fxp_readv, (message *mp, int from_int, 
+                                                       int vectored)   );
+_PROTOTYPE( static void fxp_do_conf, (fxp_t *fp)                       );
+_PROTOTYPE( static void fxp_cu_ptr_cmd, (fxp_t *fp, int cmd,
+                               phys_bytes bus_addr, int check_idle)    );
+_PROTOTYPE( static void fxp_ru_ptr_cmd, (fxp_t *fp, int cmd,
+                               phys_bytes bus_addr, int check_idle)    );
+_PROTOTYPE( static void fxp_restart_ru, (fxp_t *fp)                    );
+_PROTOTYPE( static void fxp_getstat, (message *mp)                     );
+_PROTOTYPE( static int fxp_handler, (fxp_t *fp)                                );
+_PROTOTYPE( static void fxp_check_ints, (fxp_t *fp)                    );
+_PROTOTYPE( static void fxp_watchdog_f, (timer_t *tp)                  );
+_PROTOTYPE( static int fxp_link_changed, (fxp_t *fp)                   );
+_PROTOTYPE( static void fxp_report_link, (fxp_t *fp)                   );
+_PROTOTYPE( static void fxp_stop, (void));
+_PROTOTYPE( static void reply, (fxp_t *fp, int err, int may_block)     );
+_PROTOTYPE( static void mess_reply, (message *req, message *reply)     );
+_PROTOTYPE( static void put_userdata, (int user_proc,
+               vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
+_PROTOTYPE( static u16_t eeprom_read, (fxp_t *fp, int reg)             );
+_PROTOTYPE( static void eeprom_addrsize, (fxp_t *fp)                   );
+_PROTOTYPE( static u16_t mii_read, (fxp_t *fp, int reg)                        );
+_PROTOTYPE( static void fxp_set_timer,(timer_t *tp, clock_t delta,
+                                               tmr_func_t watchdog)    );
+_PROTOTYPE( static void fxp_expire_timers,(void)                       );
+_PROTOTYPE( static u8_t do_inb, (port_t port)                          );
+_PROTOTYPE( static u32_t do_inl, (port_t port)                         );
+_PROTOTYPE( static void do_outb, (port_t port, u8_t v)                 );
+_PROTOTYPE( static void do_outl, (port_t port, u32_t v)                        );
+
+
+/*===========================================================================*
+ *                             main                                         *
+ *===========================================================================*/
+int main(void)
+{
+       message m;
+       int i, r;
+       fxp_t *fp;
+       long v;
+
+       fxp_tasknr= FXP;
+
+       v= 0;
+#if 0
+       (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
+#else
+       printf("not calling env_parse for ETH_IGN_PROTO\n");
+#endif
+       eth_ign_proto= htons((u16_t) v);
+
+#if 0  /* What about memory allocation? */
+       /* Claim buffer memory now under Minix, before MM takes it all. */
+       for (fp= &fxp_table[0]; fp < fxp_table+FXP_PORT_NR; fp++)
+               fxp_init_buf(fp);
+#endif
+
+       while (TRUE)
+       {
+               if ((r= receive(ANY, &m)) != OK)
+                       panic("fxp: receive failed", r);
+
+               switch (m.m_type)
+               {
+               case DL_WRITEV: fxp_writev(&m, FALSE, TRUE);    break;
+               case DL_WRITE:  fxp_writev(&m, FALSE, FALSE);   break;
+#if 0
+               case DL_READ:   fxp_vread(&m, FALSE);           break;
+#endif
+               case DL_READV:  fxp_readv(&m, FALSE, TRUE);     break;
+               case DL_INIT:   fxp_init(&m);                   break;
+               case DL_GETSTAT: fxp_getstat(&m);               break;
+               case HARD_INT:
+                       for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
+                       {
+                               if (fp->fxp_mode != FM_ENABLED)
+                                       continue;
+                               fxp_handler(fp);
+
+                               r= sys_irqenable(&fp->fxp_hook);
+                               if (r != OK)
+                                       panic("unable enable interrupts", r);
+
+                               if (!fp->fxp_got_int)
+                                       continue;
+                               fp->fxp_got_int= 0;
+                               assert(fp->fxp_flags & FF_ENABLED);
+                               fxp_check_ints(fp);
+                       }
+                       break;
+               case HARD_STOP: fxp_stop();                     break;
+               case SYN_ALARM: fxp_expire_timers();            break;
+               default:
+                       panic("fxp: illegal message", m.m_type);
+               }
+       }
+}
+
+
+/*===========================================================================*
+ *                             fxp_init                                     *
+ *===========================================================================*/
+static void fxp_init(mp)
+message *mp;
+{
+       static int first_time= 1;
+
+       int port;
+       fxp_t *fp;
+       message reply_mess;
+
+       if (first_time)
+       {
+               first_time= 0;
+               fxp_pci_conf(); /* Configure PCI devices. */
+
+               tmra_inittimer(&fxp_watchdog);
+               tmr_arg(&fxp_watchdog)->ta_int= 0;
+               fxp_set_timer(&fxp_watchdog, HZ, fxp_watchdog_f);
+       }
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= FXP_PORT_NR)
+       {
+               reply_mess.m_type= DL_INIT_REPLY;
+               reply_mess.m3_i1= ENXIO;
+               mess_reply(mp, &reply_mess);
+               return;
+       }
+       fp= &fxp_table[port];
+       if (fp->fxp_mode == FM_DISABLED)
+       {
+               /* This is the default, try to (re)locate the device. */
+               fxp_conf_hw(fp);
+               if (fp->fxp_mode == FM_DISABLED)
+               {
+                       /* Probe failed, or the device is configured off. */
+                       reply_mess.m_type= DL_INIT_REPLY;
+                       reply_mess.m3_i1= ENXIO;
+                       mess_reply(mp, &reply_mess);
+                       return;
+               }
+               if (fp->fxp_mode == FM_ENABLED)
+                       fxp_init_hw(fp);
+               fxp_report_link(fp);
+       }
+
+       assert(fp->fxp_mode == FM_ENABLED);
+       assert(fp->fxp_flags & FF_ENABLED);
+
+       fp->fxp_flags &= ~(FF_PROMISC | FF_MULTI | FF_BROAD);
+
+       if (mp->DL_MODE & DL_PROMISC_REQ)
+               fp->fxp_flags |= FF_PROMISC;
+       if (mp->DL_MODE & DL_MULTI_REQ)
+               fp->fxp_flags |= FF_MULTI;
+       if (mp->DL_MODE & DL_BROAD_REQ)
+               fp->fxp_flags |= FF_BROAD;
+
+       fp->fxp_client = mp->m_source;
+       fxp_rec_mode(fp);
+
+       reply_mess.m_type = DL_INIT_REPLY;
+       reply_mess.m3_i1 = mp->DL_PORT;
+       reply_mess.m3_i2 = FXP_PORT_NR;
+       *(ether_addr_t *) reply_mess.m3_ca1 = fp->fxp_address;
+
+       mess_reply(mp, &reply_mess);
+}
+
+
+/*===========================================================================*
+ *                             fxp_pci_conf                                 *
+ *===========================================================================*/
+static void fxp_pci_conf()
+{
+       static char envvar[] = FXP_ENVVAR "#";
+       static char envfmt[] = "*:d.d.d";
+
+       int i, h;
+       fxp_t *fp;
+       long v;
+
+       for (i= 0, fp= fxp_table; i<FXP_PORT_NR; i++, fp++)
+       {
+               strcpy(fp->fxp_name, "fxp#0");
+               fp->fxp_name[4] += i;
+               fp->fxp_seen= FALSE;
+               fp->fxp_features= FFE_NONE;
+               envvar[sizeof(FXP_ENVVAR)-1]= '0'+i;
+#if 0
+               if (getenv(envvar) != NULL)
+               {
+                       if (strcmp(getenv(envvar), "off") == 0)
+                       {
+                               fp->fxp_pcibus= 255;
+                               continue;
+                       }
+                       if (!env_prefix(envvar, "pci"))
+                               env_panic(envvar);
+               }
+#else
+               printf("FXP: not calling getenv\n");
+#endif
+
+               printf("not calling env_parse\n");
+               v= 0;
+#if 0
+               (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
+#endif
+               fp->fxp_pcibus= v;
+               v= 0;
+#if 0
+               (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
+#endif
+               fp->fxp_pcidev= v;
+               v= 0;
+#if 0
+               (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
+#endif
+               fp->fxp_pcifunc= v;
+       }
+
+       pci_init();
+
+       for (h= 1; h >= 0; h--) {
+               for (i= 0, fp= fxp_table; i<FXP_PORT_NR; i++, fp++)
+               {
+                       if (fp->fxp_pcibus == 255)
+                               continue;
+                       if (((fp->fxp_pcibus | fp->fxp_pcidev |
+                               fp->fxp_pcifunc) != 0) != h)
+                       {
+                               continue;
+                       }
+                       if (fxp_probe(fp))
+                               fp->fxp_seen= TRUE;
+               }
+       }
+}
+
+
+/*===========================================================================*
+ *                             fxp_probe                                    *
+ *===========================================================================*/
+static int fxp_probe(fp)
+fxp_t *fp;
+{
+       int i, r, devind, just_one;
+       u16_t vid, did;
+       u32_t bar;
+       u8_t ilr, rev;
+       char *dname, *str;
+
+       if ((fp->fxp_pcibus | fp->fxp_pcidev | fp->fxp_pcifunc) != 0)
+       {
+               /* Look for specific PCI device */
+               r= pci_find_dev(fp->fxp_pcibus, fp->fxp_pcidev,
+                       fp->fxp_pcifunc, &devind);
+               if (r == 0)
+               {
+                       printf("%s: no PCI device found at %d.%d.%d\n",
+                               fp->fxp_name, fp->fxp_pcibus,
+                               fp->fxp_pcidev, fp->fxp_pcifunc);
+                       return FALSE;
+               }
+               pci_ids(devind, &vid, &did);
+               just_one= TRUE;
+       }
+       else
+       {
+               r= pci_first_dev(&devind, &vid, &did);
+               if (r == 0)
+                       return FALSE;
+               just_one= FALSE;
+       }
+
+       for(;;)
+       {
+               for (i= 0; pcitab_fxp[i].vid != 0; i++)
+               {
+                       if (pcitab_fxp[i].vid != vid)
+                               continue;
+                       if (pcitab_fxp[i].did != did)
+                               continue;
+                       if (pcitab_fxp[i].checkclass)
+                       {
+                               panic("fxp_probe: class check not implemented",
+                                       NO_NUM);
+                       }
+                       break;
+               }
+               if (pcitab_fxp[i].vid != 0)
+                       break;
+
+               if (just_one)
+               {
+                       printf(
+               "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
+                               fp->fxp_name, vid, did,
+                               fp->fxp_pcibus,
+                               fp->fxp_pcidev, fp->fxp_pcifunc);
+                       return FALSE;
+               }
+
+               r= pci_next_dev(&devind, &vid, &did);
+               if (!r)
+                       return FALSE;
+       }
+
+       dname= pci_dev_name(vid, did);
+       if (!dname)
+               dname= "unknown device";
+       printf("%s: %s (%04x/%04x) at %s\n",
+               fp->fxp_name, dname, vid, did, pci_slot_name(devind));
+       pci_reserve(devind);
+
+       bar= pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0;
+       if ((bar & 0x3ff) >= 0x100-32 || bar < 0x400)
+       {
+               panic("fxp_probe: base address is not properly configured",
+                       NO_NUM);
+       }
+       fp->fxp_base_port= bar;
+
+       ilr= pci_attr_r8(devind, PCI_ILR);
+       fp->fxp_irq= ilr;
+       if (debug)
+       {
+               printf("%s: using I/O address 0x%lx, IRQ %d\n",
+                       fp->fxp_name, (unsigned long)bar, ilr);
+       }
+
+       rev= pci_attr_r8(devind, PCI_REV);
+       str= NULL;
+       fp->fxp_type= FT_UNKNOWN;
+       switch(rev)
+       {
+       case FXP_REV_82557A:    str= "82557A";                  /* 0x01 */
+                               fp->fxp_type= FT_82557;
+                               break;
+       case FXP_REV_82557B:    str= "82557B"; break;           /* 0x02 */
+       case FXP_REV_82557C:    str= "82557C"; break;           /* 0x03 */
+       case FXP_REV_82558A:    str= "82558A";                  /* 0x04 */
+                               fp->fxp_type= FT_82558A;
+                               break;
+       case FXP_REV_82558B:    str= "82558B"; break;           /* 0x05 */
+       case FXP_REV_82559A:    str= "82559A"; break;           /* 0x06 */
+       case FXP_REV_82559B:    str= "82559B"; break;           /* 0x07 */
+       case FXP_REV_82559C:    str= "82559C";                  /* 0x08 */
+                               fp->fxp_type= FT_82559;
+                               break;
+       case FXP_REV_82559ERA:  str= "82559ER-A"; break;        /* 0x09 */
+       case FXP_REV_82550_1:   str= "82550(1)"; break;         /* 0x0C */
+       case FXP_REV_82550_2:   str= "82550(2)"; break;         /* 0x0D */
+       case FXP_REV_82550_3:   str= "82550(3)"; break;         /* 0x0E */
+       case FXP_REV_82551_1:   str= "82551(1)"; break;         /* 0x0F */
+       case FXP_REV_82551_2:   str= "82551(2)"; break;         /* 0x10 */
+       }
+
+       if (str)
+               printf("%s: device revision: %s\n", fp->fxp_name, str);
+       else
+               printf("%s: unknown revision: 0x%x\n", fp->fxp_name, rev);
+
+       if (fp->fxp_type == FT_UNKNOWN)
+       {
+               printf("fxp_probe: device is not supported by this driver\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/*===========================================================================*
+ *                             fxp_conf_hw                                  *
+ *===========================================================================*/
+static void fxp_conf_hw(fp)
+fxp_t *fp;
+{
+       int i;
+       int mwi, ext_stat1, ext_stat2, lim_fifo, i82503, fc;
+
+       fp->fxp_mode= FM_DISABLED;      /* Superfluous */
+
+       if (!fp->fxp_seen)
+               return;
+
+       /* PCI device is present */
+       fp->fxp_mode= FM_ENABLED;
+
+       fp->fxp_flags= FF_EMPTY;
+       fp->fxp_got_int= 0;
+       fp->fxp_send_int= 0;
+       fp->fxp_ee_addrlen= 0;  /* Unknown */
+       fp->fxp_need_reset= 0;
+       fp->fxp_report_link= 0;
+       fp->fxp_link_up= -1;    /* Unknown */
+       fp->fxp_mii_busy= 0;
+       fp->fxp_read_s= 0;
+       fp->fxp_rx_need_restart= 0;
+       fp->fxp_need_conf= 0;
+       fp->fxp_tx_head= 0;
+       fp->fxp_tx_tail= 0;
+       fp->fxp_tx_alive= 0;
+       fp->fxp_tx_threshold= TXTT_MIN;
+
+       /* Try to come up with a sensible configuration for the current
+        * device. Unfortunately every device is different, defaults are
+        * not always zero, and some fields are re-used with a completely
+        * different interpretation. We start out with a sensible default
+        * for all devices and then add device specific changes.
+        */
+       fp->fxp_conf_bytes[0]= CC_BYTES_NR;
+       fp->fxp_conf_bytes[1]= CTL_DEFAULT | CRL_DEFAULT;
+       fp->fxp_conf_bytes[2]= CAI_DEFAULT;
+       fp->fxp_conf_bytes[3]= 0;
+       fp->fxp_conf_bytes[4]= 0;
+       fp->fxp_conf_bytes[5]= 0;
+       fp->fxp_conf_bytes[6]= CCB6_ESC | CCB6_ETCB | CCB6_RES;
+       fp->fxp_conf_bytes[7]= CUR_1;
+       fp->fxp_conf_bytes[8]= CCB8_503_MII;
+       fp->fxp_conf_bytes[9]= 0;
+       fp->fxp_conf_bytes[10]= CLB_NORMAL | CPAL_DEFAULT | CCB10_NSAI |
+                               CCB10_RES1;
+       fp->fxp_conf_bytes[11]= 0;
+       fp->fxp_conf_bytes[12]= CIS_DEFAULT;
+       fp->fxp_conf_bytes[13]= CCB13_DEFAULT;
+       fp->fxp_conf_bytes[14]= CCB14_DEFAULT;
+       fp->fxp_conf_bytes[15]= CCB15_RES1 | CCB15_RES2;
+       fp->fxp_conf_bytes[16]= CCB16_DEFAULT;
+       fp->fxp_conf_bytes[17]= CCB17_DEFAULT;
+       fp->fxp_conf_bytes[18]= CCB18_RES1 | CCB18_PFCT | CCB18_PE;
+       fp->fxp_conf_bytes[19]= CCB19_FDPE;
+       fp->fxp_conf_bytes[20]= CCB20_PFCL | CCB20_RES1;
+       fp->fxp_conf_bytes[21]= CCB21_RES21;
+
+       for (i= 0; i<CC_BYTES_NR; i++)
+               printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
+       printf("\n");
+
+       mwi= 0;         /* Do we want "Memory Write and Invalidate"? */
+       ext_stat1= 0;   /* Do we want extended statistical counters? */
+       ext_stat2= 0;   /* Do we want even more statistical counters? */
+       lim_fifo= 0;    /* Limit number of frame in TX FIFO */
+       i82503= 0;      /* Older 10 Mbps interface on the 82557 */
+       fc= 0;          /* Flow control */
+
+       switch(fp->fxp_type)
+       {
+       case FT_82557:
+               if (i82503)
+               {
+                       fp->fxp_conf_bytes[8] &= ~CCB8_503_MII;
+                       fp->fxp_conf_bytes[15] |= CCB15_CRSCDT;
+               }
+               break;
+       case FT_82558A:
+       case FT_82559:
+               if (mwi)
+                       fp->fxp_conf_bytes[3] |= CCB3_MWIE;
+               if (ext_stat1)
+                       fp->fxp_conf_bytes[6] &= ~CCB6_ESC;
+               if (ext_stat2)
+                       fp->fxp_conf_bytes[6] &= ~CCB6_TCOSC;
+               if (lim_fifo)
+                       fp->fxp_conf_bytes[7] |= CCB7_2FFIFO;
+               if (fc)
+               {
+                       /* From FreeBSD driver */
+                       fp->fxp_conf_bytes[16]= 0x1f;
+                       fp->fxp_conf_bytes[17]= 0x01;
+
+                       fp->fxp_conf_bytes[19] |= CCB19_FDRSTAFC |
+                               CCB19_FDRSTOFC;
+               }
+
+               fp->fxp_conf_bytes[18] |= CCB18_LROK;
+               break;
+       default:
+               panic("fxp_conf_hw: bad device type", fp->fxp_type);
+       }
+
+       for (i= 0; i<CC_BYTES_NR; i++)
+               printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
+       printf("\n");
+}
+
+
+/*===========================================================================*
+ *                             fxp_init_hw                                  *
+ *===========================================================================*/
+static void fxp_init_hw(fp)
+fxp_t *fp;
+{
+       int i, r, isr;
+       port_t port;
+       u32_t bus_addr;
+
+       port= fp->fxp_base_port;
+
+       fxp_init_buf(fp);
+
+       fp->fxp_flags = FF_EMPTY;
+       fp->fxp_flags |= FF_ENABLED;
+
+       /* set the interrupt handler */
+       r= sys_irqsetpolicy(fp->fxp_irq, 0, &fp->fxp_hook);
+       if (r != OK)
+               panic("sys_irqsetpolicy failed", r);
+
+       fxp_reset_hw(fp);
+
+       r= sys_irqenable(&fp->fxp_hook);
+       if (r != OK)
+               panic("sys_irqenable failed", r);
+
+       /* Reset PHY? */
+
+       fxp_do_conf(fp);
+
+       /* Set pointer to statistical counters */
+       r= sys_umap(SELF, D, (vir_bytes)&fp->fxp_stat, sizeof(fp->fxp_stat),
+               &bus_addr);
+       if (r != OK)
+               panic("sys_umap failed", r);
+       fxp_cu_ptr_cmd(fp, SC_CU_LOAD_DCA, bus_addr, TRUE /* check idle */);
+
+       /* Ack previous interrupts */
+       isr= fxp_inb(port, SCB_INT_STAT);
+       fxp_outb(port, SCB_INT_STAT, isr);
+
+       /* Enable interrupts */
+       fxp_outb(port, SCB_INT_MASK, 0);
+
+       fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
+               TRUE /* check idle */);
+
+       fxp_confaddr(fp);
+       if (debug)
+       {
+               printf("%s: Ethernet address ", fp->fxp_name);
+               for (i= 0; i < 6; i++)
+               {
+                       printf("%x%c", fp->fxp_address.ea_addr[i],
+                               i < 5 ? ':' : '\n');
+               }
+       }
+}
+
+
+/*===========================================================================*
+ *                             fxp_init_buf                                 *
+ *===========================================================================*/
+static void fxp_init_buf(fp)
+fxp_t *fp;
+{
+       size_t rx_totbufsize, tx_totbufsize, tot_bufsize;
+       phys_bytes buf;
+       int i, r;
+       struct rfd *rfdp;
+       struct tx *txp;
+
+       fp->fxp_rx_nbuf= N_RX_BUF;
+       rx_totbufsize= fp->fxp_rx_nbuf * sizeof(struct rfd);
+       fp->fxp_rx_bufsize= rx_totbufsize;
+
+       fp->fxp_tx_nbuf= N_TX_BUF;
+       tx_totbufsize= fp->fxp_tx_nbuf * sizeof(struct tx);
+       fp->fxp_tx_bufsize= tx_totbufsize;
+
+       tot_bufsize= tx_totbufsize + rx_totbufsize;
+
+       /* What about memory allocation? */
+       {
+               static int first_time= 1;
+
+               assert(first_time);
+               first_time= 0;
+
+               assert(tot_bufsize <= buffer);
+               buf= (phys_bytes)buffer;
+       }
+
+       fp->fxp_rx_buf= (struct rfd *)buf;
+       r= sys_umap(SELF, D, (vir_bytes)buf, rx_totbufsize,
+               &fp->fxp_rx_busaddr);
+       if (r != OK)
+               panic("sys_umap failed", r);
+       for (i= 0, rfdp= fp->fxp_rx_buf; i<fp->fxp_rx_nbuf; i++, rfdp++)
+       {
+               rfdp->rfd_status= 0;
+               rfdp->rfd_command= 0;
+               if (i != fp->fxp_rx_nbuf-1)
+               {
+                       r= sys_umap(SELF, D, (vir_bytes)&rfdp[1],
+                               sizeof(rfdp[1]), &rfdp->rfd_linkaddr);
+                       if (r != OK)
+                               panic("sys_umap failed", r);
+               }
+               else
+               {
+                       rfdp->rfd_linkaddr= fp->fxp_rx_busaddr;
+                       rfdp->rfd_command |= RFDC_EL;
+               }
+               rfdp->rfd_reserved= 0;
+               rfdp->rfd_res= 0;
+               rfdp->rfd_size= sizeof(rfdp->rfd_buf);
+
+       }
+       fp->fxp_rx_head= 0;
+
+       fp->fxp_tx_buf= (struct tx *)(buf+rx_totbufsize);
+       r= sys_umap(SELF, D, (vir_bytes)fp->fxp_tx_buf,
+               (phys_bytes)tx_totbufsize, &fp->fxp_tx_busaddr);
+       if (r != OK)
+               panic("sys_umap failed", r);
+
+       for (i= 0, txp= fp->fxp_tx_buf; i<fp->fxp_tx_nbuf; i++, txp++)
+       {
+               txp->tx_status= 0;
+               txp->tx_command= TXC_EL | CBL_NOP;      /* Just in case */
+               if (i != fp->fxp_tx_nbuf-1)
+               {
+                       r= sys_umap(SELF, D, (vir_bytes)&txp[1],
+                               (phys_bytes)sizeof(txp[1]),
+                               &txp->tx_linkaddr);
+                       if (r != OK)
+                               panic("sys_umap failed", r);
+               }
+               else
+               {
+                       txp->tx_linkaddr= fp->fxp_tx_busaddr;
+               }
+               txp->tx_tbda= TX_TBDA_NIL;
+               txp->tx_size= 0;
+               txp->tx_tthresh= fp->fxp_tx_threshold;
+               txp->tx_ntbd= 0;
+       }
+       fp->fxp_tx_idle= 1;
+}
+
+
+/*===========================================================================*
+ *                             fxp_reset_hw                                 *
+ *===========================================================================*/
+static void fxp_reset_hw(fp)
+fxp_t *fp;
+{
+/* Inline the function in init? */
+       port_t port;
+
+       port= fp->fxp_base_port;
+
+       /* Reset device */
+       fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
+       tick_delay(MICROS_TO_TICKS(CSR_PORT_RESET_DELAY));
+
+       /* Disable interrupts */
+       fxp_outb(port, SCB_INT_MASK, SIM_M);
+
+       /* Set CU base to zero */
+       fxp_cu_ptr_cmd(fp, SC_CU_LOAD_BASE, 0, TRUE /* check idle */);
+
+       /* Set RU base to zero */
+       fxp_ru_ptr_cmd(fp, SC_RU_LOAD_BASE, 0, TRUE /* check idle */);
+}
+
+
+/*===========================================================================*
+ *                             fxp_confaddr                                 *
+ *===========================================================================*/
+static void fxp_confaddr(fp)
+fxp_t *fp;
+{
+       static char eakey[]= FXP_ENVVAR "#_EA";
+       static char eafmt[]= "x:x:x:x:x:x";
+       static int timeout_flag;        /* must be static */
+
+       int i, r;
+       port_t port;
+       u32_t bus_addr;
+       long v;
+       struct ias ias;
+
+       port= fp->fxp_base_port;
+
+       /* User defined ethernet address? */
+       eakey[sizeof(FXP_ENVVAR)-1]= '0' + (fp-fxp_table);
+
+#if 0
+       for (i= 0; i < 6; i++)
+       {
+               if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
+                       break;
+               fp->fxp_address.ea_addr[i]= v;
+       }
+#else
+       i= 0;
+       printf("not calling env_parse\n");
+#endif
+
+#if 0
+       if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
+#else
+       printf("not checking for env_panic\n");
+#endif
+
+       if (i == 0)
+       {
+               /* Get ethernet address from EEPROM */
+               for (i= 0; i<3; i++)
+               {
+                       v= eeprom_read(fp, i);
+                       fp->fxp_address.ea_addr[i*2]= (v & 0xff);
+                       fp->fxp_address.ea_addr[i*2+1]= ((v >> 8) & 0xff);
+               }
+       }
+
+       /* Tell NIC about ethernet address */
+       ias.ias_status= 0;
+       ias.ias_command= CBL_C_EL | CBL_AIS;
+       ias.ias_linkaddr= 0;
+       memcpy(ias.ias_ethaddr, fp->fxp_address.ea_addr,
+               sizeof(ias.ias_ethaddr));
+       r= sys_umap(SELF, D, (vir_bytes)&ias, (phys_bytes)sizeof(ias),
+               &bus_addr);
+       if (r != OK)
+               panic("sys_umap failed", r);
+
+       fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
+
+       timeout_flag= 0;
+       sys_flagalrm(MICROS_TO_TICKS(1000), &timeout_flag);
+       do {
+               /* Wait for CU command to complete */
+               if (ias.ias_status & CBL_F_C)
+                       break;
+       } while (!timeout_flag);
+
+       if (!(ias.ias_status & CBL_F_C))
+               panic("fxp_confaddr: CU command failed to complete", NO_NUM);
+       if (!(ias.ias_status & CBL_F_OK))
+               panic("fxp_confaddr: CU command failed", NO_NUM);
+
+       printf("%s: hardware ethernet address: ", fp->fxp_name);
+       for (i= 0; i<6; i++)
+       {
+               printf("%02x%s", fp->fxp_address.ea_addr[i], 
+                       i < 5 ? ":" : "");
+       }
+       printf("\n");
+}
+
+/*===========================================================================*
+ *                             fxp_rec_mode                                 *
+ *===========================================================================*/
+static void fxp_rec_mode(fp)
+fxp_t *fp;
+{
+       fp->fxp_conf_bytes[0]= CC_BYTES_NR;     /* Just to be sure */
+       fp->fxp_conf_bytes[15] &= ~(CCB15_BD|CCB15_PM);
+       fp->fxp_conf_bytes[21] &= ~CCB21_MA;
+
+       if (fp->fxp_flags & FF_PROMISC)
+               fp->fxp_conf_bytes[15] |= CCB15_PM;
+       if (fp->fxp_flags & FF_MULTI)
+               fp->fxp_conf_bytes[21] |= CCB21_MA;
+
+       if (!(fp->fxp_flags & (FF_BROAD|FF_MULTI|FF_PROMISC)))
+               fp->fxp_conf_bytes[15] |= CCB15_BD;
+
+       /* Queue request if not idle */
+       if (fp->fxp_tx_idle)
+       {
+               fxp_do_conf(fp);
+       }
+       else
+       {
+               printf("fxp_rec_mode: setting fxp_need_conf\n");
+               fp->fxp_need_conf= TRUE;
+       }
+}
+
+
+/*===========================================================================*
+ *                             fxp_writev                                   *
+ *===========================================================================*/
+static void fxp_writev(mp, from_int, vectored)
+message *mp;
+int from_int;
+int vectored;
+{
+       vir_bytes iov_src;
+       int i, j, n, o, r, s, dl_port, count, size, prev_head;
+       int fxp_client, fxp_tx_nbuf, fxp_tx_head;
+       u16_t tx_command;
+       fxp_t *fp;
+       iovec_t *iovp;
+       struct tx *txp, *prev_txp;
+
+       dl_port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (dl_port < 0 || dl_port >= FXP_PORT_NR)
+               panic("fxp_writev: illegal port", dl_port);
+       fp= &fxp_table[dl_port];
+       fxp_client= mp->DL_PROC;
+       fp->fxp_client= fxp_client;
+
+       assert(fp->fxp_mode == FM_ENABLED);
+       assert(fp->fxp_flags & FF_ENABLED);
+
+       if (from_int)
+       {
+               assert(fp->fxp_flags & FF_SEND_AVAIL);
+               fp->fxp_flags &= ~FF_SEND_AVAIL;
+               fp->fxp_tx_alive= TRUE;
+       }
+
+       if (fp->fxp_tx_idle)
+       {
+               txp= fp->fxp_tx_buf;
+               fxp_tx_head= 0; /* lint */
+               prev_txp= NULL; /* lint */
+       }
+       else
+       {       
+               fxp_tx_nbuf= fp->fxp_tx_nbuf;
+               prev_head= fp->fxp_tx_head;
+               fxp_tx_head= prev_head+1;
+               if (fxp_tx_head == fxp_tx_nbuf)
+                       fxp_tx_head= 0;
+               assert(fxp_tx_head < fxp_tx_nbuf);
+
+               if (fxp_tx_head == fp->fxp_tx_tail)
+               {
+                       /* Send queue is full */
+                       assert(!(fp->fxp_flags & FF_SEND_AVAIL));
+                       fp->fxp_flags |= FF_SEND_AVAIL;
+                       goto suspend;
+               }
+
+               prev_txp= &fp->fxp_tx_buf[prev_head];
+               txp= &fp->fxp_tx_buf[fxp_tx_head];
+       }
+
+
+       assert(!(fp->fxp_flags & FF_SEND_AVAIL));
+       assert(!(fp->fxp_flags & FF_PACK_SENT));
+
+       if (vectored)
+       {
+
+               iov_src = (vir_bytes)mp->DL_ADDR;
+
+               size= 0;
+               o= 0;
+               for (i= 0; i<count; i += IOVEC_NR,
+                       iov_src += IOVEC_NR * sizeof(fp->fxp_iovec[0]))
+               {
+                       n= IOVEC_NR;
+                       if (i+n > count)
+                               n= count-i;
+                       r= sys_vircopy(fxp_client, D, iov_src, 
+                               SELF, D, (vir_bytes)fp->fxp_iovec,
+                               n * sizeof(fp->fxp_iovec[0]));
+                       if (r != OK)
+                               panic("fxp_writev: sys_vircopy failed", r);
+
+                       for (j= 0, iovp= fp->fxp_iovec; j<n; j++, iovp++)
+                       {
+                               s= iovp->iov_size;
+                               if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
+                               {
+                                       panic("fxp_writev: invalid packet size",
+                                               NO_NUM);
+                               }
+
+                               r= sys_vircopy(fxp_client, D, iovp->iov_addr, 
+                                       SELF, D, (vir_bytes)(txp->tx_buf+o),
+                                       s);
+                               if (r != OK)
+                               {
+                                       panic("fxp_writev: sys_vircopy failed",
+                                               r);
+                               }
+                               size += s;
+                               o += s;
+                       }
+               }
+               if (size < ETH_MIN_PACK_SIZE)
+                       panic("fxp_writev: invalid packet size", size);
+       }
+       else
+       {  
+               size= mp->DL_COUNT;
+               if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
+                       panic("fxp_writev: invalid packet size", size);
+
+               r= sys_vircopy(fxp_client, D, (vir_bytes)mp->DL_ADDR, 
+                       SELF, D, (vir_bytes)txp->tx_buf, size);
+               if (r != OK)
+                       panic("fxp_writev: sys_vircopy failed", r);
+       }
+
+       txp->tx_status= 0;
+       txp->tx_command= TXC_EL | CBL_XMIT;
+       txp->tx_tbda= TX_TBDA_NIL;
+       txp->tx_size= TXSZ_EOF | size;
+       txp->tx_tthresh= fp->fxp_tx_threshold;
+       txp->tx_ntbd= 0;
+       if (fp->fxp_tx_idle)
+       {
+               fp->fxp_tx_idle= 0;
+               fp->fxp_tx_head= fp->fxp_tx_tail= 0;
+
+               fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr,
+                       TRUE /* check idle */);
+       }
+       else
+       {
+               /* Link new request in transmit list */
+               tx_command= prev_txp->tx_command;
+               assert(tx_command == (TXC_EL | CBL_XMIT));
+               prev_txp->tx_command= CBL_XMIT;
+               fp->fxp_tx_head= fxp_tx_head;
+       }
+
+       fp->fxp_flags |= FF_PACK_SENT;
+
+       /* If the interrupt handler called, don't send a reply. The reply
+        * will be sent after all interrupts are handled. 
+        */
+       if (from_int)
+               return;
+       reply(fp, OK, FALSE);
+       return;
+
+suspend:
+       if (from_int)
+               panic("fxp: should not be sending\n", NO_NUM);
+
+       fp->fxp_tx_mess= *mp;
+       reply(fp, OK, FALSE);
+}
+
+
+/*===========================================================================*
+ *                             fxp_readv                                    *
+ *===========================================================================*/
+static void fxp_readv(mp, from_int, vectored)
+message *mp;
+int from_int;
+int vectored;
+{
+       int i, j, n, o, r, s, dl_port, fxp_client, count, size,
+               fxp_rx_head, fxp_rx_nbuf;
+       port_t port;
+       unsigned packlen;
+       vir_bytes iov_src;
+       u16_t rfd_status;
+       u16_t rfd_res;
+       u8_t scb_status;
+       fxp_t *fp;
+       iovec_t *iovp;
+       struct rfd *rfdp, *prev_rfdp;
+
+       dl_port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (dl_port < 0 || dl_port >= FXP_PORT_NR)
+               panic("fxp_readv: illegal port", dl_port);
+       fp= &fxp_table[dl_port];
+       fxp_client= mp->DL_PROC;
+       fp->fxp_client= fxp_client;
+
+       assert(fp->fxp_mode == FM_ENABLED);
+       assert(fp->fxp_flags & FF_ENABLED);
+
+       port= fp->fxp_base_port;
+
+       fxp_rx_head= fp->fxp_rx_head;
+       rfdp= &fp->fxp_rx_buf[fxp_rx_head];
+
+       rfd_status= rfdp->rfd_status;
+       if (!(rfd_status & RFDS_C))
+       {
+               /* Receive buffer is empty, suspend */
+               goto suspend;
+       }
+
+       if (!rfd_status & RFDS_OK)
+       {
+               /* Not OK? What happened? */
+               assert(0);
+       }
+       else
+       {
+               assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR |
+                       RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT | 
+                       RFDS_RXERR)));
+       }
+       rfd_res= rfdp->rfd_res;
+       assert(rfd_res & RFDR_EOF);
+       assert(rfd_res & RFDR_F);
+
+       packlen= rfd_res & RFDSZ_SIZE;
+
+       if (vectored)
+       {
+               iov_src = (vir_bytes)mp->DL_ADDR;
+
+               size= 0;
+               o= 0;
+               for (i= 0; i<count; i += IOVEC_NR,
+                       iov_src += IOVEC_NR * sizeof(fp->fxp_iovec[0]))
+               {
+                       n= IOVEC_NR;
+                       if (i+n > count)
+                               n= count-i;
+                       r= sys_vircopy(fxp_client, D, iov_src, 
+                               SELF, D, (vir_bytes)fp->fxp_iovec,
+                               n * sizeof(fp->fxp_iovec[0]));
+                       if (r != OK)
+                               panic("fxp_readv: sys_vircopy failed", r);
+
+                       for (j= 0, iovp= fp->fxp_iovec; j<n; j++, iovp++)
+                       {
+                               s= iovp->iov_size;
+                               if (size + s > packlen)
+                               {
+                                       assert(packlen > size);
+                                       s= packlen-size;
+                               }
+
+                               r= sys_vircopy(SELF, D,
+                                       (vir_bytes)(rfdp->rfd_buf+o),
+                                       fxp_client, D, iovp->iov_addr, s);
+                               if (r != OK)
+                               {
+                                       panic("fxp_readv: sys_vircopy failed",
+                                               r);
+                               }
+
+                               size += s;
+                               if (size == packlen)
+                                       break;
+                               o += s;
+                       }
+                       if (size == packlen)
+                               break;
+               }
+               if (size < packlen)
+               {
+                       assert(0);
+               }
+       }
+       else
+       {  
+               assert(0);
+       }
+
+       fp->fxp_read_s= packlen;
+       fp->fxp_flags= (fp->fxp_flags & ~FF_READING) | FF_PACK_RECV;
+
+       /* Re-init the current buffer */
+       rfdp->rfd_status= 0;
+       rfdp->rfd_command= RFDC_EL;
+       rfdp->rfd_reserved= 0;
+       rfdp->rfd_res= 0;
+       rfdp->rfd_size= sizeof(rfdp->rfd_buf);
+
+       fxp_rx_nbuf= fp->fxp_rx_nbuf;
+       if (fxp_rx_head == 0)
+       {
+               prev_rfdp= &fp->fxp_rx_buf[fxp_rx_nbuf-1];
+       }
+       else
+               prev_rfdp= &rfdp[-1];
+
+       assert(prev_rfdp->rfd_command & RFDC_EL);
+       prev_rfdp->rfd_command &= ~RFDC_EL;
+
+       fxp_rx_head++;
+       if (fxp_rx_head == fxp_rx_nbuf)
+               fxp_rx_head= 0;
+       assert(fxp_rx_head < fxp_rx_nbuf);
+       fp->fxp_rx_head= fxp_rx_head;
+
+       if (!from_int)
+               reply(fp, OK, FALSE);
+
+       return;
+
+suspend:
+       if (fp->fxp_rx_need_restart)
+       {
+               fp->fxp_rx_need_restart= 0;
+
+               /* Check the status of the RU */
+               scb_status= fxp_inb(port, SCB_STATUS);
+               if ((scb_status & SS_RUS_MASK) != SS_RU_NORES)
+               {
+                       /* Race condition? */
+                       printf("fxp_readv: restart race: 0x%x\n",
+                               scb_status);
+                       assert((scb_status & SS_RUS_MASK) == SS_RU_READY);
+               }
+               else
+               {
+                       fxp_restart_ru(fp);
+               }
+       }
+       if (from_int)
+       {
+               assert(fp->fxp_flags & FF_READING);
+
+               /* No need to store any state */
+               return;
+       }
+
+       fp->fxp_rx_mess= *mp;
+       assert(!(fp->fxp_flags & FF_READING));
+       fp->fxp_flags |= FF_READING;
+
+       reply(fp, OK, FALSE);
+}
+
+
+/*===========================================================================*
+ *                             fxp_do_conf                                  *
+ *===========================================================================*/
+static void fxp_do_conf(fp)
+fxp_t *fp;
+{
+       static int timeout_flag;        /* must be static */
+
+       int r;
+       u32_t bus_addr;
+       struct cbl_conf cc;
+
+       /* Configure device */
+       cc.cc_status= 0;
+       cc.cc_command= CBL_C_EL | CBL_CONF;
+       cc.cc_linkaddr= 0;
+       memcpy(cc.cc_bytes, fp->fxp_conf_bytes, sizeof(cc.cc_bytes));
+
+       r= sys_umap(SELF, D, (vir_bytes)&cc, (phys_bytes)sizeof(cc),
+               &bus_addr);
+       if (r != OK)
+               panic("sys_umap failed", r);
+
+       fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
+
+       timeout_flag= 0;
+       sys_flagalrm(MICROS_TO_TICKS(100000), &timeout_flag);
+       do {
+               /* Wait for CU command to complete */
+               if (cc.cc_status & CBL_F_C)
+                       break;
+       } while (!timeout_flag);
+
+       if (!(cc.cc_status & CBL_F_C))
+               panic("fxp_do_conf: CU command failed to complete", NO_NUM);
+       if (!(cc.cc_status & CBL_F_OK))
+               panic("fxp_do_conf: CU command failed", NO_NUM);
+
+}
+
+
+/*===========================================================================*
+ *                             fxp_cu_ptr_cmd                               *
+ *===========================================================================*/
+static void fxp_cu_ptr_cmd(fp, cmd, bus_addr, check_idle)
+fxp_t *fp;
+int cmd;
+phys_bytes bus_addr;
+int check_idle;
+{
+       static int timeout_flag;        /* must be static */
+
+       port_t port;
+       u8_t scb_cmd;
+
+       port= fp->fxp_base_port;
+
+       if (check_idle)
+       {
+               /* Consistency check. Make sure that CU is idle */
+               if ((fxp_inb(port, SCB_STATUS) & SS_CUS_MASK) != SS_CU_IDLE)
+                       panic("fxp_cu_ptr_cmd: CU is not idle", NO_NUM);
+       }
+
+       fxp_outl(port, SCB_POINTER, bus_addr);
+       fxp_outb(port, SCB_CMD, cmd);
+
+       /* What is a reasonable time-out? There is nothing in the
+        * documentation. 1 ms should be enough.
+        */
+       timeout_flag= 0;
+       sys_flagalrm(MICROS_TO_TICKS(1000), &timeout_flag);
+       do {
+               /* Wait for CU command to be accepted */
+               scb_cmd= fxp_inb(port, SCB_CMD);
+               if ((scb_cmd & SC_CUC_MASK) == SC_CU_NOP)
+                       break;
+       } while (!timeout_flag);
+
+       if ((scb_cmd & SC_CUC_MASK) != SC_CU_NOP)
+               panic("fxp_cu_ptr_cmd: CU does not accept command", NO_NUM);
+}
+
+
+/*===========================================================================*
+ *                             fxp_ru_ptr_cmd                               *
+ *===========================================================================*/
+static void fxp_ru_ptr_cmd(fp, cmd, bus_addr, check_idle)
+fxp_t *fp;
+int cmd;
+phys_bytes bus_addr;
+int check_idle;
+{
+       static int timeout_flag;        /* must be static */
+
+       port_t port;
+       u8_t scb_cmd;
+
+       port= fp->fxp_base_port;
+
+       if (check_idle)
+       {
+               /* Consistency check, make sure that RU is idle */
+               if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_IDLE)
+                       panic("fxp_ru_ptr_cmd: RU is not idle", NO_NUM);
+       }
+
+       fxp_outl(port, SCB_POINTER, bus_addr);
+       fxp_outb(port, SCB_CMD, cmd);
+
+       timeout_flag= 0;
+       sys_flagalrm(MICROS_TO_TICKS(1000), &timeout_flag);
+       do {
+               /* Wait for RU command to be accepted */
+               scb_cmd= fxp_inb(port, SCB_CMD);
+               if ((scb_cmd & SC_RUC_MASK) == SC_RU_NOP)
+                       break;
+       } while (!timeout_flag);
+
+       if ((scb_cmd & SC_RUC_MASK) != SC_RU_NOP)
+               panic("fxp_ru_ptr_cmd: RU does not accept command", NO_NUM);
+}
+
+
+/*===========================================================================*
+ *                             fxp_restart_ru                               *
+ *===========================================================================*/
+static void fxp_restart_ru(fp)
+fxp_t *fp;
+{
+       int i, fxp_rx_nbuf;
+       port_t port;
+       struct rfd *rfdp;
+
+       port= fp->fxp_base_port;
+
+       fxp_rx_nbuf= fp->fxp_rx_nbuf;
+       for (i= 0, rfdp= fp->fxp_rx_buf; i<fxp_rx_nbuf; i++, rfdp++)
+       {
+               rfdp->rfd_status= 0;
+               rfdp->rfd_command= 0;
+               if (i == fp->fxp_rx_nbuf-1)
+                       rfdp->rfd_command= RFDC_EL;
+               rfdp->rfd_reserved= 0;
+               rfdp->rfd_res= 0;
+               rfdp->rfd_size= sizeof(rfdp->rfd_buf);
+       }
+       fp->fxp_rx_head= 0;
+
+       /* Make sure that RU is in the 'No resources' state */
+       if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_NORES)
+               panic("fxp_restart_ru: RU is in an unexpected state", NO_NUM);
+
+       fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
+               FALSE /* do not check idle */);
+}
+
+
+/*===========================================================================*
+ *                             fxp_getstat                                  *
+ *===========================================================================*/
+static void fxp_getstat(mp)
+message *mp;
+{
+       static int timeout_flag;        /* Must be static */
+
+       int dl_port;
+       port_t port;
+       fxp_t *fp;
+       u32_t *p;
+       eth_stat_t stats;
+
+       dl_port = mp->DL_PORT;
+       if (dl_port < 0 || dl_port >= FXP_PORT_NR)
+               panic("fxp_getstat: illegal port", dl_port);
+       fp= &fxp_table[dl_port];
+       fp->fxp_client= mp->DL_PROC;
+
+       assert(fp->fxp_mode == FM_ENABLED);
+       assert(fp->fxp_flags & FF_ENABLED);
+
+       port= fp->fxp_base_port;
+
+       p= &fp->fxp_stat.sc_tx_fcp;
+       *p= 0;
+
+       /* The dump commmand doesn't take a pointer. Setting a pointer
+        * doesn't hard though.
+        */
+       fxp_cu_ptr_cmd(fp, SC_CU_DUMP_SC, 0, FALSE /* do not check idle */);
+
+       timeout_flag= 0;
+       sys_flagalrm(MICROS_TO_TICKS(1000), &timeout_flag);
+       do {
+               /* Wait for CU command to complete */
+               if (*p != 0)
+                       break;
+       } while (!timeout_flag);
+
+       if (*p == 0)
+               panic("fxp_getstat: CU command failed to complete", NO_NUM);
+       if (*p != SCM_DSC)
+               panic("fxp_getstat: bad magic", NO_NUM);
+
+       stats.ets_recvErr=
+               fp->fxp_stat.sc_rx_crc +
+               fp->fxp_stat.sc_rx_align +
+               fp->fxp_stat.sc_rx_resource +
+               fp->fxp_stat.sc_rx_overrun +
+               fp->fxp_stat.sc_rx_cd +
+               fp->fxp_stat.sc_rx_short;
+       stats.ets_sendErr=
+               fp->fxp_stat.sc_tx_maxcol +
+               fp->fxp_stat.sc_tx_latecol +
+               fp->fxp_stat.sc_tx_crs;
+       stats.ets_OVW= fp->fxp_stat.sc_rx_overrun;
+       stats.ets_CRCerr= fp->fxp_stat.sc_rx_crc;
+       stats.ets_frameAll= fp->fxp_stat.sc_rx_align;
+       stats.ets_missedP= fp->fxp_stat.sc_rx_resource;
+       stats.ets_packetR= fp->fxp_stat.sc_rx_good;
+       stats.ets_packetT= fp->fxp_stat.sc_tx_good;
+       stats.ets_transDef= fp->fxp_stat.sc_tx_defered;
+       stats.ets_collision= fp->fxp_stat.sc_tx_totcol;
+       stats.ets_transAb= fp->fxp_stat.sc_tx_maxcol;
+       stats.ets_carrSense= fp->fxp_stat.sc_tx_crs;
+       stats.ets_fifoUnder= fp->fxp_stat.sc_tx_underrun;
+       stats.ets_fifoOver= fp->fxp_stat.sc_rx_overrun;
+       stats.ets_CDheartbeat= 0;
+       stats.ets_OWC= fp->fxp_stat.sc_tx_latecol;
+
+       put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
+               (vir_bytes) sizeof(stats), &stats);
+       reply(fp, OK, FALSE);
+}
+
+
+/*===========================================================================*
+ *                             fxp_handler                                  *
+ *===========================================================================*/
+static int fxp_handler(fp)
+fxp_t *fp;
+{
+       int port;
+       u16_t isr;
+
+       RAND_UPDATE
+
+       port= fp->fxp_base_port;
+
+       /* Ack interrupt */
+       isr= fxp_inb(port, SCB_INT_STAT);
+       fxp_outb(port, SCB_INT_STAT, isr);
+
+       if (isr & SIS_FR)
+       {
+               isr &= ~SIS_FR;
+
+               if (!fp->fxp_got_int && (fp->fxp_flags & FF_READING))
+               {
+                       fp->fxp_got_int= TRUE;
+                       interrupt(fxp_tasknr);
+               }
+       }
+       if (isr & SIS_CNA)
+       {
+               isr &= ~SIS_CNA;
+               if (!fp->fxp_tx_idle)
+               {
+                       fp->fxp_send_int= TRUE;
+                       if (!fp->fxp_got_int)
+                       {
+                               fp->fxp_got_int= TRUE;
+                               interrupt(fxp_tasknr);
+                       }
+               }
+       }
+       if (isr & SIS_RNR)
+       {
+               isr &= ~SIS_RNR;
+
+               /* Assume that receive buffer is full of packets. fxp_readv
+                * will restart the RU.
+                */
+               fp->fxp_rx_need_restart= 1;
+       }
+       if (isr)
+       {
+               printf("fxp_handler: unhandled interrupt: isr = 0x%02x\n",
+                       isr);
+       }
+
+       return 1;
+}
+
+
+/*===========================================================================*
+ *                             fxp_check_ints                               *
+ *===========================================================================*/
+static void fxp_check_ints(fp)
+fxp_t *fp;
+{
+       int n, fxp_flags, prev_tail;
+       int fxp_tx_tail, fxp_tx_nbuf, fxp_tx_threshold;
+       port_t port;
+       u32_t busaddr;
+       u16_t tx_status;
+       u8_t scb_status;
+       struct tx *txp;
+
+       fxp_flags= fp->fxp_flags;
+
+       if (fxp_flags & FF_READING)
+       {
+               if (!(fp->fxp_rx_buf[fp->fxp_rx_head].rfd_status & RFDS_C))
+                       ; /* Nothing */
+               else if (fp->fxp_rx_mess.m_type == DL_READV)
+               {
+                       fxp_readv(&fp->fxp_rx_mess, TRUE /* from int */,
+                               TRUE /* vectored */);
+               }
+               else
+               {
+                       assert(fp->fxp_rx_mess.m_type == DL_READ);
+                       fxp_readv(&fp->fxp_rx_mess, TRUE /* from int */,
+                               FALSE /* !vectored */);
+               }
+       }
+       if (fp->fxp_tx_idle)
+               ;       /* Nothing to do */
+       else if (fp->fxp_send_int)
+       {
+               fp->fxp_send_int= FALSE;
+               fxp_tx_tail= fp->fxp_tx_tail;
+               fxp_tx_nbuf= fp->fxp_tx_nbuf;
+               n= 0;
+               for (;;)
+               {
+                       txp= &fp->fxp_tx_buf[fxp_tx_tail];
+                       tx_status= txp->tx_status;
+                       if (!(tx_status & TXS_C))
+                               break;
+
+                       n++;
+
+                       assert(tx_status & TXS_OK);
+                       if (tx_status & TXS_U)
+                       {
+                               fxp_tx_threshold= fp->fxp_tx_threshold;
+                               if (fxp_tx_threshold < TXTT_MAX)
+                               {
+                                       fxp_tx_threshold++;
+                                       fp->fxp_tx_threshold= fxp_tx_threshold;
+                               }
+                               printf(
+                       "fxp_check_ints: fxp_tx_threshold = 0x%x\n",
+                                       fxp_tx_threshold);
+                       }
+
+                       if (txp->tx_command & TXC_EL)
+                       {
+                               fp->fxp_tx_idle= 1;
+                               break;
+                       }
+
+                       fxp_tx_tail++;
+                       if (fxp_tx_tail == fxp_tx_nbuf)
+                               fxp_tx_tail= 0;
+                       assert(fxp_tx_tail < fxp_tx_nbuf);
+               }
+
+               if (fp->fxp_need_conf)
+               {
+                       /* Check the status of the CU */
+                       port= fp->fxp_base_port;
+                       scb_status= fxp_inb(port, SCB_STATUS);
+                       if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
+                       {
+                               /* Nothing to do */
+                               printf("scb_status = 0x%x\n", scb_status);
+                       }
+                       else
+                       {
+                               printf("fxp_check_ints: fxp_need_conf\n");
+                               fp->fxp_need_conf= FALSE;
+                               fxp_do_conf(fp);
+                       }
+               }
+
+               if (n)
+               {
+                       if (!fp->fxp_tx_idle)
+                       {
+                               fp->fxp_tx_tail= fxp_tx_tail;
+                               
+                               /* Check the status of the CU */
+                               port= fp->fxp_base_port;
+                               scb_status= fxp_inb(port, SCB_STATUS);
+                               if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
+                               {
+                                       /* Nothing to do */
+                                       printf("scb_status = 0x%x\n",
+                                               scb_status);
+
+                               }
+                               else
+                               {
+                                       if (fxp_tx_tail == 0)
+                                               prev_tail= fxp_tx_nbuf-1;
+                                       else
+                                               prev_tail= fxp_tx_tail-1;
+                                       busaddr= fp->fxp_tx_buf[prev_tail].
+                                               tx_linkaddr;
+
+                                       fxp_cu_ptr_cmd(fp, SC_CU_START,
+                                               busaddr, 1 /* check idle */);
+                               }
+                       }
+
+                       if (fp->fxp_flags & FF_SEND_AVAIL)
+                       {
+                               if (fp->fxp_tx_mess.m_type == DL_WRITEV)
+                               {
+                                       fxp_writev(&fp->fxp_tx_mess,
+                                               TRUE /* from int */,
+                                               TRUE /* vectored */);
+                               }
+                               else
+                               {
+                                       assert(fp->fxp_tx_mess.m_type ==
+                                               DL_WRITE);
+                                       fxp_writev(&fp->fxp_tx_mess,
+                                               TRUE /* from int */,
+                                               FALSE /* !vectored */);
+                               }
+                       }
+               }
+               
+       }
+       if (fp->fxp_report_link)
+               fxp_report_link(fp);
+
+       if (fp->fxp_flags & (FF_PACK_SENT | FF_PACK_RECV))
+               reply(fp, OK, TRUE);
+}
+
+
+/*===========================================================================*
+ *                             fxp_watchdog_f                               *
+ *===========================================================================*/
+static void fxp_watchdog_f(tp)
+timer_t *tp;
+{
+       int i;
+       fxp_t *fp;
+
+       tmr_arg(&fxp_watchdog)->ta_int= 0;
+       fxp_set_timer(&fxp_watchdog, HZ, fxp_watchdog_f);
+
+       for (i= 0, fp = &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
+       {
+               if (fp->fxp_mode != FM_ENABLED)
+                       continue;
+
+               /* Handle race condition, MII interface mgith be busy */
+               if(!fp->fxp_mii_busy)
+               {
+                       /* Check the link status. */
+                       if (fxp_link_changed(fp))
+                       {
+                               printf("fxp_watchdog_f: link changed\n");
+                               fp->fxp_report_link= TRUE;
+                               fp->fxp_got_int= TRUE;
+                               interrupt(fxp_tasknr);
+                       }
+               }
+               
+               if (!(fp->fxp_flags & FF_SEND_AVAIL))
+               {
+                       /* Assume that an idle system is alive */
+                       fp->fxp_tx_alive= TRUE;
+                       continue;
+               }
+               if (fp->fxp_tx_alive)
+               {
+                       fp->fxp_tx_alive= FALSE;
+                       continue;
+               }
+
+               fp->fxp_need_reset= TRUE;
+               fp->fxp_got_int= TRUE;
+               interrupt(fxp_tasknr);
+       }
+}
+
+
+/*===========================================================================*
+ *                             fxp_link_changed                             *
+ *===========================================================================*/
+static int fxp_link_changed(fp)
+fxp_t *fp;
+{
+       u16_t scr;
+
+       scr= mii_read(fp, MII_SCR);
+       scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
+
+       return (fp->fxp_mii_scr != scr);
+}
+
+
+/*===========================================================================*
+ *                             fxp_report_link                              *
+ *===========================================================================*/
+static void fxp_report_link(fp)
+fxp_t *fp;
+{
+       port_t port;
+       u16_t mii_ctrl, mii_status, mii_id1, mii_id2, 
+               mii_ana, mii_anlpa, mii_ane, mii_extstat,
+               mii_ms_ctrl, mii_ms_status, scr;
+       u32_t oui;
+       int model, rev;
+       int f, link_up, ms_regs;
+
+       /* Assume an 82555 (compatible) PHY. The should be changed for
+        * 82557 NICs with different PHYs
+        */
+       ms_regs= 0;     /* No master/slave registers. */
+
+       fp->fxp_report_link= FALSE;
+       port= fp->fxp_base_port;
+
+       scr= mii_read(fp, MII_SCR);
+       scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
+       fp->fxp_mii_scr= scr;
+
+       mii_ctrl= mii_read(fp, MII_CTRL);
+       mii_read(fp, MII_STATUS); /* Read the status register twice, why? */
+       mii_status= mii_read(fp, MII_STATUS);
+       mii_id1= mii_read(fp, MII_PHYID_H);
+       mii_id2= mii_read(fp, MII_PHYID_L);
+       mii_ana= mii_read(fp, MII_ANA);
+       mii_anlpa= mii_read(fp, MII_ANLPA);
+       mii_ane= mii_read(fp, MII_ANE);
+       if (mii_status & MII_STATUS_EXT_STAT)
+               mii_extstat= mii_read(fp, MII_EXT_STATUS);
+       else
+               mii_extstat= 0;
+       if (ms_regs)
+       {
+               mii_ms_ctrl= mii_read(fp, MII_MS_CTRL);
+               mii_ms_status= mii_read(fp, MII_MS_STATUS);
+       }
+       else
+       {
+               mii_ms_ctrl= 0;
+               mii_ms_status= 0;
+       }
+
+       /* How do we know about the link status? */
+       link_up= !!(mii_status & MII_STATUS_LS);
+
+       fp->fxp_link_up= link_up;
+       if (!link_up)
+       {
+               printf("%s: link down\n", fp->fxp_name);
+               return;
+       }
+
+
+       oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) | 
+               ((mii_id2 & MII_PL_OUI_L_MASK) >> MII_PL_OUI_L_SHIFT);
+       model= ((mii_id2 & MII_PL_MODEL_MASK) >> MII_PL_MODEL_SHIFT);
+       rev= (mii_id2 & MII_PL_REV_MASK);
+
+       printf("OUI 0x%06lx, Model 0x%02x, Revision 0x%x\n", oui, model, rev);
+
+       if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
+       {
+               printf("%s: PHY: ", fp->fxp_name);
+               f= 1;
+               if (mii_ctrl & MII_CTRL_LB)
+               {
+                       printf("loopback mode");
+                       f= 0;
+               }
+               if (mii_ctrl & MII_CTRL_PD)
+               {
+                       if (!f) printf(", ");
+                       f= 0;
+                       printf("powered down");
+               }
+               if (mii_ctrl & MII_CTRL_ISO)
+               {
+                       if (!f) printf(", ");
+                       f= 0;
+                       printf("isolated");
+               }
+               printf("\n");
+               return;
+       }
+       if (!(mii_ctrl & MII_CTRL_ANE))
+       {
+               printf("%s: manual config: ", fp->fxp_name);
+               switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
+               {
+               case MII_CTRL_SP_10:    printf("10 Mbps"); break;
+               case MII_CTRL_SP_100:   printf("100 Mbps"); break;
+               case MII_CTRL_SP_1000:  printf("1000 Mbps"); break;
+               case MII_CTRL_SP_RES:   printf("reserved speed"); break;
+               }
+               if (mii_ctrl & MII_CTRL_DM)
+                       printf(", full duplex");
+               else
+                       printf(", half duplex");
+               printf("\n");
+               return;
+       }
+
+       if (!debug) goto resspeed;
+
+       printf("%s: ", fp->fxp_name);
+       mii_print_stat_speed(mii_status, mii_extstat);
+       printf("\n");
+
+       if (!(mii_status & MII_STATUS_ANC))
+               printf("%s: auto-negotiation not complete\n", fp->fxp_name);
+       if (mii_status & MII_STATUS_RF)
+               printf("%s: remote fault detected\n", fp->fxp_name);
+       if (!(mii_status & MII_STATUS_ANA))
+       {
+               printf("%s: local PHY has no auto-negotiation ability\n",
+                       fp->fxp_name);
+       }
+       if (!(mii_status & MII_STATUS_LS))
+               printf("%s: link down\n", fp->fxp_name);
+       if (mii_status & MII_STATUS_JD)
+               printf("%s: jabber condition detected\n", fp->fxp_name);
+       if (!(mii_status & MII_STATUS_EC))
+       {
+               printf("%s: no extended register set\n", fp->fxp_name);
+               goto resspeed;
+       }
+       if (!(mii_status & MII_STATUS_ANC))
+               goto resspeed;
+
+       printf("%s: local cap.: ", fp->fxp_name);
+       if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
+       {
+               printf("1000 Mbps: T-");
+               switch(mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
+               {
+               case MII_MSC_1000T_FD:  printf("FD"); break;
+               case MII_MSC_1000T_HD:  printf("HD"); break;
+               default:                printf("FD/HD"); break;
+               }
+               if (mii_ana)
+                       printf(", ");
+       }
+       mii_print_techab(mii_ana);
+       printf("\n");
+
+       if (mii_ane & MII_ANE_PDF)
+               printf("%s: parallel detection fault\n", fp->fxp_name);
+       if (!(mii_ane & MII_ANE_LPANA))
+       {
+               printf("%s: link-partner does not support auto-negotiation\n",
+                       fp->fxp_name);
+               goto resspeed;
+       }
+
+       printf("%s: remote cap.: ", fp->fxp_name);
+       if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
+       if (mii_ms_status & (MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
+       {
+               printf("1000 Mbps: T-");
+               switch(mii_ms_status &
+                       (MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
+               {
+               case MII_MSS_LP1000T_FD:        printf("FD"); break;
+               case MII_MSS_LP1000T_HD:        printf("HD"); break;
+               default:                        printf("FD/HD"); break;
+               }
+               if (mii_anlpa)
+                       printf(", ");
+       }
+       mii_print_techab(mii_anlpa);
+       printf("\n");
+
+       if (ms_regs)
+       {
+               printf("%s: ", fp->fxp_name);
+               if (mii_ms_ctrl & MII_MSC_MS_MANUAL)
+               {
+                       printf("manual %s",
+                               (mii_ms_ctrl & MII_MSC_MS_VAL) ?
+                               "MASTER" : "SLAVE");
+               }
+               else
+               {
+                       printf("%s device",
+                               (mii_ms_ctrl & MII_MSC_MULTIPORT) ?
+                               "multiport" : "single-port");
+               }
+               if (mii_ms_ctrl & MII_MSC_RES)
+                       printf(" reserved<0x%x>", mii_ms_ctrl & MII_MSC_RES);
+               printf(": ");
+               if (mii_ms_status & MII_MSS_FAULT)
+                       printf("M/S config fault");
+               else if (mii_ms_status & MII_MSS_MASTER)
+                       printf("MASTER");
+               else
+                       printf("SLAVE");
+               printf("\n");
+       }
+
+       if (mii_ms_status & (MII_MSS_LP1000T_FD|MII_MSS_LP1000T_HD))
+       {
+               if (!(mii_ms_status & MII_MSS_LOCREC))
+               {
+                       printf("%s: local receiver not OK\n",
+                               fp->fxp_name);
+               }
+               if (!(mii_ms_status & MII_MSS_REMREC))
+               {
+                       printf("%s: remote receiver not OK\n",
+                               fp->fxp_name);
+               }
+       }
+       if (mii_ms_status & (MII_MSS_RES|MII_MSS_IDLE_ERR))
+       {
+               printf("%s", fp->fxp_name);
+               if (mii_ms_status & MII_MSS_RES)
+                       printf(" reserved<0x%x>", mii_ms_status & MII_MSS_RES);
+               if (mii_ms_status & MII_MSS_IDLE_ERR)
+               {
+                       printf(" idle error %d",
+                               mii_ms_status & MII_MSS_IDLE_ERR);
+               }
+               printf("\n");
+       }
+
+resspeed:
+       printf("%s: link up, %d Mbps, %s duplex\n",
+               fp->fxp_name, (scr & MII_SCR_100) ? 100 : 10,
+               (scr & MII_SCR_FD) ? "full" : "half");
+}
+
+
+/*===========================================================================*
+ *                             fxp_stop                                     *
+ *===========================================================================*/
+static void fxp_stop()
+{
+       int i;
+       port_t port;
+       fxp_t *fp;
+
+       for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
+       {
+               if (fp->fxp_mode != FM_ENABLED)
+                       continue;
+               if (!(fp->fxp_flags & FF_ENABLED))
+                       continue;
+               port= fp->fxp_base_port;
+
+
+               /* Reset device */
+               if (debug)
+                       printf("%s: resetting device\n", fp->fxp_name);
+               fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
+       }
+       sys_exit(0);
+}
+
+
+/*===========================================================================*
+ *                             reply                                        *
+ *===========================================================================*/
+static void reply(fp, err, may_block)
+fxp_t *fp;
+int err;
+int may_block;
+{
+       message reply;
+       int status;
+       int r;
+
+       status = 0;
+       if (fp->fxp_flags & FF_PACK_SENT)
+               status |= DL_PACK_SEND;
+       if (fp->fxp_flags & FF_PACK_RECV)
+               status |= DL_PACK_RECV;
+
+       reply.m_type = DL_TASK_REPLY;
+       reply.DL_PORT = fp - fxp_table;
+       reply.DL_PROC = fp->fxp_client;
+       reply.DL_STAT = status | ((u32_t) err << 16);
+       reply.DL_COUNT = fp->fxp_read_s;
+#if 0
+       reply.DL_CLCK = get_uptime();
+#else
+       reply.DL_CLCK = 0;
+#endif
+
+       r= send(fp->fxp_client, &reply);
+
+       if (r == ELOCKED && may_block)
+       {
+               printW(); printf("send locked\n");
+               return;
+       }
+
+       if (r < 0)
+               panic("fxp: send failed:", r);
+       
+       fp->fxp_read_s = 0;
+       fp->fxp_flags &= ~(FF_PACK_SENT | FF_PACK_RECV);
+}
+
+
+/*===========================================================================*
+ *                             mess_reply                                   *
+ *===========================================================================*/
+static void mess_reply(req, reply_mess)
+message *req;
+message *reply_mess;
+{
+       if (send(req->m_source, reply_mess) != OK)
+               panic("fxp: unable to mess_reply", NO_NUM);
+}
+
+
+/*===========================================================================*
+ *                             put_userdata                                 *
+ *===========================================================================*/
+static void put_userdata(user_proc, user_addr, count, loc_addr)
+int user_proc;
+vir_bytes user_addr;
+vir_bytes count;
+void *loc_addr;
+{
+       int r;
+
+       r= sys_vircopy(SELF, D, (vir_bytes)loc_addr,
+               user_proc, D, user_addr, count);
+       if (r != OK)
+               panic("put_userdata: sys_vircopy failed", r);
+}
+
+
+/*===========================================================================*
+ *                             eeprom_read                                  *
+ *===========================================================================*/
+PRIVATE u16_t eeprom_read(fp, reg)
+fxp_t *fp;
+int reg;
+{
+       port_t port;
+       u16_t v;
+       int b, i, alen;
+
+       alen= fp->fxp_ee_addrlen;
+       if (!alen)
+       {
+               eeprom_addrsize(fp);
+               alen= fp->fxp_ee_addrlen;
+               assert(alen == 6 || alen == 8);
+       }
+
+       port= fp->fxp_base_port;
+
+       fxp_outb(port, CSR_EEPROM, CE_EECS);    /* Enable EEPROM */
+       v= EEPROM_READ_PREFIX;
+       for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
+       {
+               b= ((v & (1 << i)) ? CE_EEDI : 0);
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);        /* bit */
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
+               micro_delay(EESK_PERIOD/2+1);
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);                
+               micro_delay(EESK_PERIOD/2+1);
+       }
+       
+       v= reg;
+       for (i= alen-1; i >= 0; i--)
+       {
+               b= ((v & (1 << i)) ? CE_EEDI : 0);
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);        /* bit */
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
+               micro_delay(EESK_PERIOD/2+1);
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);                
+               micro_delay(EESK_PERIOD/2+1);
+       }
+
+       v= 0;
+       for (i= 0; i<16; i++)
+       {
+               fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
+               micro_delay(EESK_PERIOD/2+1);
+               b= !!(fxp_inb(port, CSR_EEPROM) & CE_EEDO);
+               v= (v << 1) | b;
+               fxp_outb(port, CSR_EEPROM, CE_EECS );           
+               micro_delay(EESK_PERIOD/2+1);
+       }
+       fxp_outb(port, CSR_EEPROM, 0);  /* Disable EEPROM */
+       micro_delay(EECS_DELAY);
+
+       return v;
+}
+
+
+/*===========================================================================*
+ *                             eeprom_addrsize                              *
+ *===========================================================================*/
+PRIVATE void eeprom_addrsize(fp)
+fxp_t *fp;
+{
+       port_t port;
+       u16_t v;
+       int b, i;
+
+       port= fp->fxp_base_port;
+
+       /* Try to find out the size of the EEPROM */
+       fxp_outb(port, CSR_EEPROM, CE_EECS);    /* Enable EEPROM */
+       v= EEPROM_READ_PREFIX;
+       for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
+       {
+               b= ((v & (1 << i)) ? CE_EEDI : 0);
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);        /* bit */
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
+               micro_delay(EESK_PERIOD/2+1);
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);                
+               micro_delay(EESK_PERIOD/2+1);
+       }
+
+       for (i= 0; i<32; i++)
+       {
+               b= 0;
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);        /* bit */
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
+               micro_delay(EESK_PERIOD/2+1);
+               fxp_outb(port, CSR_EEPROM, CE_EECS | b);                
+               micro_delay(EESK_PERIOD/2+1);
+               v= fxp_inb(port, CSR_EEPROM);
+               if (!(v & CE_EEDO))
+                       break;
+       }
+       if (i >= 32)
+               panic("eeprom_addrsize: failed", NO_NUM);
+       fp->fxp_ee_addrlen= i+1;
+
+       /* Discard 16 data bits */
+       for (i= 0; i<16; i++)
+       {
+               fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
+               micro_delay(EESK_PERIOD/2+1);
+               fxp_outb(port, CSR_EEPROM, CE_EECS );           
+               micro_delay(EESK_PERIOD/2+1);
+       }
+       fxp_outb(port, CSR_EEPROM, 0);  /* Disable EEPROM */
+       micro_delay(EECS_DELAY);
+
+       printf("%s EEPROM address length: %d\n",
+               fp->fxp_name, fp->fxp_ee_addrlen);
+}
+
+
+/*===========================================================================*
+ *                             mii_read                                     *
+ *===========================================================================*/
+PRIVATE u16_t mii_read(fp, reg)
+fxp_t *fp;
+int reg;
+{
+       static int timeout_flag;        /* must be static */
+
+       port_t port;
+       u32_t v;
+
+       port= fp->fxp_base_port;
+
+       assert(!fp->fxp_mii_busy);
+       fp->fxp_mii_busy++;
+
+       if (!(fxp_inl(port, CSR_MDI_CTL) & CM_READY))
+               panic("mii_read: MDI not ready", NO_NUM);
+       fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) |
+               (reg << CM_REG_SHIFT));
+
+       timeout_flag= 0;
+       sys_flagalrm(MICROS_TO_TICKS(1000), &timeout_flag);
+       do {
+               v= fxp_inl(port, CSR_MDI_CTL);
+               if (v & CM_READY)
+                       break;
+       } while (!timeout_flag);
+
+       if (!(v & CM_READY))
+               panic("mii_read: MDI not ready after command", NO_NUM);
+
+       fp->fxp_mii_busy--;
+       assert(!fp->fxp_mii_busy);
+
+       return v & CM_DATA_MASK;
+}
+
+/*===========================================================================*
+ *                             fxp_set_timer                                *
+ *===========================================================================*/
+PRIVATE void fxp_set_timer(tp, delta, watchdog)
+timer_t *tp;                           /* timer to be set */
+clock_t delta;                         /* in how many ticks */
+tmr_func_t watchdog;                   /* watchdog function to be called */
+{
+       clock_t now;                            /* current time */
+       int r;
+
+       /* Get the current time. */
+       r= sys_getuptime(&now);
+       if (r != OK)
+               panic("unable to get uptime from clock", r);
+
+       /* Add the timer to the local timer queue. */
+       tmrs_settimer(&fxp_timers, tp, now + delta, watchdog);
+
+       /* Possibly reschedule an alarm call. This happens when a new timer
+        * is added in front. 
+        */
+       if (fxp_next_timeout == 0 || 
+               fxp_timers->tmr_exp_time < fxp_next_timeout)
+       {
+               fxp_next_timeout= fxp_timers->tmr_exp_time; 
+               printf("fxp_set_timer: calling sys_syncalrm for %d (now%+d)\n",
+                       fxp_next_timeout, fxp_next_timeout-now);
+               r= sys_syncalrm(SELF, fxp_next_timeout, 1);
+               if (r != OK)
+                       panic("unable to set synchronous alarm", r);
+       }
+}
+
+
+/*===========================================================================*
+ *                             fxp_expire_tmrs                              *
+ *===========================================================================*/
+PRIVATE void fxp_expire_timers()
+{
+/* A synchronous alarm message was received. Check if there are any expired 
+ * timers. Possibly reschedule the next alarm.  
+ */
+  clock_t now;                         /* current time */
+  timer_t *tp;
+  int r;
+
+  /* Get the current time to compare the timers against. */
+  r= sys_getuptime(&now);
+  if (r != OK)
+       panic("Unable to get uptime from clock.", r);
+
+  /* Scan the timers queue for expired timers. Dispatch the watchdog function
+   * for each expired timers. Possibly a new alarm call must be scheduled.
+   */
+  tmrs_exptimers(&fxp_timers, now);
+  if (fxp_timers == NULL)
+       fxp_next_timeout= TMR_NEVER;
+  else
+  {                                      /* set new alarm */
+       fxp_next_timeout = fxp_timers->tmr_exp_time;
+       r= sys_syncalrm(SELF, fxp_next_timeout, 1);
+       if (r != OK)
+               panic("Unable to set synchronous alarm.", r);
+  }
+}
+
+static void micro_delay(unsigned long usecs)
+{
+       tick_delay(MICROS_TO_TICKS(usecs));
+}
+
+static u8_t do_inb(port_t port)
+{
+       int r;
+       u8_t value;
+
+       r= sys_inb(port, &value);
+       if (r != OK)
+               panic("sys_inb failed", r);
+       return value;
+}
+
+static u32_t do_inl(port_t port)
+{
+       int r;
+       u32_t value;
+
+       r= sys_inl(port, &value);
+       if (r != OK)
+               panic("sys_inl failed", r);
+       return value;
+}
+
+static void do_outb(port_t port, u8_t value)
+{
+       int r;
+
+       r= sys_outb(port, value);
+       if (r != OK)
+               panic("sys_outb failed", r);
+}
+
+static void do_outl(port_t port, u32_t value)
+{
+       int r;
+
+       r= sys_outl(port, value);
+       if (r != OK)
+               panic("sys_outl failed", r);
+}
+
+#endif /* ENABLE_FXP */
+
+/*
+ * $PchId: fxp.c,v 1.4 2005/01/31 22:10:37 philip Exp $
+ */
+
diff --git a/drivers/fxp/fxp.h b/drivers/fxp/fxp.h
new file mode 100644 (file)
index 0000000..66af4fa
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ibm/fxp.h
+
+Registers and datastructures of the Intel 82557, 82558, 82559, 82550,
+and 82562 fast ethernet controllers.
+
+Created:       Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
+*/
+
+/* Revisions in PCI_REV */
+#define FXP_REV_82557A         0x01
+#define FXP_REV_82557B         0x02
+#define FXP_REV_82557C         0x03
+#define FXP_REV_82558A         0x04
+#define FXP_REV_82558B         0x05
+#define FXP_REV_82559A         0x06
+#define FXP_REV_82559B         0x07
+#define FXP_REV_82559C         0x08
+#define FXP_REV_82559ERA       0x09
+#define FXP_REV_82550_1        0x0C
+#define FXP_REV_82550_2                0x0D
+#define FXP_REV_82550_3                0x0E
+#define FXP_REV_82551_1                0x0F
+#define FXP_REV_82551_2                0x10
+
+/* Control/Status Registers (CSR). The first 8 bytes are called
+ * System Control Block (SCB)
+ */
+#define SCB_STATUS     0x00    /* Lower half of the SCB status word. CU and
+                                * RU status.
+                                */
+#define            SS_CUS_MASK         0xC0    /* CU Status */
+#define                SS_CU_IDLE              0x00    /* Idle */
+#define                SS_CU_SUSP              0x40    /* Suspended */
+#define                SS_CU_LPQA              0x80    /* LPQ Active */
+#define                SS_CU_HQPA              0xC0    /* HQP Active */
+#define            SS_RUS_MASK         0x3C    /* RU Status */
+#define                SS_RU_IDLE              0x00    /* Idle */
+#define                SS_RU_SUSP              0x04    /* Suspended */
+#define                SS_RU_NORES             0x08    /* No Resources */
+#define                SS_RU_READY             0x10    /* Ready */
+                                               /* Other values are reserved */
+#define            SS_RESERVED         0x03    /* Reserved */
+#define SCB_INT_STAT   0x01    /* Upper half of the SCB status word.
+                                * Interrupt status. Also used to acknoledge
+                                * interrupts.
+                                */
+#define                SIS_CX  0x80    /* CU command with interrupt bit set. On
+                                * 82557 also TNO Interrupt.
+                                */
+#define                SIS_FR  0x40    /* Frame Received */
+#define                SIS_CNA 0x20    /* CU Not Active */
+#define                SIS_RNR 0x10    /* RU Not Ready */
+#define                SIS_MDI 0x08    /* MDI read/write cycle completed */
+#define                SIS_SWI 0x04    /* Software Interrupt */
+#define                SIS_RES 0x02    /* Reserved */
+#define                SIS_FCP 0x01    /* Flow Control Pause Interrupt (82558 and
+                                * later, reserved on 82557)
+                                */
+#define SCB_CMD                0x02    /* Lower half of the SCB command word. CU and
+                                * RU commands.
+                                */
+#define            SC_CUC_MASK         0xF0
+#define                SC_CU_NOP               0x00    /* NOP */
+#define                SC_CU_START             0x10    /* Start CU */
+#define                SC_CU_RESUME            0x20    /* Resume CU */
+#define                SC_CU_LOAD_DCA          0x40    /* Load Dump Counters Address */
+#define                SC_CU_DUMP_SC           0x50    /* Dump Statistical Counters */
+#define                SC_CU_LOAD_BASE         0x60    /* Load CU Base */
+#define                SC_CU_DUMP_RSET_SC      0x70    /* Dump and Reset Counters */
+#define                SC_CU_STATIC_RESUME     0xA0    /* Static Resume, 82558 and
+                                                * above
+                                                */
+#define            SC_RESERVED         0x08    /* Reserved */
+#define            SC_RUC_MASK         0x07    /* RU Command Mask */
+#define                SC_RU_NOP               0x00    /* NOP */
+#define                SC_RU_START             0x01    /* Start RU */
+#define                SC_RU_RESUME            0x02    /* Resume RU */
+#define                SC_RU_DMA_REDIR         0x03    /* DMA Redirect */
+#define                SC_RU_ABORT             0x04    /* Abort RU */
+#define                SC_RU_LOAD_HDR          0x05    /* Load Header Data Size */
+#define                SC_RU_LOAD_BASE         0x06    /* Load RU Base */
+#define SCB_INT_MASK   0x03    /* Upper half of the SCB command word. 
+                                * Interrupt mask. Can also be used to
+                                * generate a 'software' interrupt.
+                                */
+                               /* The following 6 mask bits are not valid on
+                                * the 82557.
+                                */
+#define            SIM_CX      0x80    /* Mask CX */
+#define            SIM_FR      0x40    /* Mask FR */
+#define            SIM_CNA     0x20    /* Mask CNA */
+#define            SIM_RNR     0x10    /* Mask RNR */
+#define            SIM_ER      0x08    /* Mask ER */
+#define            SIM_FCP     0x04    /* Mask FCP */
+#define            SIM_SI      0x02    /* Generate Software Interrupt */
+#define            SIM_M       0x01    /* Mask all interrupts */
+#define SCB_POINTER    0x04    /* A 32-bit (pointer) argument for CU and RU
+                                * commands.
+                                */
+#define CSR_PORT       0x08    /* Control functions that bypass the SCB */
+#define            CP_PTR_MASK         0xFFFFFFF0      /* Argument pointer */
+#define            CP_CMD_MASK         0x0000000F      /* Commands bits */
+#define                CP_CMD_SOFT_RESET       0x00000000      /* Software reset */
+#define                    CSR_PORT_RESET_DELAY        10      /* Wait for reset to
+                                                        * complete. In micro
+                                                        * seconds.
+                                                        */
+#define                CP_CMD_SELF_TEST        0x00000001      /* Self test */
+#define                CP_CMD_SEL_RESET        0x00000002      /* Selective reset */
+#define                CP_CMD_DUMP             0x00000003      /* Dump */
+#define                CP_CMD_DUMP_WAKEUP      0x00000007      /* Dump and wake-up,
+                                                        * 82559 and later.
+                                                        */
+#define        CSR_RESERVED    0x0C    /* reserved, 16-bits */
+#define CSR_EEPROM     0x0E    /* EEPROM Control Register */
+#define            CE_RESERVED 0xF0    /* Reserved */
+#define            CE_EEDO     0x08    /* Serial Data Out  (of the EEPROM) */
+#define            CE_EEDI     0x04    /* Serial Data In (to the EEPROM) */
+#define            CE_EECS     0x02    /* Chip Select */
+#define            CE_EESK     0x01    /* Serial Clock */
+#define CSR_RESERVED1  0x0F    /* Reserved */
+#define CSR_MDI_CTL    0x10    /* MDI Control Register, 32-bits */
+#define            CM_RESERVED         0xC0000000      /* Reserved */
+#define            CM_IE               0x20000000      /* Enable Interrupt */
+#define            CM_READY            0x10000000      /* Command completed */
+#define            CM_OPCODE_MASK      0x0C000000      /* Opcode */
+#define                CM_WRITE                0x04000000      /* Write */
+#define                CM_READ                 0x08000000      /* Read */
+#define            CM_PHYADDR_MASK     0x03E00000      /* Which PHY */
+#define                CM_PHYADDR_SHIFT 21
+#define            CM_REG_MASK         0x001F0000      /* Which register in the PHY */
+#define                CM_REG_SHIFT    16
+#define            CM_DATA_MASK        0x0000FFFF      /* Data to be read or written */
+
+/* Control Block List (CBL) commands */
+#define CBL_NOP                0       /* No-operation */
+#define CBL_AIS                1       /* Individual Address Setup */
+#define CBL_CONF       2       /* Configure NIC */
+#define CBL_MAS                3       /* Multicast Address Setup */
+#define CBL_XMIT       4       /* Transmit */
+#define CBL_LM         5       /* Load Microcode */
+#define CBL_DUMP       6       /* Dump Internal Registers */
+#define CBL_DIAG       7       /* Diagnose Command */
+
+/* Common command fields */
+#define CBL_C_CMD_MASK 0x0007  /* Command bits */
+#define CBL_C_EL       0x8000  /* End of CBL */
+#define CBL_C_S                0x4000  /* Suspend after the completion of the CB */
+#define CBL_C_I                0x2000  /* Request CX Interrupt */
+#define CBL_C_RES      0x1FF8  /* Reserved */
+
+/* Command flags */
+#define CBL_F_C                0x8000  /* Command has completed */
+#define CBL_F_RES1     0x4000  /* Reserved */
+#define CBL_F_OK       0x2000  /* Command was executed without errors */
+#define CBL_F_RES0     0x1FFF  /* Reserved */
+
+/* Individual Address Setup (1) */
+struct ias
+{
+       u16_t ias_status;
+       u16_t ias_command;
+       u32_t ias_linkaddr;
+       u8_t ias_ethaddr[6];
+       u8_t ias_reserved[2];
+};
+
+/* Configure (2) */
+#define CC_BYTES_NR    22      /* Number of configuration bytes */
+struct cbl_conf
+{
+       u16_t cc_status;
+       u16_t cc_command;
+       u32_t cc_linkaddr;
+       u8_t cc_bytes[CC_BYTES_NR];
+};
+
+/* Byte 0 */
+#define CCB0_RES       0xC0    /* Reserved (0) */
+#define CCB0_BYTECOUNT 0x3F    /* Byte Count (typically either 8 or 22) */
+
+/* Byte 1 */
+#define CCB1_RES       0x80    /* Reserved (0) */
+#define CCB1_TXFIFO_LIM        0x70    /* Transmit FIFO Limit, in DWORDS */
+#define                CTL_DEFAULT     0x00    /* 0 bytes */
+#define CCB1_RXFIFO_LIM        0x0F    /* Receive FIFO Limit */
+#define                CRL_DEFAULT     0x08    /* 32 bytes on 82557, 64 bytes on
+                                        * 82558/82559.
+                                        */
+
+/* Byte 2 */
+#define CCB2_AIFS      0xFF    /* Adaptive IFS */
+#define                CAI_DEFAULT     0
+
+/* Byte 3 */
+                               /* Reserved (must be 0) on 82557 */
+#define CCB3_RES       0xF0    /* Reserved (0) */
+#define        CCB3_TWCL       0x08    /* Terminate Write on Cache Line */
+#define        CCB3_RAE        0x04    /* Read Alignment Enable */
+#define        CCB3_TE         0x02    /* Type Enable??? */
+#define        CCB3_MWIE       0x01    /* Memory Write and Invalidate (MWI) Enable
+                                * Additionally the MWI bit in the PCI
+                                * command register has to be set.
+                                * Recommended by Intel.
+                                */
+
+/* Byte 4 */
+#define CCB4_RES       0x80    /* Reserved (0) */
+#define CCB4_RXDMA_MAX 0x7F    /* Receive DMA Maximum Byte Count */
+
+/* Byte 5 */
+#define CCB5_DMBCE     0x80    /* DMA Maximum Byte Count Enable */
+#define CCB5_TXDMA_MAX 0x7F    /* Transmit DMA Maximum Byte Count */
+
+/* Byte 6 */
+#define CCB6_SBF       0x80    /* Save Bad Frames */
+#define CCB6_DORF      0x40    /* (Do not) Discard Overrun Receive Frame,
+                                * Set this bit to keep them.
+                                */
+#define CCB6_ESC       0x20    /* Extended Statistical Counter. Reserved
+                                * on 82557, must be set to 1.
+                                * Clear this bit to get more counters.
+                                */
+#define CCB6_ETCB      0x10    /* Extended Transmit CB. Reserved on 82557,
+                                * must be set to 1.
+                                * Clear this bit to use Extended TxCBs.
+                                */
+#define CCB6_CI_INT    0x08    /* CPU Idle (CI) Interrupt. Generate a
+                                * CI Int (bit set) or a CNA Int (bit clear)
+                                * when the CU goes to the idle state (or
+                                * to suspended for CNA).
+                                */
+#define CCB6_TNO_INT   0x04    /* Enable TNO Interrupt (82557 only) */
+#define CCB6_TCOSC     0x04    /* TCO Statistical Counter (82559 only) */
+#define CCB6_RES       0x02    /* Reserved, must be set to 1. Called "disable
+                                * direct rcv dma mode" by the FreeBSD
+                                * driver.
+                                */
+#define CCB6_LSCB      0x01    /* Late SCB Update. Only on 82557. */
+
+/* Byte 7 */
+#define CCB7_DTBD      0x80    /* Dynamic TBD. Reserved on 82557, should be
+                                * be set to 0.
+                                */
+#define CCB7_2FFIFO    0x40    /* (At Most) Two Frames in FIFO. Reserved on
+                                * 82557, should be set to 0.
+                                */
+#define CCB7_RES       0x38    /* Reserved (0) */
+#define CCB7_UR                0x06    /* Underrun Retry */
+#define            CUR_0               0x00    /* No re-transmission */
+#define            CUR_1               0x02    /* One re-transmission */
+#define            CUR_2               0x04    /* Two re-transmissions, 1st retry with
+                                        * 512 bytes.
+                                        */
+#define            CUR_3               0x06    /* Tree re-transmissions, 1st retry
+                                        * with 512 bytes, 2nd retry with 1024.
+                                        */
+#define CCB7_DSRF      0x01    /* Discard Short Receive Frames. */
+
+
+/* Byte 8 */
+#define CCB8_CSMAD     0x80    /* CSMA Disable. Reserved on 82557, should be
+                                * set to zero.
+                                */
+#define CCB8_RES       0x7E    /* Reserved (0) */
+#define CCB8_503_MII   0x01    /* 503 mode or MII mode. Reserved on 82558
+                                * and 82559, should be set to 1.
+                                */
+
+/* Byte 9 */
+#define CCB9_MMWE      0x80    /* Multicast Match Wake Enable. 82558 B-step
+                                * only, should be set to zero on other
+                                * devices.
+                                */
+#define CCB9_AWE       0x40    /* ARP Wake-up Enable. 82558 B-step only,
+                                * should be set to zero on other devices.
+                                */
+#define CCB9_LSCWE     0x20    /* Link Status Change Wake Enable. Available
+                                * on 82558 B-step and 82559. Should be
+                                * set to zero on 82557 and 82558 A-step
+                                */
+#define CCB9_VARP      0x10    /* VLAN ARP (82558 B-step) or VLAN TCO (82559).
+                                * Should be zero on 82557 and 82558 A-step
+                                */
+#define CCB9_RES       0x0E    /* Reserved (0) */
+#define CCB9_TUC       0x01    /* TCP/UDP Checksum. 82559 only, should be
+                                * zero on other devices.
+                                */
+
+/* Byte 10 */
+#define CCB10_LOOPBACK 0xC0    /* Loopback mode */
+#define            CLB_NORMAL          0x00    /* Normal operation */
+#define            CLB_INTERNAL        0x40    /* Internal loopback */
+#define            CLB_RESERVED        0x80    /* Reserved */
+#define            CLB_EXTERNAL        0xC0    /* External loopback */
+#define CCB10_PAL      0x30    /* Pre-amble length */
+#define            CPAL_1              0x00    /* 1 byte */
+#define            CPAL_3              0x10    /* 3 bytes */
+#define            CPAL_7              0x20    /* 7 bytes */
+#define            CPAL_15             0x30    /* 15 bytes */
+#define            CPAL_DEFAULT        CPAL_7
+#define CCB10_NSAI             0x08    /* No Source Address Insertion */
+#define CCB10_RES1             0x06    /* Reserved, should be set to 1 */
+#define CCB10_RES0             0x01    /* Reserved (0) */
+
+/* Byte 11 */
+#define CCB11_RES              0xF8    /* Reserved (0) */
+#define CCB11_LINPRIO          0x07    /* Linear Priority. 82557 only,
+                                        * should be zero on other devices.
+                                        */
+
+/* Byte 12 */
+#define CCB12_IS               0xF0    /* Interframe spacing in multiples of
+                                        * 16 bit times.
+                                        */
+#define            CIS_DEFAULT                 0x60    /* 96 (6 in register) */
+#define        CCB12_RES               0x0E    /* Reserved (0) */
+#define        CCB12_LPM               0x01    /* Linear Priority Mode. 82557 only,
+                                        * should be zero on other devices.
+                                        */
+
+/* Byte 13, 4th byte of IP address for ARP frame filtering. Only valid on
+ * 82558 B-step. Should be 0 on other devices.
+ */
+#define CCB13_DEFAULT          0x00
+/* Byte 14, 3rd byte of IP address for ARP fram efiltering. Only valid on
+ * 82558 B-step. Should be 0xF2 on other devices.
+ */
+#define CCB14_DEFAULT          0xF2
+
+/* Byte 15 */
+#define CCB15_CRSCDT           0x80    /* CRS or CDT. */
+#define CCB15_RES1             0x40    /* Reserved, should be set to one. */
+#define CCB15_CRC16            0x20    /* 16-bit CRC. Only on 82559,
+                                        * should be zero on other devices
+                                        */
+#define CCB15_IUL              0x10    /* Ignore U/L. Reserved on 82557 and
+                                        * should be set to zero.
+                                        */
+#define CCB15_RES2             0x08    /* Reserved, should be set to one. */
+#define CCB15_WAW              0x04    /* Wait After Win. Reserved on 82557,
+                                        * should be set to zero.
+                                        */
+#define CCB15_BD               0x02    /* Broadcast disable */
+#define CCB15_PM               0x01    /* Promiscuous mode */
+
+/* Byte 16. FC Delay Least Significant Byte. Reserved on the 82557 and
+ * should be set to zero.
+ */
+#define CCB16_DEFAULT          0x00
+
+/* Byte 17. FC Delay Most Significant Byte. This byte is reserved on the
+ * 82557 and should be set to 0x40.
+ */
+#define CCB17_DEFAULT          0x40
+
+/* Byte 18 */
+#define CCB18_RES1             0x80    /* Reserved, should be set to 1 */
+#define CCB18_PFCT             0x70    /* Priority Flow Control Threshold.
+                                        * Reserved on the 82557 and should
+                                        * be set to 1. All bits 1 (disabled)
+                                        * is the recommended default.
+                                        */
+#define CCB18_LROK             0x08    /* Long Receive OK. Reserved on the
+                                        * 82557 and should be set to zero.
+                                        * Required for VLANs.
+                                        */
+#define CCB18_RCRCT            0x04    /* Receive CRC Transfer */
+#define CCB18_PE               0x02    /* Padding Enable */
+#define CCB18_SE               0x01    /* Stripping Enable */
+
+/* Byte 19 */
+#define CCB19_FDPE             0x80    /* Full Duplex Pin Enable */
+#define CCB19_FFD              0x40    /* Force Full Duplex */
+#define CCB19_RFC              0x20    /* Reject FC. Reserved on the 82557
+                                        * and should be set to zero.
+                                        */
+#define CCB19_FDRSTAFC         0x10    /* Full Duplex Restart Flow Control.
+                                        * Reserved on the 82557 and should be
+                                        * set to zero.
+                                        */
+#define CCB19_FDRSTOFC         0x08    /* Full Duplex Restop Flow Control.
+                                        * Reserved on the 82557 and should be
+                                        * set to zero.
+                                        */
+#define CCB19_FDTFCD           0x04    /* Full Duplex Transmit Flow Control
+                                        * Disable. Reserved on the 82557 and
+                                        * should be set to zero.
+                                        */
+#define CCB19_MPWD             0x02    /* Magic Packet Wake-up Disable.
+                                        * Reserved on the 82557 and 82559ER
+                                        * and should be set to zero.
+                                        */
+#define CCB19_AW               0x01    /* Address Wake-up (82558 A-step) and
+                                        * IA Match Wake Enable (82558 B-step)
+                                        * Reserved on the 82557 and 82559 and
+                                        * should be set to zero.
+                                        */
+
+/* Byte 20 */
+#define CCB20_RES              0x80    /* Reserved (0) */
+#define CCB20_MIA              0x40    /* Multiple IA */
+#define CCB20_PFCL             0x20    /* Priority FC Location. Reserved on
+                                        * the 82557 and should be set to 1.
+                                        */
+#define CCB20_RES1             0x1F    /* Reserved, should be set to 1 */
+
+/* Byte 21 */
+#define CCB21_RES              0xF0    /* Reserved (0) */
+#define CCB21_MA               0x08    /* Multicast All */
+#define CCB21_RES1_MASK                0x07    /* Reserved, should be set to 5 */
+#define     CCB21_RES21                        0x05
+
+/* Transmit (4) */
+struct tx
+{
+       u16_t tx_status;
+       u16_t tx_command;
+       u32_t tx_linkaddr;
+       u32_t tx_tbda;
+       u16_t tx_size;
+       u8_t tx_tthresh;
+       u8_t tx_ntbd;
+       u8_t tx_buf[ETH_MAX_PACK_SIZE_TAGGED];
+};
+
+#define TXS_C          0x8000  /* Transmit DMA has completed */
+#define TXS_RES                0x4000  /* Reserved */
+#define TXS_OK         0x2000  /* Command was executed without error */
+#define TXS_U          0x1000  /* This or previous frame encoutered underrun */
+#define TXS_RES1       0x0FFF  /* Reserved (0) */
+
+#define TXC_EL         0x8000  /* End of List */
+#define TXC_S          0x4000  /* Suspend after this CB */
+#define TXC_I          0x2000  /* Interrupt after this CB */
+#define TXC_CID_MASK   0x1F00  /* CNA Interrupt Delay */
+#define TXC_RES                0x00E0  /* Reserved (0) */
+#define TXC_NC         0x0010  /* No CRC and Source Address Insertion */
+#define TXC_SF         0x0008  /* Not in Simplified Mode */
+#define TXC_CMD                0x0007  /* Command */
+
+#define TXSZ_EOF       0x8000  /* End of Frame */
+#define TXSZ_RES       0x4000  /* Reserved (0) */
+#define TXSZ_COUNT     0x3FFF  /* Transmit Byte Count */
+
+#define TX_TBDA_NIL    0xFFFFFFFF      /* Null Pointer for TBD Array */
+
+#define TXTT_MIN       0x01    /* Minimum for Transmit Threshold */
+#define TXTT_MAX       0xE0    /* Maximum for Transmit Threshold */
+
+/* Statistical Counters */
+struct sc
+{
+       u32_t sc_tx_good;       /* Transmit Good Frames */
+       u32_t sc_tx_maxcol;     /* Transmit Maximum Collisions errors */
+       u32_t sc_tx_latecol;    /* Transmit Late Collisions errors */
+       u32_t sc_tx_underrun;   /* Transmit Underrun errors */
+       u32_t sc_tx_crs;        /* Transmit Lost Carrier Sense */
+       u32_t sc_tx_defered;    /* Transmit Defered */
+       u32_t sc_tx_scol;       /* Transmit Single Collision */
+       u32_t sc_tx_mcol;       /* Transmit Multiple Collisions */
+       u32_t sc_tx_totcol;     /* Transmit Total Collisions */
+       u32_t sc_rx_good;       /* Receive Good Frames */
+       u32_t sc_rx_crc;        /* Receive CRC errors */
+       u32_t sc_rx_align;      /* Receive Alignment errors */
+       u32_t sc_rx_resource;   /* Receive Resource errors */
+       u32_t sc_rx_overrun;    /* Receive Overrun errors */
+       u32_t sc_rx_cd;         /* Receive Collision Detect errors */
+       u32_t sc_rx_short;      /* Receive Short Frame errors */
+
+                               /* Short form ends here. The magic number will
+                                * be stored in the next field.
+                                */
+
+       u32_t sc_tx_fcp;        /* Transmit Flow Control Pause */
+       u32_t sc_rx_fcp;        /* Receive Flow Control Pause */
+       u32_t sc_rx_fcu;        /* Receive Flow Control Unsupported */
+
+                               /* Longer form (82558 and later) ends here.
+                                * The magic number will be stored in the
+                                * next field.
+                                */
+
+       u32_t sc_tx_tco;        /* Transmit TCO frames */
+       u32_t sc_rx_tco;        /* Receive TCO frames */
+       u32_t sc_magic;         /* Dump of counters completed */
+};
+
+#define SCM_DSC                0x0000A005      /* Magic for SC_CU_DUMP_SC command */
+#define SCM_DRSC       0x0000A007      /* Magic for SC_CU_DUMP_RSET_SC cmd */
+
+/* Receive Frame Descriptor (RFD) */
+struct rfd
+{
+       u16_t rfd_status;
+       u16_t rfd_command;
+       u32_t rfd_linkaddr;
+       u32_t rfd_reserved;
+       u16_t rfd_res;
+       u16_t rfd_size;
+       u8_t rfd_buf[ETH_MAX_PACK_SIZE_TAGGED];
+};
+
+#define RFDS_C         0x8000  /* Frame Reception Completed */
+#define RFDS_RES       0x4000  /* Reserved (0) */
+#define RFDS_OK                0x2000  /* Frame received without any errors */
+#define RFDS_RES1      0x1000  /* Reserved */
+#define RFDS_CRCERR    0x0800  /* CRC error */
+#define RFDS_ALIGNERR  0x0400  /* Alignment error */
+#define RFDS_OUTOFBUF  0x0200  /* Ran out of buffer space (frame is frager
+                                * than supplied buffer).
+                                */
+#define RFDS_DMAOVR    0x0100  /* DMA overrun failure */
+#define RFDS_TOOSHORT  0x0080  /* Frame Too Short */
+#define RFDS_RES2      0x0040  /* Reserved */
+#define RFDS_TYPED     0x0020  /* Frame Is Typed (Type/Length field is 0 or
+                                * >1500)
+                                */
+#define RFDS_RXERR     0x0010  /* Receive Error */
+#define RFDS_RES3      0x0008  /* Reserved */
+#define RFDS_NOAM      0x0004  /* No Address Match */
+#define RFDS_NOAIAM    0x0002  /* No IA Address Match */
+#define RFDS_RXCOL     0x0001  /* Collition Detected During Reception (82557
+                                * and 82558 only)
+                                */
+#define RFDS_TCO       0x0001  /* TCO Packet (82559 and later) */
+
+#define RFDC_EL                0x8000  /* End of List */
+#define RFDC_S         0x4000  /* Suspend */
+#define RFDC_RES       0x3FE0  /* Reserved (0) */
+#define RFDC_H         0x0010  /* Header RFD */
+#define RFDC_SF                0x0008  /* (Not) Simplified Mode */
+#define RFDC_RES1      0x0007  /* Reserved (0) */
+
+#define RFDR_EOF       0x8000  /* End of Frame (all data is in the buffer) */
+#define RFDR_F         0x4000  /* Finished updating the count field */
+#define RFDR_COUNT     0x3FFF  /* Actual Count */
+
+#define RFDSZ_RES      0xC000  /* Reserved (0) */
+#define RFDSZ_SIZE     0x3FFF  /* Buffer Size */
+
+/* EEPROM commands */
+#define EEPROM_READ_PREFIX     0x6     /* Read command */
+#define EEPROM_PREFIX_LEN      3       /* Start bit and two command bits */
+
+/* EEPROM timing parameters */
+#define EECS_DELAY     1       /* Keep EECS low for at least EECS_DELAY
+                                * microseconds
+                                */
+#define EESK_PERIOD    4       /* A cycle of driving EESK high followed by
+                                * driving EESK low should take at least
+                                * EESK_PERIOD microseconds
+                                */
+
+/* Special registers in the 82555 (and compatible) PHYs. Should be moved
+ * to a separate file if other drivers need this too.
+ */
+#define MII_SCR                0x10    /* Status and Control Register */
+#define            MII_SCR_FC          0x8000  /* Flow Control */
+#define            MII_SCR_T4E         0x4000  /* Enable T4 unless auto-negotiation */
+#define            MII_SCR_CRSDC       0x2000  /* RX100 CRS Disconnect */
+#define            MII_SCR_RES         0x1000  /* Reserved */
+#define            MII_SCR_RCVSYNC     0x0800  /* RCV De-Serializer in sync */
+#define            MII_SCR_100DOWN     0x0400  /* 100Base-T Power Down */
+#define            MII_SCR_10DOWN      0x0200  /* 10Base-T Power Down */
+#define            MII_SCR_POLARITY    0x0100  /* 10Base-T Polarity */
+#define            MII_SCR_RES_1       0x00F8  /* Reserved */
+#define            MII_SCR_T4          0x0004  /* 100Base-T4 negotiated */
+#define            MII_SCR_100         0x0002  /* 100 Mbps negotiated */
+#define            MII_SCR_FD          0x0001  /* Full Duplex negotiated */
+
+/*
+ * $PchId: fxp.h,v 1.1 2004/11/23 14:34:03 philip Exp $
+ */
diff --git a/drivers/fxp/mii.c b/drivers/fxp/mii.c
new file mode 100644 (file)
index 0000000..772d6c0
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ibm/mii.c
+
+Created:       Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
+
+Media Independent (Ethernet) Interface functions
+*/
+
+#include "../drivers.h"
+#if __minix_vmd
+#include "config.h"
+#endif
+
+#if ENABLE_FXP
+
+#include "mii.h"
+
+
+/*===========================================================================*
+ *                             mii_print_stat_speed                         *
+ *===========================================================================*/
+PUBLIC void mii_print_stat_speed(stat, extstat)
+u16_t stat;
+u16_t extstat;
+{
+       int fs, ft;
+
+       fs= 1;
+       if (stat & MII_STATUS_EXT_STAT)
+       {
+               if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
+                       MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
+               {
+                       printf("1000 Mbps: ");
+                       fs= 0;
+                       ft= 1;
+                       if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
+                       {
+                               ft= 0;
+                               printf("X-");
+                               switch(extstat &
+                                       (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
+                               {
+                               case MII_ESTAT_1000XFD: printf("FD"); break;
+                               case MII_ESTAT_1000XHD: printf("HD"); break;
+                               default:                printf("FD/HD"); break;
+                               }
+                       }
+                       if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
+                       {
+                               if (!ft)
+                                       printf(", ");
+                               ft= 0;
+                               printf("T-");
+                               switch(extstat &
+                                       (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
+                               {
+                               case MII_ESTAT_1000TFD: printf("FD"); break;
+                               case MII_ESTAT_1000THD: printf("HD"); break;
+                               default:                printf("FD/HD"); break;
+                               }
+                       }
+               }
+       }
+       if (stat & (MII_STATUS_100T4 |
+               MII_STATUS_100XFD | MII_STATUS_100XHD |
+               MII_STATUS_100T2FD | MII_STATUS_100T2HD))
+       {
+               if (!fs)
+                       printf(", ");
+               fs= 0;
+               printf("100 Mbps: ");
+               ft= 1;
+               if (stat & MII_STATUS_100T4)
+               {
+                       printf("T4");
+                       ft= 0;
+               }
+               if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
+               {
+                       if (!ft)
+                               printf(", ");
+                       ft= 0;
+                       printf("TX-");
+                       switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
+                       {
+                       case MII_STATUS_100XFD: printf("FD"); break;
+                       case MII_STATUS_100XHD: printf("HD"); break;
+                       default:                printf("FD/HD"); break;
+                       }
+               }
+               if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
+               {
+                       if (!ft)
+                               printf(", ");
+                       ft= 0;
+                       printf("T2-");
+                       switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
+                       {
+                       case MII_STATUS_100T2FD:        printf("FD"); break;
+                       case MII_STATUS_100T2HD:        printf("HD"); break;
+                       default:                printf("FD/HD"); break;
+                       }
+               }
+       }
+       if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
+       {
+               if (!fs)
+                       printf(", ");
+               printf("10 Mbps: ");
+               fs= 0;
+               printf("T-");
+               switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
+               {
+               case MII_STATUS_10FD:   printf("FD"); break;
+               case MII_STATUS_10HD:   printf("HD"); break;
+               default:                printf("FD/HD"); break;
+               }
+       }
+}
+
+
+/*===========================================================================*
+ *                             mii_print_techab                             *
+ *===========================================================================*/
+PUBLIC void mii_print_techab(techab)
+u16_t techab;
+{
+       int fs, ft;
+
+       if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
+       {
+               printf("strange selector 0x%x, value 0x%x",
+                       techab & MII_ANA_SEL_M,
+                       (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
+               return;
+       }
+       fs= 1;
+       if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
+       {
+               printf("100 Mbps: ");
+               fs= 0;
+               ft= 1;
+               if (techab & MII_ANA_100T4)
+               {
+                       printf("T4");
+                       ft= 0;
+               }
+               if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
+               {
+                       if (!ft)
+                               printf(", ");
+                       ft= 0;
+                       printf("TX-");
+                       switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
+                       {
+                       case MII_ANA_100TXFD:   printf("FD"); break;
+                       case MII_ANA_100TXHD:   printf("HD"); break;
+                       default:                printf("FD/HD"); break;
+                       }
+               }
+       }
+       if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
+       {
+               if (!fs)
+                       printf(", ");
+               printf("10 Mbps: ");
+               fs= 0;
+               printf("T-");
+               switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
+               {
+               case MII_ANA_10TFD:     printf("FD"); break;
+               case MII_ANA_10THD:     printf("HD"); break;
+               default:                printf("FD/HD"); break;
+               }
+       }
+       if (techab & MII_ANA_PAUSE_SYM)
+       {
+               if (!fs)
+                       printf(", ");
+               fs= 0;
+               printf("pause(SYM)");
+       }
+       if (techab & MII_ANA_PAUSE_ASYM)
+       {
+               if (!fs)
+                       printf(", ");
+               fs= 0;
+               printf("pause(ASYM)");
+       }
+       if (techab & MII_ANA_TAF_RES)
+       {
+               if (!fs)
+                       printf(", ");
+               fs= 0;
+               printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
+       }
+}
+
+#endif /* ENABLE_FXP */
+
+/*
+ * $PchId: mii.c,v 1.2 2005/01/31 22:17:26 philip Exp $
+ */
diff --git a/drivers/fxp/mii.h b/drivers/fxp/mii.h
new file mode 100644 (file)
index 0000000..7162c26
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ibm/mii.h
+
+Created:       Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
+
+Definitions for the Media Independent (Ethernet) Interface
+*/
+
+/* Registers in the Machine Independent Interface (MII) to the PHY.
+ * IEEE 802.3 (2000 Edition) Clause 22.
+ */
+#define MII_CTRL       0x0     /* Control Register (basic) */
+#define                MII_CTRL_RST    0x8000  /* Reset PHY */
+#define                MII_CTRL_LB     0x4000  /* Enable Loopback Mode */
+#define                MII_CTRL_SP_LSB 0x2000  /* Speed Selection (LSB) */
+#define                MII_CTRL_ANE    0x1000  /* Auto Negotiation Enable */
+#define                MII_CTRL_PD     0x0800  /* Power Down */
+#define                MII_CTRL_ISO    0x0400  /* Isolate */
+#define                MII_CTRL_RAN    0x0200  /* Restart Auto-Negotiation Process */
+#define                MII_CTRL_DM     0x0100  /* Full Duplex */
+#define                MII_CTRL_CT     0x0080  /* Enable COL Signal Test */
+#define                MII_CTRL_SP_MSB 0x0040  /* Speed Selection (MSB) */
+#define                        MII_CTRL_SP_10          0x0000  /* 10 Mb/s */
+#define                        MII_CTRL_SP_100         0x2000  /* 100 Mb/s */
+#define                        MII_CTRL_SP_1000        0x0040  /* 1000 Mb/s */
+#define                        MII_CTRL_SP_RES         0x2040  /* Reserved */
+#define                MII_CTRL_RES    0x003F  /* Reserved */
+#define MII_STATUS     0x1     /* Status Register (basic) */
+#define                MII_STATUS_100T4        0x8000  /* 100Base-T4 support */
+#define                MII_STATUS_100XFD       0x4000  /* 100Base-X FD support */
+#define                MII_STATUS_100XHD       0x2000  /* 100Base-X HD support */
+#define                MII_STATUS_10FD         0x1000  /* 10 Mb/s FD support */
+#define                MII_STATUS_10HD         0x0800  /* 10 Mb/s HD support */
+#define                MII_STATUS_100T2FD      0x0400  /* 100Base-T2 FD support */
+#define                MII_STATUS_100T2HD      0x0200  /* 100Base-T2 HD support */
+#define                MII_STATUS_EXT_STAT     0x0100  /* Supports MII_EXT_STATUS */
+#define                MII_STATUS_RES          0x0080  /* Reserved */
+#define                MII_STATUS_MFPS         0x0040  /* MF Preamble Suppression */
+#define                MII_STATUS_ANC          0x0020  /* Auto-Negotiation Completed */
+#define                MII_STATUS_RF           0x0010  /* Remote Fault Detected */
+#define                MII_STATUS_ANA          0x0008  /* Auto-Negotiation Ability */
+#define                MII_STATUS_LS           0x0004  /* Link Up */
+#define                MII_STATUS_JD           0x0002  /* Jabber Condition Detected */
+#define                MII_STATUS_EC           0x0001  /* Ext Register Capabilities */
+#define MII_PHYID_H    0x2     /* PHY ID (high) */
+#define                MII_PH_OUI_H_MASK       0xFFFF  /* High part of OUI */
+#define                        MII_PH_OUI_H_C_SHIFT    6       /* Shift up in OUI */
+#define MII_PHYID_L    0x3     /* PHY ID (low) */
+#define                MII_PL_OUI_L_MASK       0xFC00  /* Low part of OUI */
+#define                        MII_PL_OUI_L_SHIFT      10
+#define                MII_PL_MODEL_MASK       0x03F0  /* Model */
+#define                        MII_PL_MODEL_SHIFT      4
+#define                MII_PL_REV_MASK         0x000F  /* Revision */
+#define MII_ANA                0x4     /* Auto-Negotiation Advertisement */
+#define                MII_ANA_NP      0x8000  /* Next PAge */
+#define                MII_ANA_RES     0x4000  /* Reserved */
+#define                MII_ANA_RF      0x2000  /* Remote Fault */
+#define                MII_ANA_TAF_M   0x1FE0   /* Technology Ability Field */
+#define                MII_ANA_TAF_S   5        /* Shift */
+#define                        MII_ANA_TAF_RES         0x1000  /* Reserved */
+#define                        MII_ANA_PAUSE_ASYM      0x0800  /* Asym. Pause */
+#define                        MII_ANA_PAUSE_SYM       0x0400  /* Sym. Pause */
+#define                        MII_ANA_100T4           0x0200  /* 100Base-T4 */
+#define                        MII_ANA_100TXFD         0x0100  /* 100Base-TX FD */
+#define                        MII_ANA_100TXHD         0x0080  /* 100Base-TX HD */
+#define                        MII_ANA_10TFD           0x0040  /* 10Base-T FD */
+#define                        MII_ANA_10THD           0x0020  /* 10Base-T HD */
+#define                MII_ANA_SEL_M   0x001F   /* Selector Field */
+#define                        MII_ANA_SEL_802_3 0x0001 /* 802.3 */
+#define MII_ANLPA      0x5     /* Auto-Neg Link Partner Ability Register */
+#define                MII_ANLPA_NP    0x8000  /* Next Page */
+#define                MII_ANLPA_ACK   0x4000  /* Acknowledge */
+#define                MII_ANLPA_RF    0x2000  /* Remote Fault */
+#define                MII_ANLPA_TAF_M 0x1FC0   /* Technology Ability Field */
+#define                MII_ANLPA_SEL_M 0x001F   /* Selector Field */
+#define MII_ANE                0x6     /* Auto-Negotiation Expansion */
+#define                MII_ANE_RES     0xFFE0  /* Reserved */
+#define                MII_ANE_PDF     0x0010  /* Parallel Detection Fault */
+#define                MII_ANE_LPNPA   0x0008  /* Link Partner is Next Page Able */
+#define                MII_ANE_NPA     0x0002  /* Local Device is Next Page Able */
+#define                MII_ANE_PR      0x0002  /* New Page has been received */
+#define                MII_ANE_LPANA   0x0001  /* Link Partner is Auto-Neg.able */
+#define MII_ANNPT      0x7     /* Auto-Negotiation Next Page Transmit */
+#define MII_ANLPRNP    0x8     /* Auto-Neg Link Partner Received Next Page */
+#define MII_MS_CTRL    0x9     /* MASTER-SLAVE Control Register */
+#define                MII_MSC_TEST_MODE       0xE000  /* Test mode */
+#define                MII_MSC_MS_MANUAL       0x1000  /* Master/slave manual config */
+#define                MII_MSC_MS_VAL          0x0800  /* Master/slave value */
+#define                MII_MSC_MULTIPORT       0x0400  /* Multi-port device */
+#define                MII_MSC_1000T_FD        0x0200  /* 1000Base-T Full Duplex */
+#define                MII_MSC_1000T_HD        0x0100  /* 1000Base-T Half Duplex */
+#define                MII_MSC_RES             0x00FF  /* Reserved */
+#define MII_MS_STATUS  0xA     /* MASTER-SLAVE Status Register */
+#define                MII_MSS_FAULT           0x8000  /* Master/slave config fault */
+#define                MII_MSS_MASTER          0x4000  /* Master */
+#define                MII_MSS_LOCREC          0x2000  /* Local Receiver OK */
+#define                MII_MSS_REMREC          0x1000  /* Remote Receiver OK */
+#define                MII_MSS_LP1000T_FD      0x0800  /* Link Partner 1000-T FD */
+#define                MII_MSS_LP1000T_HD      0x0400  /* Link Partner 1000-T HD */
+#define                MII_MSS_RES             0x0300  /* Reserved */
+#define                MII_MSS_IDLE_ERR        0x00FF  /* Idle Error Counter */
+/* 0xB ... 0xE */              /* Reserved */
+#define MII_EXT_STATUS 0xF     /* Extended Status */
+#define                MII_ESTAT_1000XFD       0x8000  /* 1000Base-X Full Duplex */
+#define                MII_ESTAT_1000XHD       0x4000  /* 1000Base-X Half Duplex */
+#define                MII_ESTAT_1000TFD       0x2000  /* 1000Base-T Full Duplex */
+#define                MII_ESTAT_1000THD       0x1000  /* 1000Base-T Half Duplex */
+#define                MII_ESTAT_RES           0x0FFF  /* Reserved */
+/* 0x10 ... 0x1F */            /* Vendor Specific */
+
+_PROTOTYPE( void mii_print_stat_speed, (U16_t stat, U16_t extstat)     );
+_PROTOTYPE( void mii_print_techab, (U16_t techab)                      );
+
+/*
+ * $PchId: mii.h,v 1.1 2004/12/27 13:33:30 philip Exp $
+ */
index 9655505aecd708289040b36970a990af20231403..77d2d2409f52b045cc49404e797473c06c9e3a9b 100644 (file)
@@ -40,12 +40,14 @@ _PROTOTYPE( void pci_attr_w32, (int devind, int port, u32_t value)  );
 #define                 PSR_SSE        0x4000  /* Signaled System Error */
 #define                 PSR_RMAS       0x2000  /* Received Master Abort Status */
 #define                 PSR_RTAS       0x1000  /* Received Target Abort Status */
+#define PCI_REV                0x08    /* Revision ID */
 #define PCI_PIFR       0x09    /* Prog. Interface Register */
 #define PCI_SCR                0x0A    /* Sub-Class Register */
 #define PCI_BCR                0x0B    /* Base-Class Register */
 #define PCI_HEADT      0x0E    /* Header type, 8-bit */
 #define                PHT_MULTIFUNC   0x80    /* Multiple functions */
 #define PCI_BAR                0x10    /* Base Address Register */
+#define PCI_BAR_2      0x14    /* Second Base Address Register */
 #define PCI_ILR                0x3C    /* Interrupt Line Register */
 #define PCI_IPR                0x3D    /* Interrupt Pin Register */
 
index ca7ef32ce07e6eb8c908aea07527c3223b4bc6e1..a00c761ca571a35ed36cd5d742ea1de580d23825 100755 (executable)
 #define FLOPPY         (AT_WINI + ENABLE_FLOPPY)   /* floppy disk */
 #define PRINTER                (FLOPPY + ENABLE_PRINTER)    /* Centronics */
 #define USR8139                (PRINTER + ENABLE_RTL8139)    /* Realtek RTL8139 */
-#define INIT_PROC_NR   (USR8139 + 1)           /* init -- goes multiuser */
+#define FXP            (USR8139 + ENABLE_FXP)        /* Intel Pro/100 */
+#define INIT_PROC_NR   (FXP + 1)       /* init -- goes multiuser */
 
 /* Number of processes contained in the system image. */
 #define IMAGE_SIZE     (NR_TASKS + \
                        5 + ENABLE_AT_WINI + ENABLE_FLOPPY + \
-                       ENABLE_PRINTER + ENABLE_RTL8139 + 1 )   
+                       ENABLE_PRINTER + ENABLE_RTL8139 + ENABLE_FXP + 1 )      
 
 
 /*===========================================================================*
index facd996c12261e96dae513280f76d6dab22e1083..f62bc7d3c655d8e97af107ee66dcf9c92c47df58 100755 (executable)
@@ -95,6 +95,7 @@
 #define   ENABLE_NE2000    0   /*   add Novell NE1000/NE2000 */
 #define   ENABLE_3C503     0   /*   add 3Com Etherlink II (3c503) */
 #define ENABLE_RTL8139  1      /* enable Realtek 8139 (rtl8139) */
+#define ENABLE_FXP      1      /* enable Intel Pro/100 (fxp) */
 
 /* Include or exclude backwards compatibility code. */
 #define ENABLE_BINCOMPAT   0   /* for binaries using obsolete calls */
index 8973ddf0febe989998d6c5d00e9e743b936a3330..c966823522c966c55d58a6f9886386031f794bb4 100755 (executable)
@@ -66,9 +66,9 @@ unsigned vec_nr;
        kprintf("\nIntel-reserved exception %d\n", vec_nr);
   else
        kprintf("\n%s\n", karg(ep->msg));
-  kprintf("process number %d", proc_number(saved_proc));
+  kprintf("process number %d", proc_number(saved_proc));
   kprintf("pc = %d:",  (unsigned) saved_proc->p_reg.cs);
-  kprintf("%d\n", (unsigned) saved_proc->p_reg.pc);
+  kprintf("0x%x\n", (unsigned) saved_proc->p_reg.pc);
 
   /* If the exception originates in the kernel, shut down MINIX. Otherwise,
    * kill the process that caused it. If MINIX is shut down and the stop 
index 2b4fd1ca1c15e9821d61b1f3a70dc46303d7299d..f1b17683fff2730e06e65fa84bf5b4744f4527a8 100644 (file)
     allow(1, CLOCK)            /* need small delays */ \
     allow(1, FS_PROC_NR)       /* FS is interface to the driver */ 
 
+#define FXP_SENDMASK \
+    allow_all_mask 
+
 #define INIT_SENDMASK \
     deny_all_mask \
     allow(1, FS_PROC_NR)       /* init makes system calls to FS and MM */ \
index de1720a38ce7493644ed07f159500974adccc7f6..60a1205da0a9aa9085fe63e984baa0cae5d1d8b9 100755 (executable)
@@ -81,6 +81,9 @@ PUBLIC struct system_image image[] = {
 #endif
 #if ENABLE_RTL8139
  { USR8139, 0,            P_DRIVER, PPRI_HIGH, 0,             RTL8139_SENDMASK,  "RTL8139" },
+#endif
+#if ENABLE_FXP
+ { FXP, 0,                P_DRIVER, PPRI_HIGH, 0,             FXP_SENDMASK,  "FXP" },
 #endif
  { INIT_PROC_NR, 0,            P_USER,   PPRI_USER, 0,             INIT_SENDMASK,    "INIT"    },
 };
index 4715bc9868d3bf7ba1c6d5b64cc8c6b8d3dfaa6c..25c0c59e00078e3f673336baa10fe1acb2a54977 100755 (executable)
@@ -17,6 +17,7 @@ PROGRAMS=     ../kernel/kernel \
        ../drivers/floppy/floppy \
        ../drivers/printer/printer \
        ../drivers/rtl8139/rtl8139 \
+       ../drivers/fxp/fxp \
        ../servers/init/init \
        #bootfs.img