From 01b6ca963c9be8447e7e0b9c5f0fe3c1b443bfad Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 13 Jun 2003 17:43:11 +0000 Subject: 2003-06-13 Greg Menke PR 405/bsps PR 393/networking * network/dec21140.c: Fix leak also known as PR393. * network/elnk.c, network/if_media.h, network/mii.h: New files. * network/Makefile.am: Reflect new files. --- c/src/libchip/ChangeLog | 8 + c/src/libchip/network/Makefile.am | 4 +- c/src/libchip/network/dec21140.c | 1478 ++++++++++------- c/src/libchip/network/elnk.c | 3267 +++++++++++++++++++++++++++++++++++++ c/src/libchip/network/if_media.h | 436 +++++ c/src/libchip/network/mii.h | 206 +++ 6 files changed, 4818 insertions(+), 581 deletions(-) create mode 100644 c/src/libchip/network/elnk.c create mode 100644 c/src/libchip/network/if_media.h create mode 100644 c/src/libchip/network/mii.h (limited to 'c/src/libchip') diff --git a/c/src/libchip/ChangeLog b/c/src/libchip/ChangeLog index c9cd91d112..1a3c9dc4a4 100644 --- a/c/src/libchip/ChangeLog +++ b/c/src/libchip/ChangeLog @@ -6,6 +6,14 @@ * network/elnk.c, network/if_media.h, network/mii.h: New files. * network/Makefile.am: Reflect new files. +2003-06-13 Greg Menke + + PR 405/bsps + PR 393/networking + * network/dec21140.c: Fix leak also known as PR393. + * network/elnk.c, network/if_media.h, network/mii.h: New files. + * network/Makefile.am: Reflect new files. + 2003-04-15 Joel Sherrill PR 387/rtems_misc diff --git a/c/src/libchip/network/Makefile.am b/c/src/libchip/network/Makefile.am index fd8aba74b2..926e4bba28 100644 --- a/c/src/libchip/network/Makefile.am +++ b/c/src/libchip/network/Makefile.am @@ -8,10 +8,10 @@ include_libchipdir = $(includedir)/libchip LIBNAME = libnetchip LIB = $(ARCH)/$(LIBNAME).a -C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c +C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c elnk.c OBJS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) -include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h +include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h if_media.h mii.h include $(top_srcdir)/../../../automake/compile.am include $(top_srcdir)/../../../automake/lib.am diff --git a/c/src/libchip/network/dec21140.c b/c/src/libchip/network/dec21140.c index 7ec952f70e..fd37cfd2e1 100644 --- a/c/src/libchip/network/dec21140.c +++ b/c/src/libchip/network/dec21140.c @@ -25,6 +25,18 @@ * look for the 21140 first. If the 21140 is not found the driver will * look for the 21143. * ------------------------------------------------------------------------ + * + * 2003-03-13, Greg Menke, gregory.menke@gsfc.nasa.gov + * + * Added support for up to 8 units (which is an arbitrary limit now), + * consolidating their support into a single pair of rx/tx daemons and a + * single ISR for all vectors servicing the DEC units. The driver now + * simply uses whatever INTERRUPT_LINE the card supplies, requiring it + * be configured either by the boot monitor or bspstart() hackery. + * Tested on a MCP750 PPC based system with 2 DEC21140 boards. + * + * Also fixed a few bugs related to board configuration, start and stop. + * */ #include @@ -39,7 +51,7 @@ #define DEC21140_SUPPORTED #endif -#if defined(__PPC__) && (defined(mpc604) || defined(mpc750)) +#if defined(__PPC__) && (defined(mpc604) || defined(mpc750) || defined(mpc603e)) #define DEC21140_SUPPORTED #endif @@ -57,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -88,9 +101,11 @@ /* note: the 21143 isn't really a DEC, it's an Intel chip */ #define PCI_INVALID_VENDORDEVICEID 0xffffffff -#define PCI_VENDOR_ID_DEC 0x1011 -#define PCI_DEVICE_ID_DEC_21140 0x0009 -#define PCI_DEVICE_ID_DEC_21143 0x0019 +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_DEC_21140 0x0009 +#define PCI_DEVICE_ID_DEC_21143 0x0019 + +#define DRIVER_PREFIX "dc" #define IO_MASK 0x3 #define MEM_MASK 0xF @@ -133,6 +148,9 @@ #define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */ + + + #define RESET_CHIP 0x00000001 #if defined(__PPC) #define CSR0_MODE 0x0030e002 /* 01b08000 */ @@ -147,43 +165,72 @@ #define CLEAR_IT 0xFFFFFFFF #define NO_IT 0x00000000 -#define NRXBUFS 32 /* number of receive buffers */ -#define NTXBUFS 16 /* number of transmit buffers */ + /* message descriptor entry */ struct MD { /* used by hardware */ volatile unsigned32 status; volatile unsigned32 counts; - unsigned32 buf1, buf2; + volatile unsigned32 buf1, buf2; /* used by software */ volatile struct mbuf *m; volatile struct MD *next; -}; +} __attribute__ ((packed)); + + + + +/* +** These buffers allocated for each unit, so ensure +** +** rtems_bsdnet_config.mbuf_bytecount +** rtems_bsdnet_config.mbuf_cluster_bytecount +** +** are adequately sized to provide enough clusters and mbufs for all the +** units. The default bsdnet configuration is sufficient for one dec +** unit, but will be nearing exhaustion with 2 or more. Although a +** little expensive in memory, the following configuration should +** eliminate all mbuf/cluster issues; +** +** rtems_bsdnet_config.mbuf_bytecount = 128*1024; +** rtems_bsdnet_config.mbuf_cluster_bytecount = 256*1024; +*/ + +#define NRXBUFS 16 /* number of receive buffers */ +#define NTXBUFS 16 /* number of transmit buffers */ + /* - * Number of DECs supported by this driver + * Number of DEC boards supported by this driver */ -#define NDECDRIVER 1 +#define NDECDRIVER 8 + /* * Receive buffer size -- Allow for a full ethernet packet including CRC */ #define RBUF_SIZE 1536 -#define ET_MINLEN 60 /* minimum message length */ +#define ET_MINLEN 60 /* minimum message length */ -/* - * RTEMS event used by interrupt handler to signal driver tasks. - * This must not be any of the events used by the network task synchronization. - */ -#define INTERRUPT_EVENT RTEMS_EVENT_1 /* - * RTEMS event used to start transmit daemon. - * This must not be the same as INTERRUPT_EVENT. - */ -#define START_TRANSMIT_EVENT RTEMS_EVENT_2 +** Events, one per unit. The event is sent to the rx task from the isr +** or from the stack to the tx task whenever a unit needs service. The +** rx/tx tasks identify the requesting unit(s) by their particular +** events so only requesting units are serviced. +*/ + +static rtems_event_set unit_signals[NDECDRIVER]= { RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6, + RTEMS_EVENT_7, + RTEMS_EVENT_8 }; + #if defined(__PPC) #define phys_to_bus(address) ((unsigned int)((address)) + PCI_DRAM_OFFSET) @@ -212,94 +259,75 @@ inline unsigned32 ld_le32(volatile unsigned32 *addr) # error "Driver must have MCLBYTES > RBUF_SIZE" #endif + + + + /* * Per-device data */ - struct dec21140_softc { +struct dec21140_softc { - struct arpcom arpcom; + struct arpcom arpcom; - rtems_irq_connect_data irqInfo; + rtems_irq_connect_data irqInfo; - volatile struct MD *MDbase; - volatile unsigned char *bufferBase; - int acceptBroadcast; - rtems_id rxDaemonTid; - rtems_id txDaemonTid; - - volatile struct MD *TxMD; - volatile struct MD *SentTxMD; - int PendingTxCount; - int TxSuspended; + rtems_event_set ioevent; - unsigned int port; - volatile unsigned int *base; + volatile struct MD *MDbase; + volatile struct MD *nextRxMD; + volatile unsigned char *bufferBase; + int acceptBroadcast; - /* - * Statistics - */ - unsigned long rxInterrupts; - unsigned long rxNotFirst; - unsigned long rxNotLast; - unsigned long rxGiant; - unsigned long rxNonOctet; - unsigned long rxRunt; - unsigned long rxBadCRC; - unsigned long rxOverrun; - unsigned long rxCollision; + volatile struct MD *TxMD; + volatile struct MD *SentTxMD; + int PendingTxCount; + int TxSuspended; + + unsigned int port; + volatile unsigned int *base; + + /* + * Statistics + */ + unsigned long rxInterrupts; + unsigned long rxNotFirst; + unsigned long rxNotLast; + unsigned long rxGiant; + unsigned long rxNonOctet; + unsigned long rxRunt; + unsigned long rxBadCRC; + unsigned long rxOverrun; + unsigned long rxCollision; - unsigned long txInterrupts; - unsigned long txDeferred; - unsigned long txHeartbeat; - unsigned long txLateCollision; - unsigned long txRetryLimit; - unsigned long txUnderrun; - unsigned long txLostCarrier; - unsigned long txRawWait; + unsigned long txInterrupts; + unsigned long txDeferred; + unsigned long txHeartbeat; + unsigned long txLateCollision; + unsigned long txRetryLimit; + unsigned long txUnderrun; + unsigned long txLostCarrier; + unsigned long txRawWait; }; static struct dec21140_softc dec21140_softc[NDECDRIVER]; +static rtems_id rxDaemonTid; +static rtems_id txDaemonTid; + + + + + + + + + + + + -/* - * DEC21140 interrupt handler - */ -static rtems_isr -dec21140Enet_interrupt_handler (rtems_vector_number v) -{ - volatile unsigned32 *tbase; - unsigned32 status; - struct dec21140_softc *sc; - - sc = &dec21140_softc[0]; - tbase = (unsigned32 *)(sc->base) ; - - /* - * Read status - */ - status = ld_le32(tbase+memCSR5); - st_le32((tbase+memCSR5), status); /* clear the bits we've read */ - - /* - * Frame received? - */ - if (status & 0x000000c0){ - sc->rxInterrupts++; - rtems_event_send (sc->rxDaemonTid, INTERRUPT_EVENT); - } -} -static void nopOn(const rtems_irq_connect_data* notUsed) -{ - /* - * code should be moved from dec21140Enet_initialize_hardware - * to this location - */ -} -static int dec21140IsOn(const rtems_irq_connect_data* irq) -{ - return BSP_irq_enabled_at_i8259s (irq->name); -} /* @@ -321,352 +349,523 @@ static int dec21140IsOn(const rtems_irq_connect_data* irq) static int eeget16(volatile unsigned int *ioaddr, int location) { - int i; - unsigned short retval = 0; - int read_cmd = location | EE_READ_CMD; + int i; + unsigned short retval = 0; + int read_cmd = location | EE_READ_CMD; - st_le32(ioaddr, EE_ENB & ~EE_CS); - st_le32(ioaddr, EE_ENB); + st_le32(ioaddr, EE_ENB & ~EE_CS); + st_le32(ioaddr, EE_ENB); - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - st_le32(ioaddr, EE_ENB | dataval); - rtems_bsp_delay_in_bus_cycles(200); - st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK); - rtems_bsp_delay_in_bus_cycles(200); - st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */ - rtems_bsp_delay_in_bus_cycles(200); - } - st_le32(ioaddr, EE_ENB); + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + st_le32(ioaddr, EE_ENB | dataval); + rtems_bsp_delay_in_bus_cycles(200); + st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK); + rtems_bsp_delay_in_bus_cycles(200); + st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */ + rtems_bsp_delay_in_bus_cycles(200); + } + st_le32(ioaddr, EE_ENB); - for (i = 16; i > 0; i--) { - st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK); - rtems_bsp_delay_in_bus_cycles(200); - retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0); - st_le32(ioaddr, EE_ENB); - rtems_bsp_delay_in_bus_cycles(200); - } - - /* Terminate the EEPROM access. */ - st_le32(ioaddr, EE_ENB & ~EE_CS); - return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); + for (i = 16; i > 0; i--) { + st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK); + rtems_bsp_delay_in_bus_cycles(200); + retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0); + st_le32(ioaddr, EE_ENB); + rtems_bsp_delay_in_bus_cycles(200); + } + + /* Terminate the EEPROM access. */ + st_le32(ioaddr, EE_ENB & ~EE_CS); + return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); +} + + + + + + + + + + + + + + + + + + + + + + +static void no_op(const rtems_irq_connect_data* irq) +{ + return; +} + + + + +static int dec21140IsOn(const rtems_irq_connect_data* irq) +{ + return BSP_irq_enabled_at_i8259s (irq->name); } + + + /* - * Initialize the ethernet hardware + * DEC21140 interrupt handler */ -static void -dec21140Enet_initialize_hardware (struct dec21140_softc *sc) +static rtems_isr +dec21140Enet_interrupt_handler ( struct dec21140_softc *sc ) { - rtems_status_code st; - volatile unsigned int *tbase; - int i; - volatile unsigned char *cp, *setup_frm, *eaddrs; - volatile unsigned char *buffer; - volatile struct MD *rmd; + volatile unsigned32 *tbase; + unsigned32 status; + + tbase = (unsigned32 *)(sc->base); + + /* + * Read status + */ + status = ld_le32(tbase+memCSR5); + st_le32((tbase+memCSR5), status); + + /* + * Frame received? + */ + if( status & 0x000000c0 ) + { + sc->rxInterrupts++; + rtems_event_send(rxDaemonTid, sc->ioevent); + } +} - tbase = sc->base; - /* - * WARNING : First write in CSR6 - * Then Reset the chip ( 1 in CSR0) - */ - st_le32( (tbase+memCSR6), CSR6_INIT); - st_le32( (tbase+memCSR0), RESET_CHIP); - rtems_bsp_delay_in_bus_cycles(200); - /* - * Init CSR0 +static rtems_isr +dec21140Enet_interrupt_handler_entry() +{ + int i; + + /* + ** Check all the initialized dec units for interrupt service */ - st_le32( (tbase+memCSR0), CSR0_MODE); + + for(i=0; i< NDECDRIVER; i++ ) + { + if( dec21140_softc[i].base ) + dec21140Enet_interrupt_handler( &dec21140_softc[i] ); + } +} + + + + + + + + + + +/* + * Initialize the ethernet hardware + */ +static void +dec21140Enet_initialize_hardware (struct dec21140_softc *sc) +{ + int i,st; + volatile unsigned int *tbase; + volatile unsigned char *cp, *setup_frm, *eaddrs; + volatile unsigned char *buffer; + volatile struct MD *rmd; + #ifdef DEC_DEBUG - printk("DC2114x %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n", - sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1], - sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3], - sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5], - sc->irqInfo.name, sc->port, (unsigned) sc->base); + printk("dec2114x : %02x:%02x:%02x:%02x:%02x:%02x name '%s%d', io %x, mem %x, int %d\n", + sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1], + sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3], + sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5], + sc->arpcom.ac_if.if_name, sc->arpcom.ac_if.if_unit, + sc->port, (unsigned) sc->base, sc->irqInfo.name ); #endif - - /* - * Init RX ring - */ - cp = (volatile unsigned char *)malloc(((NRXBUFS+NTXBUFS)*sizeof(struct MD)) - + (NTXBUFS*RBUF_SIZE) - + CPU_CACHE_ALIGNMENT_FOR_BUFFER); - sc->bufferBase = cp; - cp += (CPU_CACHE_ALIGNMENT_FOR_BUFFER - (int)cp) - & (CPU_CACHE_ALIGNMENT_FOR_BUFFER - 1); + + + + tbase = sc->base; + + /* + * WARNING : First write in CSR6 + * Then Reset the chip ( 1 in CSR0) + */ + st_le32( (tbase+memCSR6), CSR6_INIT); + st_le32( (tbase+memCSR0), RESET_CHIP); + rtems_bsp_delay_in_bus_cycles(200); + + st_le32( (tbase+memCSR7), NO_IT); + + /* + * Init CSR0 + */ + st_le32( (tbase+memCSR0), CSR0_MODE); + + /* + * Init RX ring + */ + cp = (volatile unsigned char *)malloc(((NRXBUFS+NTXBUFS)*sizeof(struct MD)) + + (NTXBUFS*RBUF_SIZE) + + CPU_CACHE_ALIGNMENT_FOR_BUFFER); + sc->bufferBase = cp; + cp += (CPU_CACHE_ALIGNMENT_FOR_BUFFER - (int)cp) & (CPU_CACHE_ALIGNMENT_FOR_BUFFER - 1); #if defined(__i386__) #ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA - if (_CPU_is_paging_enabled()) - _CPU_change_memory_mapping_attribute - (NULL, cp, - ((NRXBUFS+NTXBUFS)*sizeof(struct MD)) - + (NTXBUFS*RBUF_SIZE), - PTE_CACHE_DISABLE | PTE_WRITABLE); + if (_CPU_is_paging_enabled()) + _CPU_change_memory_mapping_attribute + (NULL, cp, + ((NRXBUFS+NTXBUFS)*sizeof(struct MD)) + + (NTXBUFS*RBUF_SIZE), + PTE_CACHE_DISABLE | PTE_WRITABLE); #endif #endif - rmd = (volatile struct MD*)cp; - sc->MDbase = rmd; - buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD)); - st_le32( (tbase+memCSR3), (long)(phys_to_bus((long)(sc->MDbase)))); - for (i=0 ; im_pkthdr.rcvif = &sc->arpcom.ac_if; - rmd->m = m; - - rmd->buf2 = phys_to_bus(rmd+1); - rmd->buf1 = phys_to_bus(mtod(m, void *)); - rmd->counts = 0xfdc00000 | (RBUF_SIZE); - rmd->status = 0x80000000; - rmd->next = rmd + 1; - rmd++; - } - /* - * mark last RX buffer. - */ - sc->MDbase [NRXBUFS-1].counts = 0xfec00000 | (RBUF_SIZE); - sc->MDbase [NRXBUFS-1].next = sc->MDbase; + rmd = (volatile struct MD*)cp; + sc->MDbase = rmd; + sc->nextRxMD = sc->MDbase; - /* - * Init TX ring - */ - st_le32( (tbase+memCSR4), (long)(phys_to_bus((long)(rmd))) ); - for (i=0 ; ibuf2 = phys_to_bus(rmd+i+1); - (rmd+i)->buf1 = phys_to_bus(buffer + (i*RBUF_SIZE)); - (rmd+i)->counts = 0x01000000; - (rmd+i)->status = 0x0; - (rmd+i)->next = rmd+i+1; - (rmd+i)->m = 0; - } + buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD)); + st_le32( (tbase+memCSR3), (long)(phys_to_bus((long)(sc->MDbase)))); - /* - * mark last TX buffer. - */ - (rmd+NTXBUFS-1)->buf2 = phys_to_bus(rmd); - (rmd+NTXBUFS-1)->next = rmd; - - /* - * Set up interrupts - */ - sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler; - sc->irqInfo.on = nopOn; - sc->irqInfo.off = nopOn; - sc->irqInfo.isOn = dec21140IsOn; - st = BSP_install_rtems_irq_handler (&sc->irqInfo); - if (!st) - rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n", - sc->irqInfo.name); + for (i=0 ; im_pkthdr.rcvif = &sc->arpcom.ac_if; + rmd->m = m; - st_le32( (tbase+memCSR7), NO_IT); + rmd->buf2 = phys_to_bus(rmd+1); + rmd->buf1 = phys_to_bus(mtod(m, void *)); + rmd->status = 0x80000000; + rmd->counts = 0xfdc00000 | (RBUF_SIZE); + rmd->next = rmd+1; + rmd++; + } + /* + * mark last RX buffer. + */ + sc->MDbase [NRXBUFS-1].buf2 = 0; + sc->MDbase [NRXBUFS-1].counts = 0xfec00000 | (RBUF_SIZE); + sc->MDbase [NRXBUFS-1].next = sc->MDbase; + + + + /* + * Init TX ring + */ + st_le32( (tbase+memCSR4), (long)(phys_to_bus((long)(rmd))) ); + for (i=0 ; ibuf2 = phys_to_bus(rmd+i+1); + (rmd+i)->buf1 = phys_to_bus(buffer + (i*RBUF_SIZE)); + (rmd+i)->counts = 0x01000000; + (rmd+i)->status = 0x0; + (rmd+i)->next = rmd+i+1; + (rmd+i)->m = 0; + } + + /* + * mark last TX buffer. + */ + (rmd+NTXBUFS-1)->buf2 = phys_to_bus(rmd); + (rmd+NTXBUFS-1)->next = rmd; + + + /* + * Build setup frame + */ + setup_frm = (volatile unsigned char *)(bus_to_phys(rmd->buf1)); + eaddrs = (char *)(sc->arpcom.ac_enaddr); + /* Fill the buffer with our physical address. */ + for (i = 1; i < 16; i++) { + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[3]; + *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[3]; + *setup_frm++ = eaddrs[4]; + *setup_frm++ = eaddrs[5]; + *setup_frm++ = eaddrs[4]; + *setup_frm++ = eaddrs[5]; + } + + /* Add the broadcast address when doing perfect filtering */ + memset((void*) setup_frm, 0xff, 12); + rmd->counts = 0x09000000 | 192 ; + rmd->status = 0x80000000; + st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX); + st_le32( (tbase+memCSR1), 1); + + while (rmd->status != 0x7fffffff); + rmd->counts = 0x01000000; + + sc->TxMD = rmd+1; + + + + + + sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler_entry; + sc->irqInfo.on = no_op; + sc->irqInfo.off = no_op; + sc->irqInfo.isOn = dec21140IsOn; + +#ifdef BSP_SHARED_HANDLER_SUPPORT + st = BSP_install_rtems_shared_irq_handler( &sc->irqInfo ); +#else + st = BSP_install_rtems_irq_handler( &sc->irqInfo ); +#endif - /* - * Build setup frame - */ - setup_frm = (volatile unsigned char *)(bus_to_phys(rmd->buf1)); - eaddrs = (char *)(sc->arpcom.ac_enaddr); - /* Fill the buffer with our physical address. */ - for (i = 1; i < 16; i++) { - *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; - *setup_frm++ = eaddrs[3]; - *setup_frm++ = eaddrs[2]; - *setup_frm++ = eaddrs[3]; - *setup_frm++ = eaddrs[4]; - *setup_frm++ = eaddrs[5]; - *setup_frm++ = eaddrs[4]; - *setup_frm++ = eaddrs[5]; - } - /* Add the broadcast address when doing perfect filtering */ - memset((void*) setup_frm, 0xff, 12); - rmd->counts = 0x09000000 | 192 ; - rmd->status = 0x80000000; - st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX); - st_le32( (tbase+memCSR1), 1); - while (rmd->status != 0x7fffffff); - rmd->counts = 0x01000000; - sc->TxMD = rmd+1; - - /* - * Enable RX and TX - */ - st_le32( (tbase+memCSR5), IT_SETUP); - st_le32( (tbase+memCSR7), IT_SETUP); - st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX); + if (!st) + rtems_panic ("dec2114x : Interrupt name %d already in use\n", sc->irqInfo.name ); } + + + + + + static void dec21140_rxDaemon (void *arg) { - volatile unsigned int *tbase; - struct ether_header *eh; - struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0]; - struct ifnet *ifp = &dp->arpcom.ac_if; - struct mbuf *m; - volatile struct MD *rmd; - unsigned int len; - rtems_event_set events; - - tbase = dec21140_softc[0].base ; - rmd = dec21140_softc[0].MDbase; + volatile unsigned int *tbase; + volatile struct MD *rmd; + struct dec21140_softc *sc; + volatile struct ifnet *ifp; + struct ether_header *eh; + struct mbuf *m; + unsigned int i,len; + rtems_event_set events; + + for (;;) + { + + rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + for(i=0; i< NDECDRIVER; i++ ) + { + sc = &dec21140_softc[i]; + if( sc->base ) + { + if( events & sc->ioevent ) + { + ifp = &sc->arpcom.ac_if; + tbase = sc->base; + rmd = sc->nextRxMD; + + /* + ** Read off all the packets we've received on this unit + */ + while((rmd->status & 0x80000000) == 0) + { + /* printk("unit %i rx\n", ifp->if_unit ); */ + + /* pass on the packet in the mbuf */ + len = (rmd->status >> 16) & 0x7ff; + m = (struct mbuf *)(rmd->m); + m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + + /* get a new mbuf for the 21140 */ + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + rmd->m = m; + rmd->buf1 = phys_to_bus(mtod(m, void *)); + + /* mark the descriptor as ready to receive */ + rmd->status = 0x80000000; + + rmd=rmd->next; + } - for (;;){ + sc->nextRxMD = rmd; + } + } + } - rtems_bsdnet_event_receive (INTERRUPT_EVENT, - RTEMS_WAIT|RTEMS_EVENT_ANY, - RTEMS_NO_TIMEOUT, - &events); - - while((rmd->status & 0x80000000) == 0){ - /* pass on the packet in the mbuf */ - len = (rmd->status >> 16) & 0x7ff; - m = (struct mbuf *)(rmd->m); - m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); - eh = mtod (m, struct ether_header *); - m->m_data += sizeof(struct ether_header); - ether_input (ifp, eh, m); - - /* get a new mbuf for the 21140 */ - MGETHDR (m, M_WAIT, MT_DATA); - MCLGET (m, M_WAIT); - m->m_pkthdr.rcvif = ifp; - rmd->m = m; - rmd->buf1 = phys_to_bus(mtod(m, void *)); - - rmd->status = 0x80000000; - - rmd=rmd->next; - } - } + } } + + + + + + static void sendpacket (struct ifnet *ifp, struct mbuf *m) { - struct dec21140_softc *dp = ifp->if_softc; - volatile struct MD *tmd; - volatile unsigned char *temp; - struct mbuf *n; - unsigned int len; - volatile unsigned int *tbase; + struct dec21140_softc *dp = ifp->if_softc; + volatile struct MD *tmd; + volatile unsigned char *temp; + struct mbuf *n; + unsigned int len; + volatile unsigned int *tbase; + + tbase = dp->base; + /* + * Waiting for Transmitter ready + */ + + tmd = dp->TxMD; + n = m; + + while ((tmd->status & 0x80000000) != 0) + { + tmd=tmd->next; + } + + len = 0; + temp = (volatile unsigned char *)(bus_to_phys(tmd->buf1)); + + for (;;) + { + len += m->m_len; + memcpy((void*) temp, (char *)m->m_data, m->m_len); + temp += m->m_len ; + if ((m = m->m_next) == NULL) + break; + } - tbase = dp->base; - /* - * Waiting for Transmitter ready - */ - tmd = dec21140_softc[0].TxMD; - n = m; + if (len < ET_MINLEN) len = ET_MINLEN; + tmd->counts = 0xe1000000 | (len & 0x7ff); + tmd->status = 0x80000000; - while ((tmd->status & 0x80000000) != 0){ - tmd=tmd->next; - } + st_le32( (tbase+memCSR1), 0x1); - len = 0; - temp = (volatile unsigned char *)(bus_to_phys(tmd->buf1)); - - for (;;){ - len += m->m_len; - memcpy((void*) temp, (char *)m->m_data, m->m_len); - temp += m->m_len ; - if ((m = m->m_next) == NULL) - break; - } - - if (len < ET_MINLEN) len = ET_MINLEN; - tmd->counts = 0xe1000000 | (len & 0x7ff); - tmd->status = 0x80000000; - - st_le32( (tbase+memCSR1), 0x1); - - m_freem(n); - dec21140_softc[0].TxMD = tmd->next; + m_freem(n); + + dp->TxMD = tmd->next; } + + + + /* * Driver transmit daemon */ void dec21140_txDaemon (void *arg) { - struct dec21140_softc *sc = (struct dec21140_softc *)arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mbuf *m; - rtems_event_set events; - - for (;;) { - /* - * Wait for packet - */ - - rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); - - /* - * Send packets till queue is empty - */ - for (;;) { + struct dec21140_softc *sc; + struct ifnet *ifp; + struct mbuf *m; + int i; + rtems_event_set events; + + for (;;) + { /* - * Get the next mbuf chain to transmit. + * Wait for packets bound for any of the dec units */ - IF_DEQUEUE(&ifp->if_snd, m); - if (!m) - break; - sendpacket (ifp, m); - } - ifp->if_flags &= ~IFF_OACTIVE; - } -} + rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + + for(i=0; i< NDECDRIVER; i++ ) + { + sc = &dec21140_softc[i]; + if( sc->base ) + { + if( events & sc->ioevent ) + { + ifp = &sc->arpcom.ac_if; + + /* + * Send packets till queue is empty + */ + for(;;) + { + IF_DEQUEUE(&ifp->if_snd, m); + if( !m ) break; + /* printk("unit %i tx\n", ifp->if_unit ); */ + sendpacket (ifp, m); + } + + ifp->if_flags &= ~IFF_OACTIVE; + } + } + } + + } +} + + static void dec21140_start (struct ifnet *ifp) { - struct dec21140_softc *sc = ifp->if_softc; - - rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); - ifp->if_flags |= IFF_OACTIVE; + struct dec21140_softc *sc = ifp->if_softc; + rtems_event_send( txDaemonTid, sc->ioevent ); + ifp->if_flags |= IFF_OACTIVE; } + + + + /* * Initialize and start the device */ static void dec21140_init (void *arg) { - struct dec21140_softc *sc = arg; - struct ifnet *ifp = &sc->arpcom.ac_if; + struct dec21140_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + volatile unsigned int *tbase; + + /* + * Set up DEC21140 hardware if its not already been done + */ + if( !sc->irqInfo.hdl ) + { + dec21140Enet_initialize_hardware (sc); + } + + /* + * Enable RX and TX + */ + tbase = sc->base; + st_le32( (tbase+memCSR5), IT_SETUP); + st_le32( (tbase+memCSR7), IT_SETUP); + st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX); + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; +} + + + - if (sc->txDaemonTid == 0) { - - /* - * Set up DEC21140 hardware - */ - dec21140Enet_initialize_hardware (sc); - - /* - * Start driver tasks - */ - sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, - dec21140_rxDaemon, sc); - sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, - dec21140_txDaemon, sc); - } - /* - * Tell the world that we're running. - */ - ifp->if_flags |= IFF_RUNNING; -} /* * Stop the device @@ -682,10 +881,11 @@ dec21140_stop (struct dec21140_softc *sc) /* * Stop the transmitter */ - tbase=dec21140_softc[0].base ; + tbase = sc->base; st_le32( (tbase+memCSR7), NO_IT); st_le32( (tbase+memCSR6), CSR6_INIT); - free((void*)sc->bufferBase); + + /* free((void*)sc->bufferBase); */ } @@ -715,55 +915,85 @@ dec21140_stats (struct dec21140_softc *sc) printf (" Raw output wait:%-8lu\n", sc->txRawWait); } + + + /* * Driver ioctl handler */ static int dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data) { - struct dec21140_softc *sc = ifp->if_softc; - int error = 0; - - switch (command) { - case SIOCGIFADDR: - case SIOCSIFADDR: - ether_ioctl (ifp, command, data); - break; - - case SIOCSIFFLAGS: - switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { - case IFF_RUNNING: - dec21140_stop (sc); - break; - - case IFF_UP: - dec21140_init (sc); - break; - - case IFF_UP | IFF_RUNNING: - dec21140_stop (sc); - dec21140_init (sc); - break; - - default: - break; - } - break; - - case SIO_RTEMS_SHOW_STATS: - dec21140_stats (sc); - break; + struct dec21140_softc *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + dec21140_stop (sc); + break; + + case IFF_UP: + dec21140_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + dec21140_stop (sc); + dec21140_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + dec21140_stats (sc); + break; - /* - * FIXME: All sorts of multicast commands need to be added here! - */ - default: - error = EINVAL; - break; - } - - return error; + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + + return error; +} + + + + + + + +/* +int iftap(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m ) +{ + int i; + + if( ifp->if_unit == 1 ) return 0; + + printf("unit %i, src ", ifp->if_unit ); + for(i=0; i< ETHER_ADDR_LEN; i++) printf("%02x", (char) eh->ether_shost[i] ); + printf(" dest "); + for(i=0; i< ETHER_ADDR_LEN; i++) printf("%02x", (char) eh->ether_dhost[i] ); + printf("\n"); + + return -1; } +*/ + + + + /* * Attach an DEC21140 driver to the system @@ -771,193 +1001,283 @@ dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data) int rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach) { - struct dec21140_softc *sc; - struct ifnet *ifp; - int mtu; - int i; + struct dec21140_softc *sc; + struct ifnet *ifp; + char *unitName; + int unitNumber; + int mtu; + unsigned char cvalue; #if defined(__i386__) - int deviceId = PCI_DEVICE_ID_DEC_21140; /* network card device ID */ + int signature; + int value; + char interrupt; + int diag; + unsigned int deviceId; #endif - - /* - * First, find a DEC board - */ +#if defined(__PPC) + int pbus, pdev, pfun; + int tmp; + unsigned int lvalue; +#endif + + + /* + * Get the instance number for the board we're going to configure + * from the user. + */ + if( (unitNumber = rtems_bsdnet_parse_driver_name( config, &unitName)) == -1 ) + { + return 0; + } + if( strcmp(unitName, DRIVER_PREFIX) ) + { + printk("dec2114x : unit name '%s' not %s\n", unitName, DRIVER_PREFIX ); + return 0; + } + + #if defined(__i386__) - int signature; - int value; - char interrupt; - int diag; + /* + * First, find a DEC board + */ - if (pcib_init() == PCIB_ERR_NOTPRESENT) - rtems_panic("PCI BIOS not found !!"); + if (pcib_init() == PCIB_ERR_NOTPRESENT) + rtems_panic("PCI BIOS not found !!"); - /* - * Try to find the network card on the PCI bus. Probe for a DEC 21140 - * card first. If not found probe the bus for a DEC/Intel 21143 card. - */ - deviceId = PCI_DEVICE_ID_DEC_21140; - diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, - 0, &signature); - if ( diag == PCIB_ERR_SUCCESS) + /* + * Try to find the network card on the PCI bus. Probe for a DEC 21140 + * card first. If not found probe the bus for a DEC/Intel 21143 card. + */ + deviceId = PCI_DEVICE_ID_DEC_21140; + diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, unitNumber-1, &signature); + + if ( diag == PCIB_ERR_SUCCESS) printk( "DEC 21140 PCI network card found\n" ); - else - { + else + { deviceId = PCI_DEVICE_ID_DEC_21143; - diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, - 0, &signature); + diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, unitNumber-1, &signature); if ( diag == PCIB_ERR_SUCCESS) - printk( "DEC/Intel 21143 PCI network card found\n" ); + printk( "DEC/Intel 21143 PCI network card found\n" ); else - rtems_panic("DEC PCI network card not found !!\n"); - } + rtems_panic("DEC PCI network card not found !!\n"); + } #endif #if defined(__PPC) - unsigned char ucSlotNumber, ucFnNumber; - unsigned int ulDeviceID, lvalue, tmp; - unsigned char cvalue; - - for(ucSlotNumber=0;ucSlotNumberarpcom.ac_if; - if (ifp->if_softc == NULL) - break; - } - if (i >= NDECDRIVER) { - printk ("Too many DEC drivers.\n"); - return 0; - } - - /* - * Process options - */ + /* + * Find the board + */ + if( BSP_pciFindDevice( PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21140, + unitNumber-1, &pbus, &pdev, &pfun) == -1 ) + { + if( BSP_pciFindDevice( PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21143, + unitNumber-1, &pbus, &pdev, &pfun) != -1 ) + { + printk("dec21143 : found device '%s', PPC support has not been tested. Using it anyway.\n", + config->name ); + + pci_write_config_dword(pbus, + pdev, + pfun, + 0x40, + PCI_DEVICE_ID_DEC_21143 ); + + } + else + { + printk("dec2114x : device '%s' not found on PCI bus\n", config->name ); + return 0; + } + } + +#ifdef DEC_DEBUG + else + { + printk("dec21140 : found device '%s', bus 0x%02x, dev 0x%02x, func 0x%02x\n", + config->name, pbus, pdev, pfun); + } +#endif + +#endif + + + + + if ((unitNumber < 1) || (unitNumber > NDECDRIVER)) + { + printk("dec2114x : unit %i is invalid, must be (1 <= n <= %d)\n", unitNumber); + return 0; + } + + sc = &dec21140_softc[unitNumber - 1]; + ifp = &sc->arpcom.ac_if; + if (ifp->if_softc != NULL) + { + printk("dec2114x : unit %i already in use.\n", unitNumber ); + return 0; + } + + + /* + ** Get this unit's rx/tx event + */ + sc->ioevent = unit_signals[unitNumber-1]; + + + /* + * Get card address spaces & retrieve its isr vector + */ #if defined(__i386__) - /* the 21143 chip must be enabled before it can be accessed */ - if ( deviceId == PCI_DEVICE_ID_DEC_21143 ) + /* the 21143 chip must be enabled before it can be accessed */ + if ( deviceId == PCI_DEVICE_ID_DEC_21143 ) pcib_conf_write32( signature, 0x40, 0 ); - pcib_conf_read32(signature, 16, &value); - sc->port = value & ~IO_MASK; + pcib_conf_read32(signature, 16, &value); + sc->port = value & ~IO_MASK; - pcib_conf_read32(signature, 20, &value); - if (_CPU_is_paging_enabled()) - _CPU_map_phys_address((void **) &(sc->base), - (void *)(value & ~MEM_MASK), - DEC_REGISTER_SIZE , - PTE_CACHE_DISABLE | PTE_WRITABLE); - else - sc->base = (unsigned int *)(value & ~MEM_MASK); + pcib_conf_read32(signature, 20, &value); + if (_CPU_is_paging_enabled()) + _CPU_map_phys_address((void **) &(sc->base), + (void *)(value & ~MEM_MASK), + DEC_REGISTER_SIZE , + PTE_CACHE_DISABLE | PTE_WRITABLE); + else + sc->base = (unsigned int *)(value & ~MEM_MASK); - pcib_conf_read8(signature, 60, &interrupt); - sc->irqInfo.name = (rtems_irq_symbolic_name)interrupt; + pcib_conf_read8(signature, 60, &interrupt); + cvalue = interrupt; #endif #if defined(__PPC) - (void)pci_read_config_dword(0, - ucSlotNumber, - ucFnNumber, - PCI_BASE_ADDRESS_0, - &lvalue); + (void)pci_read_config_dword(pbus, + pdev, + pfun, + PCI_BASE_ADDRESS_0, + &lvalue); - sc->port = lvalue & (unsigned int)(~IO_MASK); + sc->port = lvalue & (unsigned int)(~IO_MASK); - (void)pci_read_config_dword(0, - ucSlotNumber, - ucFnNumber, - PCI_BASE_ADDRESS_1 , - &lvalue); - - - tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK)) - + (unsigned int)PCI_MEM_BASE; - sc->base = (unsigned int *)(tmp); - - (void)pci_read_config_byte(0, - ucSlotNumber, - ucFnNumber, - PCI_INTERRUPT_LINE, - &cvalue); - sc->irqInfo.name = (rtems_irq_symbolic_name)cvalue; + (void)pci_read_config_dword(pbus, + pdev, + pfun, + PCI_BASE_ADDRESS_1, + &lvalue); + + tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK)) + + (unsigned int)PCI_MEM_BASE; + + sc->base = (unsigned int *)(tmp); + + pci_read_config_byte(pbus, + pdev, + pfun, + PCI_INTERRUPT_LINE, + &cvalue); + #endif - if (config->hardware_address) { - memcpy (sc->arpcom.ac_enaddr, config->hardware_address, - ETHER_ADDR_LEN); - } - else { - union {char c[64]; unsigned short s[32];} rombuf; - int i; - - for (i=0; i<32; i++){ - rombuf.s[i] = eeget16(sc->base+memCSR9, i); - } + + /* + ** Prep the board + */ + pci_write_config_word(pbus, pdev, pfun, + PCI_COMMAND, + (unsigned16)( PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE | + PCI_COMMAND_WAIT | + PCI_COMMAND_FAST_BACK ) ); + + /* + ** Store the interrupt name, we'll use it later when we initialize + ** the board. + */ + memset(&sc->irqInfo,0,sizeof(rtems_irq_connect_data)); + sc->irqInfo.name = cvalue; + + + /* printk("dec2114x : unit %d base address %08x.\n", unitNumber, sc->base ); */ + + + /* + ** Setup ethernet address + */ + if (config->hardware_address) { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, + ETHER_ADDR_LEN); + } + else { + union {char c[64]; unsigned short s[32];} rombuf; + int i; + + for (i=0; i<32; i++){ + rombuf.s[i] = eeget16( sc->base + memCSR9, i); + } #if defined(__i386__) - for (i=0 ; i<(ETHER_ADDR_LEN/2); i++){ - sc->arpcom.ac_enaddr[2*i] = rombuf.c[20+2*i+1]; - sc->arpcom.ac_enaddr[2*i+1] = rombuf.c[20+2*i]; - } + for (i=0 ; i<(ETHER_ADDR_LEN/2); i++){ + sc->arpcom.ac_enaddr[2*i] = rombuf.c[20+2*i+1]; + sc->arpcom.ac_enaddr[2*i+1] = rombuf.c[20+2*i]; + } #endif #if defined(__PPC) - memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN); + memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN); +#endif + } + + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + sc->acceptBroadcast = !config->ignore_broadcast; + + /* + * Set up network interface values + */ + +/* ifp->if_tap = iftap; */ + + ifp->if_softc = sc; + ifp->if_unit = unitNumber; + ifp->if_name = unitName; + ifp->if_mtu = mtu; + ifp->if_init = dec21140_init; + ifp->if_ioctl = dec21140_ioctl; + ifp->if_start = dec21140_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + +#ifdef DEC_DEBUG + printk( "dec2114x : driver attached\n" ); #endif - } - - if (config->mtu) - mtu = config->mtu; - else - mtu = ETHERMTU; - - sc->acceptBroadcast = !config->ignore_broadcast; - - /* - * Set up network interface values - */ - ifp->if_softc = sc; - ifp->if_unit = i + 1; - ifp->if_name = "dc"; - ifp->if_mtu = mtu; - ifp->if_init = dec21140_init; - ifp->if_ioctl = dec21140_ioctl; - ifp->if_start = dec21140_start; - ifp->if_output = ether_output; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; - if (ifp->if_snd.ifq_maxlen == 0) - ifp->if_snd.ifq_maxlen = ifqmaxlen; - - /* - * Attach the interface - */ - if_attach (ifp); - ether_ifattach (ifp); - - printk( "DC2114x : driver has been attached\n" ); - return 1; + + + /* + * Start driver tasks if this is the first dec unit initialized + */ + if (txDaemonTid == 0) + { + rxDaemonTid = rtems_bsdnet_newproc( "DCrx", 4096, + dec21140_rxDaemon, NULL); + + txDaemonTid = rtems_bsdnet_newproc( "DCtx", 4096, + dec21140_txDaemon, NULL); +#ifdef DEC_DEBUG + printk( "dec2114x : driver tasks created\n" ); +#endif + } + + return 1; }; + #endif /* DEC21140_SUPPORTED */ + +/* eof */ diff --git a/c/src/libchip/network/elnk.c b/c/src/libchip/network/elnk.c new file mode 100644 index 0000000000..be4f69a128 --- /dev/null +++ b/c/src/libchip/network/elnk.c @@ -0,0 +1,3267 @@ +/* + * RTEMS driver for Etherlink based Ethernet Controllers + * + * Copyright (C) 2003, Gregory Menke, NASA/GSFC + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * elnk.c + * + * + */ + + +/* + * Portions of this driver are taken from the Freebsd if_xl.c driver, + * version "1.133 2003/03/19 01:48:14" and are covered by the license + * text included below that was taken verbatim from the original file. + * More particularly, all structures, variables, and #defines prefixed + * with XL_ or xl_, along with their associated comments were taken + * directly from the Freebsd driver and modified as required to suit the + * purposes of this one. Additionally, much of the device setup & + * manipulation logic was also copied and modified to suit. All types + * and functions beginning with elnk are either my own creations or were + * adapted from other RTEMS components, and regardless, are subject to + * the standard OAR licensing terms given in the comments at the top of + * this file. + * + * Greg Menke + */ + + /* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* + * This driver only supports architectures with the new style + * exception processing. The following checks try to keep this + * from being compiled on systems which can't support this driver. + */ + +#if defined(__i386__) +#define ELNK_SUPPORTED +#endif + +#if defined(__PPC__) && (defined(mpc604) || defined(mpc750) || defined(mpc603e)) +#define ELNK_SUPPORTED +#endif + +/* #undef ELNK_SUPPORTED */ + + +#if defined(ELNK_SUPPORTED) +#include +#if defined(__i386__) +#include +#endif +#if defined(__PPC__) +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "if_media.h" +#include "mii.h" + +#if defined(__i386__) +#include +#endif +#if defined(__PPC) +#include +#endif + +#ifdef malloc +#undef malloc +#endif +#ifdef free +#undef free +#endif + +#define ELNK_DEBUG + + +#define DRIVER_PREFIX "elnk" + + + + + +/* +* These buffers allocated for each unit, so ensure +* +* rtems_bsdnet_config.mbuf_bytecount +* rtems_bsdnet_config.mbuf_cluster_bytecount +* +* are adequately sized to provide enough clusters and mbufs for all the +* units. The default bsdnet configuration is sufficient for one unit, +* but will be nearing exhaustion with 2 or more. Although a little +* expensive in memory, the following configuration should eliminate all +* mbuf/cluster issues; +* +* rtems_bsdnet_config.mbuf_bytecount = 128*1024; +* rtems_bsdnet_config.mbuf_cluster_bytecount = 256*1024; +* +* The default size in buffers of the rx & tx rings are given below. +* This driver honors the rtems_bsdnet_ifconfig fields 'rbuf_count' and +* 'xbuf_count', allowing the user to specify something else. +*/ + +#define RX_RING_SIZE 16 /* default number of receive buffers */ +#define TX_RING_SIZE 16 /* default number of transmit buffers */ + + +/* + * Number of boards supported by this driver + */ +#define NUM_UNITS 8 + +/* + * Receive buffer size -- Allow for a full ethernet packet including CRC + */ +#define XL_PACKET_SIZE 1540 + + +/* +** Events, one per unit. The event is sent to the rx task from the isr +** or from the stack to the tx task whenever a unit needs service. The +** rx/tx tasks identify the requesting unit(s) by their particular +** events so only requesting units are serviced. +*/ + +static rtems_event_set unit_signals[NUM_UNITS]= { RTEMS_EVENT_1, + RTEMS_EVENT_2, + RTEMS_EVENT_3, + RTEMS_EVENT_4, + RTEMS_EVENT_5, + RTEMS_EVENT_6, + RTEMS_EVENT_7, + RTEMS_EVENT_8 }; + + +#if defined(__PPC) +#define phys_to_bus(address) ((unsigned int)((address)) + PCI_DRAM_OFFSET) +#define bus_to_phys(address) ((unsigned int)((address)) - PCI_DRAM_OFFSET) +#define CPU_CACHE_ALIGNMENT_FOR_BUFFER PPC_CACHE_ALIGNMENT +#else +extern void Wait_X_ms( unsigned int timeToWait ); +#define phys_to_bus(address) ((unsigned int) ((address))) +#define bus_to_phys(address) ((unsigned int) ((address))) +#define rtems_bsp_delay_in_bus_cycles(cycle) Wait_X_ms( cycle/100 ) +#define CPU_CACHE_ALIGNMENT_FOR_BUFFER PG_SIZE + +inline void st_le32(volatile unsigned32 *addr, unsigned32 value) +{ + *(addr)=value ; +} + +inline unsigned32 ld_le32(volatile unsigned32 *addr) +{ + return(*addr); +} +#endif + +/* the actual duration waited in DELAY is not especially predictable, + * though it will be consistent. It should not be relied upon for + * specific timing given the vague per-bsp, per-architecture + * implementation of the actual delay function. It would probably be + * helpful to make this more accurate at some point... + */ +#define DELAY(n) rtems_bsp_delay_in_bus_cycles( n*20 ) + + + + +/* + * Register layouts. + */ +#define XL_COMMAND 0x0E +#define XL_STATUS 0x0E + +#define XL_TX_STATUS 0x1B +#define XL_TX_FREE 0x1C +#define XL_DMACTL 0x20 +#define XL_DOWNLIST_PTR 0x24 +#define XL_DOWN_POLL 0x2D /* 3c90xB only */ +#define XL_TX_FREETHRESH 0x2F +#define XL_UPLIST_PTR 0x38 +#define XL_UPLIST_STATUS 0x30 +#define XL_UP_POLL 0x3D /* 3c90xB only */ + +#define XL_PKTSTAT_UP_STALLED 0x00002000 +#define XL_PKTSTAT_UP_ERROR 0x00004000 +#define XL_PKTSTAT_UP_CMPLT 0x00008000 + +#define XL_DMACTL_DN_CMPLT_REQ 0x00000002 +#define XL_DMACTL_DOWN_STALLED 0x00000004 +#define XL_DMACTL_UP_CMPLT 0x00000008 +#define XL_DMACTL_DOWN_CMPLT 0x00000010 +#define XL_DMACTL_UP_RX_EARLY 0x00000020 +#define XL_DMACTL_ARM_COUNTDOWN 0x00000040 +#define XL_DMACTL_DOWN_INPROG 0x00000080 +#define XL_DMACTL_COUNTER_SPEED 0x00000100 +#define XL_DMACTL_DOWNDOWN_MODE 0x00000200 +#define XL_DMACTL_TARGET_ABORT 0x40000000 +#define XL_DMACTL_MASTER_ABORT 0x80000000 + +/* + * Command codes. Some command codes require that we wait for + * the CMD_BUSY flag to clear. Those codes are marked as 'mustwait.' + */ +#define XL_CMD_RESET 0x0000 /* mustwait */ +#define XL_CMD_WINSEL 0x0800 +#define XL_CMD_COAX_START 0x1000 +#define XL_CMD_RX_DISABLE 0x1800 +#define XL_CMD_RX_ENABLE 0x2000 +#define XL_CMD_RX_RESET 0x2800 /* mustwait */ +#define XL_CMD_UP_STALL 0x3000 /* mustwait */ +#define XL_CMD_UP_UNSTALL 0x3001 +#define XL_CMD_DOWN_STALL 0x3002 /* mustwait */ +#define XL_CMD_DOWN_UNSTALL 0x3003 +#define XL_CMD_RX_DISCARD 0x4000 +#define XL_CMD_TX_ENABLE 0x4800 +#define XL_CMD_TX_DISABLE 0x5000 +#define XL_CMD_TX_RESET 0x5800 /* mustwait */ +#define XL_CMD_INTR_FAKE 0x6000 +#define XL_CMD_INTR_ACK 0x6800 +#define XL_CMD_INTR_ENB 0x7000 +#define XL_CMD_STAT_ENB 0x7800 +#define XL_CMD_RX_SET_FILT 0x8000 +#define XL_CMD_RX_SET_THRESH 0x8800 +#define XL_CMD_TX_SET_THRESH 0x9000 +#define XL_CMD_TX_SET_START 0x9800 +#define XL_CMD_DMA_UP 0xA000 +#define XL_CMD_DMA_STOP 0xA001 +#define XL_CMD_STATS_ENABLE 0xA800 +#define XL_CMD_STATS_DISABLE 0xB000 +#define XL_CMD_COAX_STOP 0xB800 + +#define XL_CMD_SET_TX_RECLAIM 0xC000 /* 3c905B only */ +#define XL_CMD_RX_SET_HASH 0xC800 /* 3c905B only */ + +#define XL_HASH_SET 0x0400 +#define XL_HASHFILT_SIZE 256 + +/* + * status codes + * Note that bits 15 to 13 indicate the currently visible register window + * which may be anything from 0 to 7. + */ +#define XL_STAT_INTLATCH 0x0001 /* 0 */ +#define XL_STAT_ADFAIL 0x0002 /* 1 */ +#define XL_STAT_TX_COMPLETE 0x0004 /* 2 */ +#define XL_STAT_TX_AVAIL 0x0008 /* 3 first generation */ +#define XL_STAT_RX_COMPLETE 0x0010 /* 4 */ +#define XL_STAT_RX_EARLY 0x0020 /* 5 */ +#define XL_STAT_INTREQ 0x0040 /* 6 */ +#define XL_STAT_STATSOFLOW 0x0080 /* 7 */ +#define XL_STAT_DMADONE 0x0100 /* 8 first generation */ +#define XL_STAT_LINKSTAT 0x0100 /* 8 3c509B */ +#define XL_STAT_DOWN_COMPLETE 0x0200 /* 9 */ +#define XL_STAT_UP_COMPLETE 0x0400 /* 10 */ +#define XL_STAT_DMABUSY 0x0800 /* 11 first generation */ +#define XL_STAT_CMDBUSY 0x1000 /* 12 */ + +/* + * Interrupts we normally want enabled. + */ +#define XL_INTRS \ + (XL_STAT_UP_COMPLETE|XL_STAT_STATSOFLOW|XL_STAT_ADFAIL| \ + XL_STAT_DOWN_COMPLETE|XL_STAT_TX_COMPLETE|XL_STAT_INTLATCH) + + + +/* + * General constants that are fun to know. + * + * 3Com PCI vendor ID + */ +#define TC_VENDORID 0x10B7 + +/* + * 3Com chip device IDs. + */ +#define TC_DEVICEID_BOOMERANG_10BT 0x9000 +#define TC_DEVICEID_BOOMERANG_10BT_COMBO 0x9001 +#define TC_DEVICEID_BOOMERANG_10_100BT 0x9050 +#define TC_DEVICEID_BOOMERANG_100BT4 0x9051 +#define TC_DEVICEID_KRAKATOA_10BT 0x9004 +#define TC_DEVICEID_KRAKATOA_10BT_COMBO 0x9005 +#define TC_DEVICEID_KRAKATOA_10BT_TPC 0x9006 +#define TC_DEVICEID_CYCLONE_10FL 0x900A +#define TC_DEVICEID_HURRICANE_10_100BT 0x9055 +#define TC_DEVICEID_CYCLONE_10_100BT4 0x9056 +#define TC_DEVICEID_CYCLONE_10_100_COMBO 0x9058 +#define TC_DEVICEID_CYCLONE_10_100FX 0x905A +#define TC_DEVICEID_TORNADO_10_100BT 0x9200 +#define TC_DEVICEID_TORNADO_10_100BT_920B 0x9201 +#define TC_DEVICEID_HURRICANE_10_100BT_SERV 0x9800 +#define TC_DEVICEID_TORNADO_10_100BT_SERV 0x9805 +#define TC_DEVICEID_HURRICANE_SOHO100TX 0x7646 +#define TC_DEVICEID_TORNADO_HOMECONNECT 0x4500 +#define TC_DEVICEID_HURRICANE_555 0x5055 +#define TC_DEVICEID_HURRICANE_556 0x6055 +#define TC_DEVICEID_HURRICANE_556B 0x6056 +#define TC_DEVICEID_HURRICANE_575A 0x5057 +#define TC_DEVICEID_HURRICANE_575B 0x5157 +#define TC_DEVICEID_HURRICANE_575C 0x5257 +#define TC_DEVICEID_HURRICANE_656 0x6560 +#define TC_DEVICEID_HURRICANE_656B 0x6562 +#define TC_DEVICEID_TORNADO_656C 0x6564 + + + +#define XL_RXSTAT_LENMASK 0x00001FFF +#define XL_RXSTAT_UP_ERROR 0x00004000 +#define XL_RXSTAT_UP_CMPLT 0x00008000 +#define XL_RXSTAT_UP_OVERRUN 0x00010000 +#define XL_RXSTAT_RUNT 0x00020000 +#define XL_RXSTAT_ALIGN 0x00040000 +#define XL_RXSTAT_CRC 0x00080000 +#define XL_RXSTAT_OVERSIZE 0x00100000 +#define XL_RXSTAT_DRIBBLE 0x00800000 +#define XL_RXSTAT_UP_OFLOW 0x01000000 +#define XL_RXSTAT_IPCKERR 0x02000000 /* 3c905B only */ +#define XL_RXSTAT_TCPCKERR 0x04000000 /* 3c905B only */ +#define XL_RXSTAT_UDPCKERR 0x08000000 /* 3c905B only */ +#define XL_RXSTAT_BUFEN 0x10000000 /* 3c905B only */ +#define XL_RXSTAT_IPCKOK 0x20000000 /* 3c905B only */ +#define XL_RXSTAT_TCPCOK 0x40000000 /* 3c905B only */ +#define XL_RXSTAT_UDPCKOK 0x80000000 /* 3c905B only */ + +#define XL_TXSTAT_LENMASK 0x00001FFF +#define XL_TXSTAT_CRCDIS 0x00002000 +#define XL_TXSTAT_TX_INTR 0x00008000 +#define XL_TXSTAT_DL_COMPLETE 0x00010000 +#define XL_TXSTAT_IPCKSUM 0x02000000 /* 3c905B only */ +#define XL_TXSTAT_TCPCKSUM 0x04000000 /* 3c905B only */ +#define XL_TXSTAT_UDPCKSUM 0x08000000 /* 3c905B only */ +#define XL_TXSTAT_RND_DEFEAT 0x10000000 /* 3c905B only */ +#define XL_TXSTAT_EMPTY 0x20000000 /* 3c905B only */ +#define XL_TXSTAT_DL_INTR 0x80000000 + + +#define XL_FLAG_FUNCREG 0x0001 +#define XL_FLAG_PHYOK 0x0002 +#define XL_FLAG_EEPROM_OFFSET_30 0x0004 +#define XL_FLAG_WEIRDRESET 0x0008 +#define XL_FLAG_8BITROM 0x0010 +#define XL_FLAG_INVERT_LED_PWR 0x0020 +#define XL_FLAG_INVERT_MII_PWR 0x0040 +#define XL_FLAG_NO_XCVR_PWR 0x0080 +#define XL_FLAG_USE_MMIO 0x0100 + + + +#define XL_EE_READ 0x0080 /* read, 5 bit address */ +#define XL_EE_WRITE 0x0040 /* write, 5 bit address */ +#define XL_EE_ERASE 0x00c0 /* erase, 5 bit address */ +#define XL_EE_EWEN 0x0030 /* erase, no data needed */ +#define XL_EE_8BIT_READ 0x0200 /* read, 8 bit address */ +#define XL_EE_BUSY 0x8000 + +#define XL_EE_EADDR0 0x00 /* station address, first word */ +#define XL_EE_EADDR1 0x01 /* station address, next word, */ +#define XL_EE_EADDR2 0x02 /* station address, last word */ +#define XL_EE_PRODID 0x03 /* product ID code */ +#define XL_EE_MDATA_DATE 0x04 /* manufacturing data, date */ +#define XL_EE_MDATA_DIV 0x05 /* manufacturing data, division */ +#define XL_EE_MDATA_PCODE 0x06 /* manufacturing data, product code */ +#define XL_EE_MFG_ID 0x07 +#define XL_EE_PCI_PARM 0x08 +#define XL_EE_ROM_ONFO 0x09 +#define XL_EE_OEM_ADR0 0x0A +#define XL_EE_OEM_ADR1 0x0B +#define XL_EE_OEM_ADR2 0x0C +#define XL_EE_SOFTINFO1 0x0D +#define XL_EE_COMPAT 0x0E +#define XL_EE_SOFTINFO2 0x0F +#define XL_EE_CAPS 0x10 /* capabilities word */ +#define XL_EE_RSVD0 0x11 +#define XL_EE_ICFG_0 0x12 +#define XL_EE_ICFG_1 0x13 +#define XL_EE_RSVD1 0x14 +#define XL_EE_SOFTINFO3 0x15 +#define XL_EE_RSVD_2 0x16 + +/* + * Bits in the capabilities word + */ +#define XL_CAPS_PNP 0x0001 +#define XL_CAPS_FULL_DUPLEX 0x0002 +#define XL_CAPS_LARGE_PKTS 0x0004 +#define XL_CAPS_SLAVE_DMA 0x0008 +#define XL_CAPS_SECOND_DMA 0x0010 +#define XL_CAPS_FULL_BM 0x0020 +#define XL_CAPS_FRAG_BM 0x0040 +#define XL_CAPS_CRC_PASSTHRU 0x0080 +#define XL_CAPS_TXDONE 0x0100 +#define XL_CAPS_NO_TXLENGTH 0x0200 +#define XL_CAPS_RX_REPEAT 0x0400 +#define XL_CAPS_SNOOPING 0x0800 +#define XL_CAPS_100MBPS 0x1000 +#define XL_CAPS_PWRMGMT 0x2000 + + + +/* + * Window 0 registers + */ +#define XL_W0_EE_DATA 0x0C +#define XL_W0_EE_CMD 0x0A +#define XL_W0_RSRC_CFG 0x08 +#define XL_W0_ADDR_CFG 0x06 +#define XL_W0_CFG_CTRL 0x04 + +#define XL_W0_PROD_ID 0x02 +#define XL_W0_MFG_ID 0x00 + +/* + * Window 1 + */ + +#define XL_W1_TX_FIFO 0x10 + +#define XL_W1_FREE_TX 0x0C +#define XL_W1_TX_STATUS 0x0B +#define XL_W1_TX_TIMER 0x0A +#define XL_W1_RX_STATUS 0x08 +#define XL_W1_RX_FIFO 0x00 + +/* + * RX status codes + */ +#define XL_RXSTATUS_OVERRUN 0x01 +#define XL_RXSTATUS_RUNT 0x02 +#define XL_RXSTATUS_ALIGN 0x04 +#define XL_RXSTATUS_CRC 0x08 +#define XL_RXSTATUS_OVERSIZE 0x10 +#define XL_RXSTATUS_DRIBBLE 0x20 + +/* + * TX status codes + */ +#define XL_TXSTATUS_RECLAIM 0x02 /* 3c905B only */ +#define XL_TXSTATUS_OVERFLOW 0x04 +#define XL_TXSTATUS_MAXCOLS 0x08 +#define XL_TXSTATUS_UNDERRUN 0x10 +#define XL_TXSTATUS_JABBER 0x20 +#define XL_TXSTATUS_INTREQ 0x40 +#define XL_TXSTATUS_COMPLETE 0x80 + +/* + * Window 2 + */ +#define XL_W2_RESET_OPTIONS 0x0C /* 3c905B only */ +#define XL_W2_STATION_MASK_HI 0x0A +#define XL_W2_STATION_MASK_MID 0x08 +#define XL_W2_STATION_MASK_LO 0x06 +#define XL_W2_STATION_ADDR_HI 0x04 +#define XL_W2_STATION_ADDR_MID 0x02 +#define XL_W2_STATION_ADDR_LO 0x00 + +#define XL_RESETOPT_FEATUREMASK 0x0001|0x0002|0x004 +#define XL_RESETOPT_D3RESETDIS 0x0008 +#define XL_RESETOPT_DISADVFD 0x0010 +#define XL_RESETOPT_DISADV100 0x0020 +#define XL_RESETOPT_DISAUTONEG 0x0040 +#define XL_RESETOPT_DEBUGMODE 0x0080 +#define XL_RESETOPT_FASTAUTO 0x0100 +#define XL_RESETOPT_FASTEE 0x0200 +#define XL_RESETOPT_FORCEDCONF 0x0400 +#define XL_RESETOPT_TESTPDTPDR 0x0800 +#define XL_RESETOPT_TEST100TX 0x1000 +#define XL_RESETOPT_TEST100RX 0x2000 + +#define XL_RESETOPT_INVERT_LED 0x0010 +#define XL_RESETOPT_INVERT_MII 0x4000 + +/* + * Window 3 (fifo management) + */ +#define XL_W3_INTERNAL_CFG 0x00 +#define XL_W3_MAXPKTSIZE 0x04 /* 3c905B only */ +#define XL_W3_RESET_OPT 0x08 +#define XL_W3_FREE_TX 0x0C +#define XL_W3_FREE_RX 0x0A +#define XL_W3_MAC_CTRL 0x06 + +#define XL_ICFG_CONNECTOR_MASK 0x00F00000 +#define XL_ICFG_CONNECTOR_BITS 20 + +#define XL_ICFG_RAMSIZE_MASK 0x00000007 +#define XL_ICFG_RAMWIDTH 0x00000008 +#define XL_ICFG_ROMSIZE_MASK (0x00000040|0x00000080) +#define XL_ICFG_DISABLE_BASSD 0x00000100 +#define XL_ICFG_RAMLOC 0x00000200 +#define XL_ICFG_RAMPART (0x00010000|0x00020000) +#define XL_ICFG_XCVRSEL (0x00100000|0x00200000|0x00400000) +#define XL_ICFG_AUTOSEL 0x01000000 + +#define XL_XCVR_10BT 0x00 +#define XL_XCVR_AUI 0x01 +#define XL_XCVR_RSVD_0 0x02 +#define XL_XCVR_COAX 0x03 +#define XL_XCVR_100BTX 0x04 +#define XL_XCVR_100BFX 0x05 +#define XL_XCVR_MII 0x06 +#define XL_XCVR_RSVD_1 0x07 +#define XL_XCVR_AUTO 0x08 /* 3c905B only */ + +#define XL_MACCTRL_DEFER_EXT_END 0x0001 +#define XL_MACCTRL_DEFER_0 0x0002 +#define XL_MACCTRL_DEFER_1 0x0004 +#define XL_MACCTRL_DEFER_2 0x0008 +#define XL_MACCTRL_DEFER_3 0x0010 +#define XL_MACCTRL_DUPLEX 0x0020 +#define XL_MACCTRL_ALLOW_LARGE_PACK 0x0040 +#define XL_MACCTRL_EXTEND_AFTER_COL 0x0080 (3c905B only) +#define XL_MACCTRL_FLOW_CONTROL_ENB 0x0100 (3c905B only) +#define XL_MACCTRL_VLT_END 0x0200 (3c905B only) + +/* + * The 'reset options' register contains power-on reset values + * loaded from the EEPROM. This includes the supported media + * types on the card. It is also known as the media options register. + */ +#define XL_W3_MEDIA_OPT 0x08 + +#define XL_MEDIAOPT_BT4 0x0001 /* MII */ +#define XL_MEDIAOPT_BTX 0x0002 /* on-chip */ +#define XL_MEDIAOPT_BFX 0x0004 /* on-chip */ +#define XL_MEDIAOPT_BT 0x0008 /* on-chip */ +#define XL_MEDIAOPT_BNC 0x0010 /* on-chip */ +#define XL_MEDIAOPT_AUI 0x0020 /* on-chip */ +#define XL_MEDIAOPT_MII 0x0040 /* MII */ +#define XL_MEDIAOPT_VCO 0x0100 /* 1st gen chip only */ + +#define XL_MEDIAOPT_10FL 0x0100 /* 3x905B only, on-chip */ +#define XL_MEDIAOPT_MASK 0x01FF + +/* + * Window 4 (diagnostics) + */ +#define XL_W4_UPPERBYTESOK 0x0D +#define XL_W4_BADSSD 0x0C +#define XL_W4_MEDIA_STATUS 0x0A +#define XL_W4_PHY_MGMT 0x08 +#define XL_W4_NET_DIAG 0x06 +#define XL_W4_FIFO_DIAG 0x04 +#define XL_W4_VCO_DIAG 0x02 + +#define XL_W4_CTRLR_STAT 0x08 +#define XL_W4_TX_DIAG 0x00 + +#define XL_MII_CLK 0x01 +#define XL_MII_DATA 0x02 +#define XL_MII_DIR 0x04 + +#define XL_MEDIA_SQE 0x0008 +#define XL_MEDIA_10TP 0x00C0 +#define XL_MEDIA_LNK 0x0080 +#define XL_MEDIA_LNKBEAT 0x0800 + +#define XL_MEDIASTAT_CRCSTRIP 0x0004 +#define XL_MEDIASTAT_SQEENB 0x0008 +#define XL_MEDIASTAT_COLDET 0x0010 +#define XL_MEDIASTAT_CARRIER 0x0020 +#define XL_MEDIASTAT_JABGUARD 0x0040 +#define XL_MEDIASTAT_LINKBEAT 0x0080 +#define XL_MEDIASTAT_JABDETECT 0x0200 +#define XL_MEDIASTAT_POLREVERS 0x0400 +#define XL_MEDIASTAT_LINKDETECT 0x0800 +#define XL_MEDIASTAT_TXINPROG 0x1000 +#define XL_MEDIASTAT_DCENB 0x4000 +#define XL_MEDIASTAT_AUIDIS 0x8000 + +#define XL_NETDIAG_TEST_LOWVOLT 0x0001 +#define XL_NETDIAG_ASIC_REVMASK (0x0002|0x0004|0x0008|0x0010|0x0020) +#define XL_NETDIAG_UPPER_BYTES_ENABLE 0x0040 +#define XL_NETDIAG_STATS_ENABLED 0x0080 +#define XL_NETDIAG_TX_FATALERR 0x0100 +#define XL_NETDIAG_TRANSMITTING 0x0200 +#define XL_NETDIAG_RX_ENABLED 0x0400 +#define XL_NETDIAG_TX_ENABLED 0x0800 +#define XL_NETDIAG_FIFO_LOOPBACK 0x1000 +#define XL_NETDIAG_MAC_LOOPBACK 0x2000 +#define XL_NETDIAG_ENDEC_LOOPBACK 0x4000 +#define XL_NETDIAG_EXTERNAL_LOOP 0x8000 + +/* + * Window 5 + */ +#define XL_W5_STAT_ENB 0x0C +#define XL_W5_INTR_ENB 0x0A +#define XL_W5_RECLAIM_THRESH 0x09 /* 3c905B only */ +#define XL_W5_RX_FILTER 0x08 +#define XL_W5_RX_EARLYTHRESH 0x06 +#define XL_W5_TX_AVAILTHRESH 0x02 +#define XL_W5_TX_STARTTHRESH 0x00 + +/* + * RX filter bits + */ +#define XL_RXFILTER_INDIVIDUAL 0x01 +#define XL_RXFILTER_ALLMULTI 0x02 +#define XL_RXFILTER_BROADCAST 0x04 +#define XL_RXFILTER_ALLFRAMES 0x08 +#define XL_RXFILTER_MULTIHASH 0x10 /* 3c905B only */ + +/* + * Window 6 (stats) + */ +#define XL_W6_TX_BYTES_OK 0x0C +#define XL_W6_RX_BYTES_OK 0x0A +#define XL_W6_UPPER_FRAMES_OK 0x09 +#define XL_W6_DEFERRED 0x08 +#define XL_W6_RX_OK 0x07 +#define XL_W6_TX_OK 0x06 +#define XL_W6_RX_OVERRUN 0x05 +#define XL_W6_COL_LATE 0x04 +#define XL_W6_COL_SINGLE 0x03 +#define XL_W6_COL_MULTIPLE 0x02 +#define XL_W6_SQE_ERRORS 0x01 +#define XL_W6_CARRIER_LOST 0x00 + +/* + * Window 7 (bus master control) + */ +#define XL_W7_BM_ADDR 0x00 +#define XL_W7_BM_LEN 0x06 +#define XL_W7_BM_STATUS 0x0B +#define XL_W7_BM_TIMEr 0x0A + +/* + * bus master control registers + */ +#define XL_BM_PKTSTAT 0x20 +#define XL_BM_DOWNLISTPTR 0x24 +#define XL_BM_FRAGADDR 0x28 +#define XL_BM_FRAGLEN 0x2C +#define XL_BM_TXFREETHRESH 0x2F +#define XL_BM_UPPKTSTAT 0x30 +#define XL_BM_UPLISTPTR 0x38 + + + + + + + + +struct xl_mii_frame { + u_int8_t mii_stdelim; + u_int8_t mii_opcode; + u_int8_t mii_phyaddr; + u_int8_t mii_regaddr; + u_int8_t mii_turnaround; + u_int16_t mii_data; +}; + +/* + * MII constants + */ +#define XL_MII_STARTDELIM 0x01 +#define XL_MII_READOP 0x02 +#define XL_MII_WRITEOP 0x01 +#define XL_MII_TURNAROUND 0x02 + + + +/* + * The 3C905B adapters implement a few features that we want to + * take advantage of, namely the multicast hash filter. With older + * chips, you only have the option of turning on reception of all + * multicast frames, which is kind of lame. + * + * We also use this to decide on a transmit strategy. For the 3c90xB + * cards, we can use polled descriptor mode, which reduces CPU overhead. + */ +#define XL_TYPE_905B 1 +#define XL_TYPE_90X 2 + +#define XL_FLAG_FUNCREG 0x0001 +#define XL_FLAG_PHYOK 0x0002 +#define XL_FLAG_EEPROM_OFFSET_30 0x0004 +#define XL_FLAG_WEIRDRESET 0x0008 +#define XL_FLAG_8BITROM 0x0010 +#define XL_FLAG_INVERT_LED_PWR 0x0020 +#define XL_FLAG_INVERT_MII_PWR 0x0040 +#define XL_FLAG_NO_XCVR_PWR 0x0080 +#define XL_FLAG_USE_MMIO 0x0100 + +#define XL_NO_XCVR_PWR_MAGICBITS 0x0900 + + +#define XL_MIN_FRAMELEN 60 + +#define XL_LAST_FRAG 0x80000000 + + + + + + + +struct xl_stats +{ + u_int8_t xl_carrier_lost; + u_int8_t xl_sqe_errs; + u_int8_t xl_tx_multi_collision; + u_int8_t xl_tx_single_collision; + u_int8_t xl_tx_late_collision; + u_int8_t xl_rx_overrun; + u_int8_t xl_tx_frames_ok; + u_int8_t xl_rx_frames_ok; + u_int8_t xl_tx_deferred; + u_int8_t xl_upper_frames_ok; + u_int16_t xl_rx_bytes_ok; + u_int16_t xl_tx_bytes_ok; + + u_int8_t xl_upper_bytes_ok; + u_int8_t xl_badssd; + + u_int16_t intstatus; + u_int16_t rxstatus; + u_int8_t txstatus; + u_int16_t mediastatus; + + u_int16_t miianr, miipar, miistatus, miicmd; + + u_int32_t device_interrupts; + + u_int16_t smbstatus; +}; + + + +struct xl_type +{ + u_int16_t xl_vid; + u_int16_t xl_did; + char *xl_name; +}; + + + +/* + * Various supported device vendors/types and their names. + */ +static struct xl_type xl_devs[] = { + { TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT, + "3Com 3c900-TPO Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT_COMBO, + "3Com 3c900-COMBO Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_BOOMERANG_10_100BT, + "3Com 3c905-TX Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_BOOMERANG_100BT4, + "3Com 3c905-T4 Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT, + "3Com 3c900B-TPO Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT_COMBO, + "3Com 3c900B-COMBO Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT_TPC, + "3Com 3c900B-TPC Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_CYCLONE_10FL, + "3Com 3c900B-FL Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_10_100BT, + "3Com 3c905B-TX Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100BT4, + "3Com 3c905B-T4 Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100FX, + "3Com 3c905B-FX/SC Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100_COMBO, + "3Com 3c905B-COMBO Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT, + "3Com 3c905C-TX Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT_920B, + "3Com 3c920B-EMB Integrated Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_10_100BT_SERV, + "3Com 3c980 Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT_SERV, + "3Com 3c980C Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_SOHO100TX, + "3Com 3cSOHO100-TX OfficeConnect" }, + { TC_VENDORID, TC_DEVICEID_TORNADO_HOMECONNECT, + "3Com 3c450-TX HomeConnect" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_555, + "3Com 3c555 Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_556, + "3Com 3c556 Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_556B, + "3Com 3c556B Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_575A, + "3Com 3c575TX Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_575B, + "3Com 3c575B Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_575C, + "3Com 3c575C Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_656, + "3Com 3c656 Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_HURRICANE_656B, + "3Com 3c656B Fast Etherlink XL" }, + { TC_VENDORID, TC_DEVICEID_TORNADO_656C, + "3Com 3c656C Fast Etherlink XL" }, + { 0, 0, NULL } +}; + + + + + + +#define CSR_WRITE_4(sc, reg, val) outl( val, sc->ioaddr + reg) +#define CSR_WRITE_2(sc, reg, val) outw( val, sc->ioaddr + reg) +#define CSR_WRITE_1(sc, reg, val) outb( val, sc->ioaddr + reg) + +#define CSR_READ_4(sc, reg) inl(sc->ioaddr + reg) +#define CSR_READ_2(sc, reg) inw(sc->ioaddr + reg) +#define CSR_READ_1(sc, reg) inb(sc->ioaddr + reg) + +#define XL_SEL_WIN(x) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x) + +#define XL_TIMEOUT 1000 + + + + + +/* message descriptor entry, ensure this struct is aligned to 8 bytes */ +struct MD +{ + /* used by hardware */ + volatile unsigned32 next; + volatile unsigned32 status; + volatile unsigned32 addr; + volatile unsigned32 length; + /* used by software */ + struct mbuf *mbuf; /* scratch variable used in the tx ring */ + struct MD *next_md; +} __attribute__ ((packed)); + + + + + + + +/* + * Per-device data + */ +struct elnk_softc +{ + struct arpcom arpcom; + + rtems_irq_connect_data irqInfo; + rtems_event_set ioevent; + unsigned int ioaddr; + + volatile unsigned char *bufferBase, *ringBase; + + struct MD *curr_rx_md, *last_tx_md, *last_txchain_head; + + rtems_id stat_timer_id; + unsigned32 stats_update_ticks; + + struct xl_stats xl_stats; + + u_int8_t xl_unit; /* interface number */ + u_int8_t xl_type; + int xl_flags; + u_int16_t xl_media; + u_int16_t xl_caps; + u_int32_t xl_xcvr; + u_int8_t xl_stats_no_timeout; + u_int16_t xl_tx_thresh; + + int tx_idle; + + unsigned short vendorID, deviceID; + int acceptBroadcast; + int numTxbuffers, numRxbuffers; +}; + +static struct elnk_softc elnk_softc[NUM_UNITS]; +static rtems_id rxDaemonTid; +static rtems_id txDaemonTid; + + + + + + + + + + + + +/* + * Murphy's law says that it's possible the chip can wedge and + * the 'command in progress' bit may never clear. Hence, we wait + * only a finite amount of time to avoid getting caught in an + * infinite loop. Normally this delay routine would be a macro, + * but it isn't called during normal operation so we can afford + * to make it a function. + */ +static void +xl_wait(sc) + struct elnk_softc *sc; +{ + register int i; + + for (i = 0; i < XL_TIMEOUT; i++) { + if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY)) + break; + } + + if (i == XL_TIMEOUT) + printk("ek%d: command never completed!\n", sc->xl_unit); + + return; +} + + + + + + +/* + * MII access routines are provided for adapters with external + * PHYs (3c905-TX, 3c905-T4, 3c905B-T4) and those with built-in + * autoneg logic that's faked up to look like a PHY (3c905B-TX). + * Note: if you don't perform the MDIO operations just right, + * it's possible to end up with code that works correctly with + * some chips/CPUs/processor speeds/bus speeds/etc but not + * with others. + */ +#define MII_SET(x) \ + CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \ + CSR_READ_2(sc, XL_W4_PHY_MGMT) | (x)) + +#define MII_CLR(x) \ + CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \ + CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~(x)) + +/* + * Sync the PHYs by setting data bit and strobing the clock 32 times. + */ +static void +xl_mii_sync(sc) + struct elnk_softc *sc; +{ + register int i; + + XL_SEL_WIN(4); + MII_SET(XL_MII_DIR|XL_MII_DATA); + + for (i = 0; i < 32; i++) { + MII_SET(XL_MII_CLK); + MII_SET(XL_MII_DATA); + MII_CLR(XL_MII_CLK); + MII_SET(XL_MII_DATA); + } + + return; +} + +/* + * Clock a series of bits through the MII. + */ +static void +xl_mii_send(sc, bits, cnt) + struct elnk_softc *sc; + u_int32_t bits; + int cnt; +{ + int i; + + XL_SEL_WIN(4); + MII_CLR(XL_MII_CLK); + + for (i = (0x1 << (cnt - 1)); i; i >>= 1) { + if (bits & i) { + MII_SET(XL_MII_DATA); + } else { + MII_CLR(XL_MII_DATA); + } + MII_CLR(XL_MII_CLK); + MII_SET(XL_MII_CLK); + } +} + +/* + * Read an PHY register through the MII. + */ +static int +xl_mii_readreg(sc, frame) + struct elnk_softc *sc; + struct xl_mii_frame *frame; + +{ + int i, ack; + + /* + * Set up frame for RX. + */ + frame->mii_stdelim = XL_MII_STARTDELIM; + frame->mii_opcode = XL_MII_READOP; + frame->mii_turnaround = 0; + frame->mii_data = 0; + + /* + * Select register window 4. + */ + + XL_SEL_WIN(4); + + CSR_WRITE_2(sc, XL_W4_PHY_MGMT, 0); + /* + * Turn on data xmit. + */ + MII_SET(XL_MII_DIR); + + xl_mii_sync(sc); + + /* + * Send command/address info. + */ + xl_mii_send(sc, frame->mii_stdelim, 2); + xl_mii_send(sc, frame->mii_opcode, 2); + xl_mii_send(sc, frame->mii_phyaddr, 5); + xl_mii_send(sc, frame->mii_regaddr, 5); + + /* Idle bit */ + MII_CLR((XL_MII_CLK|XL_MII_DATA)); + MII_SET(XL_MII_CLK); + + /* Turn off xmit. */ + MII_CLR(XL_MII_DIR); + + /* Check for ack */ + MII_CLR(XL_MII_CLK); + ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA; + MII_SET(XL_MII_CLK); + + /* + * Now try reading data bits. If the ack failed, we still + * need to clock through 16 cycles to keep the PHY(s) in sync. + */ + if (ack) { + for(i = 0; i < 16; i++) { + MII_CLR(XL_MII_CLK); + MII_SET(XL_MII_CLK); + } + goto fail; + } + + for (i = 0x8000; i; i >>= 1) { + MII_CLR(XL_MII_CLK); + if (!ack) { + if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA) + frame->mii_data |= i; + } + MII_SET(XL_MII_CLK); + } + + fail: + + MII_CLR(XL_MII_CLK); + MII_SET(XL_MII_CLK); + + if (ack) + return(1); + return(0); +} + +/* + * Write to a PHY register through the MII. + */ +static int +xl_mii_writereg(sc, frame) + struct elnk_softc *sc; + struct xl_mii_frame *frame; + +{ + /* + * Set up frame for TX. + */ + + frame->mii_stdelim = XL_MII_STARTDELIM; + frame->mii_opcode = XL_MII_WRITEOP; + frame->mii_turnaround = XL_MII_TURNAROUND; + + /* + * Select the window 4. + */ + XL_SEL_WIN(4); + + /* + * Turn on data output. + */ + MII_SET(XL_MII_DIR); + + xl_mii_sync(sc); + + xl_mii_send(sc, frame->mii_stdelim, 2); + xl_mii_send(sc, frame->mii_opcode, 2); + xl_mii_send(sc, frame->mii_phyaddr, 5); + xl_mii_send(sc, frame->mii_regaddr, 5); + xl_mii_send(sc, frame->mii_turnaround, 2); + xl_mii_send(sc, frame->mii_data, 16); + + /* Idle bit. */ + MII_SET(XL_MII_CLK); + MII_CLR(XL_MII_CLK); + + /* + * Turn off xmit. + */ + MII_CLR(XL_MII_DIR); + + return(0); +} + +static int +xl_miibus_readreg(sc, phy, reg) + struct elnk_softc *sc; + int phy, reg; +{ + struct xl_mii_frame frame; + + /* + * Pretend that PHYs are only available at MII address 24. + * This is to guard against problems with certain 3Com ASIC + * revisions that incorrectly map the internal transceiver + * control registers at all MII addresses. This can cause + * the miibus code to attach the same PHY several times over. + */ + if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24) + { + printk("etherlink : unit elnk%d xl_miibus_readreg returned\n", sc->xl_unit); + return(0); + } + + bzero((char *)&frame, sizeof(frame)); + + frame.mii_phyaddr = phy; + frame.mii_regaddr = reg; + xl_mii_readreg(sc, &frame); + + return(frame.mii_data); +} + +static int +xl_miibus_writereg(sc, phy, reg, data) + struct elnk_softc *sc; + int phy, reg, data; +{ + struct xl_mii_frame frame; + + if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24) + { + printk("etherlink : unit elnk%d xl_miibus_writereg returned\n", sc->xl_unit); + return(0); + } + + bzero((char *)&frame, sizeof(frame)); + + frame.mii_phyaddr = phy; + frame.mii_regaddr = reg; + frame.mii_data = data; + + xl_mii_writereg(sc, &frame); + + return(0); +} + + + + + + + + + +/* + * The EEPROM is slow: give it time to come ready after issuing + * it a command. + */ +static int +xl_eeprom_wait(sc) + struct elnk_softc *sc; +{ + int i; + + for (i = 0; i < 100; i++) { + if (CSR_READ_2(sc, XL_W0_EE_CMD) & XL_EE_BUSY) + DELAY(162); + else + break; + } + + if (i == 100) { + printk("etherlink : unit elnk%d eeprom failed to come ready\n", sc->xl_unit); + return(1); + } + + return(0); +} + +/* + * Read a sequence of words from the EEPROM. Note that ethernet address + * data is stored in the EEPROM in network byte order. + */ +static int +xl_read_eeprom(sc, dest, off, cnt, swap) + struct elnk_softc *sc; + caddr_t dest; + int off; + int cnt; + int swap; +{ + int err = 0, i; + u_int16_t word = 0, *ptr; +#define EEPROM_5BIT_OFFSET(A) ((((A) << 2) & 0x7F00) | ((A) & 0x003F)) +#define EEPROM_8BIT_OFFSET(A) ((A) & 0x003F) + /* WARNING! DANGER! + * It's easy to accidentally overwrite the rom content! + * Note: the 3c575 uses 8bit EEPROM offsets. + */ + XL_SEL_WIN(0); + + if (xl_eeprom_wait(sc)) + return(1); + + if (sc->xl_flags & XL_FLAG_EEPROM_OFFSET_30) + off += 0x30; + + for (i = 0; i < cnt; i++) { + if (sc->xl_flags & XL_FLAG_8BITROM) + CSR_WRITE_2(sc, XL_W0_EE_CMD, + XL_EE_8BIT_READ | EEPROM_8BIT_OFFSET(off + i)); + else + CSR_WRITE_2(sc, XL_W0_EE_CMD, + XL_EE_READ | EEPROM_5BIT_OFFSET(off + i)); + err = xl_eeprom_wait(sc); + if (err) + break; + word = CSR_READ_2(sc, XL_W0_EE_DATA); + ptr = (u_int16_t *)(dest + (i * 2)); + if (swap) + *ptr = ntohs(word); + else + *ptr = word; + } + + return(err ? 1 : 0); +} + + + + +static void +xl_stats_update(timerid,xsc) + rtems_id timerid; + void *xsc; +{ + volatile struct elnk_softc *sc = (struct elnk_softc *)xsc; + volatile struct ifnet *ifp = &sc->arpcom.ac_if; + + int i; + + sc->xl_stats.intstatus = CSR_READ_2(sc, XL_STATUS); + + sc->xl_stats.miianr = xl_miibus_readreg(sc, 0x18, MII_ANAR ); + sc->xl_stats.miipar = xl_miibus_readreg(sc, 0x18, MII_ANLPAR ); + sc->xl_stats.miistatus = xl_miibus_readreg(sc, 0x18, MII_BMSR ); + sc->xl_stats.miicmd = xl_miibus_readreg(sc, 0x18, MII_BMCR ); + + XL_SEL_WIN(1); + sc->xl_stats.rxstatus = CSR_READ_2(sc, XL_W1_RX_STATUS ); + sc->xl_stats.txstatus = CSR_READ_1(sc, XL_W1_TX_STATUS ); + sc->xl_stats.smbstatus = CSR_READ_2(sc, 2 ); + + /* Read all the stats registers. */ + XL_SEL_WIN(6); + + sc->xl_stats.xl_carrier_lost += CSR_READ_1(sc, XL_W6_CARRIER_LOST); + sc->xl_stats.xl_sqe_errs += CSR_READ_1(sc, XL_W6_SQE_ERRORS); + sc->xl_stats.xl_tx_multi_collision += CSR_READ_1(sc, XL_W6_COL_MULTIPLE); + sc->xl_stats.xl_tx_single_collision += CSR_READ_1(sc, XL_W6_COL_SINGLE); + sc->xl_stats.xl_tx_late_collision += CSR_READ_1(sc, XL_W6_COL_LATE); + sc->xl_stats.xl_rx_overrun += CSR_READ_1(sc, XL_W6_RX_OVERRUN); + sc->xl_stats.xl_tx_frames_ok += CSR_READ_1(sc, XL_W6_TX_OK); + sc->xl_stats.xl_rx_frames_ok += CSR_READ_1(sc, XL_W6_RX_OK); + sc->xl_stats.xl_tx_deferred += CSR_READ_1(sc, XL_W6_DEFERRED); + sc->xl_stats.xl_upper_frames_ok += CSR_READ_1(sc, XL_W6_UPPER_FRAMES_OK); + + sc->xl_stats.xl_rx_bytes_ok += CSR_READ_2(sc, XL_W6_TX_BYTES_OK ); + sc->xl_stats.xl_tx_bytes_ok += CSR_READ_2(sc, XL_W6_RX_BYTES_OK ); + +/* + for (i = 0; i < 16; i++) + *p++ = CSR_READ_1(sc, XL_W6_CARRIER_LOST + i); +*/ + + ifp->if_ierrors += sc->xl_stats.xl_rx_overrun; + + ifp->if_collisions += sc->xl_stats.xl_tx_multi_collision + + sc->xl_stats.xl_tx_single_collision + + sc->xl_stats.xl_tx_late_collision; + + /* + * Boomerang and cyclone chips have an extra stats counter + * in window 4 (BadSSD). We have to read this too in order + * to clear out all the stats registers and avoid a statsoflow + * interrupt. + */ + XL_SEL_WIN(4); + sc->xl_stats.xl_upper_bytes_ok += CSR_READ_1(sc, XL_W4_UPPERBYTESOK); + sc->xl_stats.xl_badssd += CSR_READ_1(sc, XL_W4_BADSSD); + sc->xl_stats.mediastatus = CSR_READ_2(sc, XL_W4_MEDIA_STATUS ); + + XL_SEL_WIN(7); + + if (!sc->xl_stats_no_timeout) + rtems_timer_fire_after( sc->stat_timer_id, sc->stats_update_ticks, xl_stats_update, (void *)sc ); + return; +} + + + + + + + +static void +xl_reset(sc) + struct elnk_softc *sc; +{ + register int i; + + XL_SEL_WIN(0); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET | + ((sc->xl_flags & XL_FLAG_WEIRDRESET) ? + XL_RESETOPT_DISADVFD:0)); + + for (i = 0; i < XL_TIMEOUT; i++) { + DELAY(10); + if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY)) + break; + } + + if (i == XL_TIMEOUT) + printk("etherlink : unit elnk%d reset didn't complete\n", sc->xl_unit); + + /* Reset TX and RX. */ + /* Note: the RX reset takes an absurd amount of time + * on newer versions of the Tornado chips such as those + * on the 3c905CX and newer 3c908C cards. We wait an + * extra amount of time so that xl_wait() doesn't complain + * and annoy the users. + */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET); + DELAY(100000); + xl_wait(sc); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET); + xl_wait(sc); + + if (sc->xl_flags & XL_FLAG_INVERT_LED_PWR || + sc->xl_flags & XL_FLAG_INVERT_MII_PWR) { + XL_SEL_WIN(2); + CSR_WRITE_2(sc, XL_W2_RESET_OPTIONS, CSR_READ_2(sc, + XL_W2_RESET_OPTIONS) + | ((sc->xl_flags & XL_FLAG_INVERT_LED_PWR)?XL_RESETOPT_INVERT_LED:0) + | ((sc->xl_flags & XL_FLAG_INVERT_MII_PWR)?XL_RESETOPT_INVERT_MII:0) + ); + } + + /* Wait a little while for the chip to get its brains in order. */ + DELAY(100000); + return; +} + + + + +static void +xl_stop(sc) + struct elnk_softc *sc; +{ + register int i; + struct ifnet *ifp; + + ifp = &sc->arpcom.ac_if; + ifp->if_timer = 0; + + rtems_timer_cancel( sc->stat_timer_id ); + + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISCARD); + xl_wait(sc); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); + DELAY(800); + + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); + + return; +} + + + + + + + + + + + + + + + +static void +xl_setcfg(sc) + struct elnk_softc *sc; +{ + u_int32_t icfg; + + XL_SEL_WIN(3); + icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG); + icfg &= ~XL_ICFG_CONNECTOR_MASK; + if (sc->xl_media & XL_MEDIAOPT_MII || + sc->xl_media & XL_MEDIAOPT_BT4) + icfg |= (XL_XCVR_MII << XL_ICFG_CONNECTOR_BITS); + if (sc->xl_media & XL_MEDIAOPT_BTX) + icfg |= (XL_XCVR_AUTO << XL_ICFG_CONNECTOR_BITS); + + CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); + + XL_SEL_WIN(7); + return; +} + +static void +xl_setmode(sc, media) + struct elnk_softc *sc; + int media; +{ + u_int32_t icfg; + u_int16_t mediastat; + + printk("etherlink : unit elnk%d selecting ", sc->xl_unit); + + XL_SEL_WIN(4); + mediastat = CSR_READ_2(sc, XL_W4_MEDIA_STATUS); + XL_SEL_WIN(3); + icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG); + + if (sc->xl_media & XL_MEDIAOPT_BT) { + if (IFM_SUBTYPE(media) == IFM_10_T) { + printk("10baseT transceiver, "); + sc->xl_xcvr = XL_XCVR_10BT; + icfg &= ~XL_ICFG_CONNECTOR_MASK; + icfg |= (XL_XCVR_10BT << XL_ICFG_CONNECTOR_BITS); + mediastat |= XL_MEDIASTAT_LINKBEAT| + XL_MEDIASTAT_JABGUARD; + mediastat &= ~XL_MEDIASTAT_SQEENB; + } + } + + if (sc->xl_media & XL_MEDIAOPT_BFX) { + if (IFM_SUBTYPE(media) == IFM_100_FX) { + printk("100baseFX port, "); + sc->xl_xcvr = XL_XCVR_100BFX; + icfg &= ~XL_ICFG_CONNECTOR_MASK; + icfg |= (XL_XCVR_100BFX << XL_ICFG_CONNECTOR_BITS); + mediastat |= XL_MEDIASTAT_LINKBEAT; + mediastat &= ~XL_MEDIASTAT_SQEENB; + } + } + + if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) { + if (IFM_SUBTYPE(media) == IFM_10_5) { + printk("AUI port, "); + sc->xl_xcvr = XL_XCVR_AUI; + icfg &= ~XL_ICFG_CONNECTOR_MASK; + icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS); + mediastat &= ~(XL_MEDIASTAT_LINKBEAT| + XL_MEDIASTAT_JABGUARD); + mediastat |= ~XL_MEDIASTAT_SQEENB; + } + if (IFM_SUBTYPE(media) == IFM_10_FL) { + printk("10baseFL transceiver, "); + sc->xl_xcvr = XL_XCVR_AUI; + icfg &= ~XL_ICFG_CONNECTOR_MASK; + icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS); + mediastat &= ~(XL_MEDIASTAT_LINKBEAT| + XL_MEDIASTAT_JABGUARD); + mediastat |= ~XL_MEDIASTAT_SQEENB; + } + } + + if (sc->xl_media & XL_MEDIAOPT_BNC) { + if (IFM_SUBTYPE(media) == IFM_10_2) { + printk("BNC port, "); + sc->xl_xcvr = XL_XCVR_COAX; + icfg &= ~XL_ICFG_CONNECTOR_MASK; + icfg |= (XL_XCVR_COAX << XL_ICFG_CONNECTOR_BITS); + mediastat &= ~(XL_MEDIASTAT_LINKBEAT| + XL_MEDIASTAT_JABGUARD| + XL_MEDIASTAT_SQEENB); + } + } + + if ((media & IFM_GMASK) == IFM_FDX || + IFM_SUBTYPE(media) == IFM_100_FX) { + printk("full duplex\n"); + XL_SEL_WIN(3); + CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX); + } else { + printk("half duplex\n"); + XL_SEL_WIN(3); + CSR_WRITE_1(sc, XL_W3_MAC_CTRL, + (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX)); + } + + if (IFM_SUBTYPE(media) == IFM_10_2) + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START); + else + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); + CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg); + XL_SEL_WIN(4); + CSR_WRITE_2(sc, XL_W4_MEDIA_STATUS, mediastat); + DELAY(800); + XL_SEL_WIN(7); + + return; +} + + + + + + + +static void +xl_choose_xcvr(sc, verbose) + struct elnk_softc *sc; + int verbose; +{ + u_int16_t devid; + + /* + * Read the device ID from the EEPROM. + * This is what's loaded into the PCI device ID register, so it has + * to be correct otherwise we wouldn't have gotten this far. + */ + xl_read_eeprom(sc, (caddr_t)&devid, XL_EE_PRODID, 1, 0); + + switch(devid) { + case TC_DEVICEID_BOOMERANG_10BT: /* 3c900-TPO */ + case TC_DEVICEID_KRAKATOA_10BT: /* 3c900B-TPO */ + sc->xl_media = XL_MEDIAOPT_BT; + sc->xl_xcvr = XL_XCVR_10BT; + if (verbose) + printk("etherlink : unit elnk%d guessing 10BaseT " + "transceiver\n", sc->xl_unit); + break; + case TC_DEVICEID_BOOMERANG_10BT_COMBO: /* 3c900-COMBO */ + case TC_DEVICEID_KRAKATOA_10BT_COMBO: /* 3c900B-COMBO */ + sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI; + sc->xl_xcvr = XL_XCVR_10BT; + if (verbose) + printk("etherlink : unit elnk%d guessing COMBO " + "(AUI/BNC/TP)\n", sc->xl_unit); + break; + case TC_DEVICEID_KRAKATOA_10BT_TPC: /* 3c900B-TPC */ + sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC; + sc->xl_xcvr = XL_XCVR_10BT; + if (verbose) + printk("etherlink : unit elnk%d guessing TPC (BNC/TP)\n", sc->xl_unit); + break; + case TC_DEVICEID_CYCLONE_10FL: /* 3c900B-FL */ + sc->xl_media = XL_MEDIAOPT_10FL; + sc->xl_xcvr = XL_XCVR_AUI; + if (verbose) + printk("etherlink : unit elnk%d guessing 10baseFL\n", sc->xl_unit); + break; + case TC_DEVICEID_BOOMERANG_10_100BT: /* 3c905-TX */ + case TC_DEVICEID_HURRICANE_555: /* 3c555 */ + case TC_DEVICEID_HURRICANE_556: /* 3c556 */ + case TC_DEVICEID_HURRICANE_556B: /* 3c556B */ + case TC_DEVICEID_HURRICANE_575A: /* 3c575TX */ + case TC_DEVICEID_HURRICANE_575B: /* 3c575B */ + case TC_DEVICEID_HURRICANE_575C: /* 3c575C */ + case TC_DEVICEID_HURRICANE_656: /* 3c656 */ + case TC_DEVICEID_HURRICANE_656B: /* 3c656B */ + case TC_DEVICEID_TORNADO_656C: /* 3c656C */ + case TC_DEVICEID_TORNADO_10_100BT_920B: /* 3c920B-EMB */ + sc->xl_media = XL_MEDIAOPT_MII; + sc->xl_xcvr = XL_XCVR_MII; + if (verbose) + printk("etherlink : unit elnk%d guessing MII\n", sc->xl_unit); + break; + case TC_DEVICEID_BOOMERANG_100BT4: /* 3c905-T4 */ + case TC_DEVICEID_CYCLONE_10_100BT4: /* 3c905B-T4 */ + sc->xl_media = XL_MEDIAOPT_BT4; + sc->xl_xcvr = XL_XCVR_MII; + if (verbose) + printk("etherlink : unit elnk%d guessing 100BaseT4/MII\n", sc->xl_unit); + break; + case TC_DEVICEID_HURRICANE_10_100BT: /* 3c905B-TX */ + case TC_DEVICEID_HURRICANE_10_100BT_SERV:/*3c980-TX */ + case TC_DEVICEID_TORNADO_10_100BT_SERV: /* 3c980C-TX */ + case TC_DEVICEID_HURRICANE_SOHO100TX: /* 3cSOHO100-TX */ + case TC_DEVICEID_TORNADO_10_100BT: /* 3c905C-TX */ + case TC_DEVICEID_TORNADO_HOMECONNECT: /* 3c450-TX */ + sc->xl_media = XL_MEDIAOPT_BTX; + sc->xl_xcvr = XL_XCVR_AUTO; + if (verbose) + printk("etherlink : unit elnk%d guessing 10/100 internal\n", sc->xl_unit); + break; + case TC_DEVICEID_CYCLONE_10_100_COMBO: /* 3c905B-COMBO */ + sc->xl_media = XL_MEDIAOPT_BTX|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI; + sc->xl_xcvr = XL_XCVR_AUTO; + if (verbose) + printk("etherlink : unit elnk%d guessing 10/100 " + "plus BNC/AUI\n", sc->xl_unit); + break; + default: + printk("etherlink : unit elnk%d unknown device ID: %x -- " + "defaulting to 10baseT\n", sc->xl_unit, devid); + sc->xl_media = XL_MEDIAOPT_BT; + break; + } + + return; +} + + + + + + + +/* + * This routine is a kludge to work around possible hardware faults + * or manufacturing defects that can cause the media options register + * (or reset options register, as it's called for the first generation + * 3c90x adapters) to return an incorrect result. I have encountered + * one Dell Latitude laptop docking station with an integrated 3c905-TX + * which doesn't have any of the 'mediaopt' bits set. This screws up + * the attach routine pretty badly because it doesn't know what media + * to look for. If we find ourselves in this predicament, this routine + * will try to guess the media options values and warn the user of a + * possible manufacturing defect with his adapter/system/whatever. + */ +static void +xl_mediacheck(sc) + struct elnk_softc *sc; +{ + + /* + * If some of the media options bits are set, assume they are + * correct. If not, try to figure it out down below. + * XXX I should check for 10baseFL, but I don't have an adapter + * to test with. + */ + if (sc->xl_media & (XL_MEDIAOPT_MASK & ~XL_MEDIAOPT_VCO)) { + /* + * Check the XCVR value. If it's not in the normal range + * of values, we need to fake it up here. + */ + if (sc->xl_xcvr <= XL_XCVR_AUTO) + return; + else { + printk("etherlink : unit elnk%d bogus xcvr value " + "in EEPROM (%x)\n", sc->xl_unit, sc->xl_xcvr); + printk("etherlink : unit elnk%d choosing new default based " + "on card type\n", sc->xl_unit); + } + } else { + if (sc->xl_type == XL_TYPE_905B && + sc->xl_media & XL_MEDIAOPT_10FL) + return; + printk("etherlink : unit elnk%d WARNING: no media options bits set in " + "the media options register!!\n", sc->xl_unit); + printk("etherlink : unit elnk%d this could be a manufacturing defect in " + "your adapter or system\n", sc->xl_unit); + printk("etherlink : unit elnk%d attempting to guess media type; you " + "should probably consult your vendor\n", sc->xl_unit); + } + + xl_choose_xcvr(sc, 1); + return; +} + + + + + + + + + + + + + + + + + + + + + + + + + +static void no_op(const rtems_irq_connect_data* irq) +{ + return; +} + + + + +static int elnkIsOn(const rtems_irq_connect_data* irq) +{ + return BSP_irq_enabled_at_i8259s (irq->name); +} + + + + + + +static void +elnk_start_txchain( struct elnk_softc *sc, struct MD *chaintop ) +{ + printk("unit elnk%d tx start\n", sc->xl_unit ); + + sc->tx_idle = 0; + + /* save the address of the TX list */ + sc->last_txchain_head = chaintop; + + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL); + xl_wait(sc); + CSR_WRITE_4(sc, XL_DOWNLIST_PTR, phys_to_bus( sc->last_txchain_head )); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL); +} + + + + + +/* + * ELNK interrupt handler + */ +static rtems_isr +elnk_interrupt_handler ( struct elnk_softc *sc ) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + u_int16_t status; + + while( (status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS && status != 0xFFFF) + { + sc->xl_stats.device_interrupts++; + + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|(status & XL_INTRS)); + +#if 0 + printk("etherlink : unit elnk%d intstatus %04x\n", sc->xl_unit, status ); +#endif + + if (status & XL_STAT_UP_COMPLETE) + { +#if 0 + printk("etherlink : unit elnk%d rx\n", sc->xl_unit ); +#endif + /* received packets */ + rtems_event_send(rxDaemonTid, sc->ioevent); + } + + if (status & XL_STAT_DOWN_COMPLETE) + { + struct MD *chaintailmd = NULL; + + /* all packets uploaded to the device */ + + if( sc->last_txchain_head->mbuf ) + { + /* either this is a chain of 2 or more packets, or its a + * single packet chain and another chain is also ready to send + */ + if( (int)sc->last_txchain_head->mbuf == -1 ) + { + /* single packet was sent, no indirection to the last entry + in the chain. since mbuf is != 0, then another chain + is ready */ + chaintailmd = sc->last_txchain_head; + } + else + { + /* otherwise, this is a pointer to the last packet in the + chain */ + chaintailmd = (struct MD *)sc->last_txchain_head->mbuf; + if( !chaintailmd->mbuf ) chaintailmd = NULL; + } + } + + if( chaintailmd ) + { + /* the next MD is the start of another chain */ + elnk_start_txchain(sc, chaintailmd->next_md ); + } + else + { + /* otherwise, we have nothing else to send */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL); + sc->tx_idle = -1; + printk("unit elnk%d tx done\n", sc->xl_unit ); + } + } + + if (status & XL_STAT_TX_COMPLETE) + { + ifp->if_oerrors++; + printk("etherlink : unit elnk%d transmission error\n", sc->xl_unit ); + } + if (status & XL_STAT_ADFAIL) + { + printk("etherlink : unit elnk%d Catastrophic bus failure\n", sc->xl_unit ); + } + if (status & XL_STAT_STATSOFLOW) + { + sc->xl_stats_no_timeout = 1; + xl_stats_update(sc->stat_timer_id,sc); + sc->xl_stats_no_timeout = 0; + } + } + + +#if 0 + { + unsigned16 intstatus, intenable, indenable; + + intstatus = CSR_READ_2(sc, XL_STATUS ); + + XL_SEL_WIN(5); + intenable = CSR_READ_2(sc, XL_W5_INTR_ENB ); + indenable = CSR_READ_2(sc, XL_W5_STAT_ENB ); + XL_SEL_WIN(7); + printk("etherlink : unit elnk%d istat %04x, ien %04x, ind %04x\n", sc->xl_unit, intstatus, intenable, indenable ); + } +#endif +} + + + + + +static rtems_isr +elnk_interrupt_handler_entry() +{ + int i; + + /* + ** Check all the initialized units for interrupt service + */ + + for(i=0; i< NUM_UNITS; i++ ) + { + if( elnk_softc[i].ioaddr ) + elnk_interrupt_handler( &elnk_softc[i] ); + } +} + + + + + + + + + + + +/* + * Initialize the ethernet hardware + */ +static void +elnk_initialize_hardware (struct elnk_softc *sc) +{ + volatile unsigned char *cp; + int nb, i, rxsize, txsize, ringsize; + + /* + * Init RX ring + */ + cp = (volatile unsigned char *)malloc( (nb = + (ringsize = ((rxsize = (sc->numRxbuffers * sizeof(struct MD))) + + (txsize = (sc->numTxbuffers * sizeof(struct MD))))) + + (sc->numTxbuffers * XL_PACKET_SIZE)) + + + CPU_CACHE_ALIGNMENT_FOR_BUFFER); + sc->bufferBase = cp; + cp += (CPU_CACHE_ALIGNMENT_FOR_BUFFER - (int)cp) & (CPU_CACHE_ALIGNMENT_FOR_BUFFER - 1); +#if defined(__i386__) +#ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA + if (_CPU_is_paging_enabled()) + _CPU_change_memory_mapping_attribute + (NULL, cp, nb, PTE_CACHE_DISABLE | PTE_WRITABLE); +#endif +#endif + sc->ringBase = cp; + + { + volatile unsigned char *txpackets; + struct MD *rx_ring, *tx_ring, *nxtmd, *thismd; + struct mbuf *m; + + /* rebuild tx and rx rings */ + + rx_ring = (struct MD *)sc->ringBase; + tx_ring = (struct MD *)&sc->ringBase[ rxsize ]; + txpackets = &sc->ringBase[ringsize]; + + /* + * The rx ring is easy as its just an array of MD structs, the mbuf + * data is dynamically requested from the ip stack. + */ + for(i=0 ; inumRxbuffers; i++) + { + /* allocate an mbuf for each receive descriptor */ + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = &sc->arpcom.ac_if; + + if( i == sc->numRxbuffers-1 ) + nxtmd = &rx_ring[0]; + else + nxtmd = &rx_ring[i+1]; + + rx_ring[i].next_md = nxtmd; + rx_ring[i].mbuf = m; + + rx_ring[i].status = 0; + st_le32( &rx_ring[i].addr, (unsigned32)phys_to_bus( mtod(m, void *) )); + st_le32( &rx_ring[i].length, XL_LAST_FRAG | XL_PACKET_SIZE ); + st_le32( &rx_ring[i].next, (unsigned32)phys_to_bus( nxtmd )); + } + sc->curr_rx_md = &rx_ring[0]; + + + /* + * The tx ring is more complex. Each MD has a packet buffer + * permanently assigned to it. Although the next_md fields form a + * ring, the DPD next is filled only when packets are added to the + * tx chain. mbuf is a scratch register used to form chains of tx + * packets. + */ + + for(i=0 ; inumTxbuffers; i++) + { + if( i == sc->numTxbuffers-1 ) + nxtmd = &tx_ring[0]; + else + nxtmd = &tx_ring[i+1]; + + thismd = &tx_ring[i]; + + thismd->next_md = nxtmd; + thismd->mbuf = NULL; + + st_le32( &thismd->status, XL_TXSTAT_DL_COMPLETE ); + st_le32( &thismd->addr, (unsigned32)phys_to_bus( &txpackets[ i * XL_PACKET_SIZE ] )); + st_le32( &thismd->length, XL_LAST_FRAG ); + thismd->next = 0; + } + sc->last_tx_md = &tx_ring[0]; + + } + + + + +#ifdef ELNK_DEBUG + printk("etherlink : %02x:%02x:%02x:%02x:%02x:%02x name 'elnk%d', io %x, int %d\n", + sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1], + sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3], + sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5], + sc->xl_unit, + (unsigned)sc->ioaddr, sc->irqInfo.name ); +#endif + + + sc->irqInfo.hdl = (rtems_irq_hdl)elnk_interrupt_handler_entry; + sc->irqInfo.on = no_op; + sc->irqInfo.off = no_op; + sc->irqInfo.isOn = elnkIsOn; + + if( sc->irqInfo.name != 255 ) + { + int st; + +#ifdef BSP_SHARED_HANDLER_SUPPORT + st = BSP_install_rtems_shared_irq_handler( &sc->irqInfo ); +#else + st = BSP_install_rtems_irq_handler( &sc->irqInfo ); +#endif + if (!st) + rtems_panic ("etherlink : unit elnk%d Interrupt name %d already in use\n", sc->xl_unit, sc->irqInfo.name ); + } + else + { + printk("etherlink : unit elnk%d Interrupt not specified by device\n", sc->xl_unit ); + } +} + + + + + + + + + + + +static void +elnk_rxDaemon (void *arg) +{ + struct elnk_softc *sc; + volatile struct ifnet *ifp; + struct ether_header *eh; + struct mbuf *m; + volatile struct MD *rmd; + unsigned int i,len, rxstat; + rtems_event_set events; + + for (;;) + { + + rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + for(;;) + { + for(i=0; i< NUM_UNITS; i++ ) + { + sc = &elnk_softc[i]; + if( sc->ioaddr ) + { + if( events & sc->ioevent ) + { + struct ifnet *ifp = &sc->arpcom.ac_if; + + rmd = sc->curr_rx_md; + + /* + ** Read off all the packets we've received on this unit + */ + while( (rxstat = ld_le32(&rmd->status)) ) + { + if (rxstat & XL_RXSTAT_UP_ERROR) + { + printk("unit %i up error\n", sc->xl_unit ); + ifp->if_ierrors++; + } + + if( (rxstat & XL_RXSTAT_UP_CMPLT) ) + { + +#if 0 + { + char *pkt, *delim; + int i; + pkt = mtod(rmd->mbuf, char *); + printk("unit %i rx pkt (%08x) ", sc->xl_unit, pkt ); + for(delim="", i=0; i < sizeof(struct ether_header)+8; i++, delim=":") + printk("%s%02x", delim, (char) pkt[i] ); + printk("\n"); + } +#endif + + /* pass on the packet in the mbuf */ + len = ( ld_le32(&rmd->status) & XL_RXSTAT_LENMASK); + m = rmd->mbuf; + m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); + eh = mtod(m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + + ether_input(ifp, eh, m); + + /* get a new mbuf */ + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + rmd->mbuf = m; + rmd->status = 0; + st_le32( &rmd->addr, (unsigned32)phys_to_bus(mtod(m, void *)) ); + } + else + { + /* some kind of packet failure */ + printk("etherlink : unit elnk%d bad receive status -- packet dropped\n", sc->xl_unit); + ifp->if_ierrors++; + } + /* clear descriptor status */ + rmd->status = 0; + + rmd = rmd->next_md; + } + + sc->curr_rx_md = rmd; + } + } + } + + /* + ** If more events are pending, service them before we go back to sleep + */ + if( rtems_event_receive( RTEMS_ALL_EVENTS, + RTEMS_NO_WAIT | RTEMS_EVENT_ANY, + 0, + &events ) == RTEMS_UNSATISFIED ) break; + } + } +} + + + + + + + + + + + + +/* + * Driver transmit daemon + */ +void +elnk_txDaemon (void *arg) +{ + struct elnk_softc *sc; + struct ifnet *ifp; + struct mbuf *m; + struct mbuf *hold; + volatile struct MD *lastmd, *nextmd, *firstmd; + unsigned char *pktbuff, *buffer; + unsigned int len; + int chainCount,i; + rtems_event_set events; + + for (;;) + { + /* + * Wait for packets bound for any of the units + */ + rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + + for(i=0; i< NUM_UNITS; i++ ) + { + sc = &elnk_softc[i]; + if( sc->ioaddr ) + { + if( events & sc->ioevent ) + { + ifp = &sc->arpcom.ac_if; + + /* + * Send packets till queue is empty or tx ring is full + */ + chainCount = 0; + firstmd = NULL; + + lastmd = sc->last_tx_md; + + for(;;) + { + nextmd = lastmd->next_md; + + /* stop when ring is full */ + if( ! (ld_le32(&nextmd->status) & XL_TXSTAT_DL_COMPLETE) ) + { + printk("etherlink : unit elnk%d tx ring full!\n", sc->xl_unit); + break; + } + + IF_DEQUEUE(&ifp->if_snd, m); + if( !m ) break; + + + + hold = m; + len = 0; + + buffer = pktbuff = (char *)bus_to_phys( ld_le32(&nextmd->addr) ); + for(;;) + { + len += m->m_len; + memcpy((void*) buffer, (char *)m->m_data, m->m_len); + buffer += m->m_len ; + if ((m = m->m_next) == NULL) + break; + } + m_freem( hold ); + + + { + char *pkt = pktbuff, *delim; + int i; + printk("unit %i queued pkt (%08x) ", sc->xl_unit, (unsigned32)pkt ); + for(delim="", i=0; i < sizeof(struct ether_header)+8; i++, delim=":") + printk("%s%02x", delim, (char) pkt[i] ); + printk("\n"); + } + + + if (len < XL_MIN_FRAMELEN ) len = XL_MIN_FRAMELEN; + st_le32( &nextmd->length, XL_LAST_FRAG | (len & XL_TXSTAT_LENMASK) ); + + /* this packet will be the new end of the list */ + nextmd->next = 0; + nextmd->status = 0; + + if( !firstmd ) + { + /* keep track of the first packet we add to the chain */ + firstmd = nextmd; + + /* use the mbuf pointer of the last packet of the + * previous chain as a flag so when a dnComplete + * interrupt indicates the card is finished, the + * isr can immediately start the next chain. Note + * several chains of packets may be assembled this + * way- but this assignment won't have any effect + * if a chain isn't already being transmitted. + */ + lastmd->mbuf = (struct mbuf *)-1; + } + else + { + /* hook this packet to the previous one */ + st_le32( &lastmd->next, (unsigned32)phys_to_bus( nextmd )); + } + + ++chainCount; + lastmd = nextmd; + } + + + + if( firstmd ) + { + /* save the last descriptor we set up in the chain */ + sc->last_tx_md = lastmd; + + /* + * We've added one or more packets to a chain, flag + * the last packet so we get an dnComplete interrupt + * when the card finishes accepting the chain + */ + st_le32(&lastmd->status, XL_TXSTAT_DL_INTR ); + + /* + * point the chain head's mbuf to the tail so we can + * locate the next chain to send inside the isr. If + * we're only sending one packet, then don't bother + * with the link, as the mbuf value will either be 0 + * if theres no next chain or -1 if there is. + */ + if( chainCount > 1 ) + firstmd->mbuf = (struct mbuf *)lastmd; + + /* clear our "next chain present" flag. If another + * chain is added later, this flag will be set to -1 + */ + lastmd->mbuf = NULL; + + + if( sc->tx_idle == 0 && CSR_READ_4(sc, XL_DOWNLIST_PTR) == 0 ) + { + printk("etherlink : unit elnk%d tx forced!\n", sc->xl_unit); + sc->tx_idle = -1; + } + + /* start sending this chain of packets if tx isn't busy */ + if( sc->tx_idle ) + { + elnk_start_txchain(sc, firstmd); + } + } + + ifp->if_flags &= ~IFF_OACTIVE; + } + } + } + } +} + + + + + + + + + + + +static void +elnk_start (struct ifnet *ifp) +{ + struct elnk_softc *sc = ifp->if_softc; +#if 0 + printk("unit %i tx signaled\n", sc->xl_unit ); +#endif + ifp->if_flags |= IFF_OACTIVE; + rtems_event_send( txDaemonTid, sc->ioevent ); +} + + + + + + + + + + + + + + + +/* + * Initialize and start the device + */ +static void +elnk_init (void *arg) +{ + int i; + struct elnk_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + xl_stop(sc); + + XL_SEL_WIN(3); + CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX); + + { + unsigned32 cr,sr; + + xl_miibus_writereg(sc, 0x18, MII_BMCR, BMCR_RESET ); + + while( (cr = xl_miibus_readreg(sc, 0x18, MII_BMCR )) & BMCR_RESET ) + { + DELAY(100000); + } + + xl_miibus_writereg(sc, 0x18, MII_ANAR, ANAR_10 | ANAR_10_FD | ANAR_TX | ANAR_TX_FD | ANAR_T4); + xl_miibus_writereg(sc, 0x18, MII_BMCR, BMCR_AUTOEN ); + + /* while( ((sr = xl_miibus_readreg(sc, 0x18, MII_BMSR)) & BMSR_ACOMP) == 0 ); */ + } + + + XL_SEL_WIN(7); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET); + xl_wait(sc); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET); + xl_wait(sc); + DELAY(10000); + + sc->tx_idle = -1; + + /* + * Set up hardware if its not already been done + */ + if( !sc->irqInfo.hdl ) + { + elnk_initialize_hardware(sc); + } + + /* + * Enable the card + */ + { + u_int8_t rxfilt; + + /* + * Cancel pending I/O + */ + + /* Init our MAC address */ + XL_SEL_WIN(2); + for (i = 0; i < ETHER_ADDR_LEN; i++) + { + CSR_WRITE_1(sc, XL_W2_STATION_ADDR_LO + i, sc->arpcom.ac_enaddr[i]); + } + + /* Clear the station mask. */ + for (i = 0; i < 3; i++) + CSR_WRITE_2(sc, XL_W2_STATION_MASK_LO + (i * 2), 0); + + /* + * Set the TX freethresh value. + * Note that this has no effect on 3c905B "cyclone" + * cards but is required for 3c900/3c905 "boomerang" + * cards in order to enable the download engine. + */ + CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8); + + /* Set the TX start threshold for best performance. */ + sc->xl_tx_thresh = XL_MIN_FRAMELEN; + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_SET_START|sc->xl_tx_thresh); + + /* + * If this is a 3c905B, also set the tx reclaim threshold. + * This helps cut down on the number of tx reclaim errors + * that could happen on a busy network. The chip multiplies + * the register value by 16 to obtain the actual threshold + * in bytes, so we divide by 16 when setting the value here. + * The existing threshold value can be examined by reading + * the register at offset 9 in window 5. + */ + if (sc->xl_type == XL_TYPE_905B) { + CSR_WRITE_2(sc, XL_COMMAND, + XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4)); + } + + /* Set RX filter bits. */ + XL_SEL_WIN(5); + rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER); + + /* Set the individual bit to receive frames for this host only. */ + rxfilt |= XL_RXFILTER_INDIVIDUAL; + + /* If we want promiscuous mode, set the allframes bit. */ + if (ifp->if_flags & IFF_PROMISC) { + rxfilt |= XL_RXFILTER_ALLFRAMES; + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt); + } else { + rxfilt &= ~XL_RXFILTER_ALLFRAMES; + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt); + } + + /* + * Set capture broadcast bit to capture broadcast frames. + */ + if (ifp->if_flags & IFF_BROADCAST) { + rxfilt |= XL_RXFILTER_BROADCAST; + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt); + } else { + rxfilt &= ~XL_RXFILTER_BROADCAST; + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt); + } + +#if 0 + /* + * Program the multicast filter, if necessary. + */ + if (sc->xl_type == XL_TYPE_905B) + xl_setmulti_hash(sc); + else + xl_setmulti(sc); +#endif + /* + * Load the address of the RX list. We have to + * stall the upload engine before we can manipulate + * the uplist pointer register, then unstall it when + * we're finished. We also have to wait for the + * stall command to complete before proceeding. + * Note that we have to do this after any RX resets + * have completed since the uplist register is cleared + * by a reset. + */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL); + xl_wait(sc); + CSR_WRITE_4(sc, XL_UPLIST_PTR, phys_to_bus( sc->curr_rx_md )); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL); + xl_wait(sc); + + + if (sc->xl_type == XL_TYPE_905B) { + /* Set polling interval */ + CSR_WRITE_1(sc, XL_DOWN_POLL, 64); + xl_wait(sc); + } + + /* + * If the coax transceiver is on, make sure to enable + * the DC-DC converter. + */ + XL_SEL_WIN(3); + if (sc->xl_xcvr == XL_XCVR_COAX) + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START); + else + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); + + /* increase packet size to allow reception of 802.1q or ISL packets */ + if (sc->xl_type == XL_TYPE_905B) + CSR_WRITE_2(sc, XL_W3_MAXPKTSIZE, XL_PACKET_SIZE); + /* Clear out the stats counters. */ + + memset( &sc->xl_stats, 0, sizeof(struct xl_stats)); + + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE); + sc->xl_stats_no_timeout = 1; + xl_stats_update(sc->stat_timer_id,sc); + sc->xl_stats_no_timeout = 0; + XL_SEL_WIN(4); + CSR_WRITE_2(sc, XL_W4_NET_DIAG, XL_NETDIAG_UPPER_BYTES_ENABLE); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_ENABLE); + + + /* + * Enable interrupts. + */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS); + + /* Set the RX early threshold */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_THRESH|(XL_PACKET_SIZE >>2)); + CSR_WRITE_2(sc, XL_DMACTL, XL_DMACTL_UP_RX_EARLY ); + +#if 0 + { + unsigned32 icfg; + unsigned16 mctl; + + XL_SEL_WIN(3); + icfg = CSR_READ_4( sc, XL_W3_INTERNAL_CFG ); + mctl = CSR_READ_2( sc, XL_W3_MAC_CTRL ); + + printk("etherlink : unit elnk%d intcfg %08x, macctl %04x\n", sc->xl_unit, icfg, mctl); + } +#endif + + /* Enable receiver and transmitter. */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE); + xl_wait(sc); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE); + xl_wait(sc); + + /* Select window 7 for normal operations. */ + XL_SEL_WIN(7); + + /* schedule the stats update timer */ + rtems_timer_fire_after( sc->stat_timer_id, sc->stats_update_ticks, xl_stats_update, (void *)sc ); + } + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; +} + + + + + + + +/* + * Stop the device + */ +static void +elnk_stop (struct elnk_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + + /* + * Stop the transmitter + */ + xl_stop(sc); + + ifp->if_flags &= ~IFF_RUNNING; +} + + + + +/* + * Show interface statistics + */ +static void +elnk_stats (struct elnk_softc *sc) +{ + printf(" MII PHY data { anr:%04x lpar:%04x stat:%04x ctl:%04x }\n", + sc->xl_unit, + sc->xl_stats.miianr, + sc->xl_stats.miipar, + sc->xl_stats.miistatus, + sc->xl_stats.miicmd); + + printf(" interrupts:%-5d intstatus:%04x mediastat:%04x\n", + sc->xl_stats.device_interrupts, + sc->xl_stats.intstatus, + sc->xl_stats.mediastatus); + + printf(" rxstatus:%04x txstatus:%02x smbstat:%04x\n", + sc->xl_stats.rxstatus, + sc->xl_stats.txstatus, + sc->xl_stats.smbstatus); + + printf(" carrier_lost:%-5d sqe_errs:%-5d\n", + sc->xl_stats.xl_carrier_lost, + sc->xl_stats.xl_sqe_errs); + + printf(" tx_multi_collision:%-5d tx_single_collision:%-5d\n", + sc->xl_stats.xl_tx_multi_collision, + sc->xl_stats.xl_tx_single_collision); + + printf(" tx_late_collision:%-5d rx_overrun:%-5d\n", + sc->xl_stats.xl_tx_late_collision, + sc->xl_stats.xl_rx_overrun); + + printf(" tx_deferred:%-5d badssd:%-5d\n", + sc->xl_stats.xl_tx_deferred, + sc->xl_stats.xl_badssd); + + printf(" rx_frames_ok:%-5d tx_frames_ok:%-5d\n", + sc->xl_stats.xl_rx_frames_ok + ((sc->xl_stats.xl_upper_frames_ok & 3) << 16), + sc->xl_stats.xl_tx_frames_ok + (((sc->xl_stats.xl_upper_frames_ok >> 4) & 3) << 16) ); + + printf(" rx_bytes_ok:%-5d tx_bytes_ok:%-5d\n", + sc->xl_stats.xl_rx_bytes_ok + ((sc->xl_stats.xl_upper_bytes_ok & 7) << 16), + sc->xl_stats.xl_tx_bytes_ok + (((sc->xl_stats.xl_upper_bytes_ok >> 4) & 7) << 16) ); +} + + + + + + + +/* + * Driver ioctl handler + */ +static int +elnk_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct elnk_softc *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + elnk_stop (sc); + break; + + case IFF_UP: + elnk_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + elnk_stop (sc); + elnk_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + elnk_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + + return error; +} + + + + + + + + +#if 0 +static int iftap(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m ) +{ + int i; + char *delim, *pkt; + + printk("unit %i, src ", ifp->if_unit ); + for(delim= "", i=0; i< ETHER_ADDR_LEN; i++, delim=":") + printk("%s%02x", delim, (char) eh->ether_shost[i] ); + + printk(" dest "); + + for(delim= "", i=0; i< ETHER_ADDR_LEN; i++, delim=":") + printk("%s%02x", delim, (char) eh->ether_dhost[i] ); + printk(" pkt "); + + pkt = (char *)eh; + for(delim="", i=0; i < sizeof(struct ether_header); i++, delim=":") + printk("%s%02x", delim, (char) pkt[i] ); + + printk("\n"); + return 0; +} +#endif + + + +struct el_boards +{ + int pbus,pdev,pfun, vid, did, tindex; +}; + + + +/* + * Attach an ELNK driver to the system + */ +int +rtems_elnk_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach) +{ + struct elnk_softc *sc; + struct ifnet *ifp; + char *unitName; + int unitNumber; + int mtu, i; + unsigned char cvalue; + int pbus, pdev, pfun; + unsigned int lvalue; + struct el_boards sysboards[NUM_UNITS]; + int numFound = 0; + + + /* + * Get the instance number for the board we're going to configure + * from the user. + */ + if( (unitNumber = rtems_bsdnet_parse_driver_name( config, &unitName)) == -1 ) + { + return 0; + } + + if( strcmp(unitName, DRIVER_PREFIX) ) + { + printk("etherlink : invalid unit name '%s'\n", unitName ); + return 0; + } + + if ((unitNumber < 1) || (unitNumber > NUM_UNITS)) + { + printk("etherlink : unit %i is invalid, must be (1 <= n <= %d)\n", unitNumber, NUM_UNITS); + return 0; + } + + + { + int done= 0, unum; + + /* + * Run thru the list of boards, finding all that are present in + * the system. Sort by slot,dev - and then use the unitNumber-1 + * to index the list and select the device. Yucky. + */ + for( i=0; !done && xl_devs[i].xl_vid; i++) + { + for(unum= 1; + !done && BSP_pciFindDevice( xl_devs[i].xl_vid, xl_devs[i].xl_did, unum-1, + &sysboards[numFound].pbus, + &sysboards[numFound].pdev, + &sysboards[numFound].pfun)==0; + unum++) + { + if( numFound == NUM_UNITS ) + { + printk("etherlink : Maximum of %d units found, extra devices ignored.\n", NUM_UNITS ); + done=-1; + } + else + { + sysboards[numFound].vid = xl_devs[i].xl_vid; + sysboards[numFound].did = xl_devs[i].xl_did; + sysboards[numFound].tindex = i; + ++numFound; + } + } + } + + if( ! numFound ) + { + printk("etherlink : No Etherlink devices found\n"); + return 0; + } + + if( unitNumber-1 >= numFound ) + { + printk("etherlink : device '%s' not found\n", config->name ); + return 0; + } + + /* + * Got the list of etherlink boards in the system, now sort by + * slot,device. bubble sorts aren't all that wonderful, but this + * is a short & infrequently sorted list. + */ + if( numFound > 1 ) + { + struct el_boards tboard; + int didsort; + + do + { + didsort = 0; + + for(i=1; i sysboards[i].pbus || + (sysboards[i-1].pbus == sysboards[i].pbus && sysboards[i-1].pdev > sysboards[i].pdev) ) + { + memcpy(&tboard, &sysboards[i-1], sizeof(struct el_boards)); + memcpy(&sysboards[i-1], &sysboards[i], sizeof(struct el_boards)); + memcpy(&sysboards[i], &tboard, sizeof(struct el_boards)); + didsort++; + } + } + } + while( didsort ); + } + + /* + ** board list is sorted, now select the unit + */ + + pbus = sysboards[unitNumber-1].pbus; + pdev = sysboards[unitNumber-1].pdev; + pfun = sysboards[unitNumber-1].pfun; + } + + sc = &elnk_softc[unitNumber - 1]; + ifp = &sc->arpcom.ac_if; + if (ifp->if_softc != NULL) + { + printk("etherlink : unit %i already in use.\n", unitNumber ); + return 0; + } + + /* + ** Save various things + */ + sc->xl_unit = unitNumber; + sc->xl_type = sysboards[ unitNumber-1 ].tindex; + + sc->vendorID = sysboards[numFound].vid; + sc->deviceID = sysboards[numFound].did; + + sc->numRxbuffers = (config->rbuf_count) ? config->rbuf_count : RX_RING_SIZE; + sc->numTxbuffers = (config->xbuf_count) ? config->xbuf_count : TX_RING_SIZE; + + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + sc->acceptBroadcast = !config->ignore_broadcast; + + + +#ifdef ELNK_DEBUG + printk("etherlink : device '%s', name 'elnk%d', pci %02x:%02x.%02x, %d rx/%d tx buffers\n", + xl_devs[sc->xl_type].xl_name, sc->xl_unit, + pbus, pdev, pfun, + sc->numRxbuffers, sc->numTxbuffers); +#endif + + + /* + ** Create this unit's stats timer + */ + if( rtems_timer_create( rtems_build_name( 'X', 'L', 't', (char)(sc->xl_unit & 255)), + &sc->stat_timer_id ) != RTEMS_SUCCESSFUL ) + { + printk("etherlink : unit elnk%d unable to create stats timer\n", sc->xl_unit ); + return 0; + } + + /* update stats 1 times/second if things aren't incrementing fast + * enough to trigger stats interrupts + */ + rtems_clock_get( RTEMS_CLOCK_GET_TICKS_PER_SECOND, &sc->stats_update_ticks ); + + + /* + ** Get this unit's rx/tx event + */ + sc->ioevent = unit_signals[unitNumber-1]; + + + /* + ** Prep the board + */ + pci_write_config_word(pbus, pdev, pfun, + PCI_COMMAND, + (unsigned16)( PCI_COMMAND_IO | + PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE | + PCI_COMMAND_WAIT | + PCI_COMMAND_FAST_BACK ) ); + + /* + * Get the devices base address + */ + pci_read_config_dword(pbus, pdev, pfun, + PCI_BASE_ADDRESS_0, + &lvalue); + + sc->ioaddr = (unsigned32)lvalue & PCI_BASE_ADDRESS_IO_MASK; + + + /* + ** Store the interrupt name, we'll use it later when we initialize + ** the board. + */ + pci_read_config_byte(pbus, pdev, pfun, + PCI_INTERRUPT_LINE, + &cvalue); + + memset(&sc->irqInfo,0,sizeof(rtems_irq_connect_data)); + sc->irqInfo.name = cvalue; + + + /* + ** Establish basic board config, set node address from config or + ** board eeprom, do stuff with additional device properties + */ + +#if 0 + { + unsigned8 pci_latency; + unsigned8 new_latency = 248; + + /* Check the PCI latency value. On the 3c590 series the latency timer + must be set to the maximum value to avoid data corruption that occurs + when the timer expires during a transfer. This bug exists the Vortex + chip only. */ + pci_read_config_byte(pbus,pdev,pfun, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < new_latency) + { + printk("etherlink : unit elnk%d Overriding PCI latency, timer (CFLT) setting of %d, new value is %d.\n", sc->xl_unit, pci_latency, new_latency ); + pci_write_config_byte(pbus,pdev,pfun, PCI_LATENCY_TIMER, new_latency); + } + } +#endif + + + /* Reset the adapter. */ + xl_reset(sc); + + + { + u_int16_t xcvr[2]; + u_char eaddr[ETHER_ADDR_LEN]; + int media = IFM_ETHER|IFM_100_TX|IFM_FDX; + + sc->xl_flags = 0; + if (sc->deviceID == TC_DEVICEID_HURRICANE_555) + sc->xl_flags |= XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_PHYOK; + if (sc->deviceID == TC_DEVICEID_HURRICANE_556 || + sc->deviceID == TC_DEVICEID_HURRICANE_556B) + sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK | + XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_WEIRDRESET | + XL_FLAG_INVERT_LED_PWR | XL_FLAG_INVERT_MII_PWR; + if (sc->deviceID == TC_DEVICEID_HURRICANE_555 || + sc->deviceID == TC_DEVICEID_HURRICANE_556) + sc->xl_flags |= XL_FLAG_8BITROM; + if (sc->deviceID == TC_DEVICEID_HURRICANE_556B) + sc->xl_flags |= XL_FLAG_NO_XCVR_PWR; + + if (sc->deviceID == TC_DEVICEID_HURRICANE_575A || + sc->deviceID == TC_DEVICEID_HURRICANE_575B || + sc->deviceID == TC_DEVICEID_HURRICANE_575C || + sc->deviceID == TC_DEVICEID_HURRICANE_656B || + sc->deviceID == TC_DEVICEID_TORNADO_656C) + sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK | + XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_8BITROM; + if (sc->deviceID == TC_DEVICEID_HURRICANE_656) + sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK; + if (sc->deviceID == TC_DEVICEID_HURRICANE_575B) + sc->xl_flags |= XL_FLAG_INVERT_LED_PWR; + if (sc->deviceID == TC_DEVICEID_HURRICANE_575C) + sc->xl_flags |= XL_FLAG_INVERT_MII_PWR; + if (sc->deviceID == TC_DEVICEID_TORNADO_656C) + sc->xl_flags |= XL_FLAG_INVERT_MII_PWR; + if (sc->deviceID == TC_DEVICEID_HURRICANE_656 || + sc->deviceID == TC_DEVICEID_HURRICANE_656B) + sc->xl_flags |= XL_FLAG_INVERT_MII_PWR | + XL_FLAG_INVERT_LED_PWR; + if (sc->deviceID == TC_DEVICEID_TORNADO_10_100BT_920B) + sc->xl_flags |= XL_FLAG_PHYOK; + + + if (config->hardware_address) + { + memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + } + else + { + if (xl_read_eeprom(sc, (caddr_t)&eaddr, XL_EE_OEM_ADR0, 3, 1)) + { + printk("etherlink : unit elnk%d Failed to read station address\n", sc->xl_unit ); + return 0; + } + memcpy((char *)&sc->arpcom.ac_enaddr, eaddr, ETHER_ADDR_LEN); + } + + /* + * Figure out the card type. 3c905B adapters have the + * 'supportsNoTxLength' bit set in the capabilities + * word in the EEPROM. + */ + xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0); + if (sc->xl_caps & XL_CAPS_NO_TXLENGTH) + sc->xl_type = XL_TYPE_905B; + else + sc->xl_type = XL_TYPE_90X; + + + /* + * Now we have to see what sort of media we have. + * This includes probing for an MII interace and a + * possible PHY. + */ + XL_SEL_WIN(3); + sc->xl_media = CSR_READ_2(sc, XL_W3_MEDIA_OPT); + + xl_read_eeprom(sc, (char *)&xcvr, XL_EE_ICFG_0, 2, 0); + sc->xl_xcvr = xcvr[0] | xcvr[1] << 16; + sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK; + sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS; + +#if 0 + printk("etherlink : unit elnk%d EEPROM set xcvr to 0x%x\n", sc->xl_unit, sc->xl_xcvr); +#endif + + { + char msg[255]; + int i; + + struct _availmedia + { + int bit; + char *name; + } _am[]= {{ XL_MEDIAOPT_BT4, "100BaseT4" }, + { XL_MEDIAOPT_BTX, "100BaseTX" }, + { XL_MEDIAOPT_BFX, "100BaseFX" }, + { XL_MEDIAOPT_BT, "10BaseT" }, + { XL_MEDIAOPT_BNC, "10Base2" }, + { XL_MEDIAOPT_AUI, "10mbps AUI"}, + { XL_MEDIAOPT_MII, "MII"}, + { 0, NULL }}; + + msg[0]= 0; + for( i=0; _am[i].bit; i++) + { + if( sc->xl_media & _am[i].bit ) + sprintf( &msg[strlen(msg)], ",%s", _am[i].name ); + } + if( !strlen(msg) ) strcpy( &msg[1], ""); + + printk("etherlink : unit elnk%d available media : %s\n", sc->xl_unit, &msg[1]); + } + + xl_mediacheck(sc); + +#if 0 +/* this has already been called by xl_mediacheck()- hopefully + I've not messed something up here */ + /* + * Sanity check. If the user has selected "auto" and this isn't + * a 10/100 card of some kind, we need to force the transceiver + * type to something sane. + */ + if (sc->xl_xcvr == XL_XCVR_AUTO) + xl_choose_xcvr(sc, 1); +#endif + + + /* Choose a default media. */ + switch(sc->xl_xcvr) { + case XL_XCVR_10BT: + media = IFM_ETHER|IFM_10_T; + xl_setmode(sc, media); + break; + case XL_XCVR_AUI: + if (sc->xl_type == XL_TYPE_905B && + sc->xl_media == XL_MEDIAOPT_10FL) { + media = IFM_ETHER|IFM_10_FL; + xl_setmode(sc, media); + } else { + media = IFM_ETHER|IFM_10_5; + xl_setmode(sc, media); + } + break; + case XL_XCVR_COAX: + media = IFM_ETHER|IFM_10_2; + xl_setmode(sc, media); + break; + case XL_XCVR_AUTO: + case XL_XCVR_100BTX: + xl_setcfg(sc); + break; + case XL_XCVR_MII: + printk("etherlink : unit elnk%d MII media not supported!\n", sc->xl_unit); + break; + case XL_XCVR_100BFX: + media = IFM_ETHER|IFM_100_FX; + break; + default: + printk("etherlink : unit elnk%d unknown XCVR type: %d\n", sc->xl_unit, sc->xl_xcvr); + /* + * This will probably be wrong, but it prevents + * the ifmedia code from panicking. + */ + media = IFM_ETHER|IFM_10_T; + break; + } + + + if (sc->xl_flags & XL_FLAG_NO_XCVR_PWR) { + XL_SEL_WIN(0); + CSR_WRITE_2(sc, XL_W0_MFG_ID, XL_NO_XCVR_PWR_MAGICBITS); + } + + XL_SEL_WIN(7); + } + + + + /* + * Set up network interface + */ + ifp->if_softc = sc; + ifp->if_name = unitName; + ifp->if_unit = sc->xl_unit; + ifp->if_mtu = mtu; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_init = elnk_init; + ifp->if_start = elnk_start; + ifp->if_ioctl = elnk_ioctl; + ifp->if_output = ether_output; + +#if 0 + ifp->if_tap = iftap; +#endif + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + +#ifdef ELNK_DEBUG + printk( "etherlink : unit elnk%d driver attached\n", sc->xl_unit ); +#endif + + /* + * Start driver tasks if this is the first unit initialized + */ + if (txDaemonTid == 0) + { + rxDaemonTid = rtems_bsdnet_newproc( "XLrx", 4096, + elnk_rxDaemon, NULL); + + txDaemonTid = rtems_bsdnet_newproc( "XLtx", 4096, + elnk_txDaemon, NULL); +#ifdef ELNK_DEBUG + printk( "etherlink : driver tasks created\n" ); +#endif + } + + return 1; +}; + +#endif /* ELNK_SUPPORTED */ + +/* eof */ diff --git a/c/src/libchip/network/if_media.h b/c/src/libchip/network/if_media.h new file mode 100644 index 0000000000..926a803ddb --- /dev/null +++ b/c/src/libchip/network/if_media.h @@ -0,0 +1,436 @@ +/* $NetBSD: if_media.h,v 1.3 1997/03/26 01:19:27 thorpej Exp $ */ +/* $FreeBSD: /repoman/r/ncvs/src/sys/net/if_media.h,v 1.18 2002/07/14 21:58:19 kbyanc Exp $ */ + +/* + * Copyright (c) 1997 + * Jonathan Stone and Jason R. Thorpe. All rights reserved. + * + * This software is derived from information provided by Matt Thomas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jonathan Stone + * and Jason R. Thorpe for the NetBSD Project. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NET_IF_MEDIA_H_ +#define _NET_IF_MEDIA_H_ + +/* + * Prototypes and definitions for BSD/OS-compatible network interface + * media selection. + * + * Where it is safe to do so, this code strays slightly from the BSD/OS + * design. Software which uses the API (device drivers, basically) + * shouldn't notice any difference. + * + * Many thanks to Matt Thomas for providing the information necessary + * to implement this interface. + */ + +#ifdef _KERNEL + +#include + +/* + * Driver callbacks for media status and change requests. + */ +typedef int (*ifm_change_cb_t)(struct ifnet *ifp); +typedef void (*ifm_stat_cb_t)(struct ifnet *ifp, struct ifmediareq *req); + +/* + * In-kernel representation of a single supported media type. + */ +struct ifmedia_entry { + LIST_ENTRY(ifmedia_entry) ifm_list; + int ifm_media; /* description of this media attachment */ + int ifm_data; /* for driver-specific use */ + void *ifm_aux; /* for driver-specific use */ +}; + +/* + * One of these goes into a network interface's softc structure. + * It is used to keep general media state. + */ +struct ifmedia { + int ifm_mask; /* mask of changes we don't care about */ + int ifm_media; /* current user-set media word */ + struct ifmedia_entry *ifm_cur; /* currently selected media */ + LIST_HEAD(, ifmedia_entry) ifm_list; /* list of all supported media */ + ifm_change_cb_t ifm_change; /* media change driver callback */ + ifm_stat_cb_t ifm_status; /* media status driver callback */ +}; + +/* Initialize an interface's struct if_media field. */ +void ifmedia_init(struct ifmedia *ifm, int dontcare_mask, + ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback); + +/* Remove all mediums from a struct ifmedia. */ +void ifmedia_removeall( struct ifmedia *ifm); + +/* Add one supported medium to a struct ifmedia. */ +void ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux); + +/* Add an array (of ifmedia_entry) media to a struct ifmedia. */ +void ifmedia_list_add(struct ifmedia *mp, struct ifmedia_entry *lp, + int count); + +/* Set default media type on initialization. */ +void ifmedia_set(struct ifmedia *ifm, int mword); + +/* Common ioctl function for getting/setting media, called by driver. */ +int ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, + struct ifmedia *ifm, u_long cmd); + +#endif /*_KERNEL */ + +/* + * if_media Options word: + * Bits Use + * ---- ------- + * 0-4 Media variant + * 5-7 Media type + * 8-15 Type specific options + * 16-19 RFU + * 20-27 Shared (global) options + * 28-31 Instance + */ + +/* + * Ethernet + */ +#define IFM_ETHER 0x00000020 +#define IFM_10_T 3 /* 10BaseT - RJ45 */ +#define IFM_10_2 4 /* 10Base2 - Thinnet */ +#define IFM_10_5 5 /* 10Base5 - AUI */ +#define IFM_100_TX 6 /* 100BaseTX - RJ45 */ +#define IFM_100_FX 7 /* 100BaseFX - Fiber */ +#define IFM_100_T4 8 /* 100BaseT4 - 4 pair cat 3 */ +#define IFM_100_VG 9 /* 100VG-AnyLAN */ +#define IFM_100_T2 10 /* 100BaseT2 */ +#define IFM_1000_SX 11 /* 1000BaseSX - multi-mode fiber */ +#define IFM_10_STP 12 /* 10BaseT over shielded TP */ +#define IFM_10_FL 13 /* 10BaseFL - Fiber */ +#define IFM_1000_LX 14 /* 1000baseLX - single-mode fiber */ +#define IFM_1000_CX 15 /* 1000baseCX - 150ohm STP */ +#define IFM_1000_T 16 /* 1000baseT - 4 pair cat 5 */ +#define IFM_HPNA_1 17 /* HomePNA 1.0 (1Mb/s) */ +/* note 31 is the max! */ + +#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */ + +/* + * Token ring + */ +#define IFM_TOKEN 0x00000040 +#define IFM_TOK_STP4 3 /* Shielded twisted pair 4m - DB9 */ +#define IFM_TOK_STP16 4 /* Shielded twisted pair 16m - DB9 */ +#define IFM_TOK_UTP4 5 /* Unshielded twisted pair 4m - RJ45 */ +#define IFM_TOK_UTP16 6 /* Unshielded twisted pair 16m - RJ45 */ +#define IFM_TOK_STP100 7 /* Shielded twisted pair 100m - DB9 */ +#define IFM_TOK_UTP100 8 /* Unshielded twisted pair 100m - RJ45 */ +#define IFM_TOK_ETR 0x00000200 /* Early token release */ +#define IFM_TOK_SRCRT 0x00000400 /* Enable source routing features */ +#define IFM_TOK_ALLR 0x00000800 /* All routes / Single route bcast */ +#define IFM_TOK_DTR 0x00002000 /* Dedicated token ring */ +#define IFM_TOK_CLASSIC 0x00004000 /* Classic token ring */ +#define IFM_TOK_AUTO 0x00008000 /* Automatic Dedicate/Classic token ring */ + +/* + * FDDI + */ +#define IFM_FDDI 0x00000060 +#define IFM_FDDI_SMF 3 /* Single-mode fiber */ +#define IFM_FDDI_MMF 4 /* Multi-mode fiber */ +#define IFM_FDDI_UTP 5 /* CDDI / UTP */ +#define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */ + +/* + * IEEE 802.11 Wireless + */ +#define IFM_IEEE80211 0x00000080 +#define IFM_IEEE80211_FH1 3 /* Frequency Hopping 1Mbps */ +#define IFM_IEEE80211_FH2 4 /* Frequency Hopping 2Mbps */ +#define IFM_IEEE80211_DS1 5 /* Direct Sequence 1Mbps */ +#define IFM_IEEE80211_DS2 6 /* Direct Sequence 2Mbps */ +#define IFM_IEEE80211_DS5 7 /* Direct Sequence 5.5Mbps */ +#define IFM_IEEE80211_DS11 8 /* Direct Sequence 11Mbps */ +#define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */ +#define IFM_IEEE80211_ODFM6 10 /* ODFM 6Mbps */ +#define IFM_IEEE80211_ODFM9 11 /* ODFM 9Mbps */ +#define IFM_IEEE80211_ODFM12 12 /* ODFM 12Mbps */ +#define IFM_IEEE80211_ODFM18 13 /* ODFM 18Mbps */ +#define IFM_IEEE80211_ODFM24 14 /* ODFM 24Mbps */ +#define IFM_IEEE80211_ODFM36 15 /* ODFM 36Mbps */ +#define IFM_IEEE80211_ODFM48 16 /* ODFM 48Mbps */ +#define IFM_IEEE80211_ODFM54 17 /* ODFM 54Mbps */ +#define IFM_IEEE80211_ODFM72 18 /* ODFM 72Mbps */ +#define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */ +#define IFM_IEEE80211_HOSTAP 0x00000200 /* Operate in Host AP mode */ +#define IFM_IEEE80211_IBSS 0x00000400 /* Operate in IBSS mode */ +#define IFM_IEEE80211_IBSSMASTER 0x00000800 /* Operate as an IBSS master */ + +/* + * Shared media sub-types + */ +#define IFM_AUTO 0 /* Autoselect best media */ +#define IFM_MANUAL 1 /* Jumper/dipswitch selects media */ +#define IFM_NONE 2 /* Deselect all media */ + +/* + * Shared options + */ +#define IFM_FDX 0x00100000 /* Force full duplex */ +#define IFM_HDX 0x00200000 /* Force half duplex */ +#define IFM_FLAG0 0x01000000 /* Driver defined flag */ +#define IFM_FLAG1 0x02000000 /* Driver defined flag */ +#define IFM_FLAG2 0x04000000 /* Driver defined flag */ +#define IFM_LOOP 0x08000000 /* Put hardware in loopback */ + +/* + * Masks + */ +#define IFM_NMASK 0x000000e0 /* Network type */ +#define IFM_TMASK 0x0000001f /* Media sub-type */ +#define IFM_IMASK 0xf0000000 /* Instance */ +#define IFM_ISHIFT 28 /* Instance shift */ +#define IFM_OMASK 0x0000ff00 /* Type specific options */ +#define IFM_GMASK 0x0ff00000 /* Global options */ + +/* + * Status bits + */ +#define IFM_AVALID 0x00000001 /* Active bit valid */ +#define IFM_ACTIVE 0x00000002 /* Interface attached to working net */ + +/* + * Macros to extract various bits of information from the media word. + */ +#define IFM_TYPE(x) ((x) & IFM_NMASK) +#define IFM_SUBTYPE(x) ((x) & IFM_TMASK) +#define IFM_TYPE_OPTIONS(x) ((x) & IFM_OMASK) +#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT) +#define IFM_OPTIONS(x) ((x) & (IFM_OMASK|IFM_GMASK)) + +#define IFM_INST_MAX IFM_INST(IFM_IMASK) + +/* + * Macro to create a media word. + */ +#define IFM_MAKEWORD(type, subtype, options, instance) \ + ((type) | (subtype) | (options) | ((instance) << IFM_ISHIFT)) + +/* + * NetBSD extension not defined in the BSDI API. This is used in various + * places to get the canonical description for a given type/subtype. + * + * NOTE: all but the top-level type descriptions must contain NO whitespace! + * Otherwise, parsing these in ifconfig(8) would be a nightmare. + */ +struct ifmedia_description { + int ifmt_word; /* word value; may be masked */ + const char *ifmt_string; /* description */ +}; + +#define IFM_TYPE_DESCRIPTIONS { \ + { IFM_ETHER, "Ethernet" }, \ + { IFM_TOKEN, "Token ring" }, \ + { IFM_FDDI, "FDDI" }, \ + { IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_DESCRIPTIONS { \ + { IFM_10_T, "10baseT/UTP" }, \ + { IFM_10_2, "10base2/BNC" }, \ + { IFM_10_5, "10base5/AUI" }, \ + { IFM_100_TX, "100baseTX" }, \ + { IFM_100_FX, "100baseFX" }, \ + { IFM_100_T4, "100baseT4" }, \ + { IFM_100_VG, "100baseVG" }, \ + { IFM_100_T2, "100baseT2" }, \ + { IFM_10_STP, "10baseSTP" }, \ + { IFM_10_FL, "10baseFL" }, \ + { IFM_1000_SX, "1000baseSX" }, \ + { IFM_1000_LX, "1000baseLX" }, \ + { IFM_1000_CX, "1000baseCX" }, \ + { IFM_1000_T, "1000baseTX" }, \ + { IFM_1000_T, "1000baseT" }, \ + { IFM_HPNA_1, "homePNA" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_ALIASES { \ + { IFM_10_T, "UTP" }, \ + { IFM_10_T, "10UTP" }, \ + { IFM_10_2, "BNC" }, \ + { IFM_10_2, "10BNC" }, \ + { IFM_10_5, "AUI" }, \ + { IFM_10_5, "10AUI" }, \ + { IFM_100_TX, "100TX" }, \ + { IFM_100_T4, "100T4" }, \ + { IFM_100_VG, "100VG" }, \ + { IFM_100_T2, "100T2" }, \ + { IFM_10_STP, "10STP" }, \ + { IFM_10_FL, "10FL" }, \ + { IFM_1000_SX, "1000SX" }, \ + { IFM_1000_LX, "1000LX" }, \ + { IFM_1000_CX, "1000CX" }, \ + { IFM_1000_T, "1000TX" }, \ + { IFM_1000_T, "1000T" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS { \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_DESCRIPTIONS { \ + { IFM_TOK_STP4, "DB9/4Mbit" }, \ + { IFM_TOK_STP16, "DB9/16Mbit" }, \ + { IFM_TOK_UTP4, "UTP/4Mbit" }, \ + { IFM_TOK_UTP16, "UTP/16Mbit" }, \ + { IFM_TOK_STP100, "STP/100Mbit" }, \ + { IFM_TOK_UTP100, "UTP/100Mbit" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_ALIASES { \ + { IFM_TOK_STP4, "4STP" }, \ + { IFM_TOK_STP16, "16STP" }, \ + { IFM_TOK_UTP4, "4UTP" }, \ + { IFM_TOK_UTP16, "16UTP" }, \ + { IFM_TOK_STP100, "100STP" }, \ + { IFM_TOK_UTP100, "100UTP" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS { \ + { IFM_TOK_ETR, "EarlyTokenRelease" }, \ + { IFM_TOK_SRCRT, "SourceRouting" }, \ + { IFM_TOK_ALLR, "AllRoutes" }, \ + { IFM_TOK_DTR, "Dedicated" }, \ + { IFM_TOK_CLASSIC,"Classic" }, \ + { IFM_TOK_AUTO, " " }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_DESCRIPTIONS { \ + { IFM_FDDI_SMF, "Single-mode" }, \ + { IFM_FDDI_MMF, "Multi-mode" }, \ + { IFM_FDDI_UTP, "UTP" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_ALIASES { \ + { IFM_FDDI_SMF, "SMF" }, \ + { IFM_FDDI_MMF, "MMF" }, \ + { IFM_FDDI_UTP, "CDDI" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS { \ + { IFM_FDDI_DA, "Dual-attach" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_DESCRIPTIONS { \ + { IFM_IEEE80211_FH1, "FH/1Mbps" }, \ + { IFM_IEEE80211_FH2, "FH/2Mbps" }, \ + { IFM_IEEE80211_DS1, "DS/1Mbps" }, \ + { IFM_IEEE80211_DS2, "DS/2Mbps" }, \ + { IFM_IEEE80211_DS5, "DS/5.5Mbps" }, \ + { IFM_IEEE80211_DS11, "DS/11Mbps" }, \ + { IFM_IEEE80211_DS22, "DS/22Mbps" }, \ + { IFM_IEEE80211_ODFM6, "ODFM/6Mbps" }, \ + { IFM_IEEE80211_ODFM9, "ODFM/9Mbps" }, \ + { IFM_IEEE80211_ODFM12, "ODFM/12Mbps" }, \ + { IFM_IEEE80211_ODFM18, "ODFM/18Mbps" }, \ + { IFM_IEEE80211_ODFM24, "ODFM/24Mbps" }, \ + { IFM_IEEE80211_ODFM36, "ODFM/36Mbps" }, \ + { IFM_IEEE80211_ODFM48, "ODFM/48Mbps" }, \ + { IFM_IEEE80211_ODFM54, "ODFM/54Mbps" }, \ + { IFM_IEEE80211_ODFM72, "ODFM/72Mbps" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_ALIASES { \ + { IFM_IEEE80211_FH1, "FH1" }, \ + { IFM_IEEE80211_FH2, "FH2" }, \ + { IFM_IEEE80211_FH1, "FrequencyHopping/1Mbps" }, \ + { IFM_IEEE80211_FH2, "FrequencyHopping/2Mbps" }, \ + { IFM_IEEE80211_DS1, "DS1" }, \ + { IFM_IEEE80211_DS2, "DS2" }, \ + { IFM_IEEE80211_DS5, "DS5.5" }, \ + { IFM_IEEE80211_DS11, "DS11" }, \ + { IFM_IEEE80211_DS22, "DS22" }, \ + { IFM_IEEE80211_DS1, "DirectSequence/1Mbps" }, \ + { IFM_IEEE80211_DS2, "DirectSequence/2Mbps" }, \ + { IFM_IEEE80211_DS5, "DirectSequence/5.5Mbps" }, \ + { IFM_IEEE80211_DS11, "DirectSequence/11Mbps" }, \ + { IFM_IEEE80211_DS22, "DirectSequence/22Mbps" }, \ + { IFM_IEEE80211_ODFM6, "ODFM6" }, \ + { IFM_IEEE80211_ODFM9, "ODFM9" }, \ + { IFM_IEEE80211_ODFM12, "ODFM12" }, \ + { IFM_IEEE80211_ODFM18, "ODFM18" }, \ + { IFM_IEEE80211_ODFM24, "ODFM24" }, \ + { IFM_IEEE80211_ODFM36, "ODFM36" }, \ + { IFM_IEEE80211_ODFM48, "ODFM48" }, \ + { IFM_IEEE80211_ODFM54, "ODFM54" }, \ + { IFM_IEEE80211_ODFM72, "ODFM72" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS { \ + { IFM_IEEE80211_ADHOC, "adhoc" }, \ + { IFM_IEEE80211_HOSTAP, "hostap" }, \ + { IFM_IEEE80211_IBSS, "ibss" }, \ + { IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_SHARED_DESCRIPTIONS { \ + { IFM_AUTO, "autoselect" }, \ + { IFM_MANUAL, "manual" }, \ + { IFM_NONE, "none" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_SHARED_ALIASES { \ + { IFM_AUTO, "auto" }, \ + { 0, NULL }, \ +} + +#define IFM_SHARED_OPTION_DESCRIPTIONS { \ + { IFM_FDX, "full-duplex" }, \ + { IFM_HDX, "half-duplex" }, \ + { IFM_FLAG0, "flag0" }, \ + { IFM_FLAG1, "flag1" }, \ + { IFM_FLAG2, "flag2" }, \ + { IFM_LOOP, "hw-loopback" }, \ + { 0, NULL }, \ +} + +#endif /* _NET_IF_MEDIA_H_ */ diff --git a/c/src/libchip/network/mii.h b/c/src/libchip/network/mii.h new file mode 100644 index 0000000000..dca3ff4ed5 --- /dev/null +++ b/c/src/libchip/network/mii.h @@ -0,0 +1,206 @@ +/* $NetBSD: mii.h,v 1.9 2001/05/31 03:07:14 thorpej Exp $ */ + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Modification to match BSD/OS 3.0 MII interface by Jason R. Thorpe, + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/dev/mii/mii.h,v 1.4 2002/04/29 11:57:28 phk Exp $ + */ + +#ifndef _DEV_MII_MII_H_ +#define _DEV_MII_MII_H_ + +/* + * Registers common to all PHYs. + */ + +#define MII_NPHY 32 /* max # of PHYs per MII */ + +/* + * MII commands, used if a device must drive the MII lines + * manually. + */ +#define MII_COMMAND_START 0x01 +#define MII_COMMAND_READ 0x02 +#define MII_COMMAND_WRITE 0x01 +#define MII_COMMAND_ACK 0x02 + +#define MII_BMCR 0x00 /* Basic mode control register (rw) */ +#define BMCR_RESET 0x8000 /* reset */ +#define BMCR_LOOP 0x4000 /* loopback */ +#define BMCR_SPEED0 0x2000 /* speed selection (LSB) */ +#define BMCR_AUTOEN 0x1000 /* autonegotiation enable */ +#define BMCR_PDOWN 0x0800 /* power down */ +#define BMCR_ISO 0x0400 /* isolate */ +#define BMCR_STARTNEG 0x0200 /* restart autonegotiation */ +#define BMCR_FDX 0x0100 /* Set duplex mode */ +#define BMCR_CTEST 0x0080 /* collision test */ +#define BMCR_SPEED1 0x0040 /* speed selection (MSB) */ + +#define BMCR_S10 0x0000 /* 10 Mb/s */ +#define BMCR_S100 BMCR_SPEED0 /* 100 Mb/s */ +#define BMCR_S1000 BMCR_SPEED1 /* 1000 Mb/s */ + +#define BMCR_SPEED(x) ((x) & (BMCR_SPEED0|BMCR_SPEED1)) + +#define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define BMSR_100T4 0x8000 /* 100 base T4 capable */ +#define BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */ +#define BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */ +#define BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */ +#define BMSR_10THDX 0x0800 /* 10 base T half duplex capable */ +#define BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */ +#define BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */ +#define BMSR_EXTSTAT 0x0100 /* Extended status in register 15 */ +#define BMSR_MFPS 0x0040 /* MII Frame Preamble Suppression */ +#define BMSR_ACOMP 0x0020 /* Autonegotiation complete */ +#define BMSR_RFAULT 0x0010 /* Link partner fault */ +#define BMSR_ANEG 0x0008 /* Autonegotiation capable */ +#define BMSR_LINK 0x0004 /* Link status */ +#define BMSR_JABBER 0x0002 /* Jabber detected */ +#define BMSR_EXTCAP 0x0001 /* Extended capability */ + +/* + * Note that the EXTSTAT bit indicates that there is extended status + * info available in register 15, but 802.3 section 22.2.4.3 also + * states that that all 1000 Mb/s capable PHYs will set this bit to 1. + */ +#if 0 +#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \ + BMSR_10THDX|BMSR_ANEG) + +#else +/* NetBSD uses: */ +#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX| \ + BMSR_10TFDX|BMSR_10THDX|BMSR_100T2FDX|BMSR_100T2HDX) +#endif + +/* + * Convert BMSR media capabilities to ANAR bits for autonegotiation. + * Note the shift chopps off the BMSR_ANEG bit. + */ +#define BMSR_MEDIA_TO_ANAR(x) (((x) & BMSR_MEDIAMASK) >> 6) + +#define MII_PHYIDR1 0x02 /* ID register 1 (ro) */ + +#define MII_PHYIDR2 0x03 /* ID register 2 (ro) */ +#define IDR2_OUILSB 0xfc00 /* OUI LSB */ +#define IDR2_MODEL 0x03f0 /* vendor model */ +#define IDR2_REV 0x000f /* vendor revision */ + +#define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10)) +#define MII_MODEL(id2) (((id2) & IDR2_MODEL) >> 4) +#define MII_REV(id2) ((id2) & IDR2_REV) + +#define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANAR_NP 0x8000 /* Next page (ro) */ +#define ANAR_ACK 0x4000 /* link partner abilities acknowledged (ro) */ +#define ANAR_RF 0x2000 /* remote fault (ro) */ +#define ANAR_FC 0x0400 /* local device supports PAUSE */ +#define ANAR_T4 0x0200 /* local device supports 100bT4 */ +#define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */ +#define ANAR_TX 0x0080 /* local device supports 100bTx */ +#define ANAR_10_FD 0x0040 /* local device supports 10bT FD */ +#define ANAR_10 0x0020 /* local device supports 10bT */ +#define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */ + +#define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ +#define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ +#define ANAR_X_PAUSE_NONE (0 << 7) +#define ANAR_X_PAUSE_SYM (1 << 7) +#define ANAR_X_PAUSE_ASYM (2 << 7) +#define ANAR_X_PAUSE_TOWARDS (3 << 7) + +#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANLPAR_NP 0x8000 /* Next page (ro) */ +#define ANLPAR_ACK 0x4000 /* link partner accepted ACK (ro) */ +#define ANLPAR_RF 0x2000 /* remote fault (ro) */ +#define ANLPAR_FC 0x0400 /* link partner supports PAUSE */ +#define ANLPAR_T4 0x0200 /* link partner supports 100bT4 */ +#define ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */ +#define ANLPAR_TX 0x0080 /* link partner supports 100bTx */ +#define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */ +#define ANLPAR_10 0x0020 /* link partner supports 10bT */ +#define ANLPAR_CSMA 0x0001 /* protocol selector CSMA/CD */ + +#define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ +#define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ +#define ANLPAR_X_PAUSE_MASK (3 << 7) +#define ANLPAR_X_PAUSE_NONE (0 << 7) +#define ANLPAR_X_PAUSE_SYM (1 << 7) +#define ANLPAR_X_PAUSE_ASYM (2 << 7) +#define ANLPAR_X_PAUSE_TOWARDS (3 << 7) + +#define MII_ANER 0x06 /* Autonegotiation expansion (ro) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANER_MLF 0x0010 /* multiple link detection fault */ +#define ANER_LPNP 0x0008 /* link parter next page-able */ +#define ANER_NP 0x0004 /* next page-able */ +#define ANER_PAGE_RX 0x0002 /* Page received */ +#define ANER_LPAN 0x0001 /* link parter autoneg-able */ + +#define MII_ANNP 0x07 /* Autonegotiation next page */ + /* section 28.2.4.1 and 37.2.6.1 */ + +#define MII_ANLPRNP 0x08 /* Autonegotiation link partner rx next page */ + /* section 32.5.1 and 37.2.6.1 */ + + /* This is also the 1000baseT control register */ +#define MII_100T2CR 0x09 /* 100base-T2 control register */ +#define GTCR_TEST_MASK 0xe000 /* see 802.3ab ss. 40.6.1.1.2 */ +#define GTCR_MAN_MS 0x1000 /* enable manual master/slave control */ +#define GTCR_ADV_MS 0x0800 /* 1 = adv. master, 0 = adv. slave */ +#define GTCR_PORT_TYPE 0x0400 /* 1 = DCE, 0 = DTE (NIC) */ +#define GTCR_ADV_1000TFDX 0x0200 /* adv. 1000baseT FDX */ +#define GTCR_ADV_1000THDX 0x0100 /* adv. 1000baseT HDX */ + + /* This is also the 1000baseT status register */ +#define MII_100T2SR 0x0a /* 100base-T2 status register */ +#define GTSR_MAN_MS_FLT 0x8000 /* master/slave config fault */ +#define GTSR_MS_RES 0x4000 /* result: 1 = master, 0 = slave */ +#define GTSR_LRS 0x2000 /* local rx status, 1 = ok */ +#define GTSR_RRS 0x1000 /* remove rx status, 1 = ok */ +#define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */ +#define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */ +#define GTSR_LP_ASM_DIR 0x0200 /* link partner asym. pause dir. capable */ +#define GTSR_IDLE_ERR 0x00ff /* IDLE error count */ + +#define MII_EXTSR 0x0f /* Extended status register */ +#define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */ +#define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */ +#define EXTSR_1000TFDX 0x2000 /* 1000T full-duplex capable */ +#define EXTSR_1000THDX 0x1000 /* 1000T half-duplex capable */ + +#define EXTSR_MEDIAMASK (EXTSR_1000XFDX|EXTSR_1000XHDX| \ + EXTSR_1000TFDX|EXTSR_1000THDX) + +#endif /* _DEV_MII_MII_H_ */ -- cgit v1.2.3