📄 rtl8139.c
字号:
}/* Serial EEPROM section. *//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */#define EE_CS 0x08 /* EEPROM chip select. */#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */#define EE_WRITE_0 0x00#define EE_WRITE_1 0x02#define EE_DATA_READ 0x01 /* EEPROM chip data out. */#define EE_ENB (0x80 | EE_CS)/* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.*/#define eeprom_delay() inl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5)#define EE_READ_CMD (6)#define EE_ERASE_CMD (7)static int read_eeprom(int location, int addr_len){ int i; unsigned int retval = 0; long ee_addr = ioaddr + Cfg9346; int read_cmd = location | (EE_READ_CMD << addr_len); outb(EE_ENB & ~EE_CS, ee_addr); outb(EE_ENB, ee_addr); eeprom_delay(); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outb(EE_ENB | dataval, ee_addr); eeprom_delay(); outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); } outb(EE_ENB, ee_addr); eeprom_delay(); for (i = 16; i > 0; i--) { outb(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); outb(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outb(~EE_CS, ee_addr); eeprom_delay(); return retval;}static const unsigned int rtl8139_rx_config = (RX_BUF_LEN_IDX << 11) | (RX_FIFO_THRESH << 13) | (RX_DMA_BURST << 8);static void set_rx_mode(struct eth_device *dev) { unsigned int mc_filter[2]; int rx_mode; /* !IFF_PROMISC */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; outl(rtl8139_rx_config | rx_mode, ioaddr + RxConfig); outl(mc_filter[0], ioaddr + MAR0 + 0); outl(mc_filter[1], ioaddr + MAR0 + 4);}static void rtl_reset(struct eth_device *dev){ int i; outb(CmdReset, ioaddr + ChipCmd); cur_rx = 0; cur_tx = 0; /* Give the chip 10ms to finish the reset. */ for (i=0; i<100; ++i){ if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break; udelay (100); /* wait 100us */ } for (i = 0; i < ETH_ALEN; i++) outb(dev->enetaddr[i], ioaddr + MAC0 + i); /* Must enable Tx/Rx before setting transfer thresholds! */ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8), ioaddr + RxConfig); /* accept no frames yet! */ outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig); /* The Linux driver changes Config1 here to use a different LED pattern * for half duplex or full/autodetect duplex (for full/autodetect, the * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses * TX/RX, Link100, Link10). This is messy, because it doesn't match * the inscription on the mounting bracket. It should not be changed * from the configuration EEPROM default, because the card manufacturer * should have set that to match the card. */#ifdef DEBUG_RX printf("rx ring address is %X\n",(unsigned long)rx_ring);#endif outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf); /* If we add multicast support, the MAR0 register would have to be * initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); outl(rtl8139_rx_config, ioaddr + RxConfig); /* Start the chip's Tx and Rx process. */ outl(0, ioaddr + RxMissed); /* set_rx_mode */ set_rx_mode(dev); /* Disable all known interrupts by setting the interrupt mask. */ outw(0, ioaddr + IntrMask);}static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length){ unsigned int status, to; unsigned long txstatus; unsigned int len = length; ioaddr = dev->iobase; memcpy((char *)tx_buffer, (char *)packet, (int)length);#ifdef DEBUG_TX printf("sending %d bytes\n", len);#endif /* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4 * bytes are sent automatically for the FCS, totalling to 64 bytes). */ while (len < ETH_ZLEN) { tx_buffer[len++] = '\0'; } outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4); outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len, ioaddr + TxStatus0 + cur_tx*4); to = currticks() + RTL_TIMEOUT; do { status = inw(ioaddr + IntrStatus); /* Only acknlowledge interrupt sources we can properly handle * here - the RxOverflow/RxFIFOOver MUST be handled in the * rtl_poll() function. */ outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus); if ((status & (TxOK | TxErr | PCIErr)) != 0) break; } while (currticks() < to); txstatus = inl(ioaddr + TxStatus0 + cur_tx*4); if (status & TxOK) { cur_tx = (cur_tx + 1) % NUM_TX_DESC;#ifdef DEBUG_TX printf("tx done (%d ticks), status %hX txstatus %X\n", to-currticks(), status, txstatus);#endif return length; } else {#ifdef DEBUG_TX printf("tx timeout/error (%d ticks), status %hX txstatus %X\n", currticks()-to, status, txstatus);#endif rtl_reset(dev); return 0; }}static int rtl_poll(struct eth_device *dev){ unsigned int status; unsigned int ring_offs; unsigned int rx_size, rx_status; int length=0; ioaddr = dev->iobase; if (inb(ioaddr + ChipCmd) & RxBufEmpty) { return 0; } status = inw(ioaddr + IntrStatus); /* See below for the rest of the interrupt acknowledges. */ outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);#ifdef DEBUG_RX printf("rtl_poll: int %hX ", status);#endif ring_offs = cur_rx % RX_BUF_LEN; rx_status = *(unsigned int*)KSEG1ADDR((rx_ring + ring_offs)); rx_size = rx_status >> 16; rx_status &= 0xffff; if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) || (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) { printf("rx error %hX\n", rx_status); rtl_reset(dev); /* this clears all interrupts still pending */ return 0; } /* Received a good packet */ length = rx_size - 4; /* no one cares about the FCS */ if (ring_offs+4+rx_size-4 > RX_BUF_LEN) { int semi_count = RX_BUF_LEN - ring_offs - 4; unsigned char rxdata[RX_BUF_LEN]; memcpy(rxdata, rx_ring + ring_offs + 4, semi_count); memcpy(&(rxdata[semi_count]), rx_ring, rx_size-4-semi_count); NetReceive(rxdata, length);#ifdef DEBUG_RX printf("rx packet %d+%d bytes", semi_count,rx_size-4-semi_count);#endif } else { NetReceive(rx_ring + ring_offs + 4, length);#ifdef DEBUG_RX printf("rx packet %d bytes", rx_size-4);#endif } cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; outw(cur_rx - 16, ioaddr + RxBufPtr); /* See RTL8139 Programming Guide V0.1 for the official handling of * Rx overflow situations. The document itself contains basically no * usable information, except for a few exception handling rules. */ outw(status & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus); return length;}static void rtl_disable(struct eth_device *dev){ int i; ioaddr = dev->iobase; /* reset the chip */ outb(CmdReset, ioaddr + ChipCmd); /* Give the chip 10ms to finish the reset. */ for (i=0; i<100; ++i){ if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break; udelay (100); /* wait 100us */ }}#endif /* CFG_CMD_NET && CONFIG_NET_MULTI && CONFIG_RTL8139 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -