Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / geekos / rtl8139.c
1 /*
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
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.
14  *
15  * Author: Matt Wojcik
16  * Author: Peter Kamm
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
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>
28 #include <uip/uip.h>
29 #include <uip/uip_arp.h>
30
31
32 #define RX_BUF_LEN (32768 + 16 + 2048)
33 #define TX_BUF_SIZE 1536
34 #define TX_FIFO_THRESH 256
35 uchar_t *rx_buf;
36 uchar_t *tx_buf;
37 uint_t cur_tx;
38 uint_t cur_rx;
39 uint_t tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
40 uint_t pkt_cntr = 0;
41
42 /* The macros below were copied straight from the linux 8139too.c driver. */
43 enum ClearBitMasks {
44         MultiIntrClear = 0xF000,
45         ChipCmdClear = 0xE2,
46         Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
47 };
48
49 enum ChipCmdBits {
50         CmdReset = 0x10,
51         CmdRxEnb = 0x08,
52         CmdTxEnb = 0x04,
53         RxBufEmpty = 0x01,
54 };
55
56 /* Interrupt register bits */
57 enum IntrStatusBits {
58         PCIErr = 0x8000,
59         PCSTimeout = 0x4000,
60         RxFIFOOver = 0x40,
61         RxUnderrun = 0x20,
62         RxOverflow = 0x10,
63         TxErr = 0x08,
64         TxOK = 0x04,
65         RxErr = 0x02,
66         RxOK = 0x01,
67
68         RxAckBits = RxFIFOOver | RxOverflow | RxOK,
69 };
70
71 enum TxStatusBits {
72         TxHostOwns = 0x2000,
73         TxUnderrun = 0x4000,
74         TxStatOK = 0x8000,
75         TxOutOfWindow = 0x20000000,
76         TxAborted = 0x40000000,
77         TxCarrierLost = 0x80000000,
78 };
79 enum RxStatusBits {
80         RxMulticast = 0x8000,
81         RxPhysical = 0x4000,
82         RxBroadcast = 0x2000,
83         RxBadSymbol = 0x0020,
84         RxRunt = 0x0010,
85         RxTooLong = 0x0008,
86         RxCRCErr = 0x0004,
87         RxBadAlign = 0x0002,
88         RxStatusOK = 0x0001,
89 };
90
91 /* Bits in RxConfig. */
92 enum rx_mode_bits {
93         AcceptErr = 0x20,
94         AcceptRunt = 0x10,
95         AcceptBroadcast = 0x08,
96         AcceptMulticast = 0x04,
97         AcceptMyPhys = 0x02,
98         AcceptAllPhys = 0x01,
99 };
100
101 /* Bits in TxConfig. */
102 enum tx_config_bits {
103
104         /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
105         TxIFGShift = 24,
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) */
110
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 */
116
117         TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
118 };
119
120 /* Bits in Config1 */
121 enum Config1Bits {
122         Cfg1_PM_Enable = 0x01,
123         Cfg1_VPD_Enable = 0x02,
124         Cfg1_PIO = 0x04,
125         Cfg1_MMIO = 0x08,
126         LWAKE = 0x10,           /* not on 8139, 8139A */
127         Cfg1_Driver_Load = 0x20,
128         Cfg1_LED0 = 0x40,
129         Cfg1_LED1 = 0x80,
130         SLEEP = (1 << 1),       /* only on 8139, 8139A */
131         PWRDN = (1 << 0),       /* only on 8139, 8139A */
132 };
133
134 /* Bits in Config3 */
135 enum Config3Bits {
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 */
144 };
145
146 /* Bits in Config4 */
147 enum Config4Bits {
148         LWPTN = (1 << 2),       /* not on 8139, 8139A */
149 };
150
151 /* Bits in Config5 */
152 enum Config5Bits {
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 */
160 };
161
162 enum RxConfigBits {
163         /* rx fifo threshold */
164         RxCfgFIFOShift = 13,
165         RxCfgFIFONone = (7 << RxCfgFIFOShift),
166
167         /* Max DMA burst */
168         RxCfgDMAShift = 8,
169         RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
170
171         /* rx ring buffer length */
172         RxCfgRcv8K = 0,
173         RxCfgRcv16K = (1 << 11),
174         RxCfgRcv32K = (1 << 12),
175         RxCfgRcv64K = (1 << 11) | (1 << 12),
176
177         /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
178         RxNoWrap = (1 << 7),
179 };
180
181 /* Twister tuning parameters from RealTek.
182    Completely undocumented, but required to tune bad links on some boards. */
183 enum CSCRBits {
184         CSCR_LinkOKBit = 0x0400,
185         CSCR_LinkChangeBit = 0x0800,
186         CSCR_LinkStatusBits = 0x0f000,
187         CSCR_LinkDownOffCmd = 0x003c0,
188         CSCR_LinkDownCmd = 0x0f3c0,
189 };
190
191 enum Cfg9346Bits {
192         Cfg9346_Lock = 0x00,
193         Cfg9346_Unlock = 0xC0,
194 };
195
196 static const uint_t rtl8139_intr_mask =
197         PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
198         TxErr | TxOK | RxErr | RxOK;
199
200 //static void Init_8139(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet))
201
202
203 static void rtl8139_interrupt( struct Interrupt_State * state )
204 {
205         Begin_IRQ(state);
206
207         uint_t status = In_Word(RTL8139_ISR);
208
209         PrintBoth("Interrupt Received: %x\n", status);
210
211         if( status == PKT_RX )
212                 rtl8139_Receive();
213
214         rtl8139_Clear_IRQ(status);
215         End_IRQ(state);
216
217 }
218
219 void rtl8139_Clear_IRQ(uint_t interrupts)
220 {
221         Out_Word(RTL8139_ISR, interrupts);
222 }
223
224 void Init_8139()
225 {
226         cur_tx = 0;
227         cur_rx = 0;
228
229         /* Reset the chip */
230         Out_Byte(RTL8139_CR, CmdReset);
231
232         //while( In_Byte(RTL8139_CR) != 0 )
233                 /*udelay(10)*/;
234
235         /* Unlock Config[01234] and BMCR register writes */
236         Out_Byte(RTL8139_9346CR, Cfg9346_Unlock);
237
238         /* Enable Tx/Rx before setting transfer thresholds */
239         Out_Byte(RTL8139_CR, CmdRxEnb | CmdTxEnb);
240
241         /* Using 32K ring */
242         Out_DWord(RTL8139_RCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift)
243                                  | AcceptBroadcast | AcceptMyPhys);
244
245 //      Out_DWord(RTL8139_TCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift));
246
247         Out_DWord(RTL8139_TCR, TxIFG96 | (6 << TxDMAShift) | (8 << TxRetryShift));
248
249         /* Lock Config[01234] and BMCR register writes */
250         Out_Byte(RTL8139_9346CR, Cfg9346_Lock);
251
252         /* init Rx ring buffer DMA address */
253         rx_buf = Malloc(RX_BUF_LEN);
254         Out_DWord(RTL8139_RBSTART, (uint_t)rx_buf);
255
256         /* init Tx buffer DMA addresses (4 registers) */
257         tx_buf = Malloc(TX_BUF_SIZE * 4);
258         int i;
259         for(i = 0; i < 4; i++)
260                 Out_DWord(RTL8139_TSAD0 + (i * 4), ((uint_t)tx_buf) + (i * TX_BUF_SIZE));
261
262         /* missed packet counter */
263         Out_DWord(RTL8139_MPC, 0);
264
265         // rtl8139_set_rx_mode does some stuff here.
266         Out_DWord(RTL8139_RCR, In_DWord(RTL8139_RCR) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
267                                 AcceptAllPhys);
268
269         for(i = 0; i < 8; i++)
270                 Out_Byte(RTL8139_MAR0 + i, 0xff);
271
272         /* no early-rx interrupts */
273         Out_Word(RTL8139_MULINT, In_Word(RTL8139_MULINT) & MultiIntrClear);
274
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);
278
279         /* Enable all known interrupts by setting the interrupt mask. */
280         Out_Word(RTL8139_IMR, rtl8139_intr_mask);
281
282         Install_IRQ(RTL8139_IRQ, rtl8139_interrupt);
283         Enable_IRQ(RTL8139_IRQ);
284
285         PrintBoth("8139 initialized\n");
286 }
287
288 int rtl8139_Send(uchar_t *packet, uint_t size)
289 {
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);
293         cur_tx++;
294         PrintBoth("Packet transmitted.  cur_tx = %d\n", cur_tx);
295         return 0;
296 }
297
298 int rtl8139_Receive()
299 {
300         PrintBoth("Packet Received\n");
301         int i;
302
303         while( (In_Byte(RTL8139_CR) & RxBufEmpty) == 0){
304
305                 uint_t ring_offset = cur_rx % RX_BUF_LEN;
306
307                 uint_t rx_status = ((uint_t)rx_buf + ring_offset);
308
309                 PrintBoth("RX Status = %x\n", rx_status);
310
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;
313
314                 PrintBoth("Packet Size = %d\n", pkt_len);
315         
316                 for (i = 0; i < pkt_len; i++){
317                         PrintBoth(" %x ", *((uchar_t *)(rx_status + i)));
318                 }
319                 PrintBoth("\n");
320
321                 cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
322                 Out_Word(RTL8139_CAPR, (ushort_t)(cur_rx - 16));
323
324                 pkt_cntr++;
325
326                 PrintBoth("Packet counter at %d\n", pkt_cntr);
327         }
328
329
330
331         return 0;
332 }