2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Matt Wojcik
11 * Copyright (c) 2008, Peter Kamm
12 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
13 * All rights reserved.
18 * This is free software. You are permitted to use,
19 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
22 #include <geekos/rtl8139.h>
23 #include <geekos/debug.h>
24 #include <geekos/io.h>
25 #include <geekos/irq.h>
26 #include <geekos/malloc.h>
27 #include <geekos/string.h>
29 #include <uip/uip_arp.h>
32 #define RX_BUF_LEN (32768 + 16 + 2048)
33 #define TX_BUF_SIZE 1536
34 #define TX_FIFO_THRESH 256
39 uint_t tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
42 /* The macros below were copied straight from the linux 8139too.c driver. */
44 MultiIntrClear = 0xF000,
46 Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
56 /* Interrupt register bits */
68 RxAckBits = RxFIFOOver | RxOverflow | RxOK,
75 TxOutOfWindow = 0x20000000,
76 TxAborted = 0x40000000,
77 TxCarrierLost = 0x80000000,
91 /* Bits in RxConfig. */
95 AcceptBroadcast = 0x08,
96 AcceptMulticast = 0x04,
101 /* Bits in TxConfig. */
102 enum tx_config_bits {
104 /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
106 TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
107 TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
108 TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
109 TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
111 TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
112 TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
113 TxClearAbt = (1 << 0), /* Clear abort (WO) */
114 TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
115 TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
117 TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
120 /* Bits in Config1 */
122 Cfg1_PM_Enable = 0x01,
123 Cfg1_VPD_Enable = 0x02,
126 LWAKE = 0x10, /* not on 8139, 8139A */
127 Cfg1_Driver_Load = 0x20,
130 SLEEP = (1 << 1), /* only on 8139, 8139A */
131 PWRDN = (1 << 0), /* only on 8139, 8139A */
134 /* Bits in Config3 */
136 Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
137 Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
138 Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
139 Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
140 Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
141 Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
142 Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
143 Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
146 /* Bits in Config4 */
148 LWPTN = (1 << 2), /* not on 8139, 8139A */
151 /* Bits in Config5 */
153 Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
154 Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
155 Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
156 Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
157 Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
158 Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
159 Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
163 /* rx fifo threshold */
165 RxCfgFIFONone = (7 << RxCfgFIFOShift),
169 RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
171 /* rx ring buffer length */
173 RxCfgRcv16K = (1 << 11),
174 RxCfgRcv32K = (1 << 12),
175 RxCfgRcv64K = (1 << 11) | (1 << 12),
177 /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
181 /* Twister tuning parameters from RealTek.
182 Completely undocumented, but required to tune bad links on some boards. */
184 CSCR_LinkOKBit = 0x0400,
185 CSCR_LinkChangeBit = 0x0800,
186 CSCR_LinkStatusBits = 0x0f000,
187 CSCR_LinkDownOffCmd = 0x003c0,
188 CSCR_LinkDownCmd = 0x0f3c0,
193 Cfg9346_Unlock = 0xC0,
196 static const uint_t rtl8139_intr_mask =
197 PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
198 TxErr | TxOK | RxErr | RxOK;
200 //static void Init_8139(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet))
203 static void rtl8139_interrupt( struct Interrupt_State * state )
207 uint_t status = In_Word(RTL8139_ISR);
209 PrintBoth("Interrupt Received: %x\n", status);
211 if( status == PKT_RX )
214 rtl8139_Clear_IRQ(status);
219 void rtl8139_Clear_IRQ(uint_t interrupts)
221 Out_Word(RTL8139_ISR, interrupts);
230 Out_Byte(RTL8139_CR, CmdReset);
232 //while( In_Byte(RTL8139_CR) != 0 )
235 /* Unlock Config[01234] and BMCR register writes */
236 Out_Byte(RTL8139_9346CR, Cfg9346_Unlock);
238 /* Enable Tx/Rx before setting transfer thresholds */
239 Out_Byte(RTL8139_CR, CmdRxEnb | CmdTxEnb);
242 Out_DWord(RTL8139_RCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift)
243 | AcceptBroadcast | AcceptMyPhys);
245 // Out_DWord(RTL8139_TCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift));
247 Out_DWord(RTL8139_TCR, TxIFG96 | (6 << TxDMAShift) | (8 << TxRetryShift));
249 /* Lock Config[01234] and BMCR register writes */
250 Out_Byte(RTL8139_9346CR, Cfg9346_Lock);
252 /* init Rx ring buffer DMA address */
253 rx_buf = Malloc(RX_BUF_LEN);
254 Out_DWord(RTL8139_RBSTART, (uint_t)rx_buf);
256 /* init Tx buffer DMA addresses (4 registers) */
257 tx_buf = Malloc(TX_BUF_SIZE * 4);
259 for(i = 0; i < 4; i++)
260 Out_DWord(RTL8139_TSAD0 + (i * 4), ((uint_t)tx_buf) + (i * TX_BUF_SIZE));
262 /* missed packet counter */
263 Out_DWord(RTL8139_MPC, 0);
265 // rtl8139_set_rx_mode does some stuff here.
266 Out_DWord(RTL8139_RCR, In_DWord(RTL8139_RCR) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
269 for(i = 0; i < 8; i++)
270 Out_Byte(RTL8139_MAR0 + i, 0xff);
272 /* no early-rx interrupts */
273 Out_Word(RTL8139_MULINT, In_Word(RTL8139_MULINT) & MultiIntrClear);
275 /* make sure RxTx has started */
276 if(!(In_Byte(RTL8139_CR) & CmdRxEnb) || !(In_Byte(RTL8139_CR) & CmdTxEnb))
277 Out_Byte(RTL8139_CR, CmdRxEnb | CmdTxEnb);
279 /* Enable all known interrupts by setting the interrupt mask. */
280 Out_Word(RTL8139_IMR, rtl8139_intr_mask);
282 Install_IRQ(RTL8139_IRQ, rtl8139_interrupt);
283 Enable_IRQ(RTL8139_IRQ);
285 PrintBoth("8139 initialized\n");
288 int rtl8139_Send(uchar_t *packet, uint_t size)
290 uint_t entry = cur_tx % 4;
291 memcpy(tx_buf + (entry * TX_BUF_SIZE), packet, size);
292 Out_DWord(RTL8139_TSD0 + (entry * 4), tx_flag | size);
294 PrintBoth("Packet transmitted. cur_tx = %d\n", cur_tx);
298 int rtl8139_Receive()
300 PrintBoth("Packet Received\n");
303 while( (In_Byte(RTL8139_CR) & RxBufEmpty) == 0){
305 uint_t ring_offset = cur_rx % RX_BUF_LEN;
307 uint_t rx_status = ((uint_t)rx_buf + ring_offset);
309 PrintBoth("RX Status = %x\n", rx_status);
311 uint_t rx_size = (uint_t)((*(uchar_t *)(rx_status + 3) << 8) | (*(uchar_t *)(rx_status + 2)));
312 uint_t pkt_len = rx_size - 4;
314 PrintBoth("Packet Size = %d\n", pkt_len);
316 for (i = 0; i < pkt_len; i++){
317 PrintBoth(" %x ", *((uchar_t *)(rx_status + i)));
321 cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
322 Out_Word(RTL8139_CAPR, (ushort_t)(cur_rx - 16));
326 PrintBoth("Packet counter at %d\n", pkt_cntr);