📄 rtl8169.c
字号:
/**************************************************************************SEND - Transmit a frame***************************************************************************/static int rtl_send(struct eth_device *dev, volatile void *packet, int length){ /* send the packet to destination */ u32 to; u8 *ptxb; int entry = tpc->cur_tx % NUM_TX_DESC; u32 len = length;#ifdef DEBUG_RTL8169_TX int stime = currticks(); printf ("%s\n", __FUNCTION__); printf("sending %d bytes\n", len);#endif ioaddr = dev->iobase; /* point to the current txb incase multiple tx_rings are used */ ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE]; memcpy(ptxb, (char *)packet, (int)length); while (len < ETH_ZLEN) ptxb[len++] = '\0'; tpc->TxDescArray[entry].buf_addr = virt_to_bus(ptxb); if (entry != (NUM_TX_DESC - 1)) { tpc->TxDescArray[entry].status = (OWNbit | FSbit | LSbit) | ((len > ETH_ZLEN) ? len : ETH_ZLEN); } else { tpc->TxDescArray[entry].status = (OWNbit | EORbit | FSbit | LSbit) | ((len > ETH_ZLEN) ? length : ETH_ZLEN); } RTL_W8(TxPoll, 0x40); /* set polling bit */ tpc->cur_tx++; to = currticks() + TX_TIMEOUT; while ((tpc->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */ if (currticks() >= to) {#ifdef DEBUG_RTL8169_TX puts ("tx timeout/error\n"); printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);#endif return 0; } else {#ifdef DEBUG_RTL8169_TX puts("tx done\n");#endif return length; }}static void rtl8169_set_rx_mode(struct eth_device *dev){ u32 mc_filter[2]; /* Multicast hash filter */ int rx_mode; u32 tmp = 0;#ifdef DEBUG_RTL8169 printf ("%s\n", __FUNCTION__);#endif /* IFF_ALLMULTI */ /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; tmp = rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) & rtl_chip_info[tpc->chipset].RxConfigMask); RTL_W32(RxConfig, tmp); RTL_W32(MAR0 + 0, mc_filter[0]); RTL_W32(MAR0 + 4, mc_filter[1]);}static void rtl8169_hw_start(struct eth_device *dev){ u32 i;#ifdef DEBUG_RTL8169 int stime = currticks(); printf ("%s\n", __FUNCTION__);#endif#if 0 /* Soft reset the chip. */ RTL_W8(ChipCmd, CmdReset); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; else udelay(10); }#endif RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(EarlyTxThres, EarlyTxThld); /* For gigabit rtl8169 */ RTL_W16(RxMaxSize, RxPacketMaxSize); /* Set Rx Config register */ i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tpc->chipset].RxConfigMask); RTL_W32(RxConfig, i); /* Set DMA burst size and Interframe Gap Time */ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift)); tpc->cur_rx = 0; RTL_W32(TxDescStartAddr, virt_to_le32desc(tpc->TxDescArray)); RTL_W32(RxDescStartAddr, virt_to_le32desc(tpc->RxDescArray)); RTL_W8(Cfg9346, Cfg9346_Lock); udelay(10); RTL_W32(RxMissed, 0); rtl8169_set_rx_mode(dev); /* no early-rx interrupts */ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);#ifdef DEBUG_RTL8169 printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);#endif}static void rtl8169_init_ring(struct eth_device *dev){ int i;#ifdef DEBUG_RTL8169 int stime = currticks(); printf ("%s\n", __FUNCTION__);#endif tpc->cur_rx = 0; tpc->cur_tx = 0; tpc->dirty_tx = 0; memset(tpc->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc)); memset(tpc->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc)); for (i = 0; i < NUM_TX_DESC; i++) { tpc->Tx_skbuff[i] = &txb[i]; } for (i = 0; i < NUM_RX_DESC; i++) { if (i == (NUM_RX_DESC - 1)) tpc->RxDescArray[i].status = (OWNbit | EORbit) + RX_BUF_SIZE; else tpc->RxDescArray[i].status = OWNbit + RX_BUF_SIZE; tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; tpc->RxDescArray[i].buf_addr = virt_to_bus(tpc->RxBufferRing[i]); }#ifdef DEBUG_RTL8169 printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);#endif}/**************************************************************************RESET - Finish setting up the ethernet interface***************************************************************************/static void rtl_reset(struct eth_device *dev, bd_t *bis){ int i; u8 diff; u32 TxPhyAddr, RxPhyAddr;#ifdef DEBUG_RTL8169 int stime = currticks(); printf ("%s\n", __FUNCTION__);#endif tpc->TxDescArrays = tx_ring; if (tpc->TxDescArrays == 0) puts("Allot Error"); /* Tx Desscriptor needs 256 bytes alignment; */ TxPhyAddr = virt_to_bus(tpc->TxDescArrays); diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8)); TxPhyAddr += diff; tpc->TxDescArray = (struct TxDesc *) (tpc->TxDescArrays + diff); tpc->RxDescArrays = rx_ring; /* Rx Desscriptor needs 256 bytes alignment; */ RxPhyAddr = virt_to_bus(tpc->RxDescArrays); diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8)); RxPhyAddr += diff; tpc->RxDescArray = (struct RxDesc *) (tpc->RxDescArrays + diff); if (tpc->TxDescArrays == NULL || tpc->RxDescArrays == NULL) { puts("Allocate RxDescArray or TxDescArray failed\n"); return; } rtl8169_init_ring(dev); rtl8169_hw_start(dev); /* Construct a perfect filter frame with the mac address as first match * and broadcast for all others */ for (i = 0; i < 192; i++) txb[i] = 0xFF; txb[0] = dev->enetaddr[0]; txb[1] = dev->enetaddr[1]; txb[2] = dev->enetaddr[2]; txb[3] = dev->enetaddr[3]; txb[4] = dev->enetaddr[4]; txb[5] = dev->enetaddr[5];#ifdef DEBUG_RTL8169 printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime);#endif}/**************************************************************************HALT - Turn off ethernet interface***************************************************************************/static void rtl_halt(struct eth_device *dev){ int i;#ifdef DEBUG_RTL8169 printf ("%s\n", __FUNCTION__);#endif ioaddr = dev->iobase; /* Stop the chip's Tx and Rx DMA processes. */ RTL_W8(ChipCmd, 0x00); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16(IntrMask, 0x0000); RTL_W32(RxMissed, 0); tpc->TxDescArrays = NULL; tpc->RxDescArrays = NULL; tpc->TxDescArray = NULL; tpc->RxDescArray = NULL; for (i = 0; i < NUM_RX_DESC; i++) { tpc->RxBufferRing[i] = NULL; }}/**************************************************************************INIT - Look for an adapter, this routine's visible to the outside***************************************************************************/#define board_found 1#define valid_link 0static int rtl_init(struct eth_device *dev, bd_t *bis){ static int board_idx = -1; static int printed_version = 0; int i, rc; int option = -1, Cap10_100 = 0, Cap1000 = 0;#ifdef DEBUG_RTL8169 printf ("%s\n", __FUNCTION__);#endif ioaddr = dev->iobase; board_idx++; printed_version = 1; /* point to private storage */ tpc = &tpx; rc = rtl8169_init_board(dev); if (rc) return rc; /* Get MAC address. FIXME: read EEPROM */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->enetaddr[i] = RTL_R8(MAC0 + i);#ifdef DEBUG_RTL8169 printf("MAC Address"); for (i = 0; i < MAC_ADDR_LEN; i++) printf(":%02x", dev->enetaddr[i]); putc('\n');#endif#ifdef DEBUG_RTL8169 /* Print out some hardware info */ printf("%s: at ioaddr 0x%x\n", dev->name, ioaddr);#endif /* if TBI is not endbled */ if (!(RTL_R8(PHYstatus) & TBI_Enable)) { int val = mdio_read(PHY_AUTO_NEGO_REG); option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; /* Force RTL8169 in 10/100/1000 Full/Half mode. */ if (option > 0) {#ifdef DEBUG_RTL8169 printf("%s: Force-mode Enabled.\n", dev->name);#endif Cap10_100 = 0, Cap1000 = 0; switch (option) { case _10_Half: Cap10_100 = PHY_Cap_10_Half; Cap1000 = PHY_Cap_Null; break; case _10_Full: Cap10_100 = PHY_Cap_10_Full; Cap1000 = PHY_Cap_Null; break; case _100_Half: Cap10_100 = PHY_Cap_100_Half; Cap1000 = PHY_Cap_Null; break; case _100_Full: Cap10_100 = PHY_Cap_100_Full; Cap1000 = PHY_Cap_Null; break; case _1000_Full: Cap10_100 = PHY_Cap_Null; Cap1000 = PHY_Cap_1000_Full; break; default: break; } mdio_write(PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F)); /* leave PHY_AUTO_NEGO_REG bit4:0 unchanged */ mdio_write(PHY_1000_CTRL_REG, Cap1000); } else {#ifdef DEBUG_RTL8169 printf("%s: Auto-negotiation Enabled.\n", dev->name);#endif /* enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged */ mdio_write(PHY_AUTO_NEGO_REG, PHY_Cap_10_Half | PHY_Cap_10_Full | PHY_Cap_100_Half | PHY_Cap_100_Full | (val & 0x1F)); /* enable 1000 Full Mode */ mdio_write(PHY_1000_CTRL_REG, PHY_Cap_1000_Full); } /* Enable auto-negotiation and restart auto-nigotiation */ mdio_write(PHY_CTRL_REG, PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego); udelay(100); /* wait for auto-negotiation process */ for (i = 10000; i > 0; i--) { /* check if auto-negotiation complete */ if (mdio_read(PHY_STAT_REG) & PHY_Auto_Neco_Comp) { udelay(100); option = RTL_R8(PHYstatus); if (option & _1000bpsF) {#ifdef DEBUG_RTL8169 printf("%s: 1000Mbps Full-duplex operation.\n", dev->name);#endif } else {#ifdef DEBUG_RTL8169 printf ("%s: %sMbps %s-duplex operation.\n", dev->name, (option & _100bps) ? "100" : "10", (option & FullDup) ? "Full" : "Half");#endif } break; } else { udelay(100); } } /* end for-loop to wait for auto-negotiation process */ } else { udelay(100);#ifdef DEBUG_RTL8169 printf ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n", dev->name, (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");#endif } return 1;}int rtl8169_initialize(bd_t *bis){ pci_dev_t devno; int card_number = 0; struct eth_device *dev; u32 iobase; int idx=0; while(1){ /* Find RTL8169 */ if ((devno = pci_find_devices(supported, idx++)) < 0) break; pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase); iobase &= ~0xf; debug ("rtl8169: REALTEK RTL8169 @0x%x\n", iobase); dev = (struct eth_device *)malloc(sizeof *dev); sprintf (dev->name, "RTL8169#%d", card_number); dev->priv = (void *) devno; dev->iobase = (int)bus_to_phys(iobase); dev->init = rtl_reset; dev->halt = rtl_halt; dev->send = rtl_send; dev->recv = rtl_recv; eth_register (dev); rtl_init(dev, bis); card_number++; } return card_number;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -