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