📄 tulip.c
字号:
0x01000000 means chain on buffer2 address, 0x02000000 means use the ring start address in CSR2/3. Note: Some work-alike chips do not function correctly in chained mode. The ASIX chip works only in chained mode. Thus we indicate ring mode, but always write the 'next' field for chained mode as well. */#define DESC_RING_WRAP 0x02000000/* transmit and receive descriptor format */struct tulip_rx_desc { volatile u32 status; u32 length; u32 buffer1, buffer2;};struct tulip_tx_desc { volatile u32 status; u32 length; u32 buffer1, buffer2;};/*********************************************************************//* Global Storage *//*********************************************************************/static u32 ioaddr;/* Note: transmit and receive buffers must be longword aligned and longword divisable */#define TX_RING_SIZE 2static struct tulip_tx_desc tx_ring[TX_RING_SIZE] __attribute__ ((aligned(4)));static unsigned char txb[BUFLEN] __attribute__ ((aligned(4)));#define RX_RING_SIZE 4static struct tulip_rx_desc rx_ring[RX_RING_SIZE] __attribute__ ((aligned(4)));static unsigned char rxb[RX_RING_SIZE * BUFLEN] __attribute__ ((aligned(4)));static struct tulip_private { int cur_rx; int chip_id; /* index into tulip_tbl[] */ int pci_id_idx; /* index into pci_id_tbl[] */ int revision; int flags; unsigned short vendor_id; /* PCI card vendor code */ unsigned short dev_id; /* PCI card device code */ unsigned char ehdr[ETH_HLEN]; /* buffer for ethernet header */ const char *nic_name; unsigned int csr0, csr6; /* Current CSR0, CSR6 settings. */ unsigned int if_port; unsigned int full_duplex; /* Full-duplex operation requested. */ unsigned int full_duplex_lock; unsigned int medialock; /* Do not sense media type. */ unsigned int mediasense; /* Media sensing in progress. */ unsigned int nway, nwayset; /* 21143 internal NWay. */ unsigned int default_port; unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ u8 media_table_storage[(sizeof(struct mediatable) + 32*sizeof(struct medialeaf))]; u16 sym_advertise, mii_advertise; /* NWay to-advertise. */ struct mediatable *mtable; u16 lpar; /* 21143 Link partner ability. */ u16 advertising[4]; /* MII advertise, from SROM table. */ signed char phys[4], mii_cnt; /* MII device addresses. */ int cur_index; /* Current media index. */ int saved_if_port;} tpx;static struct tulip_private *tp;/* Known cards that have old-style EEPROMs. Writing this table is described at http://cesdis.gsfc.nasa.gov/linux/drivers/tulip-drivers/tulip-media.html */static struct fixups { char *name; unsigned char addr0, addr1, addr2; u16 newtable[32]; /* Max length below. */} eeprom_fixups[] = { {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, 0x0000, 0x009E, /* 10baseT */ 0x0004, 0x009E, /* 10baseT-FD */ 0x0903, 0x006D, /* 100baseTx */ 0x0905, 0x006D, /* 100baseTx-FD */ }}, {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, 0x0107, 0x8021, /* 100baseFx */ 0x0108, 0x8021, /* 100baseFx-FD */ 0x0100, 0x009E, /* 10baseT */ 0x0104, 0x009E, /* 10baseT-FD */ 0x0103, 0x006D, /* 100baseTx */ 0x0105, 0x006D, /* 100baseTx-FD */ }}, {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ 0x0000, 0x009E, /* 10baseT */ 0x0004, 0x009E, /* 10baseT-FD */ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ }}, {0, 0, 0, 0, {}}};static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};/*********************************************************************//* Function Prototypes *//*********************************************************************/static int mdio_read(struct nic *nic, int phy_id, int location);static void mdio_write(struct nic *nic, int phy_id, int location, int value);static int read_eeprom(unsigned long ioaddr, int location, int addr_len);static void parse_eeprom(struct nic *nic);static int tulip_probe(struct dev *dev, struct pci_device *pci);static void tulip_init_ring(struct nic *nic);static void tulip_reset(struct nic *nic);static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);static int tulip_poll(struct nic *nic);static void tulip_disable(struct dev *dev);static void nway_start(struct nic *nic);static void pnic_do_nway(struct nic *nic);static void select_media(struct nic *nic, int startup);static void init_media(struct nic *nic);static void start_link(struct nic *nic);static int tulip_check_duplex(struct nic *nic);static void tulip_wait(unsigned int nticks);#ifdef TULIP_DEBUG_WHEREstatic void whereami(const char *str);#endif#ifdef TULIP_DEBUGstatic void tulip_more(void);#endif/*********************************************************************//* Utility Routines *//*********************************************************************/#ifdef TULIP_DEBUG_WHEREstatic void whereami (const char *str){ printf("%s: %s\n", tp->nic_name, str); /* sleep(2); */}#endif#ifdef TULIP_DEBUGstatic void tulip_more(void){ printf("\n\n-- more --"); while (!iskey()) /* wait */; getchar(); printf("\n\n");}#endif /* TULIP_DEBUG */static void tulip_wait(unsigned int nticks){ unsigned int to = currticks() + nticks; while (currticks() < to) /* wait */ ;}/*********************************************************************//* Media Descriptor Code *//*********************************************************************//* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. *//* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues or future 66Mhz PCI. */#define mdio_delay() inl(mdio_addr)/* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */#define MDIO_SHIFT_CLK 0x10000#define MDIO_DATA_WRITE0 0x00000#define MDIO_DATA_WRITE1 0x20000#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */#define MDIO_ENB_IN 0x40000#define MDIO_DATA_READ 0x80000/* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. */int mdio_read(struct nic *nic __unused, int phy_id, int location){ int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; long mdio_addr = ioaddr + CSR9;#ifdef TULIP_DEBUG_WHERE whereami("mdio_read\n");#endif if (tp->chip_id == LC82C168) { int i = 1000; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); inl(ioaddr + 0xA0); inl(ioaddr + 0xA0); while (--i > 0) if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) return retval & 0xffff; return 0xffff; } if (tp->chip_id == COMET) { if (phy_id == 1) { if (location < 7) return inl(ioaddr + 0xB4 + (location<<2)); else if (location == 17) return inl(ioaddr + 0xD0); else if (location >= 29 && location <= 31) return inl(ioaddr + 0xD4 + ((location-29)<<2)); } return 0xffff; } /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return (retval>>1) & 0xffff;}void mdio_write(struct nic *nic __unused, int phy_id, int location, int value){ int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; long mdio_addr = ioaddr + CSR9;#ifdef TULIP_DEBUG_WHERE whereami("mdio_write\n");#endif if (tp->chip_id == LC82C168) { int i = 1000; outl(cmd, ioaddr + 0xA0); do if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) break; while (--i > 0); return; } if (tp->chip_id == COMET) { if (phy_id != 1) return; if (location < 7) outl(value, ioaddr + 0xB4 + (location<<2)); else if (location == 17) outl(value, ioaddr + 0xD0); else if (location >= 29 && location <= 31) outl(value, ioaddr + 0xD4 + ((location-29)<<2)); return; } /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); }}/*********************************************************************//* EEPROM Reading Code *//*********************************************************************//* EEPROM routines adapted from the Linux Tulip Code *//* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/static int read_eeprom(unsigned long ioaddr, int location, int addr_len){ int i; unsigned short retval = 0; long ee_addr = ioaddr + CSR9; int read_cmd = location | EE_READ_CMD;#ifdef TULIP_DEBUG_WHERE whereami("read_eeprom\n");#endif outl(EE_ENB & ~EE_CS, ee_addr); outl(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outl(EE_ENB | dataval, ee_addr); eeprom_delay(); outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); } outl(EE_ENB, ee_addr); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); outl(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); return retval;}/*********************************************************************//* EEPROM Parsing Code */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -