PCI cleanup and better BAR handling
[akaros.git] / kern / drivers / net / 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 "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 <time.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         printk("Network Card MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", 
89            device_mac[0],device_mac[1],device_mac[2],
90            device_mac[3],device_mac[4],device_mac[5]);
91         //ne2k_test_interrupts();
92         send_frame = &ne2k_send_frame;
93
94         ne2k_setup_interrupts();
95
96         eth_up = 1;
97
98         return;
99 }
100
101
102 int ne2k_scan_pci() {
103         struct pci_device *pcidev;
104         uint32_t result;
105         printk("Searching for NE2000 Network device...");
106         STAILQ_FOREACH(pcidev, &pci_devices, all_dev) {
107                 /* Ignore non NE2K Devices */
108                 if ((pcidev->ven_id != NE2K_VENDOR_ID) ||
109                    (pcidev->dev_id != NE2K_DEV_ID))
110                         continue;
111                 printk(" found on BUS %x DEV %x\n", pcidev->bus, pcidev->dev);
112                 /* Find the IRQ */
113                 ne2k_irq = pcidev->irqline;
114                 ne2k_debug("-->IRQ: %u\n", ne2k_irq);
115                 /* Loop over the BARs */
116                 for (int k = 0; k <= 5; k++) {
117                         int reg = 4 + k;
118                 result = pcidev_read32(pcidev, reg << 2);       // SHAME!
119                         if (result == 0) // (0 denotes no valid data)
120                                 continue;
121                         // Read the bottom bit of the BAR. 
122                         if (result & PCI_BAR_IO) {
123                                 result = result & PCI_BAR_IO_MASK;
124                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
125                         } else {
126                                 result = result & PCI_BAR_MEM_MASK;
127                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
128                         }
129                         // TODO Switch to memory mapped instead of IO?
130                         if (k == 0) // BAR0 denotes the IO Addr for the device
131                                 ne2k_io_base_addr = result;                                             
132                 }
133                 return 0;
134         }
135         printk(" not found. No device configured.\n");
136         return -1;
137 }
138
139 void ne2k_configure_nic() {
140         
141         ne2k_debug("-->Configuring Device.\n");
142         
143         // Reset. Yes reading from this addr resets it
144         inb(ne2k_io_base_addr + NE2K_RESET_R_ADDR);
145
146         // Configure
147         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
148         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTRT,  NE2K_FIRST_RECV_PAGE);
149         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, NE2K_FIRST_RECV_PAGE + 1);
150
151         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (0x22 & 0x3F) | 0x40);
152         outb(ne2k_io_base_addr + NE2K_PG1_RW_CURR, NE2K_FIRST_RECV_PAGE + 2);
153         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x22);
154         outb(ne2k_io_base_addr + NE2K_PG0_W_PSTP, NE2K_LAST_RECV_PAGE);
155         outb(ne2k_io_base_addr + NE2K_PG0_W_DCR, 0x94); 
156         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x22);
157         
158         outb(ne2k_io_base_addr + NE2K_PG0_W_RCR,  0xDF);
159         outb(ne2k_io_base_addr + NE2K_PG0_W_TCR,  0xE0);
160         
161
162         //uint8_t isr = inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
163         //cprintf("isr: %x\n", isr);
164
165         
166         return;
167 }
168
169 void ne2k_setup_interrupts() {
170         
171         extern handler_t interrupt_handlers[];
172         
173         ne2k_debug("-->Setting interrupts.\n");
174         
175         // Kernel based interrupt stuff
176         register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + ne2k_irq, ne2k_interrupt_handler, (void *)0);
177         
178 #ifdef CONFIG_ENABLE_MPTABLES
179         ioapic_route_irq(ne2k_irq, 0);  
180 #else
181         pic_unmask_irq(ne2k_irq);
182         unmask_lapic_lvt(LAPIC_LVT_LINT0);
183         enable_irq();
184 #endif
185         
186         SET_PAGE_0();
187
188         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xBF);
189
190         outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR, 0xFF);
191         return;
192 }
193
194 void ne2k_mem_alloc() {
195         
196         num_pages = ROUNDUP(NE2K_NUM_PAGES * NE2K_PAGE_SIZE, PGSIZE) / PGSIZE;
197         base_page = get_cont_pages(LOG2_UP(num_pages), 0);      
198 }
199
200 void ne2k_read_mac() {
201
202         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
203         
204         // Set correct bits
205         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0xA);
206         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
207         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, 0x0);
208         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0x6);
209         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x0);
210
211
212         for (int i = 0; i < 6; i++)
213                 device_mac[i] = inb(ne2k_io_base_addr + 0x10) & inb(ne2k_io_base_addr + 0x10);
214
215         // Set page 1
216         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
217
218         for (int i = 0; i < 6; i++) 
219            outb(ne2k_io_base_addr + NE2K_PG1_RW_PAR + i, device_mac[i]);
220
221         
222         ne2k_debug("-->DEVICE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & device_mac[0], 0xFF & device_mac[1],        
223                                                                     0xFF & device_mac[2], 0xFF & device_mac[3], 
224                                                                 0xFF & device_mac[4], 0xFF & device_mac[5]);
225         // Restore old setting.
226         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
227         return;
228 }
229
230 void ne2k_test_interrupts() {
231         
232         cprintf("Generating Interrupt...\n");
233         outb(ne2k_io_base_addr + 0x0A, 0x00);
234         outb(ne2k_io_base_addr + 0x0B, 0x00);
235         outb(ne2k_io_base_addr + 0x00, 0x0A);
236         udelay(10000000);
237
238         cprintf("Generating Interrupt again...\n");
239         outb(ne2k_io_base_addr + 0x0A, 0x00);
240         outb(ne2k_io_base_addr + 0x0B, 0x00);
241         outb(ne2k_io_base_addr + 0x00, 0x0A);
242         udelay(10000000);
243         
244 }
245
246 // We need to evaluate this routine in terms of concurrency.
247 // We also need to figure out whats up with different core interrupts
248 void ne2k_interrupt_handler(struct hw_trapframe *hw_tf, void *data)
249 {
250         
251         ne2k_interrupt_debug("\nNE2K interrupt on core %u!\n", lapic_get_id());
252
253         SET_PAGE_0();
254
255         uint8_t isr= inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
256         ne2k_interrupt_debug("isr: %x\n", isr);
257         
258         while (isr != 0x0) {
259
260                 // TODO: Other interrupt cases.
261
262                 if (isr & 0x1) {
263                         ne2k_interrupt_debug("-->Packet received.\n");
264                         ne2k_handle_rx_packet();
265                 }
266                 
267                 SET_PAGE_0();
268
269                 // Clear interrupts
270                 isr = inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR);
271                 outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR, isr);
272
273         }
274
275         ne2k_handle_rx_packet();
276         
277         return;                         
278 }
279
280 // @TODO: Is this broken? Didn't change it after kmalloc changed
281 void ne2k_handle_rx_packet() {
282         
283         SET_PAGE_0();
284
285         uint8_t bound = inb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY);
286
287         uint8_t cr = inb(ne2k_io_base_addr + NE2K_PG0_RW_CR);
288         
289         // Set page 1
290         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, (cr & 0x3F) | 0x40);
291
292         uint8_t next = inb(ne2k_io_base_addr + NE2K_PG1_RW_CURR);
293
294         // Restore old setting.
295         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, cr);
296
297         uint8_t start = NE2K_FIRST_RECV_PAGE;
298         uint8_t stop = NE2K_LAST_RECV_PAGE;
299
300         // Broken mult packets?
301         if (((bound + 1) == next) || (((bound + 1) == stop) && (start == next))) {
302                 ne2k_debug("NO PACKET TO PROCESS\n");
303                 return;
304         }
305
306         uint32_t kmalloc_size;
307
308         if (MAX_FRAME_SIZE % NE2K_PAGE_SIZE) {
309                 kmalloc_size = ((MAX_FRAME_SIZE / NE2K_PAGE_SIZE) + 1) * NE2K_PAGE_SIZE;
310         } else {
311                 kmalloc_size = MAX_FRAME_SIZE;
312         }
313         
314         char *rx_buffer = kmalloc(kmalloc_size, 0);
315         
316         if (rx_buffer == NULL) panic ("Can't allocate page for incoming packet.");
317
318         uint8_t curr = bound + 1;
319
320         uint8_t header[4];
321         uint16_t packet_len = 0xFFFF;
322         uint16_t page_count = 0;
323         for (int i = 0, n = 0; i < (MAX_FRAME_SIZE / NE2K_PAGE_SIZE); i++) {
324                 if (curr == stop)
325                         curr = start;                   
326
327                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
328                 outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, curr);
329
330
331                 // Fix this. Its hard coded to 256
332                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, 0);
333                 outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, 0x1);
334         
335                 outb(ne2k_io_base_addr + NE2K_PG0_RW_CR, 0x0A);
336
337                 for (int j = 0; j < NE2K_PAGE_SIZE; j++) {
338                         uint8_t val = inb(ne2k_io_base_addr + 0x10);
339                         if ((i == 0) && (j < 4)) {
340                                 header[j] = val;
341                         } else { 
342                                 rx_buffer[n++] = val;
343                         }
344                 }
345
346                 if (i == 0) {
347                         packet_len = ((uint16_t)header[3] << 8) | (uint16_t)header[2];
348                         if (packet_len % NE2K_PAGE_SIZE) {
349                                 page_count = (packet_len / NE2K_PAGE_SIZE) + 1;
350                         } else {
351                                 page_count = (packet_len / NE2K_PAGE_SIZE);
352                         }
353                 }
354                 
355                 if ((i + 1) == page_count)
356                         break;
357
358                 curr++;
359         
360         }
361         outb(ne2k_io_base_addr + NE2K_PG0_RW_BNRY, curr);
362
363         if (packet_len == 0) {
364                 ne2k_debug("Triggered on an empty packet.\n");
365                 return;
366         }
367
368 #ifdef CONFIG_APPSERVER
369         // Treat as a syscall frontend response packet if eth_type says so
370         // Will eventually go away, so not too worried about elegance here...
371         #include <frontend.h>
372         #include <arch/frontend.h>
373         uint16_t eth_type = htons(*(uint16_t*)(rx_buffer + 12));
374         if(eth_type == APPSERVER_ETH_TYPE) {
375                 handle_appserver_packet(rx_buffer, packet_len);
376                 kfree(rx_buffer);
377                 return;
378         }
379 #endif
380
381         spin_lock(&packet_buffers_lock);
382
383         if (num_packet_buffers >= MAX_PACKET_BUFFERS) {
384                 printk("WARNING: DROPPING PACKET!\n");
385                 spin_unlock(&packet_buffers_lock);
386                 kfree(rx_buffer);
387                 return;
388         }
389
390         packet_buffers[packet_buffers_tail] = rx_buffer;
391         packet_buffers_sizes[packet_buffers_tail] = packet_len;
392
393         packet_buffers_tail = (packet_buffers_tail + 1) % MAX_PACKET_BUFFERS;
394         num_packet_buffers++;
395
396         spin_unlock(&packet_buffers_lock);
397         
398         return;
399 }
400
401 // Main routine to send a frame. May be completely broken.
402 int ne2k_send_frame(const char *data, size_t len) {
403
404         if (data == NULL)
405                 return -1;
406         if (len == 0)
407                 return 0;
408
409
410         if (len > MAX_FRAME_SIZE) {
411                 ne2k_frame_debug("-->Frame Too Large!\n");
412                 return -1;
413         }
414
415         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0x00);
416
417
418         // The TPSR takes a page #
419         // The RSAR takes a byte offset, but since a page is 256 bits
420         // and we are writing on page boundries, the low bits are 0, and
421         // the high bits are a page #
422         outb(ne2k_io_base_addr + NE2K_PG0_W_TPSR, NE2K_FIRST_SEND_PAGE);
423         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR0, 0x0);
424         outb(ne2k_io_base_addr + NE2K_PG0_W_RSAR1, NE2K_FIRST_SEND_PAGE);
425
426         
427         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR0, len & 0xFF);
428         outb(ne2k_io_base_addr + NE2K_PG0_W_TBCR1, len >> 8);
429
430         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR0, len & 0xFF);
431         outb(ne2k_io_base_addr + NE2K_PG0_W_RBCR1, len >> 8);
432
433         
434         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x12);
435         
436
437         for (int i = 0; i<len; i = i + 1) {
438                 outb(ne2k_io_base_addr + 0x10, *(uint8_t*)(data + i));
439                 //ne2k_debug("sent: %x\n", *(uint8_t*)(data + i));
440         }
441         
442         while(( inb(ne2k_io_base_addr + NE2K_PG0_RW_ISR) & 0x40) == 0);
443
444         outb(ne2k_io_base_addr + NE2K_PG0_RW_ISR,  0x40);
445
446         outb(ne2k_io_base_addr + NE2K_PG0_W_IMR,  0xBF);
447
448         outb(ne2k_io_base_addr + NE2K_PG0_RW_CR,  0x1E);
449         
450         
451         return len;
452 }
453