17c478bd9Sstevel@tonic-gate /**************************************************************************
27c478bd9Sstevel@tonic-gate * r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit
37c478bd9Sstevel@tonic-gate * Written 2003 by Timothy Legge <tlegge@rogers.com>
47c478bd9Sstevel@tonic-gate *
57c478bd9Sstevel@tonic-gate * This program is free software; you can redistribute it and/or modify
67c478bd9Sstevel@tonic-gate * it under the terms of the GNU General Public License as published by
77c478bd9Sstevel@tonic-gate * the Free Software Foundation; either version 2 of the License, or
87c478bd9Sstevel@tonic-gate * (at your option) any later version.
97c478bd9Sstevel@tonic-gate *
107c478bd9Sstevel@tonic-gate * This program is distributed in the hope that it will be useful,
117c478bd9Sstevel@tonic-gate * but WITHOUT ANY WARRANTY; without even the implied warranty of
127c478bd9Sstevel@tonic-gate * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
137c478bd9Sstevel@tonic-gate * GNU General Public License for more details.
147c478bd9Sstevel@tonic-gate *
157c478bd9Sstevel@tonic-gate * You should have received a copy of the GNU General Public License
167c478bd9Sstevel@tonic-gate * along with this program; if not, write to the Free Software
177c478bd9Sstevel@tonic-gate * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * Portions of this code based on:
207c478bd9Sstevel@tonic-gate * r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver
217c478bd9Sstevel@tonic-gate * for Linux kernel 2.4.x.
227c478bd9Sstevel@tonic-gate *
237c478bd9Sstevel@tonic-gate * Written 2002 ShuChen <shuchen@realtek.com.tw>
247c478bd9Sstevel@tonic-gate * See Linux Driver for full information
257c478bd9Sstevel@tonic-gate *
267c478bd9Sstevel@tonic-gate * Linux Driver Version 1.27a, 10.02.2002
277c478bd9Sstevel@tonic-gate *
287c478bd9Sstevel@tonic-gate * Thanks to:
297c478bd9Sstevel@tonic-gate * Jean Chen of RealTek Semiconductor Corp. for
307c478bd9Sstevel@tonic-gate * providing the evaluation NIC used to develop
317c478bd9Sstevel@tonic-gate * this driver. RealTek's support for Etherboot
327c478bd9Sstevel@tonic-gate * is appreciated.
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * REVISION HISTORY:
357c478bd9Sstevel@tonic-gate * ================
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * v1.0 11-26-2003 timlegge Initial port of Linux driver
387c478bd9Sstevel@tonic-gate * v1.5 01-17-2004 timlegge Initial driver output cleanup
397c478bd9Sstevel@tonic-gate * v1.6 03-27-2004 timlegge Additional Cleanup
407c478bd9Sstevel@tonic-gate *
417c478bd9Sstevel@tonic-gate * Indent Options: indent -kr -i8
427c478bd9Sstevel@tonic-gate ***************************************************************************/
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate /* to get some global routines like printf */
457c478bd9Sstevel@tonic-gate #include "etherboot.h"
467c478bd9Sstevel@tonic-gate /* to get the interface to the body of the program */
477c478bd9Sstevel@tonic-gate #include "nic.h"
487c478bd9Sstevel@tonic-gate /* to get the PCI support functions, if this is a PCI NIC */
497c478bd9Sstevel@tonic-gate #include "pci.h"
507c478bd9Sstevel@tonic-gate #include "timer.h"
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate #define drv_version "v1.6"
537c478bd9Sstevel@tonic-gate #define drv_date "03-27-2004"
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate typedef unsigned char u8;
567c478bd9Sstevel@tonic-gate typedef signed char s8;
577c478bd9Sstevel@tonic-gate typedef unsigned short u16;
587c478bd9Sstevel@tonic-gate typedef signed short s16;
597c478bd9Sstevel@tonic-gate typedef unsigned int u32;
607c478bd9Sstevel@tonic-gate typedef signed int s32;
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate #define HZ 1000
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate static u32 ioaddr;
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate #ifdef EDEBUG
677c478bd9Sstevel@tonic-gate #define dprintf(x) printf x
687c478bd9Sstevel@tonic-gate #else
697c478bd9Sstevel@tonic-gate #define dprintf(x)
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate /* Condensed operations for readability. */
737c478bd9Sstevel@tonic-gate #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
747c478bd9Sstevel@tonic-gate #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /* media options
797c478bd9Sstevel@tonic-gate _10_Half = 0x01,
807c478bd9Sstevel@tonic-gate _10_Full = 0x02,
817c478bd9Sstevel@tonic-gate _100_Half = 0x04,
827c478bd9Sstevel@tonic-gate _100_Full = 0x08,
837c478bd9Sstevel@tonic-gate _1000_Full = 0x10,
847c478bd9Sstevel@tonic-gate */
857c478bd9Sstevel@tonic-gate static int media = -1;
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate #if 0
887c478bd9Sstevel@tonic-gate /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
897c478bd9Sstevel@tonic-gate static int max_interrupt_work = 20;
907c478bd9Sstevel@tonic-gate #endif
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate #if 0
937c478bd9Sstevel@tonic-gate /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
947c478bd9Sstevel@tonic-gate The RTL chips use a 64 element hash table based on the Ethernet CRC. */
957c478bd9Sstevel@tonic-gate static int multicast_filter_limit = 32;
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate /* MAC address length*/
997c478bd9Sstevel@tonic-gate #define MAC_ADDR_LEN 6
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate /* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
1027c478bd9Sstevel@tonic-gate #define MAX_ETH_FRAME_SIZE 1536
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate #define TX_FIFO_THRESH 256 /* In bytes */
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate #define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
1077c478bd9Sstevel@tonic-gate #define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
1087c478bd9Sstevel@tonic-gate #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
1097c478bd9Sstevel@tonic-gate #define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
1107c478bd9Sstevel@tonic-gate #define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */
1117c478bd9Sstevel@tonic-gate #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate #define NUM_TX_DESC 1 /* Number of Tx descriptor registers */
1147c478bd9Sstevel@tonic-gate #define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
1157c478bd9Sstevel@tonic-gate #define RX_BUF_SIZE 1536 /* Rx Buffer size */
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate #define RTL_MIN_IO_SIZE 0x80
1187c478bd9Sstevel@tonic-gate #define TX_TIMEOUT (6*HZ)
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate /* write/read MMIO register */
1217c478bd9Sstevel@tonic-gate #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
1227c478bd9Sstevel@tonic-gate #define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
1237c478bd9Sstevel@tonic-gate #define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
1247c478bd9Sstevel@tonic-gate #define RTL_R8(reg) readb (ioaddr + (reg))
1257c478bd9Sstevel@tonic-gate #define RTL_R16(reg) readw (ioaddr + (reg))
1267c478bd9Sstevel@tonic-gate #define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate enum RTL8169_registers {
1297c478bd9Sstevel@tonic-gate MAC0 = 0, /* Ethernet hardware address. */
1307c478bd9Sstevel@tonic-gate MAR0 = 8, /* Multicast filter. */
1317c478bd9Sstevel@tonic-gate TxDescStartAddr = 0x20,
1327c478bd9Sstevel@tonic-gate TxHDescStartAddr = 0x28,
1337c478bd9Sstevel@tonic-gate FLASH = 0x30,
1347c478bd9Sstevel@tonic-gate ERSR = 0x36,
1357c478bd9Sstevel@tonic-gate ChipCmd = 0x37,
1367c478bd9Sstevel@tonic-gate TxPoll = 0x38,
1377c478bd9Sstevel@tonic-gate IntrMask = 0x3C,
1387c478bd9Sstevel@tonic-gate IntrStatus = 0x3E,
1397c478bd9Sstevel@tonic-gate TxConfig = 0x40,
1407c478bd9Sstevel@tonic-gate RxConfig = 0x44,
1417c478bd9Sstevel@tonic-gate RxMissed = 0x4C,
1427c478bd9Sstevel@tonic-gate Cfg9346 = 0x50,
1437c478bd9Sstevel@tonic-gate Config0 = 0x51,
1447c478bd9Sstevel@tonic-gate Config1 = 0x52,
1457c478bd9Sstevel@tonic-gate Config2 = 0x53,
1467c478bd9Sstevel@tonic-gate Config3 = 0x54,
1477c478bd9Sstevel@tonic-gate Config4 = 0x55,
1487c478bd9Sstevel@tonic-gate Config5 = 0x56,
1497c478bd9Sstevel@tonic-gate MultiIntr = 0x5C,
1507c478bd9Sstevel@tonic-gate PHYAR = 0x60,
1517c478bd9Sstevel@tonic-gate TBICSR = 0x64,
1527c478bd9Sstevel@tonic-gate TBI_ANAR = 0x68,
1537c478bd9Sstevel@tonic-gate TBI_LPAR = 0x6A,
1547c478bd9Sstevel@tonic-gate PHYstatus = 0x6C,
1557c478bd9Sstevel@tonic-gate RxMaxSize = 0xDA,
1567c478bd9Sstevel@tonic-gate CPlusCmd = 0xE0,
1577c478bd9Sstevel@tonic-gate RxDescStartAddr = 0xE4,
1587c478bd9Sstevel@tonic-gate EarlyTxThres = 0xEC,
1597c478bd9Sstevel@tonic-gate FuncEvent = 0xF0,
1607c478bd9Sstevel@tonic-gate FuncEventMask = 0xF4,
1617c478bd9Sstevel@tonic-gate FuncPresetState = 0xF8,
1627c478bd9Sstevel@tonic-gate FuncForceEvent = 0xFC,
1637c478bd9Sstevel@tonic-gate };
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate enum RTL8169_register_content {
1667c478bd9Sstevel@tonic-gate /*InterruptStatusBits */
1677c478bd9Sstevel@tonic-gate SYSErr = 0x8000,
1687c478bd9Sstevel@tonic-gate PCSTimeout = 0x4000,
1697c478bd9Sstevel@tonic-gate SWInt = 0x0100,
1707c478bd9Sstevel@tonic-gate TxDescUnavail = 0x80,
1717c478bd9Sstevel@tonic-gate RxFIFOOver = 0x40,
1727c478bd9Sstevel@tonic-gate RxUnderrun = 0x20,
1737c478bd9Sstevel@tonic-gate RxOverflow = 0x10,
1747c478bd9Sstevel@tonic-gate TxErr = 0x08,
1757c478bd9Sstevel@tonic-gate TxOK = 0x04,
1767c478bd9Sstevel@tonic-gate RxErr = 0x02,
1777c478bd9Sstevel@tonic-gate RxOK = 0x01,
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate /*RxStatusDesc */
1807c478bd9Sstevel@tonic-gate RxRES = 0x00200000,
1817c478bd9Sstevel@tonic-gate RxCRC = 0x00080000,
1827c478bd9Sstevel@tonic-gate RxRUNT = 0x00100000,
1837c478bd9Sstevel@tonic-gate RxRWT = 0x00400000,
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate /*ChipCmdBits */
1867c478bd9Sstevel@tonic-gate CmdReset = 0x10,
1877c478bd9Sstevel@tonic-gate CmdRxEnb = 0x08,
1887c478bd9Sstevel@tonic-gate CmdTxEnb = 0x04,
1897c478bd9Sstevel@tonic-gate RxBufEmpty = 0x01,
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate /*Cfg9346Bits */
1927c478bd9Sstevel@tonic-gate Cfg9346_Lock = 0x00,
1937c478bd9Sstevel@tonic-gate Cfg9346_Unlock = 0xC0,
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate /*rx_mode_bits */
1967c478bd9Sstevel@tonic-gate AcceptErr = 0x20,
1977c478bd9Sstevel@tonic-gate AcceptRunt = 0x10,
1987c478bd9Sstevel@tonic-gate AcceptBroadcast = 0x08,
1997c478bd9Sstevel@tonic-gate AcceptMulticast = 0x04,
2007c478bd9Sstevel@tonic-gate AcceptMyPhys = 0x02,
2017c478bd9Sstevel@tonic-gate AcceptAllPhys = 0x01,
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate /*RxConfigBits */
2047c478bd9Sstevel@tonic-gate RxCfgFIFOShift = 13,
2057c478bd9Sstevel@tonic-gate RxCfgDMAShift = 8,
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate /*TxConfigBits */
2087c478bd9Sstevel@tonic-gate TxInterFrameGapShift = 24,
2097c478bd9Sstevel@tonic-gate TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*rtl8169_PHYstatus */
2127c478bd9Sstevel@tonic-gate TBI_Enable = 0x80,
2137c478bd9Sstevel@tonic-gate TxFlowCtrl = 0x40,
2147c478bd9Sstevel@tonic-gate RxFlowCtrl = 0x20,
2157c478bd9Sstevel@tonic-gate _1000bpsF = 0x10,
2167c478bd9Sstevel@tonic-gate _100bps = 0x08,
2177c478bd9Sstevel@tonic-gate _10bps = 0x04,
2187c478bd9Sstevel@tonic-gate LinkStatus = 0x02,
2197c478bd9Sstevel@tonic-gate FullDup = 0x01,
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /*GIGABIT_PHY_registers */
2227c478bd9Sstevel@tonic-gate PHY_CTRL_REG = 0,
2237c478bd9Sstevel@tonic-gate PHY_STAT_REG = 1,
2247c478bd9Sstevel@tonic-gate PHY_AUTO_NEGO_REG = 4,
2257c478bd9Sstevel@tonic-gate PHY_1000_CTRL_REG = 9,
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate /*GIGABIT_PHY_REG_BIT */
2287c478bd9Sstevel@tonic-gate PHY_Restart_Auto_Nego = 0x0200,
2297c478bd9Sstevel@tonic-gate PHY_Enable_Auto_Nego = 0x1000,
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate /* PHY_STAT_REG = 1; */
2327c478bd9Sstevel@tonic-gate PHY_Auto_Neco_Comp = 0x0020,
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate /* PHY_AUTO_NEGO_REG = 4; */
2357c478bd9Sstevel@tonic-gate PHY_Cap_10_Half = 0x0020,
2367c478bd9Sstevel@tonic-gate PHY_Cap_10_Full = 0x0040,
2377c478bd9Sstevel@tonic-gate PHY_Cap_100_Half = 0x0080,
2387c478bd9Sstevel@tonic-gate PHY_Cap_100_Full = 0x0100,
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /* PHY_1000_CTRL_REG = 9; */
2417c478bd9Sstevel@tonic-gate PHY_Cap_1000_Full = 0x0200,
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate PHY_Cap_Null = 0x0,
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate /*_MediaType*/
2467c478bd9Sstevel@tonic-gate _10_Half = 0x01,
2477c478bd9Sstevel@tonic-gate _10_Full = 0x02,
2487c478bd9Sstevel@tonic-gate _100_Half = 0x04,
2497c478bd9Sstevel@tonic-gate _100_Full = 0x08,
2507c478bd9Sstevel@tonic-gate _1000_Full = 0x10,
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate /*_TBICSRBit*/
2537c478bd9Sstevel@tonic-gate TBILinkOK = 0x02000000,
2547c478bd9Sstevel@tonic-gate };
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate static struct {
2577c478bd9Sstevel@tonic-gate const char *name;
2587c478bd9Sstevel@tonic-gate u8 version; /* depend on RTL8169 docs */
2597c478bd9Sstevel@tonic-gate u32 RxConfigMask; /* should clear the bits supported by this chip */
2607c478bd9Sstevel@tonic-gate } rtl_chip_info[] = {
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate "RTL-8169", 0x00, 0xff7e1880,},};
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate enum _DescStatusBit {
2657c478bd9Sstevel@tonic-gate OWNbit = 0x80000000,
2667c478bd9Sstevel@tonic-gate EORbit = 0x40000000,
2677c478bd9Sstevel@tonic-gate FSbit = 0x20000000,
2687c478bd9Sstevel@tonic-gate LSbit = 0x10000000,
2697c478bd9Sstevel@tonic-gate };
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate struct TxDesc {
2727c478bd9Sstevel@tonic-gate u32 status;
2737c478bd9Sstevel@tonic-gate u32 vlan_tag;
2747c478bd9Sstevel@tonic-gate u32 buf_addr;
2757c478bd9Sstevel@tonic-gate u32 buf_Haddr;
2767c478bd9Sstevel@tonic-gate };
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate struct RxDesc {
2797c478bd9Sstevel@tonic-gate u32 status;
2807c478bd9Sstevel@tonic-gate u32 vlan_tag;
2817c478bd9Sstevel@tonic-gate u32 buf_addr;
2827c478bd9Sstevel@tonic-gate u32 buf_Haddr;
2837c478bd9Sstevel@tonic-gate };
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate /* The descriptors for this card are required to be aligned on
2867c478bd9Sstevel@tonic-gate 256 byte boundaries. As the align attribute does not do more than
2877c478bd9Sstevel@tonic-gate 16 bytes of alignment it requires some extra steps. Add 256 to the
2887c478bd9Sstevel@tonic-gate size of the array and the init_ring adjusts the alignment */
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate /* Define the TX Descriptor */
2917c478bd9Sstevel@tonic-gate static u8 tx_ring[NUM_TX_DESC * sizeof(struct TxDesc) + 256];
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate /* Create a static buffer of size RX_BUF_SZ for each
2947c478bd9Sstevel@tonic-gate TX Descriptor. All descriptors point to a
2957c478bd9Sstevel@tonic-gate part of this buffer */
2967c478bd9Sstevel@tonic-gate static unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate /* Define the RX Descriptor */
2997c478bd9Sstevel@tonic-gate static u8 rx_ring[NUM_RX_DESC * sizeof(struct TxDesc) + 256];
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate /* Create a static buffer of size RX_BUF_SZ for each
3027c478bd9Sstevel@tonic-gate RX Descriptor All descriptors point to a
3037c478bd9Sstevel@tonic-gate part of this buffer */
3047c478bd9Sstevel@tonic-gate static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate struct rtl8169_private {
3077c478bd9Sstevel@tonic-gate void *mmio_addr; /* memory map physical address */
3087c478bd9Sstevel@tonic-gate int chipset;
3097c478bd9Sstevel@tonic-gate unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
3107c478bd9Sstevel@tonic-gate unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
3117c478bd9Sstevel@tonic-gate unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */
3127c478bd9Sstevel@tonic-gate unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */
3137c478bd9Sstevel@tonic-gate struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
3147c478bd9Sstevel@tonic-gate struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
3157c478bd9Sstevel@tonic-gate unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */
3167c478bd9Sstevel@tonic-gate unsigned char *Tx_skbuff[NUM_TX_DESC];
3177c478bd9Sstevel@tonic-gate } tpx;
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate static struct rtl8169_private *tpc;
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate static const u16 rtl8169_intr_mask =
3227c478bd9Sstevel@tonic-gate SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr |
3237c478bd9Sstevel@tonic-gate TxOK | RxErr | RxOK;
3247c478bd9Sstevel@tonic-gate static const unsigned int rtl8169_rx_config =
3257c478bd9Sstevel@tonic-gate (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
3267c478bd9Sstevel@tonic-gate
mdio_write(int RegAddr,int value)3277c478bd9Sstevel@tonic-gate void mdio_write(int RegAddr, int value)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate int i;
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
3327c478bd9Sstevel@tonic-gate udelay(1000);
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate for (i = 2000; i > 0; i--) {
3357c478bd9Sstevel@tonic-gate /* Check if the RTL8169 has completed writing to the specified MII register */
3367c478bd9Sstevel@tonic-gate if (!(RTL_R32(PHYAR) & 0x80000000)) {
3377c478bd9Sstevel@tonic-gate break;
3387c478bd9Sstevel@tonic-gate } else {
3397c478bd9Sstevel@tonic-gate udelay(100);
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
mdio_read(int RegAddr)3447c478bd9Sstevel@tonic-gate int mdio_read(int RegAddr)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate int i, value = -1;
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
3497c478bd9Sstevel@tonic-gate udelay(1000);
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate for (i = 2000; i > 0; i--) {
3527c478bd9Sstevel@tonic-gate /* Check if the RTL8169 has completed retrieving data from the specified MII register */
3537c478bd9Sstevel@tonic-gate if (RTL_R32(PHYAR) & 0x80000000) {
3547c478bd9Sstevel@tonic-gate value = (int) (RTL_R32(PHYAR) & 0xFFFF);
3557c478bd9Sstevel@tonic-gate break;
3567c478bd9Sstevel@tonic-gate } else {
3577c478bd9Sstevel@tonic-gate udelay(100);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate return value;
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate
rtl8169_init_board(struct pci_device * pdev)3637c478bd9Sstevel@tonic-gate static int rtl8169_init_board(struct pci_device *pdev)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate int i;
3667c478bd9Sstevel@tonic-gate unsigned long rtreg_base, rtreg_len;
3677c478bd9Sstevel@tonic-gate u32 tmp;
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate rtreg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_1);
3707c478bd9Sstevel@tonic-gate rtreg_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_1);
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate /* check for weird/broken PCI region reporting */
3737c478bd9Sstevel@tonic-gate if (rtreg_len < RTL_MIN_IO_SIZE) {
3747c478bd9Sstevel@tonic-gate printf("Invalid PCI region size(s), aborting\n");
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate adjust_pci_device(pdev);
3787c478bd9Sstevel@tonic-gate /* pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); */
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /* ioremap MMIO region */
3817c478bd9Sstevel@tonic-gate ioaddr = (unsigned long) ioremap(rtreg_base, rtreg_len);
3827c478bd9Sstevel@tonic-gate if (ioaddr == 0)
3837c478bd9Sstevel@tonic-gate return 0;
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate tpc->mmio_addr = &ioaddr;
3867c478bd9Sstevel@tonic-gate /* Soft reset the chip. */
3877c478bd9Sstevel@tonic-gate RTL_W8(ChipCmd, CmdReset);
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /* Check that the chip has finished the reset. */
3907c478bd9Sstevel@tonic-gate for (i = 1000; i > 0; i--)
3917c478bd9Sstevel@tonic-gate if ((RTL_R8(ChipCmd) & CmdReset) == 0)
3927c478bd9Sstevel@tonic-gate break;
3937c478bd9Sstevel@tonic-gate else
3947c478bd9Sstevel@tonic-gate udelay(10);
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /* identify chip attached to board */
3977c478bd9Sstevel@tonic-gate tmp = RTL_R32(TxConfig);
3987c478bd9Sstevel@tonic-gate tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
4017c478bd9Sstevel@tonic-gate if (tmp == rtl_chip_info[i].version) {
4027c478bd9Sstevel@tonic-gate tpc->chipset = i;
4037c478bd9Sstevel@tonic-gate goto match;
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate /* if unknown chip, assume array element #0, original RTL-8169 in this case */
4067c478bd9Sstevel@tonic-gate dprintf(("PCI device: unknown chip version, assuming RTL-8169\n"));
4077c478bd9Sstevel@tonic-gate dprintf(("PCI device: TxConfig = 0x%hX\n",
4087c478bd9Sstevel@tonic-gate (unsigned long) RTL_R32(TxConfig)));
4097c478bd9Sstevel@tonic-gate tpc->chipset = 0;
4107c478bd9Sstevel@tonic-gate return 1;
4117c478bd9Sstevel@tonic-gate match:
4127c478bd9Sstevel@tonic-gate return 0;
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate /**************************************************************************
4177c478bd9Sstevel@tonic-gate IRQ - Wait for a frame
4187c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_irq(struct nic * nic __unused,irq_action_t action)4197c478bd9Sstevel@tonic-gate void r8169_irq ( struct nic *nic __unused, irq_action_t action ) {
4207c478bd9Sstevel@tonic-gate int intr_status = 0;
4217c478bd9Sstevel@tonic-gate int interested = RxUnderrun | RxOverflow | RxFIFOOver | RxErr | RxOK;
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate switch ( action ) {
4247c478bd9Sstevel@tonic-gate case DISABLE:
4257c478bd9Sstevel@tonic-gate case ENABLE:
4267c478bd9Sstevel@tonic-gate intr_status = RTL_R16(IntrStatus);
4277c478bd9Sstevel@tonic-gate /* h/w no longer present (hotplug?) or major error,
4287c478bd9Sstevel@tonic-gate bail */
4297c478bd9Sstevel@tonic-gate if (intr_status == 0xFFFF)
4307c478bd9Sstevel@tonic-gate break;
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate intr_status = intr_status & ~interested;
4337c478bd9Sstevel@tonic-gate if ( action == ENABLE )
4347c478bd9Sstevel@tonic-gate intr_status = intr_status | interested;
4357c478bd9Sstevel@tonic-gate RTL_W16(IntrMask, intr_status);
4367c478bd9Sstevel@tonic-gate break;
4377c478bd9Sstevel@tonic-gate case FORCE :
4387c478bd9Sstevel@tonic-gate RTL_W8(TxPoll, (RTL_R8(TxPoll) | 0x01));
4397c478bd9Sstevel@tonic-gate break;
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate /**************************************************************************
4447c478bd9Sstevel@tonic-gate POLL - Wait for a frame
4457c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_poll(struct nic * nic,int retreive)4467c478bd9Sstevel@tonic-gate static int r8169_poll(struct nic *nic, int retreive)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate /* return true if there's an ethernet packet ready to read */
4497c478bd9Sstevel@tonic-gate /* nic->packet should contain data on return */
4507c478bd9Sstevel@tonic-gate /* nic->packetlen should contain length of data */
4517c478bd9Sstevel@tonic-gate int cur_rx;
4527c478bd9Sstevel@tonic-gate unsigned int intr_status = 0;
4537c478bd9Sstevel@tonic-gate cur_rx = tpc->cur_rx;
4547c478bd9Sstevel@tonic-gate if ((tpc->RxDescArray[cur_rx].status & OWNbit) == 0) {
4557c478bd9Sstevel@tonic-gate /* There is a packet ready */
4567c478bd9Sstevel@tonic-gate if(!retreive)
4577c478bd9Sstevel@tonic-gate return 1;
4587c478bd9Sstevel@tonic-gate intr_status = RTL_R16(IntrStatus);
4597c478bd9Sstevel@tonic-gate /* h/w no longer present (hotplug?) or major error,
4607c478bd9Sstevel@tonic-gate bail */
4617c478bd9Sstevel@tonic-gate if (intr_status == 0xFFFF)
4627c478bd9Sstevel@tonic-gate return 0;
4637c478bd9Sstevel@tonic-gate RTL_W16(IntrStatus, intr_status &
4647c478bd9Sstevel@tonic-gate ~(RxFIFOOver | RxOverflow | RxOK));
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate if (!(tpc->RxDescArray[cur_rx].status & RxRES)) {
4677c478bd9Sstevel@tonic-gate nic->packetlen = (int) (tpc->RxDescArray[cur_rx].
4687c478bd9Sstevel@tonic-gate status & 0x00001FFF) - 4;
4697c478bd9Sstevel@tonic-gate memcpy(nic->packet, tpc->RxBufferRing[cur_rx],
4707c478bd9Sstevel@tonic-gate nic->packetlen);
4717c478bd9Sstevel@tonic-gate if (cur_rx == NUM_RX_DESC - 1)
4727c478bd9Sstevel@tonic-gate tpc->RxDescArray[cur_rx].status =
4737c478bd9Sstevel@tonic-gate (OWNbit | EORbit) + RX_BUF_SIZE;
4747c478bd9Sstevel@tonic-gate else
4757c478bd9Sstevel@tonic-gate tpc->RxDescArray[cur_rx].status =
4767c478bd9Sstevel@tonic-gate OWNbit + RX_BUF_SIZE;
4777c478bd9Sstevel@tonic-gate tpc->RxDescArray[cur_rx].buf_addr =
4787c478bd9Sstevel@tonic-gate virt_to_bus(tpc->RxBufferRing[cur_rx]);
4797c478bd9Sstevel@tonic-gate } else
4807c478bd9Sstevel@tonic-gate printf("Error Rx");
4817c478bd9Sstevel@tonic-gate /* FIXME: shouldn't I reset the status on an error */
4827c478bd9Sstevel@tonic-gate cur_rx = (cur_rx + 1) % NUM_RX_DESC;
4837c478bd9Sstevel@tonic-gate tpc->cur_rx = cur_rx;
4847c478bd9Sstevel@tonic-gate RTL_W16(IntrStatus, intr_status &
4857c478bd9Sstevel@tonic-gate (RxFIFOOver | RxOverflow | RxOK));
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate return 1;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate tpc->cur_rx = cur_rx;
4917c478bd9Sstevel@tonic-gate /* FIXME: There is no reason to do this as cur_rx did not change */
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate return (0); /* initially as this is called to flush the input */
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate /**************************************************************************
4987c478bd9Sstevel@tonic-gate TRANSMIT - Transmit a frame
4997c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)5007c478bd9Sstevel@tonic-gate static void r8169_transmit(struct nic *nic, const char *d, /* Destination */
5017c478bd9Sstevel@tonic-gate unsigned int t, /* Type */
5027c478bd9Sstevel@tonic-gate unsigned int s, /* size */
5037c478bd9Sstevel@tonic-gate const char *p)
5047c478bd9Sstevel@tonic-gate { /* Packet */
5057c478bd9Sstevel@tonic-gate /* send the packet to destination */
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate u16 nstype;
5087c478bd9Sstevel@tonic-gate u32 to;
5097c478bd9Sstevel@tonic-gate u8 *ptxb;
5107c478bd9Sstevel@tonic-gate int entry = tpc->cur_tx % NUM_TX_DESC;
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate /* point to the current txb incase multiple tx_rings are used */
5137c478bd9Sstevel@tonic-gate ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
5147c478bd9Sstevel@tonic-gate memcpy(ptxb, d, ETH_ALEN);
5157c478bd9Sstevel@tonic-gate memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN);
5167c478bd9Sstevel@tonic-gate nstype = htons((u16) t);
5177c478bd9Sstevel@tonic-gate memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
5187c478bd9Sstevel@tonic-gate memcpy(ptxb + ETH_HLEN, p, s);
5197c478bd9Sstevel@tonic-gate s += ETH_HLEN;
5207c478bd9Sstevel@tonic-gate s &= 0x0FFF;
5217c478bd9Sstevel@tonic-gate while (s < ETH_ZLEN)
5227c478bd9Sstevel@tonic-gate ptxb[s++] = '\0';
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate tpc->TxDescArray[entry].buf_addr = virt_to_bus(ptxb);
5257c478bd9Sstevel@tonic-gate if (entry != (NUM_TX_DESC - 1))
5267c478bd9Sstevel@tonic-gate tpc->TxDescArray[entry].status =
5277c478bd9Sstevel@tonic-gate (OWNbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s :
5287c478bd9Sstevel@tonic-gate ETH_ZLEN);
5297c478bd9Sstevel@tonic-gate else
5307c478bd9Sstevel@tonic-gate tpc->TxDescArray[entry].status =
5317c478bd9Sstevel@tonic-gate (OWNbit | EORbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s
5327c478bd9Sstevel@tonic-gate : ETH_ZLEN);
5337c478bd9Sstevel@tonic-gate RTL_W8(TxPoll, 0x40); /* set polling bit */
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate tpc->cur_tx++;
5367c478bd9Sstevel@tonic-gate to = currticks() + TX_TIMEOUT;
5377c478bd9Sstevel@tonic-gate while ((tpc->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate if (currticks() >= to) {
5407c478bd9Sstevel@tonic-gate printf("TX Time Out");
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate
rtl8169_set_rx_mode(struct nic * nic __unused)5447c478bd9Sstevel@tonic-gate static void rtl8169_set_rx_mode(struct nic *nic __unused)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate u32 mc_filter[2]; /* Multicast hash filter */
5477c478bd9Sstevel@tonic-gate int rx_mode;
5487c478bd9Sstevel@tonic-gate u32 tmp = 0;
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /* IFF_ALLMULTI */
5517c478bd9Sstevel@tonic-gate /* Too many to filter perfectly -- accept all multicasts. */
5527c478bd9Sstevel@tonic-gate rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
5537c478bd9Sstevel@tonic-gate mc_filter[1] = mc_filter[0] = 0xffffffff;
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate tmp =
5567c478bd9Sstevel@tonic-gate rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
5577c478bd9Sstevel@tonic-gate rtl_chip_info[tpc->chipset].
5587c478bd9Sstevel@tonic-gate RxConfigMask);
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate RTL_W32(RxConfig, tmp);
5617c478bd9Sstevel@tonic-gate RTL_W32(MAR0 + 0, mc_filter[0]);
5627c478bd9Sstevel@tonic-gate RTL_W32(MAR0 + 4, mc_filter[1]);
5637c478bd9Sstevel@tonic-gate }
rtl8169_hw_start(struct nic * nic)5647c478bd9Sstevel@tonic-gate static void rtl8169_hw_start(struct nic *nic)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate u32 i;
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate /* Soft reset the chip. */
5697c478bd9Sstevel@tonic-gate RTL_W8(ChipCmd, CmdReset);
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate /* Check that the chip has finished the reset. */
5727c478bd9Sstevel@tonic-gate for (i = 1000; i > 0; i--) {
5737c478bd9Sstevel@tonic-gate if ((RTL_R8(ChipCmd) & CmdReset) == 0)
5747c478bd9Sstevel@tonic-gate break;
5757c478bd9Sstevel@tonic-gate else
5767c478bd9Sstevel@tonic-gate udelay(10);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate
5797c478bd9Sstevel@tonic-gate RTL_W8(Cfg9346, Cfg9346_Unlock);
5807c478bd9Sstevel@tonic-gate RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5817c478bd9Sstevel@tonic-gate RTL_W8(EarlyTxThres, EarlyTxThld);
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate /* For gigabit rtl8169 */
5847c478bd9Sstevel@tonic-gate RTL_W16(RxMaxSize, RxPacketMaxSize);
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate /* Set Rx Config register */
5877c478bd9Sstevel@tonic-gate i = rtl8169_rx_config | (RTL_R32(RxConfig) &
5887c478bd9Sstevel@tonic-gate rtl_chip_info[tpc->chipset].RxConfigMask);
5897c478bd9Sstevel@tonic-gate RTL_W32(RxConfig, i);
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate /* Set DMA burst size and Interframe Gap Time */
5927c478bd9Sstevel@tonic-gate RTL_W32(TxConfig,
5937c478bd9Sstevel@tonic-gate (TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
5947c478bd9Sstevel@tonic-gate TxInterFrameGapShift));
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate tpc->cur_rx = 0;
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate RTL_W32(TxDescStartAddr, virt_to_le32desc(tpc->TxDescArray));
6007c478bd9Sstevel@tonic-gate RTL_W32(RxDescStartAddr, virt_to_le32desc(tpc->RxDescArray));
6017c478bd9Sstevel@tonic-gate RTL_W8(Cfg9346, Cfg9346_Lock);
6027c478bd9Sstevel@tonic-gate udelay(10);
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate RTL_W32(RxMissed, 0);
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate rtl8169_set_rx_mode(nic);
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate /* no early-rx interrupts */
6097c478bd9Sstevel@tonic-gate RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate
rtl8169_init_ring(struct nic * nic __unused)6127c478bd9Sstevel@tonic-gate static void rtl8169_init_ring(struct nic *nic __unused)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate int i;
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gate tpc->cur_rx = 0;
6177c478bd9Sstevel@tonic-gate tpc->cur_tx = 0;
6187c478bd9Sstevel@tonic-gate memset(tpc->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc));
6197c478bd9Sstevel@tonic-gate memset(tpc->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc));
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_TX_DESC; i++) {
6227c478bd9Sstevel@tonic-gate tpc->Tx_skbuff[i] = &txb[i];
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_RX_DESC; i++) {
6267c478bd9Sstevel@tonic-gate if (i == (NUM_RX_DESC - 1))
6277c478bd9Sstevel@tonic-gate tpc->RxDescArray[i].status =
6287c478bd9Sstevel@tonic-gate (OWNbit | EORbit) + RX_BUF_SIZE;
6297c478bd9Sstevel@tonic-gate else
6307c478bd9Sstevel@tonic-gate tpc->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
6337c478bd9Sstevel@tonic-gate tpc->RxDescArray[i].buf_addr =
6347c478bd9Sstevel@tonic-gate virt_to_bus(tpc->RxBufferRing[i]);
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate /**************************************************************************
6397c478bd9Sstevel@tonic-gate RESET - Finish setting up the ethernet interface
6407c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_reset(struct nic * nic)6417c478bd9Sstevel@tonic-gate static void r8169_reset(struct nic *nic)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate int i;
6447c478bd9Sstevel@tonic-gate u8 diff;
6457c478bd9Sstevel@tonic-gate u32 TxPhyAddr, RxPhyAddr;
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate tpc->TxDescArrays = tx_ring;
6487c478bd9Sstevel@tonic-gate if (tpc->TxDescArrays == 0)
6497c478bd9Sstevel@tonic-gate printf("Allot Error");
6507c478bd9Sstevel@tonic-gate /* Tx Desscriptor needs 256 bytes alignment; */
6517c478bd9Sstevel@tonic-gate TxPhyAddr = virt_to_bus(tpc->TxDescArrays);
6527c478bd9Sstevel@tonic-gate diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8));
6537c478bd9Sstevel@tonic-gate TxPhyAddr += diff;
6547c478bd9Sstevel@tonic-gate tpc->TxDescArray = (struct TxDesc *) (tpc->TxDescArrays + diff);
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate tpc->RxDescArrays = rx_ring;
6577c478bd9Sstevel@tonic-gate /* Rx Desscriptor needs 256 bytes alignment; */
6587c478bd9Sstevel@tonic-gate RxPhyAddr = virt_to_bus(tpc->RxDescArrays);
6597c478bd9Sstevel@tonic-gate diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8));
6607c478bd9Sstevel@tonic-gate RxPhyAddr += diff;
6617c478bd9Sstevel@tonic-gate tpc->RxDescArray = (struct RxDesc *) (tpc->RxDescArrays + diff);
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate if (tpc->TxDescArrays == NULL || tpc->RxDescArrays == NULL) {
6647c478bd9Sstevel@tonic-gate printf("Allocate RxDescArray or TxDescArray failed\n");
6657c478bd9Sstevel@tonic-gate return;
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate rtl8169_init_ring(nic);
6697c478bd9Sstevel@tonic-gate rtl8169_hw_start(nic);
6707c478bd9Sstevel@tonic-gate /* Construct a perfect filter frame with the mac address as first match
6717c478bd9Sstevel@tonic-gate * and broadcast for all others */
6727c478bd9Sstevel@tonic-gate for (i = 0; i < 192; i++)
6737c478bd9Sstevel@tonic-gate txb[i] = 0xFF;
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate txb[0] = nic->node_addr[0];
6767c478bd9Sstevel@tonic-gate txb[1] = nic->node_addr[1];
6777c478bd9Sstevel@tonic-gate txb[2] = nic->node_addr[2];
6787c478bd9Sstevel@tonic-gate txb[3] = nic->node_addr[3];
6797c478bd9Sstevel@tonic-gate txb[4] = nic->node_addr[4];
6807c478bd9Sstevel@tonic-gate txb[5] = nic->node_addr[5];
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate /**************************************************************************
6847c478bd9Sstevel@tonic-gate DISABLE - Turn off ethernet interface
6857c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_disable(struct dev * dev __unused)6867c478bd9Sstevel@tonic-gate static void r8169_disable(struct dev *dev __unused)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate int i;
6897c478bd9Sstevel@tonic-gate /* Stop the chip's Tx and Rx DMA processes. */
6907c478bd9Sstevel@tonic-gate RTL_W8(ChipCmd, 0x00);
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /* Disable interrupts by clearing the interrupt mask. */
6937c478bd9Sstevel@tonic-gate RTL_W16(IntrMask, 0x0000);
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate RTL_W32(RxMissed, 0);
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate tpc->TxDescArrays = NULL;
6987c478bd9Sstevel@tonic-gate tpc->RxDescArrays = NULL;
6997c478bd9Sstevel@tonic-gate tpc->TxDescArray = NULL;
7007c478bd9Sstevel@tonic-gate tpc->RxDescArray = NULL;
7017c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_RX_DESC; i++) {
7027c478bd9Sstevel@tonic-gate tpc->RxBufferRing[i] = NULL;
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate /**************************************************************************
7077c478bd9Sstevel@tonic-gate PROBE - Look for an adapter, this routine's visible to the outside
7087c478bd9Sstevel@tonic-gate ***************************************************************************/
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate #define board_found 1
7117c478bd9Sstevel@tonic-gate #define valid_link 0
r8169_probe(struct dev * dev,struct pci_device * pci)7127c478bd9Sstevel@tonic-gate static int r8169_probe(struct dev *dev, struct pci_device *pci)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate struct nic *nic = (struct nic *) dev;
7157c478bd9Sstevel@tonic-gate static int board_idx = -1;
7167c478bd9Sstevel@tonic-gate static int printed_version = 0;
7177c478bd9Sstevel@tonic-gate int i, rc;
7187c478bd9Sstevel@tonic-gate int option = -1, Cap10_100 = 0, Cap1000 = 0;
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate printf("r8169.c: Found %s, Vendor=%hX Device=%hX\n",
7217c478bd9Sstevel@tonic-gate pci->name, pci->vendor, pci->dev_id);
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate board_idx++;
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate printed_version = 1;
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /* point to private storage */
7287c478bd9Sstevel@tonic-gate tpc = &tpx;
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate rc = rtl8169_init_board(pci); /* Return code is meaningless */
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate /* Get MAC address. FIXME: read EEPROM */
7337c478bd9Sstevel@tonic-gate for (i = 0; i < MAC_ADDR_LEN; i++)
7347c478bd9Sstevel@tonic-gate nic->node_addr[i] = RTL_R8(MAC0 + i);
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate dprintf(("%s: Identified chip type is '%s'.\n", pci->name,
7377c478bd9Sstevel@tonic-gate rtl_chip_info[tpc->chipset].name));
7387c478bd9Sstevel@tonic-gate /* Print out some hardware info */
7397c478bd9Sstevel@tonic-gate printf("%s: %! at ioaddr %hX, ", pci->name, nic->node_addr,
7407c478bd9Sstevel@tonic-gate ioaddr);
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate /* if TBI is not endbled */
7437c478bd9Sstevel@tonic-gate if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
7447c478bd9Sstevel@tonic-gate int val = mdio_read(PHY_AUTO_NEGO_REG);
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate option = media;
7477c478bd9Sstevel@tonic-gate /* Force RTL8169 in 10/100/1000 Full/Half mode. */
7487c478bd9Sstevel@tonic-gate if (option > 0) {
7497c478bd9Sstevel@tonic-gate printf(" Force-mode Enabled.\n");
7507c478bd9Sstevel@tonic-gate Cap10_100 = 0, Cap1000 = 0;
7517c478bd9Sstevel@tonic-gate switch (option) {
7527c478bd9Sstevel@tonic-gate case _10_Half:
7537c478bd9Sstevel@tonic-gate Cap10_100 = PHY_Cap_10_Half;
7547c478bd9Sstevel@tonic-gate Cap1000 = PHY_Cap_Null;
7557c478bd9Sstevel@tonic-gate break;
7567c478bd9Sstevel@tonic-gate case _10_Full:
7577c478bd9Sstevel@tonic-gate Cap10_100 = PHY_Cap_10_Full;
7587c478bd9Sstevel@tonic-gate Cap1000 = PHY_Cap_Null;
7597c478bd9Sstevel@tonic-gate break;
7607c478bd9Sstevel@tonic-gate case _100_Half:
7617c478bd9Sstevel@tonic-gate Cap10_100 = PHY_Cap_100_Half;
7627c478bd9Sstevel@tonic-gate Cap1000 = PHY_Cap_Null;
7637c478bd9Sstevel@tonic-gate break;
7647c478bd9Sstevel@tonic-gate case _100_Full:
7657c478bd9Sstevel@tonic-gate Cap10_100 = PHY_Cap_100_Full;
7667c478bd9Sstevel@tonic-gate Cap1000 = PHY_Cap_Null;
7677c478bd9Sstevel@tonic-gate break;
7687c478bd9Sstevel@tonic-gate case _1000_Full:
7697c478bd9Sstevel@tonic-gate Cap10_100 = PHY_Cap_Null;
7707c478bd9Sstevel@tonic-gate Cap1000 = PHY_Cap_1000_Full;
7717c478bd9Sstevel@tonic-gate break;
7727c478bd9Sstevel@tonic-gate default:
7737c478bd9Sstevel@tonic-gate break;
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate /* leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
7767c478bd9Sstevel@tonic-gate mdio_write(PHY_AUTO_NEGO_REG,
7777c478bd9Sstevel@tonic-gate Cap10_100 | (val & 0x1F));
7787c478bd9Sstevel@tonic-gate mdio_write(PHY_1000_CTRL_REG, Cap1000);
7797c478bd9Sstevel@tonic-gate } else {
7807c478bd9Sstevel@tonic-gate dprintf(("Auto-negotiation Enabled.\n",
7817c478bd9Sstevel@tonic-gate pci->name));
7827c478bd9Sstevel@tonic-gate
7837c478bd9Sstevel@tonic-gate /* enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
7847c478bd9Sstevel@tonic-gate mdio_write(PHY_AUTO_NEGO_REG,
7857c478bd9Sstevel@tonic-gate PHY_Cap_10_Half | PHY_Cap_10_Full |
7867c478bd9Sstevel@tonic-gate PHY_Cap_100_Half | PHY_Cap_100_Full |
7877c478bd9Sstevel@tonic-gate (val & 0x1F));
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate /* enable 1000 Full Mode */
7907c478bd9Sstevel@tonic-gate mdio_write(PHY_1000_CTRL_REG, PHY_Cap_1000_Full);
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate /* Enable auto-negotiation and restart auto-nigotiation */
7957c478bd9Sstevel@tonic-gate mdio_write(PHY_CTRL_REG,
7967c478bd9Sstevel@tonic-gate PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
7977c478bd9Sstevel@tonic-gate udelay(100);
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate /* wait for auto-negotiation process */
8007c478bd9Sstevel@tonic-gate for (i = 10000; i > 0; i--) {
8017c478bd9Sstevel@tonic-gate /* Check if auto-negotiation complete */
8027c478bd9Sstevel@tonic-gate if (mdio_read(PHY_STAT_REG) & PHY_Auto_Neco_Comp) {
8037c478bd9Sstevel@tonic-gate udelay(100);
8047c478bd9Sstevel@tonic-gate option = RTL_R8(PHYstatus);
8057c478bd9Sstevel@tonic-gate if (option & _1000bpsF) {
8067c478bd9Sstevel@tonic-gate printf
8077c478bd9Sstevel@tonic-gate ("1000Mbps Full-duplex operation.\n");
8087c478bd9Sstevel@tonic-gate } else {
8097c478bd9Sstevel@tonic-gate printf
8107c478bd9Sstevel@tonic-gate ("%sMbps %s-duplex operation.\n",
8117c478bd9Sstevel@tonic-gate (option & _100bps) ? "100" :
8127c478bd9Sstevel@tonic-gate "10",
8137c478bd9Sstevel@tonic-gate (option & FullDup) ? "Full" :
8147c478bd9Sstevel@tonic-gate "Half");
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate break;
8177c478bd9Sstevel@tonic-gate } else {
8187c478bd9Sstevel@tonic-gate udelay(100);
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate } /* end for-loop to wait for auto-negotiation process */
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate } else {
8237c478bd9Sstevel@tonic-gate udelay(100);
8247c478bd9Sstevel@tonic-gate printf
8257c478bd9Sstevel@tonic-gate ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
8267c478bd9Sstevel@tonic-gate pci->name,
8277c478bd9Sstevel@tonic-gate (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate r8169_reset(nic);
8327c478bd9Sstevel@tonic-gate /* point to NIC specific routines */
8337c478bd9Sstevel@tonic-gate dev->disable = r8169_disable;
8347c478bd9Sstevel@tonic-gate nic->poll = r8169_poll;
8357c478bd9Sstevel@tonic-gate nic->transmit = r8169_transmit;
8367c478bd9Sstevel@tonic-gate nic->irqno = pci->irq;
8377c478bd9Sstevel@tonic-gate nic->irq = r8169_irq;
8387c478bd9Sstevel@tonic-gate nic->ioaddr = ioaddr;
8397c478bd9Sstevel@tonic-gate return 1;
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate static struct pci_id r8169_nics[] = {
8447c478bd9Sstevel@tonic-gate PCI_ROM(0x10ec, 0x8169, "r8169", "RealTek RTL8169 Gigabit Ethernet"),
8457c478bd9Sstevel@tonic-gate };
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate struct pci_driver r8169_driver = {
8487c478bd9Sstevel@tonic-gate .type = NIC_DRIVER,
8497c478bd9Sstevel@tonic-gate .name = "r8169/PCI",
8507c478bd9Sstevel@tonic-gate .probe = r8169_probe,
8517c478bd9Sstevel@tonic-gate .ids = r8169_nics,
8527c478bd9Sstevel@tonic-gate .id_count = sizeof(r8169_nics) / sizeof(r8169_nics[0]),
8537c478bd9Sstevel@tonic-gate .class = 0,
8547c478bd9Sstevel@tonic-gate };
855