Moved all NIC related stuff into rl8168.c/h from testing. Cleaned up nic code
[akaros.git] / kern / src / rl8168.c
1 #ifdef __DEPUTY__
2 #pragma nodeputy
3 #endif
4
5 #include <arch/mmu.h>
6 #include <arch/x86.h>
7 #include <arch/smp.h>
8 #include <arch/apic.h>
9
10 #include <ros/memlayout.h>
11
12 #include <atomic.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <rl8168.h>
16 #include <trap.h>
17
18 #include <pmap.h>
19
20 /* RealTek 8168d (8111d) NIC Driver
21  *
22  * Written by Paul Pearce.
23  *
24  * This is a really rough "driver". Really, its not a driver, just a kernel hack to give
25  * the kernel a way to receive and send packets. The basis of the init code is the OSDEV
26  * page on the 8169 chipset, which is a varient of this chipset (most 8169 drivers work 
27  * on the 8168d). http://wiki.osdev.org/RTL8169
28  * 
29  * Basic ideas (although no direct code) were gleamed from the OpenBSD re(4) driver,
30  * which can be found in sys/dev/ic/re.c. sys/dev/ic/rtl81x9reg.h is needed to make
31  * sense of the constants used in re.c.
32  *
33  * This is an ongoing work in progress. Main thing is we need a kernel interface for PCI
34  * devices and network devices, that we can hook into, instead of providing arbitary functions
35  */
36
37 #define nic_debug(...)  cprintf(__VA_ARGS__)  
38 #define nic_interrupt_debug(...)  cprintf(__VA_ARGS__)  
39
40
41 #define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)( (BUS << 16) | (DEV << 11) | \
42                                                              (FUNC << 8) | REG  | \
43                                                              ((uint32_t)0x80000000))
44 #define PCI_CONFIG_ADDR     0xCF8
45 #define PCI_CONFIG_DATA     0xCFC
46
47 #define REALTEK_VENDOR_ID   0x10ec
48 #define INVALID_VENDOR_ID   0xFFFF
49 #define REALTEK_DEV_ID      0x8168
50
51 #define PCI_IO_MASK         0xFFF8
52 #define PCI_MEM_MASK        0xFFFFFFF0
53 #define PCI_IRQ_MASK            0xFF
54 #define PCI_VENDOR_MASK         0xFFFF
55 #define PCI_DEVICE_OFFSET       0x10
56 #define PCI_IRQ_REG                     0x3c
57
58 #define PCI_MAX_BUS                     256
59 #define PCI_MAX_DEV                     32
60 #define PCI_BAR_IO_MASK         0x1
61
62 #define RL_CTRL_RESET_MASK  0x10
63 #define RL_CTRL_RXTX_MASK       0x0C
64
65 #define RL_HWREV_REG            0x40
66 #define RL_HWREV_MASK           0x7C800000
67
68 #define RL_MAC_OFFSET           0x0
69
70 #define RL_CTRL_REG         0x37
71 #define RL_IM_REG                       0x3c
72 #define RL_IS_REG                       0x3E
73 #define RL_EP_CTRL_REG          0x50
74 #define RL_RX_CTRL_REG      0x44
75 #define RL_TX_CTRL_REG      0x40
76 #define RL_RX_MXPKT_REG     0xDA
77 #define RL_TX_MXPKT_REG     0xEC
78 #define RL_RX_DES_REG       0xE4
79 #define RL_TX_DES_REG       0x20
80
81 #define RL_RX_MAX_SIZE          0x1000 // This is in units of bytes. 0x1000 = 4096
82 #define RL_TX_MAX_SIZE          0x20   // This is in units of 128bytes, 128 * 0x20 = 4096
83 #define RL_EP_CTRL_UL_MASK      0xC0
84 #define RL_EP_CTRL_L_MASK       0x00
85
86 // NOTE: THESE SHOULD BE BROKEN DOWN INTO A SERIES OF BITS TO REPERSENT THE VARIOUS OPTIONS
87 // AND THEN THE MASK SHOULD BE DEFINED TO BE AN OR OF THOSE BITS. THIS IS A QUICK HACK JOB.
88 #define RL_RX_CFG_MASK          0x0000E70F  // RXFTH: unlimited, MXDMA: unlimited, AAP: set (promisc. mode set)
89 #define RL_TX_CFG_MASK          0x03000700  // IFG: normal, MXDMA: unlimited
90 #define RL_INTERRUPT_MASK       0xFFFF      // All enabled
91
92
93
94 #define RL_INT_SERR                     0x8000
95 #define RL_INT_TIMEOUT          0x4000
96 #define RL_INT_SWINT            0x0100
97 #define RL_INT_TDU                      0x0080
98 #define RL_INT_FOVW                     0x0040
99 #define RL_INT_LINKCHG          0x0020
100 #define RL_INT_RDU                      0x0010
101 #define RL_INT_TERR                     0x0008
102 #define RL_INT_TOK                      0x0004
103 #define RL_INT_RERR                     0x0002
104 #define RL_INT_ROK                      0x0001
105
106
107 #define DES_OWN_MASK            0x80000000
108 #define DES_EOR_MASK            0x40000000
109 #define DES_SIZE_MASK           0x3FFF
110 #define DES_FS_MASK                     0x20000000
111 #define DES_LS_MASK                     0x10000000
112
113 #define KERNEL_IRQ_OFFSET       32
114
115
116 struct Descriptor
117 {
118     unsigned int command,  /* command/status dword */
119                  vlan,     /* currently unused */
120                  low_buf,  /* low 32-bits of physical buffer address */
121                  high_buf; /* high 32-bits of physical buffer address */
122 };
123
124
125 uint32_t io_base_addr = 0;
126 uint32_t irq = 0;
127 char mac_address[6];
128
129 int rx_buffer_len = PGSIZE;
130 int num_of_rx_descriptors = PGSIZE/sizeof(struct Descriptor);
131
132 struct Descriptor *rx_des_kva;
133 struct Descriptor *rx_des_pa;
134
135 struct Descriptor *tx_des_kva;
136 struct Descriptor *tx_des_pa;
137
138 struct Descriptor *rx_des_cur;
139 struct Descriptor *tx_des_cur;
140
141
142 int scan_pci() {
143         
144         uint32_t address;
145         uint32_t lbus = 0;
146         uint32_t ldev = 0;
147         uint32_t lfunc = 0; // We only look at function 0 for now.
148         uint32_t lreg = 0; 
149         uint32_t result  = 0;
150  
151         cprintf("Searching for RealTek 8168 Network device......");
152
153         for (int i = 0; i < PCI_MAX_BUS; i++)
154                 for (int j = 0; j < PCI_MAX_DEV; j++) {
155
156                 lbus = i;
157                 ldev = j;
158                 lreg = 0; // PCI REGISTER 0
159
160                 address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg); 
161
162                 // Probe current bus/dev
163                 outl(PCI_CONFIG_ADDR, address);
164                 result = inl(PCI_CONFIG_DATA);
165         
166                 uint16_t dev_id = result >> PCI_DEVICE_OFFSET;
167                 uint16_t ven_id = result & PCI_VENDOR_MASK;
168
169                 // Vender DNE
170                 if (ven_id == INVALID_VENDOR_ID) 
171                         continue;
172
173                 // Ignore non RealTek 8168 Devices
174                 if (ven_id != REALTEK_VENDOR_ID || dev_id != REALTEK_DEV_ID)
175                         continue;
176                 cprintf(" found on BUS %x DEV %x\n", i, j);
177
178                 // Find the IRQ
179                 address = MK_CONFIG_ADDR(lbus, ldev, lfunc, PCI_IRQ_REG);
180                 outl(PCI_CONFIG_ADDR, address);
181                 irq = inl(PCI_CONFIG_DATA) & PCI_IRQ_MASK;
182                 nic_debug("-->IRQ: %u\n", irq);
183
184                 // Loop over the BARs
185                 for (int k = 0; k <= 5; k++) {
186                         lreg = 4 + k;
187                         address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
188                 outl(PCI_CONFIG_ADDR, address);
189                 result = inl(PCI_CONFIG_DATA);
190                                         
191                         if (result == 0) // (0 denotes no valid data)
192                                 continue;
193
194                         // Read the bottom bit of the BAR. 
195                         if (result & PCI_BAR_IO_MASK) {
196                                 result = result & PCI_IO_MASK;
197                                 nic_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
198                         } else {
199                                 result = result & PCI_MEM_MASK;
200                                 nic_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
201                         }
202
203                         if (k == 0) // BAR0 denotes the IO Addr for the device
204                                 io_base_addr = result;                                          
205                 }
206                 
207                 nic_debug("-->hwrev: %x\n", inl(io_base_addr + RL_HWREV_REG) & RL_HWREV_MASK);
208                 
209                 return 0;
210         }
211         cprintf(" not found. No device configured.\n");
212         
213         return -1;
214 }
215
216 void read_mac() {
217         
218         for (int i = 0; i < 6; i++)
219            mac_address[i] = inb(io_base_addr + RL_MAC_OFFSET + i); 
220         
221         nic_debug("-->DEVICE MAC: %x:%x:%x:%x:%x:%x\n", 0xFF & mac_address[0], 0xFF & mac_address[1],   
222                                                         0xFF & mac_address[2], 0xFF & mac_address[3],   
223                                                     0xFF & mac_address[4], 0xFF & mac_address[5]);
224         return;
225 }
226
227 void reset_nic() {
228         
229         nic_debug("-->Resetting device..... ");
230         outb(io_base_addr + RL_CTRL_REG, RL_CTRL_RESET_MASK);
231         while (inb(io_base_addr + RL_CTRL_REG) & RL_CTRL_RESET_MASK);
232         nic_debug(" done.\n");
233 }
234
235 void setup_interrupts() {
236         
237         extern handler_t interrupt_handlers[];
238         
239         nic_debug("-->Setting interrupts.\n");
240         
241         // Enable all NIC interrupts only
242         outw(io_base_addr + RL_IM_REG, RL_INTERRUPT_MASK);
243         
244         //Clear the current interrupts.
245         outw(io_base_addr + RL_IS_REG, RL_INTERRUPT_MASK);
246         
247         // Kernel based interrupt stuff
248         register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + irq, nic_interrupt_handler, 0);
249         pic_unmask_irq(irq);
250         unmask_lapic_lvt(LAPIC_LVT_LINT0);
251         enable_irq();
252 }
253
254 void setup_rx_descriptors() {
255         
256         nic_debug("-->Setting up rx descriptors.\n");
257         
258         page_t *rx_des_page = NULL, *tx_des_page = NULL;
259                         
260         page_alloc(&rx_des_page);
261         page_alloc(&tx_des_page);
262         
263         rx_des_kva = page2kva(rx_des_page);
264         tx_des_kva = page2kva(tx_des_page);
265         
266         rx_des_pa = page2pa(rx_des_page);
267         tx_des_pa = page2pa(tx_des_page);
268
269         
270     for (int i = 0; i < num_of_rx_descriptors; i++) 
271     {
272         if (i == (num_of_rx_descriptors - 1)) /* Last descriptor? if so, set the EOR bit */
273                         rx_des_kva[i].command = (DES_OWN_MASK | DES_EOR_MASK | (rx_buffer_len & DES_SIZE_MASK));
274         else
275                         rx_des_kva[i].command = (DES_OWN_MASK | (rx_buffer_len & DES_SIZE_MASK));
276                 
277                 page_t *rx_buf_page;
278                 page_alloc(&rx_buf_page);
279         rx_des_kva[i].low_buf = page2pa(rx_buf_page); 
280                 //.high_buf used if we do 64bit.
281     }
282
283         rx_des_cur = rx_des_kva;
284 }
285
286 void configure_nic() {
287         
288         nic_debug("-->Configuring Device.\n");
289
290         outb(io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_UL_MASK);                // Unlock EPPROM CTRL REG
291         outl(io_base_addr + RL_RX_CTRL_REG, RL_RX_CFG_MASK);                    // Configure RX
292         outl(io_base_addr + RL_TX_CTRL_REG, RL_TX_CFG_MASK);                    // Configure TX
293     outw(io_base_addr + RL_RX_MXPKT_REG, RL_RX_MAX_SIZE);                       // Set max RX Packet Size
294     outb(io_base_addr + RL_TX_MXPKT_REG, RL_TX_MAX_SIZE);                       // Set max TX Packet Size
295
296         // Note: These are the addresses the physical device will use, so we need the physical addresses of the rings
297     outl(io_base_addr + RL_TX_DES_REG, (unsigned long)tx_des_pa);       // Set TX Des Ring Start Addr
298     outl(io_base_addr + RL_RX_DES_REG, (unsigned long)rx_des_pa);       // Set RX Des Ring Start Addr
299
300     outb(io_base_addr + RL_CTRL_REG, RL_CTRL_RXTX_MASK);                        // Enable RX and TX in the CTRL Reg
301     outl(io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_L_MASK);             // Unlock the EPPROM Ctrl REG
302         
303         return;
304 }
305
306 void poll_rx_descriptors() {
307         
308         while (1) {
309                 udelay(3000000);
310                 int seen = 0;
311                 for (int i = 0; i < num_of_rx_descriptors; i++) {
312                         
313                         if ((rx_des_kva[i].command & DES_OWN_MASK) == 0) {
314                                 cprintf("des: %u Status: %x OWN: %u FS: %u LS: %u SIZE: %u\n", 
315                                                                                 i, 
316                                                                                 rx_des_kva[i].command, 
317                                                                                 rx_des_kva[i].command & DES_OWN_MASK, 
318                                                                                 ((rx_des_kva[i].command & DES_FS_MASK) != 0),
319                                                                                 ((rx_des_kva[i].command & DES_LS_MASK) != 0),
320                                                                                 rx_des_kva[i].command & DES_SIZE_MASK);                         
321                         }
322                 }
323         }
324         
325         return;
326 }
327
328 void init_nic() {
329         
330         if (scan_pci() < 0) return;
331         read_mac();
332         setup_interrupts();
333         setup_rx_descriptors();
334         configure_nic();
335
336         poll_rx_descriptors();
337                                 
338         // Trigger sw based nic interrupt
339         //outb(io_base_addr + 0x38, 0x1);
340         //nic_debug("Triggered NIC interrupt.\n");
341         
342         return;
343         
344 }
345 // We need to evaluate this routine in terms of concurrency.
346 // We also need to figure out whats up with different core interrupts
347 void nic_interrupt_handler(trapframe_t *tf, void* data) {
348         
349         nic_interrupt_debug("\nNic interrupt!\n");
350         
351         // Read the offending interrupt(s)
352         uint16_t interrupt_status = inw(io_base_addr + RL_IS_REG);
353
354         // We can have multiple interrupts fire at once
355         // I've personally seen this. I saw RL_INT_LINKCHG and RL_INT_ROK fire at the same time.
356         // This means we need to handle this as a series of independent if's
357         
358         if (interrupt_status & RL_INT_ROK) {
359                 nic_interrupt_debug("-->RX OK\n");
360         }       
361         
362         if (interrupt_status & RL_INT_RERR) {
363                 nic_interrupt_debug("-->RX ERR\n");
364         }
365         
366         if (interrupt_status & RL_INT_TOK) {
367                 nic_interrupt_debug("-->TX OK\n");
368         }
369         
370         if (interrupt_status & RL_INT_TERR) {
371                 nic_interrupt_debug("-->TX ERR\n");
372         }
373         
374         if (interrupt_status & RL_INT_RDU) {
375                 nic_interrupt_debug("-->RX Descriptor Unavailable\n");
376         }
377         
378         if (interrupt_status & RL_INT_LINKCHG) {
379                 nic_interrupt_debug("-->Link Status Changed\n");
380         }
381         
382         if (interrupt_status & RL_INT_FOVW) {
383                 nic_interrupt_debug("-->RX Fifo Overflow\n");
384         }
385         
386         if (interrupt_status & RL_INT_TDU) {
387                 nic_interrupt_debug("-->TX Descriptor Unavailable\n");
388         }
389         
390         if (interrupt_status & RL_INT_SWINT) {
391                 nic_interrupt_debug("-->Software Generated Interrupt\n");
392         }
393         
394         if (interrupt_status & RL_INT_TIMEOUT) {
395                 nic_interrupt_debug("-->Timer Expired\n");
396         }
397         
398         if (interrupt_status & RL_INT_SERR) {
399                 nic_interrupt_debug("-->PCI Bus System Error\n");
400         }
401         
402         nic_interrupt_debug("\n");
403                 
404         // Clear interrupts     
405         outw(io_base_addr + RL_IS_REG, RL_INTERRUPT_MASK);
406         return;
407 }
408
409 void nic_handle_rx_packet() {
410         return;
411 }