📄 rtl81xx.c
字号:
if (i < MACADDR_LEN - 1) uart_puts(":"); } uart_puts("\n"); // Setup MAC address, only permits access by 4 bytes // Before programming the IDR registers, unlock some registers rtl81xx_writel(CR93C46_EEM_CONFIGWEN, REG_CR93C46); for (i = 0; i < 2; ++i) rtl81xx_writel(((unsigned int *) dev->dev_addr)[i], REG_IDR + i * 4); rtl81xx_writel(CR93C46_EEM_NORMAL, REG_CR93C46); // enable Rx and Tx rtl81xx_writeb(CR_TE | CR_RE, REG_CR); rtl81xx_writel(g_rx_config, REG_RCR); rtl81xx_writel(g_tx_config, REG_TCR); // disable early rx interrupt rtl81xx_writew(rtl81xx_readw(REG_MULINT) & 0xf000, REG_MULINT); // setup Rx and Tx buffer rtl81xx_writel(db->rx_buf_dma, REG_RBSTART); for (i = 0; i < TX_DESC_NUM; ++i) rtl81xx_writel(db->tx_bufs_dma[i], REG_TSAD0 + i * 4); db->rx_cur = 0; db->tx_cur = 0; db->tx_last = 0; // enable interrupt rtl81xx_writew(g_imr, REG_IMR); return 0;}int rtl81xx_open(struct net_device *dev){ board_info_t *db = (board_info_t *) dev->priv; rtl81xx_init(dev); em86xx_request_irq(db->pcidev.irqline, rtl81xx_irq, dev); dev->state = NETDEV_UP; return 0;}int rtl81xx_close(struct net_device *dev){ board_info_t *db = (board_info_t *) dev->priv; /* Disable TX/RX */ rtl81xx_writeb(0, REG_CR); em86xx_free_irq(db->pcidev.irqline); dev->state = NETDEV_DOWN; return 0;}int rtl81xx_rx_interrupt(struct net_device *dev){ board_info_t *db = (board_info_t *) dev->priv; struct sk_buff *skb; unsigned int rx_cur = db->rx_cur; int npacket = 0;#if RTL81XX_VERBOSE uart_printf("RX : CBR = %04x, CAPR = %04x, rx_cur = %08x\n", rtl81xx_readw(REG_CBR), rtl81xx_readw(REG_CAPR), rx_cur);#endif for (;;) { int offset = rx_cur & (RX_BUF_LEN - 1); unsigned int rx_status, rx_size; // if Rx buffer is empty, clear Rx interrupt and exit if (rtl81xx_readb(REG_CR) & CR_BUFE) { if (rtl81xx_readw(REG_ISR) & ISR_ROK) rtl81xx_writew(ISR_ROK, REG_ISR); break; } // flush cache because transfer is done by PCI bus mastering em86xx_flush_cache_data_region(db->rx_buf + offset, db->rx_buf + offset + ETH_BUF_LEN); // read packet information rx_status = *(unsigned int *) (db->rx_buf + offset); rx_size = rx_status >> 16; // check the validity of packet if (rx_size > ETH_BUF_LEN + 4 || rx_size <= 16 + 4) { uart_printf("RTL81XX: Received invalid packet size %d\n", rx_size - 4); return -1; } if ((rx_status & RXHEADER_ROK) == 0) { uart_printf("RTL81XX: Received error packet\n"); return -1; }#if RTL81XX_VERBOSE { int i; unsigned char *ptr = (unsigned char *) db->rx_buf + offset + 4; uart_printf(" size = %d : ", rx_size); for (i = 0; i < 12; ++i) uart_printf("%02X ", ptr[i]); uart_puts("\n"); }#endif // copy packet : packet size is rx_size - header size (4 bytes) ++npacket; if ((skb = skb_alloc(rx_size)) != NULL) { skb->len = rx_size - 4; memcpy(skb->data, (void *) (db->rx_buf + offset + 4), skb->len); skb_put(skb); } // update pointer, align on 32 bits boundary db->rx_cur = rx_cur = (rx_cur + rx_size + 4 + 3) & ~3; rtl81xx_writew(rx_cur - 16, REG_CAPR); } return npacket;}void rtl81xx_tx_interrupt(struct net_device *dev){ board_info_t *db = (board_info_t *) dev->priv; unsigned int status; int i, idx; for (i = db->tx_last; i < db->tx_cur; ++i) { idx = i % TX_DESC_NUM; status = rtl81xx_readl(REG_TSD0 + idx * 4); if (status & (TSD_TABT | TSD_OWC | TSD_TUN)) { uart_printf("RTL81XX: Transmit failed for %d\n", i); // if abort, clear abort bit if (status & TSD_TABT) { rtl81xx_writel(TCR_CLRABT, REG_TCR); rtl81xx_writew(ISR_TER, REG_ISR); } } else if (status & TSD_TOK) {#if RTL81XX_VERBOSE uart_printf("TX : Success %d\n", i);#endif } else break; skb_free((struct sk_buff *) db->tx_skb[idx]); db->tx_skb[idx] = NULL; ++db->tx_last; }}void rtl81xx_irq(int irq, void *pdata){ struct net_device *dev = (struct net_device *) pdata; unsigned int isr; while ((isr = rtl81xx_readw(REG_ISR)) != 0) {/*if (isr & ISR_ROK)uart_puts("[R]");if (isr & ISR_TOK)uart_puts("[t]");*/#if RTL81XX_VERBOSE uart_puts("[ "); if (isr & ISR_ROK) uart_puts("RxOK "); if (isr & ISR_RER) uart_puts("RxErr "); if (isr & ISR_TOK) uart_puts("TxOK "); if (isr & ISR_TER) uart_puts("TxErr "); if (isr & ISR_RXOVW) uart_puts("RxOverflow "); if (isr & ISR_PUNLINKCHG) uart_puts("Underrun "); if (isr & ISR_FOVW) uart_puts("RxFifoOverflow "); if (isr & ISR_LENCHG) uart_puts("LenChange "); if (isr & ISR_TIMEOUT) uart_puts("Timeout "); if (isr & ISR_SERR) uart_puts("SERR "); uart_puts("]\n");#endif if (isr & (ISR_RXOVW | ISR_FOVW)) uart_puts("RTL81XX: Buffer overflow error\n"); rtl81xx_writew(isr & ~(ISR_ROK | ISR_FOVW | ISR_RXOVW | ISR_TER), REG_ISR); if (isr & (ISR_ROK | ISR_FOVW | ISR_RXOVW)) rtl81xx_rx_interrupt(dev); if (isr & (ISR_RER | ISR_RXOVW | ISR_PUNLINKCHG | ISR_FOVW | ISR_TIMEOUT | ISR_SERR)) { if (isr & (ISR_RXOVW | ISR_FOVW)) rtl81xx_writew(ISR_RXOVW | ISR_FOVW, REG_ISR); } if (isr & (ISR_TOK | ISR_TER)) rtl81xx_tx_interrupt(dev); }}int rtl81xx_send_packet(struct sk_buff *skb, struct net_device *dev, int async){ board_info_t *db = (board_info_t *) dev->priv; int tx_cur = db->tx_cur % TX_DESC_NUM; unsigned int len = skb->len; // check the validity of packet if (skb->len > ETH_BUF_LEN) { uart_printf("RTL81XX: Packet size too big (%d)\n", skb->len); return 1; } // copy payload if (skb->len < ETH_ZLEN) { memset((void *) db->tx_bufs[tx_cur], 0, ETH_ZLEN); len = ETH_ZLEN; } memcpy((void *) db->tx_bufs[tx_cur], skb->data, skb->len); em86xx_clean_cache_data_region(db->tx_bufs[tx_cur], db->tx_bufs[tx_cur] + skb->len); // update data structure db->tx_skb[tx_cur] = skb; ++db->tx_cur; // set TSD register//uart_puts("[T]");#if RTL81XX_VERBOSE uart_printf("TX: Transmit packet %d\n", tx_cur);#if 0 { struct sk_buff *new_skb = skb_dup(skb); ipv4_dump_packet(new_skb, 0, 1); skb_free(new_skb); }#endif#endif rtl81xx_writel(g_tsd | len, REG_TSD0 + tx_cur * 4); // wait for the completion if (!async) { unsigned int startticks = timer_getticks(); // check current mode and interrupt status // synchronous mode must not be used in interrupt mode if (!em86xx_irqenabled()) { uart_puts("RTL81XX: Interrupt is disabled in synchronous mode\n"); return 0; } do { if (db->tx_skb[tx_cur] == NULL) return 0; } while (!timer_timeout(startticks, 3000)); uart_printf("RTL81XX: Transmit failure %d\n", db->tx_cur - 1); rtl81xx_writel(0, REG_TSD0 + tx_cur * 4); skb_free(skb); } return 0;}int rtl81xx_receive_packet(struct net_device *dev){ board_info_t *db = (board_info_t *) dev->priv; em86xx_mask_irq(db->pcidev.irqline); // if (rtl81xx_readw(REG_ISR) & ISR_ROK) // return rtl81xx_rx_interrupt(dev); rtl81xx_irq(0, dev); em86xx_unmask_irq(db->pcidev.irqline); return 0;}void rtl81xx_print_status(struct net_device *dev){}//// Supplmentary functions//void rtl81xx_chip_reset(void){ /* Disable TX/RX */ rtl81xx_writeb(0, REG_CR); // send reset command rtl81xx_writeb(CR_RST, REG_CR); // wait for reset is done while (rtl81xx_readb(REG_CR) & CR_RST) ;}#define rtl81xx_eeprom_delay() rtl81xx_readb(REG_CR)#define rtl81xx_eeprom_strobe(data, sk) rtl81xx_writeb(CR93C46_EEM_PROGRAM | CR93C46_EECS | (data) | ((sk) ? CR93C46_EESK : 0), REG_CR93C46)#define rtl81xx_read_eeprom_bit() ((rtl81xx_readb(REG_CR93C46) & CR93C46_EEDO) ? 1 : 0)#define rtl81xx_write_eeprom_bit(bit, sk) rtl81xx_eeprom_strobe((bit) ? CR93C46_EEDI : 0, sk)__inline__ void rtl81xx_write_eeprom_bits(int data, int bits){ int i; // send bits (MSB first) for (i = bits - 1; i >= 0; --i) { rtl81xx_write_eeprom_bit(data & (1 << i), 0); rtl81xx_eeprom_delay(); rtl81xx_write_eeprom_bit(data & (1 << i), 1); rtl81xx_eeprom_delay(); }}__inline__ unsigned int rtl81xx_read_eeprom_bits(int bits){ int i; unsigned int data = 0; for (i = 0; i < bits; ++i) { rtl81xx_eeprom_strobe(0, 1); rtl81xx_eeprom_delay(); data <<= 1; data |= rtl81xx_read_eeprom_bit(); rtl81xx_eeprom_strobe(0, 0); rtl81xx_eeprom_delay(); } return data;}// addr : address// addr_len : bits of addressunsigned int rtl81xx_read_eeprom(int addr, int addr_len){ unsigned int data; // start EEPROM access rtl81xx_writeb(CR93C46_EEM_PROGRAM, REG_CR93C46); rtl81xx_writeb(CR93C46_EEM_PROGRAM | CR93C46_EECS, REG_CR93C46); rtl81xx_eeprom_delay(); // sends 5 bits command rtl81xx_write_eeprom_bits(CR93C46_CMD_READ, 5); // sends address rtl81xx_write_eeprom_bits(addr, addr_len); rtl81xx_eeprom_strobe(0, 0); rtl81xx_eeprom_delay(); // read 16 bits data data = rtl81xx_read_eeprom_bits(16); // terminate EEPROM access rtl81xx_writeb(0, REG_CR93C46); rtl81xx_eeprom_delay(); return data;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -