1 #include <geekos/rtl8139.h>
2 #include <geekos/debug.h>
4 #include <geekos/irq.h>
5 #include <geekos/malloc.h>
6 #include <geekos/string.h>
8 #include <uip/uip_arp.h>
11 #define RX_BUF_LEN (32768 + 16 + 2048)
12 #define TX_BUF_SIZE 1536
13 #define TX_FIFO_THRESH 256
18 uint_t tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
21 /* The macros below were copied straight from the linux 8139too.c driver. */
23 MultiIntrClear = 0xF000,
25 Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
35 /* Interrupt register bits */
47 RxAckBits = RxFIFOOver | RxOverflow | RxOK,
54 TxOutOfWindow = 0x20000000,
55 TxAborted = 0x40000000,
56 TxCarrierLost = 0x80000000,
70 /* Bits in RxConfig. */
74 AcceptBroadcast = 0x08,
75 AcceptMulticast = 0x04,
80 /* Bits in TxConfig. */
83 /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
85 TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
86 TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
87 TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
88 TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
90 TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
91 TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
92 TxClearAbt = (1 << 0), /* Clear abort (WO) */
93 TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
94 TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
96 TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
101 Cfg1_PM_Enable = 0x01,
102 Cfg1_VPD_Enable = 0x02,
105 LWAKE = 0x10, /* not on 8139, 8139A */
106 Cfg1_Driver_Load = 0x20,
109 SLEEP = (1 << 1), /* only on 8139, 8139A */
110 PWRDN = (1 << 0), /* only on 8139, 8139A */
113 /* Bits in Config3 */
115 Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
116 Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
117 Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
118 Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
119 Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
120 Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
121 Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
122 Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
125 /* Bits in Config4 */
127 LWPTN = (1 << 2), /* not on 8139, 8139A */
130 /* Bits in Config5 */
132 Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
133 Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
134 Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
135 Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
136 Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
137 Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
138 Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
142 /* rx fifo threshold */
144 RxCfgFIFONone = (7 << RxCfgFIFOShift),
148 RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
150 /* rx ring buffer length */
152 RxCfgRcv16K = (1 << 11),
153 RxCfgRcv32K = (1 << 12),
154 RxCfgRcv64K = (1 << 11) | (1 << 12),
156 /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
160 /* Twister tuning parameters from RealTek.
161 Completely undocumented, but required to tune bad links on some boards. */
163 CSCR_LinkOKBit = 0x0400,
164 CSCR_LinkChangeBit = 0x0800,
165 CSCR_LinkStatusBits = 0x0f000,
166 CSCR_LinkDownOffCmd = 0x003c0,
167 CSCR_LinkDownCmd = 0x0f3c0,
172 Cfg9346_Unlock = 0xC0,
175 static const uint_t rtl8139_intr_mask =
176 PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
177 TxErr | TxOK | RxErr | RxOK;
179 //static void Init_8139(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet))
182 static void rtl8139_interrupt( struct Interrupt_State * state )
186 uint_t status = In_Word(RTL8139_ISR);
188 PrintBoth("Interrupt Received: %x\n", status);
190 if( status == PKT_RX )
193 rtl8139_Clear_IRQ(status);
198 void rtl8139_Clear_IRQ(uint_t interrupts)
200 Out_Word(RTL8139_ISR, interrupts);
209 Out_Byte(RTL8139_CR, CmdReset);
211 //while( In_Byte(RTL8139_CR) != 0 )
214 /* Unlock Config[01234] and BMCR register writes */
215 Out_Byte(RTL8139_9346CR, Cfg9346_Unlock);
217 /* Enable Tx/Rx before setting transfer thresholds */
218 Out_Byte(RTL8139_CR, CmdRxEnb | CmdTxEnb);
221 Out_DWord(RTL8139_RCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift)
222 | AcceptBroadcast | AcceptMyPhys);
224 // Out_DWord(RTL8139_TCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift));
226 Out_DWord(RTL8139_TCR, TxIFG96 | (6 << TxDMAShift) | (8 << TxRetryShift));
228 /* Lock Config[01234] and BMCR register writes */
229 Out_Byte(RTL8139_9346CR, Cfg9346_Lock);
231 /* init Rx ring buffer DMA address */
232 rx_buf = Malloc(RX_BUF_LEN);
233 Out_DWord(RTL8139_RBSTART, (uint_t)rx_buf);
235 /* init Tx buffer DMA addresses (4 registers) */
236 tx_buf = Malloc(TX_BUF_SIZE * 4);
238 for(i = 0; i < 4; i++)
239 Out_DWord(RTL8139_TSAD0 + (i * 4), ((uint_t)tx_buf) + (i * TX_BUF_SIZE));
241 /* missed packet counter */
242 Out_DWord(RTL8139_MPC, 0);
244 // rtl8139_set_rx_mode does some stuff here.
245 Out_DWord(RTL8139_RCR, In_DWord(RTL8139_RCR) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
248 for(i = 0; i < 8; i++)
249 Out_Byte(RTL8139_MAR0 + i, 0xff);
251 /* no early-rx interrupts */
252 Out_Word(RTL8139_MULINT, In_Word(RTL8139_MULINT) & MultiIntrClear);
254 /* make sure RxTx has started */
255 if(!(In_Byte(RTL8139_CR) & CmdRxEnb) || !(In_Byte(RTL8139_CR) & CmdTxEnb))
256 Out_Byte(RTL8139_CR, CmdRxEnb | CmdTxEnb);
258 /* Enable all known interrupts by setting the interrupt mask. */
259 Out_Word(RTL8139_IMR, rtl8139_intr_mask);
261 Install_IRQ(RTL8139_IRQ, rtl8139_interrupt);
262 Enable_IRQ(RTL8139_IRQ);
264 PrintBoth("8139 initialized\n");
267 int rtl8139_Send(uchar_t *packet, uint_t size)
269 uint_t entry = cur_tx % 4;
270 memcpy(tx_buf + (entry * TX_BUF_SIZE), packet, size);
271 Out_DWord(RTL8139_TSD0 + (entry * 4), tx_flag | size);
273 PrintBoth("Packet transmitted. cur_tx = %d\n", cur_tx);
277 int rtl8139_Receive()
279 PrintBoth("Packet Received\n");
282 while( (In_Byte(RTL8139_CR) & RxBufEmpty) == 0){
284 uint_t ring_offset = cur_rx % RX_BUF_LEN;
286 uint_t rx_status = ((uint_t)rx_buf + ring_offset);
288 PrintBoth("RX Status = %x\n", rx_status);
290 uint_t rx_size = (uint_t)((*(uchar_t *)(rx_status + 3) << 8) | (*(uchar_t *)(rx_status + 2)));
291 uint_t pkt_len = rx_size - 4;
293 PrintBoth("Packet Size = %d\n", pkt_len);
295 for (i = 0; i < pkt_len; i++){
296 PrintBoth(" %x ", *((uchar_t *)(rx_status + i)));
300 cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
301 Out_Word(RTL8139_CAPR, (ushort_t)(cur_rx - 16));
305 PrintBoth("Packet counter at %d\n", pkt_cntr);