📄 fxp.c
字号:
/* * fxp.c * * This file contains an ethernet device driver for Intel 82557, 82558, * 82559, 82550, and 82562 fast ethernet controllers. * * The valid messages and their parameters are: * * m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR * |------------+----------+---------+----------+---------+---------| * | HARDINT | | | | | | * |------------|----------|---------|----------|---------|---------| * | DL_WRITE | port nr | proc nr | count | mode | address | * |------------|----------|---------|----------|---------|---------| * | DL_WRITEV | port nr | proc nr | count | mode | address | * |------------|----------|---------|----------|---------|---------| * | DL_READ | port nr | proc nr | count | | address | * |------------|----------|---------|----------|---------|---------| * | DL_READV | port nr | proc nr | count | | address | * |------------|----------|---------|----------|---------|---------| * | DL_INIT | port nr | proc nr | mode | | address | * |------------|----------|---------|----------|---------|---------| * | DL_GETSTAT | port nr | proc nr | | | address | * |------------|----------|---------|----------|---------|---------| * | DL_STOP | port_nr | | | | | * |------------|----------|---------|----------|---------|---------| * * The messages sent are: * * m-type DL_PORT DL_PROC DL_COUNT DL_STAT DL_CLCK * |-------------+----------+---------+----------+---------+---------| * |DL_TASK_REPLY| port nr | proc nr | rd-count | err|stat| clock | * |-------------+----------+---------+----------+---------+---------| * * m_type m3_i1 m3_i2 m3_ca1 * |-------------+---------+-----------+---------------| * |DL_INIT_REPLY| port nr | last port | ethernet addr | * |-------------+---------+-----------+---------------| * * Created: Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com> */#include "../drivers.h"#include <stdlib.h>#include <net/hton.h>#include <net/gen/ether.h>#include <net/gen/eth_io.h>#include <timers.h>#define tmra_ut timer_t#define tmra_inittimer(tp) tmr_inittimer(tp)#define Proc_number(p) proc_number(p)#define debug 0#define RAND_UPDATE /**/#define printW() ((void)0)#define vm_1phys2bus(p) (p)#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 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) 0char 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 0x4static fxp_t fxp_table[FXP_PORT_NR];static int fxp_tasknr= ANY;static u16_t eth_ign_proto;static tmra_ut fxp_watchdog;static char *progname;extern int errno;#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 void fxp_getname, (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(int argc, char *argv[]){ message m; int i, r, tasknr; fxp_t *fp; long v; if ((fxp_tasknr= getprocnr())<0) panic("FXP", "couldn't get proc nr", errno); if (argc < 1) panic("FXP", "A head which at this time has no name", NO_NUM); (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]); v= 0;#if 0 (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);#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 /* Try to notify inet that we are present (again) */ r = findproc("inet", &tasknr); if (r == OK) notify(tasknr); while (TRUE) { if ((r= receive(ANY, &m)) != OK) panic("FXP","receive failed", r); switch (m.m_type) { case DEV_PING: notify(m.m_source); continue; 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 DL_GETNAME: fxp_getname(&m); break; case HARD_INT: for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++) { if (fp->fxp_mode != FM_ENABLED) continue; fxp_handler(fp); r= sys_irqenable(&fp->fxp_hook); if (r != OK) panic("FXP","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 SYS_SIG: { sigset_t sigset = m.NOTIFY_ARG; if (sigismember(&sigset, SIGKSTOP)) fxp_stop(); break; } case SYN_ALARM: fxp_expire_timers(); break; default: panic("FXP"," illegal message", m.m_type); } }}/*===========================================================================* * fxp_init * *===========================================================================*/static void fxp_init(mp)message *mp;{ static int first_time= 1; int port; fxp_t *fp; message reply_mess; if (first_time) { first_time= 0; fxp_pci_conf(); /* Configure PCI devices. */ tmra_inittimer(&fxp_watchdog); tmr_arg(&fxp_watchdog)->ta_int= 0; fxp_set_timer(&fxp_watchdog, HZ, fxp_watchdog_f); } port = mp->DL_PORT; if (port < 0 || port >= FXP_PORT_NR) { reply_mess.m_type= DL_INIT_REPLY; reply_mess.m3_i1= ENXIO; mess_reply(mp, &reply_mess); return; } fp= &fxp_table[port]; if (fp->fxp_mode == FM_DISABLED) { /* This is the default, try to (re)locate the device. */ fxp_conf_hw(fp); if (fp->fxp_mode == FM_DISABLED) { /* Probe failed, or the device is configured off. */ reply_mess.m_type= DL_INIT_REPLY; reply_mess.m3_i1= ENXIO; mess_reply(mp, &reply_mess); return; } if (fp->fxp_mode == FM_ENABLED) fxp_init_hw(fp); fxp_report_link(fp); } assert(fp->fxp_mode == FM_ENABLED); assert(fp->fxp_flags & FF_ENABLED); fp->fxp_flags &= ~(FF_PROMISC | FF_MULTI | FF_BROAD); if (mp->DL_MODE & DL_PROMISC_REQ) fp->fxp_flags |= FF_PROMISC; if (mp->DL_MODE & DL_MULTI_REQ) fp->fxp_flags |= FF_MULTI; if (mp->DL_MODE & DL_BROAD_REQ) fp->fxp_flags |= FF_BROAD; fp->fxp_client = mp->m_source; fxp_rec_mode(fp); reply_mess.m_type = DL_INIT_REPLY; reply_mess.m3_i1 = mp->DL_PORT; reply_mess.m3_i2 = FXP_PORT_NR; *(ether_addr_t *) reply_mess.m3_ca1 = fp->fxp_address; mess_reply(mp, &reply_mess);}/*===========================================================================* * fxp_pci_conf * *===========================================================================*/static void fxp_pci_conf(){ static char envvar[] = FXP_ENVVAR "#"; static char envfmt[] = "*:d.d.d"; int i, h; fxp_t *fp; long v; for (i= 0, fp= fxp_table; i<FXP_PORT_NR; i++, fp++) { strcpy(fp->fxp_name, "fxp#0"); fp->fxp_name[4] += i; fp->fxp_seen= FALSE; fp->fxp_features= FFE_NONE; envvar[sizeof(FXP_ENVVAR)-1]= '0'+i;#if 0 if (getenv(envvar) != NULL) { if (strcmp(getenv(envvar), "off") == 0) { fp->fxp_pcibus= 255; continue; } if (!env_prefix(envvar, "pci")) env_panic(envvar); }#endif v= 0;#if 0 (void) env_parse(envvar, envfmt, 1, &v, 0, 255);#endif fp->fxp_pcibus= v; v= 0;#if 0 (void) env_parse(envvar, envfmt, 2, &v, 0, 255);#endif fp->fxp_pcidev= v; v= 0;#if 0 (void) env_parse(envvar, envfmt, 3, &v, 0, 255);#endif fp->fxp_pcifunc= v; } pci_init(); for (h= 1; h >= 0; h--) { for (i= 0, fp= fxp_table; i<FXP_PORT_NR; i++, fp++) { if (fp->fxp_pcibus == 255) continue; if (((fp->fxp_pcibus | fp->fxp_pcidev | fp->fxp_pcifunc) != 0) != h) { continue; } if (fxp_probe(fp)) fp->fxp_seen= TRUE; } }}/*===========================================================================* * fxp_probe * *===========================================================================*/static int fxp_probe(fp)fxp_t *fp;{ int i, r, devind, just_one; u16_t vid, did; u32_t bar; u8_t ilr, rev; char *dname, *str; if ((fp->fxp_pcibus | fp->fxp_pcidev | fp->fxp_pcifunc) != 0) { /* Look for specific PCI device */ r= pci_find_dev(fp->fxp_pcibus, fp->fxp_pcidev, fp->fxp_pcifunc, &devind); if (r == 0) { printf("%s: no PCI device found at %d.%d.%d\n", fp->fxp_name, fp->fxp_pcibus, fp->fxp_pcidev, fp->fxp_pcifunc); return FALSE; } pci_ids(devind, &vid, &did); just_one= TRUE; } else { r= pci_first_dev(&devind, &vid, &did); if (r == 0) return FALSE; just_one= FALSE; } for(;;) { for (i= 0; pcitab_fxp[i].vid != 0; i++) { if (pcitab_fxp[i].vid != vid) continue; if (pcitab_fxp[i].did != did) continue; if (pcitab_fxp[i].checkclass) { panic("FXP","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 VERBOSE if (!dname) dname= "unknown device"; printf("%s: %s (%04x/%04x) at %s\n", fp->fxp_name, dname, vid, did, pci_slot_name(devind));#endif pci_reserve(devind); bar= pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0; if ((bar & 0x3ff) >= 0x100-32 || bar < 0x400) { panic("FXP","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 VERBOSE if (str) printf("%s: device revision: %s\n", fp->fxp_name, str); else printf("%s: unknown revision: 0x%x\n", fp->fxp_name, rev);#endif 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -