📄 elnk.c
字号:
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; short chain_lengths[NUM_CHAIN_LENGTHS]; int chlenIndex; 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;static rtems_id chainRecoveryQueue;#if defined(__i386__)#define CSR_WRITE_4(sc, reg, val) i386_outport_long( sc->ioaddr + reg, val )#define CSR_WRITE_2(sc, reg, val) i386_outport_word( sc->ioaddr + reg, val )#define CSR_WRITE_1(sc, reg, val) i386_outport_byte( sc->ioaddr + reg, val )inline unsigned int CSR_READ_4( struct elnk_softc *sc, int reg){ unsigned int myval; i386_inport_long( sc->ioaddr + reg, myval ); return myval;}inline unsigned short CSR_READ_2( struct elnk_softc *sc, int reg){ unsigned short myval; i386_inport_word( sc->ioaddr + reg, myval ); return myval;}inline unsigned char CSR_READ_1( struct elnk_softc *sc, int reg){ unsigned char myval; i386_inport_byte( sc->ioaddr + reg, myval ); return myval;}#endif#if defined(__PPC__)#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)#endif#define XL_SEL_WIN(x) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x)/* * 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 voidxl_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("etherlink : unit elnk%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 voidxl_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 voidxl_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 intxl_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 intxl_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 intxl_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); } memset((char *)&frame, 0, sizeof(frame)); frame.mii_phyaddr = phy; frame.mii_regaddr = reg; xl_mii_readreg(sc, &frame); return(frame.mii_data);}static intxl_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); } memset((char *)&frame, 0, 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 intxl_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 intxl_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 voidxl_stats_update(timerid,xsc) rtems_id timerid; void *xsc;{ struct elnk_softc *sc = (struct elnk_softc *)xsc; struct ifnet *ifp = &sc->arpcom.ac_if; u_int32_t t1; 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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -