Merge branch 'net-dev'. See body of commit for details.
[akaros.git] / kern / arch / i386 / ne2k.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * See LICENSE for details.
4  */
5
6 #ifdef __DEPUTY__
7 #pragma nodeputy
8 #endif
9
10 #ifdef __SHARC__
11 #pragma nosharc
12 #endif
13
14 #include <arch/mmu.h>
15 #include <arch/x86.h>
16 #include <arch/smp.h>
17 #include <arch/apic.h>
18 #include <arch/pci.h>
19 #include <arch/ne2k.h>
20
21 #include <ros/memlayout.h>
22
23 #include <atomic.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <trap.h>
27 #include <kmalloc.h>
28
29 #include <pmap.h>
30 #include <timing.h>
31
32 /** @file
33  * @brief NE2K Driver Sketch
34  *
35  * EXPERIMENTAL. DO NOT USE IF YOU DONT KNOW WHAT YOU ARE DOING
36  *
37  * This driver will attempt to detect a ne2k device and run some interrupt
38  * tests. This is used for ioapic debugging in simulation
39  *
40  * @author Paul Pearce <pearce@eecs.berkeley.edu>
41  *
42  * @todo Everything
43  */
44
45 extern uint32_t eth_up; // Fix this                               
46 uint32_t ne2k_irq;      // And this
47 uint32_t ne2k_io_base_addr;
48
49
50 void ne2k_init() {
51         
52         if (ne2k_scan_pci() < 0) return;
53         ne2k_setup_interrupts();
54         ne2k_configure_nic();
55         eth_up = 1;
56         
57         return;
58 }
59
60
61 int ne2k_scan_pci() {
62         
63         extern pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
64         extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
65
66         cprintf("Searching for NE2000 Network device...");
67
68         for (int i = 0; i < PCI_MAX_BUS; i++)
69                 for (int j = 0; j < PCI_MAX_DEV; j++)
70                         for (int k = 0; k < PCI_MAX_FUNC; k++) {
71                                 uint32_t address;
72                                 uint32_t lbus = i;
73                                 uint32_t ldev = j;
74                                 uint32_t lfunc = k;
75                                 uint32_t lreg = 0; 
76                                 uint32_t result  = 0;
77         
78                                 uint16_t dev_id = pci_dev_map[i][j][k].dev_id;
79                                 uint16_t ven_id = pci_dev_map[i][j][k].ven_id;
80
81                                 // Vender DNE
82                                 if (ven_id == INVALID_VENDOR_ID) 
83                                         continue;
84
85                                 // Ignore non RealTek 8168 Devices
86                                 if (ven_id != NE2K_VENDOR_ID || dev_id != NE2K_DEV_ID)
87                                         continue;
88                                 cprintf(" found on BUS %x DEV %x\n", i, j);
89
90                                 // Find the IRQ
91                                 ne2k_irq = pci_irq_map[i][j][k];
92                                 ne2k_debug("-->IRQ: %u\n", ne2k_irq);
93
94                                 // Loop over the BARs
95                                 for (int k = 0; k <= 5; k++) {
96                                         lreg = 4 + k;
97                                         address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
98                                 outl(PCI_CONFIG_ADDR, address);
99                                 result = inl(PCI_CONFIG_DATA);
100                                         
101                                         if (result == 0) // (0 denotes no valid data)
102                                                 continue;
103
104                                         // Read the bottom bit of the BAR. 
105                                         if (result & PCI_BAR_IO_MASK) {
106                                                 result = result & PCI_IO_MASK;
107                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
108                                         } else {
109                                                 result = result & PCI_MEM_MASK;
110                                                 ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
111                                         }
112                         
113                                         // TODO Switch to memory mapped instead of IO?
114                                         if (k == 0) // BAR0 denotes the IO Addr for the device
115                                                 ne2k_io_base_addr = result;                                             
116                                 }
117                                 
118                 return 0;
119         }
120         cprintf(" not found. No device configured.\n");
121         
122         return -1;
123 }
124
125 void ne2k_configure_nic() {
126         
127         ne2k_debug("-->Configuring Device.\n");
128
129         // Reset
130         inb(ne2k_io_base_addr + 0x1f);
131
132         // Configure
133         outb(ne2k_io_base_addr + 0x00, 0x22);
134         outb(ne2k_io_base_addr + 0x07, 0xFF);
135         outb(ne2k_io_base_addr + 0x0F, 0xFF);
136
137         uint8_t isr = inb(ne2k_io_base_addr + 0x07);
138         //cprintf("isr: %x\n", isr);
139
140
141         cprintf("Generating Interrupt...\n");
142         outb(ne2k_io_base_addr + 0x0A, 0x00);
143         outb(ne2k_io_base_addr + 0x0B, 0x00);
144         outb(ne2k_io_base_addr + 0x00, 0x0A);
145         udelay(10000000);
146
147         cprintf("Generating Interrupt again...\n");
148         outb(ne2k_io_base_addr + 0x0A, 0x00);
149         outb(ne2k_io_base_addr + 0x0B, 0x00);
150         outb(ne2k_io_base_addr + 0x00, 0x0A);
151         udelay(10000000);
152         
153         return;
154 }
155
156 void ne2k_setup_interrupts() {
157         
158         extern handler_t interrupt_handlers[];
159         
160         ne2k_debug("-->Setting interrupts.\n");
161         
162         // Kernel based interrupt stuff
163         register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + ne2k_irq, ne2k_interrupt_handler, 0);
164         
165         ioapic_route_irq(ne2k_irq, 6);  
166         
167         return;
168 }
169
170 // We need to evaluate this routine in terms of concurrency.
171 // We also need to figure out whats up with different core interrupts
172 void ne2k_interrupt_handler(trapframe_t *tf, void* data) {
173         
174         cprintf("\nNE2K interrupt on core %u!\n", lapic_get_id());
175         uint8_t isr= inb(ne2k_io_base_addr + 0x07);
176         cprintf("isr: %x\n", isr);
177         outb(ne2k_io_base_addr + 0x07, isr);
178
179         return;                         
180 }