📄 tulip.c
字号:
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)));#ifdef USE_LOWMEM_BUFFER#define txb ((char *)0x10000 - BUFLEN)#elsestatic unsigned char txb[BUFLEN] __attribute__ ((aligned(4)));#endif#define RX_RING_SIZE 4static struct tulip_rx_desc rx_ring[RX_RING_SIZE] __attribute__ ((aligned(4)));#ifdef USE_LOWMEM_BUFFER#define rxb ((char *)0x10000 - RX_RING_SIZE * BUFLEN - BUFLEN)#elsestatic unsigned char rxb[RX_RING_SIZE * BUFLEN] __attribute__ ((aligned(4)));#endifstatic 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);struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, 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 nic *nic);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, 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, 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -