From 129b82d2070061d8ad26be13779e6b23b0d89a5f Mon Sep 17 00:00:00 2001 From: Philip Homburg Date: Thu, 19 May 2005 13:27:05 +0000 Subject: [PATCH] Added fxp driver for the Intel Pro/100 series ethernet cards Print PC in hex for easier debugging. --- drivers/Makefile | 1 + drivers/fxp/Makefile | 47 + drivers/fxp/fxp.c | 2483 ++++++++++++++++++++++++++++++++++++++++ drivers/fxp/fxp.h | 575 ++++++++++ drivers/fxp/mii.c | 204 ++++ drivers/fxp/mii.h | 116 ++ drivers/libpci/pci.h | 2 + include/minix/com.h | 5 +- include/minix/config.h | 1 + kernel/exception.c | 4 +- kernel/sendmask.h | 3 + kernel/table.c | 3 + tools/Makefile | 1 + 13 files changed, 3441 insertions(+), 4 deletions(-) create mode 100644 drivers/fxp/Makefile create mode 100644 drivers/fxp/fxp.c create mode 100644 drivers/fxp/fxp.h create mode 100644 drivers/fxp/mii.c create mode 100644 drivers/fxp/mii.h diff --git a/drivers/Makefile b/drivers/Makefile index e7a515b8f..b9eb9d784 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -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 index 000000000..16093d344 --- /dev/null +++ b/drivers/fxp/Makefile @@ -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 index 000000000..e3748d56d --- /dev/null +++ b/drivers/fxp/fxp.c @@ -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 + */ + +#include "../drivers.h" + +#include +#include +#include +#include + +#include + +#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]; ifxp_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; ifxp_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; ifxp_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; ifxp_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; ifxp_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; ifxp_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; ifxp_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; ifxp_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; jiov_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; ifxp_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; jiov_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; irfd_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]; ifxp_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]; ifxp_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 index 000000000..66af4fa23 --- /dev/null +++ b/drivers/fxp/fxp.h @@ -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 +*/ + +/* 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 index 000000000..772d6c089 --- /dev/null +++ b/drivers/fxp/mii.c @@ -0,0 +1,204 @@ +/* +ibm/mii.c + +Created: Nov 2004 by Philip Homburg + +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 index 000000000..7162c26bd --- /dev/null +++ b/drivers/fxp/mii.h @@ -0,0 +1,116 @@ +/* +ibm/mii.h + +Created: Nov 2004 by Philip Homburg + +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 $ + */ diff --git a/drivers/libpci/pci.h b/drivers/libpci/pci.h index 9655505ae..77d2d2409 100644 --- a/drivers/libpci/pci.h +++ b/drivers/libpci/pci.h @@ -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 */ diff --git a/include/minix/com.h b/include/minix/com.h index ca7ef32ce..a00c761ca 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -54,12 +54,13 @@ #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 ) /*===========================================================================* diff --git a/include/minix/config.h b/include/minix/config.h index facd996c1..f62bc7d3c 100755 --- a/include/minix/config.h +++ b/include/minix/config.h @@ -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 */ diff --git a/kernel/exception.c b/kernel/exception.c index 8973ddf0f..c96682352 100755 --- a/kernel/exception.c +++ b/kernel/exception.c @@ -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 diff --git a/kernel/sendmask.h b/kernel/sendmask.h index 2b4fd1ca1..f1b17683f 100644 --- a/kernel/sendmask.h +++ b/kernel/sendmask.h @@ -146,6 +146,9 @@ 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 */ \ diff --git a/kernel/table.c b/kernel/table.c index de1720a38..60a1205da 100755 --- a/kernel/table.c +++ b/kernel/table.c @@ -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" }, }; diff --git a/tools/Makefile b/tools/Makefile index 4715bc986..25c0c59e0 100755 --- a/tools/Makefile +++ b/tools/Makefile @@ -17,6 +17,7 @@ PROGRAMS= ../kernel/kernel \ ../drivers/floppy/floppy \ ../drivers/printer/printer \ ../drivers/rtl8139/rtl8139 \ + ../drivers/fxp/fxp \ ../servers/init/init \ #bootfs.img