More work towards getting the appservers combined
[akaros.git] / kern / arch / i686 / ne2k.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * See LICENSE for details.
4  */
5
6 #ifdef __SHARC__
7 #pragma nosharc
8 #endif
9
10 #include <arch/mmu.h>
11 #include <arch/x86.h>
12 #include <arch/smp.h>
13 #include <arch/apic.h>
14 #include <arch/pci.h>
15 #include <arch/ne2k.h>
16
17 #include <ros/memlayout.h>
18
19 #include <atomic.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <trap.h>
23 #include <kmalloc.h>
24
25 #include <pmap.h>
26 #include <timing.h>
27
28 /** @file
29  * @brief NE2K Driver Sketch
30  *
31  * EXPERIMENTAL.
32  *
33  * Rough driver. Appears to work in QEMU. Probably completely broken under heavy load.
34  *
35  * @author Paul Pearce <pearce@eecs.berkeley.edu>
36  *
37  * @todo Everything
38  */
39
40 #define NE2K_RESET_R_ADDR 0x1f
41 #define NE2K_PG0_RW_CR  0x00
42 #define NE2K_PG0_RW_ISR 0x07
43 #define NE2K_PG0_W_IMR  0x0F
44 #define NE2K_PG0_W_PSTRT 0x1
45 #define NE2K_PG0_W_PSTP 0x2
46 #define NE2K_PG0_W_RCR 0xC
47 #define NE2K_PG0_R_RSR 0xC
48 #define NE2K_PG0_R_TSR 0x4
49 #define NE2K_PG0_W_TCR 0xD
50 #define NE2K_PG1_RW_PAR 0x1
51 #define NE2K_PG0_W_RSAR0 0x08
52 #define NE2K_PG0_W_RSAR1 0x09
53 #define NE2K_PG0_W_RBCR0 0x0A
54 #define NE2K_PG0_W_RBCR1 0x0B
55 #define NE2K_PG0_W_TBCR0 0x05
56 #define NE2K_PG0_W_TBCR1 0x06
57 #define NE2K_PG0_W_TPSR  0x04
58 #define NE2K_PG0_W_DCR 0x0E
59 #define NE2K_PG1_RW_CURR 0x07
60 #define NE2K_PG0_RW_BNRY 0x03
61
62 #define NE2K_PAGE_SIZE 256
63
64 #define NE2K_PMEM_START   (16*1024)
65 #define NE2K_PMEM_SIZE    (32*1024)
66 #define NE2K_NUM_PAGES          ((NE2K_PMEM_SIZE - NE2K_PMEM_START) / NE2K_PAGE_SIZE)
67 #define NE2K_NUM_RECV_PAGES     (NE2K_NUM_PAGES / 2)
68 #define NE2K_NUM_SEND_PAGES     (NE2K_NUM_PAGES / 2)
69 #define NE2K_FIRST_RECV_PAGE    (NE2K_PMEM_START / NE2K_PAGE_SIZE)
70 #define NE2K_LAST_RECV_PAGE     NE2K_FIRST_RECV_PAGE + NE2K_NUM_RECV_PAGES
71 #define NE2K_FIRST_SEND_PAGE    NE2K_LAST_RECV_PAGE + 1
72
73
74 #define SET_PAGE_0() (inb(ne2k_io_base_addr + NE2K_PG0_RW_CR) & 0x3F)
75
76 uint32_t ne2k_irq;      // Fix this
77 uint32_t ne2k_io_base_addr;
78
79 void* base_page;
80 uint32_t num_pages = 0;
81
82 void ne2k_init() {
83         
84         if (ne2k_scan_pci() < 0) return;
85         ne2k_mem_alloc();
86         ne2k_configure_nic();
87         ne2k_read_mac();
88         //ne2k_test_interrupts();
89         send_frame = &ne2k_send_frame;
90
91         ne2k_setup_interrupts();
92
93         eth_up = 1;
94
95         return;
96 }
97
98
99 int ne2k_scan_pci() {
100         
101         extern pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
102         extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
103
104         cprintf("Searching for NE2000 Network device...");
105
106         for (int i = 0; i < PCI_MAX_BUS; i++)
107                 for (int j = 0; j < PCI_MAX_DEV; j++)
108                         for (int k = 0; k < PCI_MAX_FUNC; k++) {
109                                 uint32_t address;
110                                 uint32_t lbus = i;
111                                 uint32_t ldev = j;
112                                 uint32_t lfunc = k;
113                                 uint32_t lreg = 0; 
114                                 uint32_t result  = 0;
115         
116                                 uint16_t dev_id = pci_dev_map[i][j][k].dev_id;
117                                 uint16_t ven_id = pci_dev_map[i][j][k].ven_id;
118
119                                 // Vender DNE
120                                 if (ven_id == INVALID_VENDOR_ID) 
121                                         continue;
122
123                                 // Ignore non RealTek 8168 Devices
124                                 if (ven_id != NE2K_VENDOR_ID || dev_id != NE2K_DEV_ID)
125                                         continue;
126                                 cprintf(" found on BUS %x DEV %x\n", i, j);
127
128                                 // Find the IRQ
129                                 ne2k_irq = pci_irq_map[i][j][k];
130                                 ne2k_debug("-->IRQ: %u\n", ne2k_irq);
131
132                                 // Loop over the BARs
133                                 for (int k = 0; k <= 5; k++) {
134                                         lreg = 4 + k;
135                                         address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
136                                 outl(PCI_CONFIG_ADDR, address);
137                                 result = inl(PCI_CONFIG_DATA);
138                                         
139                                         if (result == 0) // (0 denotes no valid data)
140                                                 continue;
141
142                                         // Read the bottom bit of the BAR. 
143                                         if (result & PCI_BAR_IO_MASK) {
144                                                 result = result & PCI_IO_MASK;
145                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
146                                         } else {
147                                                 result = result & PCI_MEM_MASK;
148                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
149                                         }
150                         
151                                         // TODO Switch to memory mapped instead of IO?
152                                         if (k == 0) // BAR0 denotes the IO Addr for the device
153                                                 ne2k_io_base_addr = result;                                             
154                                 }
155                                 
156                 return 0;
157         }
158         cprintf(" not found. No device configured.\n");
159         
160         return -1;
161 }
162
163 void ne2k_configure_nic() {
164         
165         ne2k_debug("-->Configuring Device.\n");
166         
167         // Reset. Yes reading from this addr resets it
168         inb(ne2k_io_base_addr + NE2K_RESET_R_ADDR);
169
170         // Configure
171         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
172         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTRT,  NE2K_FIRST_RECV_PAGE);
173         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, NE2K_FIRST_RECV_PAGE + 1);
174
175         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (0x22 & 0x3F) | 0x40);
176         outb(ne2k_io_base_addr + NE2K_PG1_RW_CURR, NE2K_FIRST_RECV_PAGE + 2);
177         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x22);
178         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTP, NE2K_LAST_RECV_PAGE);
179         outb(ne2k_io_base_addr + NE2K_PG0_W_DCR, 0x94); 
180         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
181         
182         outb(ne2k_io_base_addr + NE2K_PG0_W_RCR,  0xDF);
183         outb(ne2k_io_base_addr + NE2K_PG0_W_TCR,  0xE0);
184         
185
186         //uint8_t isr = inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
187         //cprintf("isr: %x\n", isr);
188
189         
190         return;
191 }
192
193 void ne2k_setup_interrupts() {
194         
195         extern handler_t interrupt_handlers[];
196         
197         ne2k_debug("-->Setting interrupts.\n");
198         
199         // Kernel based interrupt stuff
200         register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + ne2k_irq, ne2k_interrupt_handler, (void *)0);
201         
202         ioapic_route_irq(ne2k_irq, 6);  
203         
204         SET_PAGE_0();
205
206         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xBF);
207
208         outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR, 0xFF);
209         return;
210 }
211
212 void ne2k_mem_alloc() {
213         
214         num_pages = ROUNDUP(NE2K_NUM_PAGES * NE2K_PAGE_SIZE, PGSIZE) / PGSIZE;
215         base_page = get_cont_pages(LOG2_UP(num_pages), 0);      
216 }
217
218 void ne2k_read_mac() {
219
220         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
221         
222         // Set correct bits
223         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0xA);
224         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
225         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, 0x0);
226         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0x6);
227         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x0);
228
229
230         for (int i = 0; i < 6; i++)
231                 device_mac[i] = inb(ne2k_io_base_addr + 0x10) & inb(ne2k_io_base_addr + 0x10);
232
233         // Set page 1
234         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
235
236         for (int i = 0; i < 6; i++) 
237            outb(ne2k_io_base_addr + NE2K_PG1_RW_PAR + i, device_mac[i]);
238
239         
240         ne2k_debug("-->DEVICE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & device_mac[0], 0xFF & device_mac[1],        
241                                                                     0xFF & device_mac[2], 0xFF & device_mac[3], 
242                                                                 0xFF & device_mac[4], 0xFF & device_mac[5]);
243         // Restore old setting.
244         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
245         return;
246 }
247
248 void ne2k_test_interrupts() {
249         
250         cprintf("Generating Interrupt...\n");
251         outb(ne2k_io_base_addr + 0x0A, 0x00);
252         outb(ne2k_io_base_addr + 0x0B, 0x00);
253         outb(ne2k_io_base_addr + 0x00, 0x0A);
254         udelay(10000000);
255
256         cprintf("Generating Interrupt again...\n");
257         outb(ne2k_io_base_addr + 0x0A, 0x00);
258         outb(ne2k_io_base_addr + 0x0B, 0x00);
259         outb(ne2k_io_base_addr + 0x00, 0x0A);
260         udelay(10000000);
261         
262 }
263
264 // We need to evaluate this routine in terms of concurrency.
265 // We also need to figure out whats up with different core interrupts
266 void ne2k_interrupt_handler(trapframe_t *tf, void* data) {
267         
268         ne2k_interrupt_debug("\nNE2K interrupt on core %u!\n", lapic_get_id());
269
270         SET_PAGE_0();
271
272         uint8_t isr= inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
273         ne2k_interrupt_debug("isr: %x\n", isr);
274         
275         while (isr != 0x0) {
276
277                 // TODO: Other interrupt cases.
278
279                 if (isr & 0x1) {
280                         ne2k_interrupt_debug("-->Packet received.\n");
281                         ne2k_handle_rx_packet();
282                 }
283                 
284                 SET_PAGE_0();
285
286                 // Clear interrupts
287                 isr = inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
288                 outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR, isr);
289
290         }
291
292         ne2k_handle_rx_packet();
293         
294         return;                         
295 }
296
297 // @TODO: Is this broken? Didn't change it after kmalloc changed
298 void ne2k_handle_rx_packet() {
299         
300         SET_PAGE_0();
301
302         uint8_t bound = inb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY);
303
304         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
305         
306         // Set page 1
307         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
308
309         uint8_t next = inb(ne2k_io_base_addr + NE2K_PG1_RW_CURR);
310
311         // Restore old setting.
312         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
313
314         uint8_t start = NE2K_FIRST_RECV_PAGE;
315         uint8_t stop = NE2K_LAST_RECV_PAGE;
316
317         // Broken mult packets?
318         if (((bound + 1) == next) || (((bound + 1) == stop) && (start == next))) {
319                 ne2k_debug("NO PACKET TO PROCESS\n");
320                 return;
321         }
322
323         uint32_t kmalloc_size;
324
325         if (MAX_FRAME_SIZE % NE2K_PAGE_SIZE) {
326                 kmalloc_size = ((MAX_FRAME_SIZE / NE2K_PAGE_SIZE) + 1) * NE2K_PAGE_SIZE;
327         } else {
328                 kmalloc_size = MAX_FRAME_SIZE;
329         }
330         
331         char *rx_buffer = kmalloc(kmalloc_size, 0);
332         
333         if (rx_buffer == NULL) panic ("Can't allocate page for incoming packet.");
334
335         uint8_t curr = bound + 1;
336
337         uint8_t header[4];
338         uint16_t packet_len = 0xFFFF;
339         uint16_t page_count = 0;
340         for (int i = 0, n = 0; i < (MAX_FRAME_SIZE / NE2K_PAGE_SIZE); i++) {
341                 if (curr == stop)
342                         curr = start;                   
343
344                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
345                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, curr);
346
347
348                 // Fix this. Its hard coded to 256
349                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0);
350                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x1);
351         
352                 outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x0A);
353
354                 for (int j = 0; j < NE2K_PAGE_SIZE; j++) {
355                         uint8_t val = inb(ne2k_io_base_addr + 0x10);
356                         if ((i == 0) && (j < 4)) {
357                                 header[j] = val;
358                         } else { 
359                                 rx_buffer[n++] = val;
360                         }
361                 }
362
363                 if (i == 0) {
364                         packet_len = ((uint16_t)header[3] << 8) | (uint16_t)header[2];
365                         if (packet_len % NE2K_PAGE_SIZE) {
366                                 page_count = (packet_len / NE2K_PAGE_SIZE) + 1;
367                         } else {
368                                 page_count = (packet_len / NE2K_PAGE_SIZE);
369                         }
370                 }
371                 
372                 if ((i + 1) == page_count)
373                         break;
374
375                 curr++;
376         
377         }
378         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, curr);
379
380         if (packet_len == 0) {
381                 ne2k_debug("Triggered on an empty packet.\n");
382                 return;
383         }
384
385         // Treat as a syscall frontend response packet if eth_type says so
386         // Will eventually go away, so not too worried about elegance here...
387         #include <frontend.h>
388         #include <arch/frontend.h>
389         if((uint16_t)(rx_buffer[13]) == APPSERVER_ETH_TYPE) {
390                 handle_appserver_packet(rx_buffer, packet_len);
391                 kfree(rx_buffer);
392                 return;
393         }
394
395         spin_lock(&packet_buffers_lock);
396
397         if (num_packet_buffers >= MAX_PACKET_BUFFERS) {
398                 printk("WARNING: DROPPING PACKET!\n");
399                 spin_unlock(&packet_buffers_lock);
400                 kfree(rx_buffer);
401                 return;
402         }
403
404         packet_buffers[packet_buffers_tail] = rx_buffer;
405         packet_buffers_sizes[packet_buffers_tail] = packet_len;
406
407         packet_buffers_tail = (packet_buffers_tail + 1) % MAX_PACKET_BUFFERS;
408         num_packet_buffers++;
409
410         spin_unlock(&packet_buffers_lock);
411         
412         return;
413 }
414
415 // copied with love (and modification) from tcp/ip illistrated vl 2 1995 pg 236
416 // bsd licenced
417 uint16_t cksum(char *CT(len) ip, int len) {
418         
419         uint32_t sum = 0;
420         // Next two lines for ivy. Grr.
421         char *curr_ip = ip;
422         int curr_len = len;
423
424         while(curr_len > 1) {
425                 sum += *((uint16_t*) curr_ip);
426                 curr_ip = curr_ip + 2;
427                 
428                 if(sum & 0x80000000)    /* if high order bit set, fold */
429                         sum = (sum & 0xFFFF) + (sum >> 16);
430                         curr_len -= 2;
431                 }
432
433                 if(curr_len)             /* take care of left over byte */
434                         sum += *curr_ip;
435                   
436                 while(sum>>16)
437                         sum = (sum & 0xFFFF) + (sum >> 16);
438
439                 return ~sum;
440 }
441
442
443 // Main routine to send a frame. May be completely broken.
444 int ne2k_send_frame(const char *data, size_t len) {
445
446         if (data == NULL)
447                 return -1;
448         if (len == 0)
449                 return 0;
450
451
452         if (len > MAX_FRAME_SIZE) {
453                 ne2k_frame_debug("-->Frame Too Large!\n");
454                 return -1;
455         }
456
457         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0x00);
458
459
460         // The TPSR takes a page #
461         // The RSAR takes a byte offset, but since a page is 256 bits
462         // and we are writing on page boundries, the low bits are 0, and
463         // the high bits are a page #
464         outb(ne2k_io_base_addr + NE2K_PG0_W_TPSR, NE2K_FIRST_SEND_PAGE);
465         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
466         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, NE2K_FIRST_SEND_PAGE);
467
468         
469         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR0, len & 0xFF);
470         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR1, len >> 8);
471
472         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, len & 0xFF);
473         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, len >> 8);
474
475         
476         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x12);
477         
478
479         for (int i = 0; i<len; i = i + 1) {
480                 outb(ne2k_io_base_addr + 0x10, *(uint8_t*)(data + i));
481                 //printk("sent: %x\n", *(uint8_t*)(data + i));
482         }
483         
484         while(( inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR) & 0x40) == 0);
485
486         outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR,  0x40);
487
488         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xBF);
489
490         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x1E);
491         
492         
493         return len;
494 }
495