--- /dev/null
+/*
+ * 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 $
+ */
+
--- /dev/null
+/*
+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 $
+ */