source: mainline/uspace/srv/hw/netif/dp8390/ne2000.c@ 1ffa73b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1ffa73b was 3c106e88, checked in by martin@…>, 15 years ago

complete rewrite of the NE2000 network interface driver

  • remove almost all stuff which was not directly related to NE2000 ISA to improve readability (optional support for NE1000, already defunct host DMA support, etc.)
  • correct input and output buffering and correct synchronization w.r.t. fibrils (the only remaining fibril-related question is whether multiple overlaping IRQ notifications can cause any troubles)

this implementation finally provides solid foundations for the next lowest networking layers (ARP, IP) and provide a way to debug UDP and TCP

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * Copyright (c) 2011 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup ne2000
31 * @{
32 */
33
34/** @file
35 * NE2000 network interface implementation.
36 */
37
38#include <assert.h>
39#include <async.h>
40#include <ddi.h>
41#include <errno.h>
42#include <err.h>
43#include <malloc.h>
44#include <sysinfo.h>
45#include <ipc/ipc.h>
46#include <ipc/services.h>
47#include <ipc/irc.h>
48#include <net/modules.h>
49#include <packet_client.h>
50#include <adt/measured_strings.h>
51#include <net/device.h>
52#include <netif_skel.h>
53#include <nil_interface.h>
54#include "dp8390.h"
55
56/** Return the device from the interrupt call.
57 *
58 * @param[in] call The interrupt call.
59 *
60 */
61#define IRQ_GET_DEVICE(call) ((device_id_t) IPC_GET_IMETHOD(call))
62
63/** Return the ISR from the interrupt call.
64 *
65 * @param[in] call The interrupt call.
66 *
67 */
68#define IRQ_GET_ISR(call) ((int) IPC_GET_ARG2(call))
69
70static int irc_service = 0;
71static int irc_phone = -1;
72
73/** DP8390 kernel interrupt command sequence.
74 *
75 */
76static irq_cmd_t ne2k_cmds[] = {
77 {
78 .cmd = CMD_PIO_READ_8,
79 .addr = NULL,
80 .dstarg = 2
81 },
82 {
83 .cmd = CMD_BTEST,
84 .value = 0x7f,
85 .srcarg = 2,
86 .dstarg = 3,
87 },
88 {
89 .cmd = CMD_PREDICATE,
90 .value = 2,
91 .srcarg = 3
92 },
93 {
94 .cmd = CMD_PIO_WRITE_A_8,
95 .addr = NULL,
96 .srcarg = 3
97 },
98 {
99 .cmd = CMD_ACCEPT
100 }
101};
102
103/** DP8390 kernel interrupt code.
104 *
105 */
106static irq_code_t ne2k_code = {
107 sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
108 ne2k_cmds
109};
110
111/** Handle the interrupt notification.
112 *
113 * This is the interrupt notification function.
114 *
115 * @param[in] iid Interrupt notification identifier.
116 * @param[in] call Interrupt notification.
117 *
118 */
119static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
120{
121 device_id_t device_id = IRQ_GET_DEVICE(*call);
122 netif_device_t *device;
123 int nil_phone;
124 ne2k_t *ne2k;
125
126 fibril_rwlock_read_lock(&netif_globals.lock);
127
128 if (find_device(device_id, &device) == EOK) {
129 nil_phone = device->nil_phone;
130 ne2k = (ne2k_t *) device->specific;
131 } else
132 ne2k = NULL;
133
134 fibril_rwlock_read_unlock(&netif_globals.lock);
135
136 if (ne2k != NULL)
137 ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), nil_phone, device_id);
138}
139
140/** Change the network interface state.
141 *
142 * @param[in,out] device Network interface.
143 * @param[in] state New state.
144 *
145 */
146static void change_state(netif_device_t *device, device_state_t state)
147{
148 if (device->state != state) {
149 device->state = state;
150
151 const char *desc;
152 switch (state) {
153 case NETIF_ACTIVE:
154 desc = "active";
155 break;
156 case NETIF_STOPPED:
157 desc = "stopped";
158 break;
159 default:
160 desc = "unknown";
161 }
162
163 printf("%s: State changed to %s\n", NAME, desc);
164 }
165}
166
167int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
168 ipc_call_t *answer, size_t *count)
169{
170 return ENOTSUP;
171}
172
173int netif_get_device_stats(device_id_t device_id, device_stats_t *stats)
174{
175 if (!stats)
176 return EBADMEM;
177
178 netif_device_t *device;
179 int rc = find_device(device_id, &device);
180 if (rc != EOK)
181 return rc;
182
183 ne2k_t *ne2k = (ne2k_t *) device->specific;
184
185 memcpy(stats, &ne2k->stats, sizeof(device_stats_t));
186 return EOK;
187}
188
189int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
190{
191 if (!address)
192 return EBADMEM;
193
194 netif_device_t *device;
195 int rc = find_device(device_id, &device);
196 if (rc != EOK)
197 return rc;
198
199 ne2k_t *ne2k = (ne2k_t *) device->specific;
200
201 address->value = ne2k->mac;
202 address->length = ETH_ADDR;
203 return EOK;
204}
205
206int netif_probe_message(device_id_t device_id, int irq, void *io)
207{
208 netif_device_t *device =
209 (netif_device_t *) malloc(sizeof(netif_device_t));
210 if (!device)
211 return ENOMEM;
212
213 ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
214 if (!ne2k) {
215 free(device);
216 return ENOMEM;
217 }
218
219 void *port;
220 int rc = pio_enable((void *) io, NE2K_IO_SIZE, &port);
221 if (rc != EOK) {
222 free(ne2k);
223 free(device);
224 return rc;
225 }
226
227 bzero(device, sizeof(netif_device_t));
228 bzero(ne2k, sizeof(ne2k_t));
229
230 device->device_id = device_id;
231 device->nil_phone = -1;
232 device->specific = (void *) ne2k;
233 device->state = NETIF_STOPPED;
234
235 rc = ne2k_probe(ne2k, port, irq);
236 if (rc != EOK) {
237 printf("%s: No ethernet card found at I/O address %p\n",
238 NAME, port);
239 free(ne2k);
240 free(device);
241 return rc;
242 }
243
244 rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
245 if (rc != EOK) {
246 free(ne2k);
247 free(device);
248 return rc;
249 }
250
251 printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
252 NAME, port, irq);
253
254 unsigned int i;
255 for (i = 0; i < ETH_ADDR; i++)
256 printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
257
258 return EOK;
259}
260
261int netif_start_message(netif_device_t *device)
262{
263 if (device->state != NETIF_ACTIVE) {
264 ne2k_t *ne2k = (ne2k_t *) device->specific;
265
266 ne2k_cmds[0].addr = ne2k->port + DP_ISR;
267 ne2k_cmds[3].addr = ne2k_cmds[0].addr;
268
269 int rc = ipc_register_irq(ne2k->irq, device->device_id,
270 device->device_id, &ne2k_code);
271 if (rc != EOK)
272 return rc;
273
274 rc = ne2k_up(ne2k);
275 if (rc != EOK) {
276 ipc_unregister_irq(ne2k->irq, device->device_id);
277 return rc;
278 }
279
280 if (irc_service)
281 async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
282
283 change_state(device, NETIF_ACTIVE);
284 }
285
286 return device->state;
287}
288
289int netif_stop_message(netif_device_t *device)
290{
291 if (device->state != NETIF_STOPPED) {
292 ne2k_t *ne2k = (ne2k_t *) device->specific;
293
294 ne2k_down(ne2k);
295 ipc_unregister_irq(ne2k->irq, device->device_id);
296 change_state(device, NETIF_STOPPED);
297 }
298
299 return EOK;
300}
301
302int netif_send_message(device_id_t device_id, packet_t *packet,
303 services_t sender)
304{
305 netif_device_t *device;
306 int rc = find_device(device_id, &device);
307 if (rc != EOK)
308 return rc;
309
310 if (device->state != NETIF_ACTIVE) {
311 netif_pq_release(packet_get_id(packet));
312 return EFORWARD;
313 }
314
315 ne2k_t *ne2k = (ne2k_t *) device->specific;
316
317 /*
318 * Process the packet queue
319 */
320
321 do {
322 packet_t *next = pq_detach(packet);
323 ne2k_send(ne2k, packet);
324 netif_pq_release(packet_get_id(packet));
325 packet = next;
326 } while (packet);
327
328 return EOK;
329}
330
331int netif_initialize(void)
332{
333 sysarg_t apic;
334 sysarg_t i8259;
335
336 if ((sysinfo_get_value("apic", &apic) == EOK) && (apic))
337 irc_service = SERVICE_APIC;
338 else if ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))
339 irc_service = SERVICE_I8259;
340
341 if (irc_service) {
342 while (irc_phone < 0) {
343 irc_phone = ipc_connect_me_to_blocking(PHONE_NS, irc_service,
344 0, 0);
345 }
346 }
347
348 async_set_interrupt_received(irq_handler);
349
350 sysarg_t phonehash;
351 return ipc_connect_to_me(PHONE_NS, SERVICE_DP8390, 0, 0, &phonehash);
352}
353
354int main(int argc, char *argv[])
355{
356 /* Start the module */
357 return netif_module_start();
358}
359
360/** @}
361 */
Note: See TracBrowser for help on using the repository browser.