source: mainline/uspace/srv/hw/netif/dp8390/ne2000.c@ 7300c37

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7300c37 was 7300c37, checked in by Martin Decky <martin@…>, 14 years ago

fetching of frames from the network card is still single-threaded, but sending the frames to NIL uses parallelism

  • Property mode set to 100644
File size: 9.0 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
70/** Return the TSR from the interrupt call.
71 *
72 * @param[in] call The interrupt call.
73 *
74 */
75#define IRQ_GET_TSR(call) ((int) IPC_GET_ARG3(call))
76
77static int irc_service = 0;
78static int irc_phone = -1;
79
80/** DP8390 kernel interrupt command sequence.
81 *
82 */
83static irq_cmd_t ne2k_cmds[] = {
84 {
85 /* Read Interrupt Status Register */
86 .cmd = CMD_PIO_READ_8,
87 .addr = NULL,
88 .dstarg = 2
89 },
90 {
91 /* Mask supported interrupt causes */
92 .cmd = CMD_BTEST,
93 .value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
94 ISR_CNT | ISR_RDC),
95 .srcarg = 2,
96 .dstarg = 3,
97 },
98 {
99 /* Predicate for accepting the interrupt */
100 .cmd = CMD_PREDICATE,
101 .value = 4,
102 .srcarg = 3
103 },
104 {
105 /*
106 * Mask future interrupts via
107 * Interrupt Mask Register
108 */
109 .cmd = CMD_PIO_WRITE_8,
110 .addr = NULL,
111 .value = 0
112 },
113 {
114 /* Acknowledge the current interrupt */
115 .cmd = CMD_PIO_WRITE_A_8,
116 .addr = NULL,
117 .srcarg = 3
118 },
119 {
120 /* Read Transmit Status Register */
121 .cmd = CMD_PIO_READ_8,
122 .addr = NULL,
123 .dstarg = 3
124 },
125 {
126 .cmd = CMD_ACCEPT
127 }
128};
129
130/** DP8390 kernel interrupt code.
131 *
132 */
133static irq_code_t ne2k_code = {
134 sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
135 ne2k_cmds
136};
137
138/** Handle the interrupt notification.
139 *
140 * This is the interrupt notification function. It is quarantied
141 * that there is only a single instance of this notification
142 * function running at one time until the return from the
143 * ne2k_interrupt() function (where the interrupts are unmasked
144 * again).
145 *
146 * @param[in] iid Interrupt notification identifier.
147 * @param[in] call Interrupt notification.
148 *
149 */
150static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
151{
152 device_id_t device_id = IRQ_GET_DEVICE(*call);
153 netif_device_t *device;
154 int nil_phone;
155 ne2k_t *ne2k;
156
157 fibril_rwlock_read_lock(&netif_globals.lock);
158
159 if (find_device(device_id, &device) == EOK) {
160 nil_phone = device->nil_phone;
161 ne2k = (ne2k_t *) device->specific;
162 } else
163 ne2k = NULL;
164
165 fibril_rwlock_read_unlock(&netif_globals.lock);
166
167 if (ne2k != NULL) {
168 link_t *frames =
169 ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
170
171 if (frames != NULL) {
172 while (!list_empty(frames)) {
173 frame_t *frame =
174 list_get_instance(frames->next, frame_t, link);
175
176 list_remove(&frame->link);
177 nil_received_msg(nil_phone, device_id, frame->packet,
178 SERVICE_NONE);
179 free(frame);
180 }
181
182 free(frames);
183 }
184 }
185}
186
187/** Change the network interface state.
188 *
189 * @param[in,out] device Network interface.
190 * @param[in] state New state.
191 *
192 */
193static void change_state(netif_device_t *device, device_state_t state)
194{
195 if (device->state != state) {
196 device->state = state;
197
198 const char *desc;
199 switch (state) {
200 case NETIF_ACTIVE:
201 desc = "active";
202 break;
203 case NETIF_STOPPED:
204 desc = "stopped";
205 break;
206 default:
207 desc = "unknown";
208 }
209
210 printf("%s: State changed to %s\n", NAME, desc);
211 }
212}
213
214int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
215 ipc_call_t *answer, size_t *count)
216{
217 return ENOTSUP;
218}
219
220int netif_get_device_stats(device_id_t device_id, device_stats_t *stats)
221{
222 if (!stats)
223 return EBADMEM;
224
225 netif_device_t *device;
226 int rc = find_device(device_id, &device);
227 if (rc != EOK)
228 return rc;
229
230 ne2k_t *ne2k = (ne2k_t *) device->specific;
231
232 memcpy(stats, &ne2k->stats, sizeof(device_stats_t));
233 return EOK;
234}
235
236int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
237{
238 if (!address)
239 return EBADMEM;
240
241 netif_device_t *device;
242 int rc = find_device(device_id, &device);
243 if (rc != EOK)
244 return rc;
245
246 ne2k_t *ne2k = (ne2k_t *) device->specific;
247
248 address->value = ne2k->mac;
249 address->length = ETH_ADDR;
250 return EOK;
251}
252
253int netif_probe_message(device_id_t device_id, int irq, void *io)
254{
255 netif_device_t *device =
256 (netif_device_t *) malloc(sizeof(netif_device_t));
257 if (!device)
258 return ENOMEM;
259
260 ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
261 if (!ne2k) {
262 free(device);
263 return ENOMEM;
264 }
265
266 void *port;
267 int rc = pio_enable((void *) io, NE2K_IO_SIZE, &port);
268 if (rc != EOK) {
269 free(ne2k);
270 free(device);
271 return rc;
272 }
273
274 bzero(device, sizeof(netif_device_t));
275 bzero(ne2k, sizeof(ne2k_t));
276
277 device->device_id = device_id;
278 device->nil_phone = -1;
279 device->specific = (void *) ne2k;
280 device->state = NETIF_STOPPED;
281
282 rc = ne2k_probe(ne2k, port, irq);
283 if (rc != EOK) {
284 printf("%s: No ethernet card found at I/O address %p\n",
285 NAME, port);
286 free(ne2k);
287 free(device);
288 return rc;
289 }
290
291 rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
292 if (rc != EOK) {
293 free(ne2k);
294 free(device);
295 return rc;
296 }
297
298 printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
299 NAME, port, irq);
300
301 unsigned int i;
302 for (i = 0; i < ETH_ADDR; i++)
303 printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
304
305 return EOK;
306}
307
308int netif_start_message(netif_device_t *device)
309{
310 if (device->state != NETIF_ACTIVE) {
311 ne2k_t *ne2k = (ne2k_t *) device->specific;
312
313 ne2k_cmds[0].addr = ne2k->port + DP_ISR;
314 ne2k_cmds[3].addr = ne2k->port + DP_IMR;
315 ne2k_cmds[4].addr = ne2k_cmds[0].addr;
316
317 int rc = ipc_register_irq(ne2k->irq, device->device_id,
318 device->device_id, &ne2k_code);
319 if (rc != EOK)
320 return rc;
321
322 rc = ne2k_up(ne2k);
323 if (rc != EOK) {
324 ipc_unregister_irq(ne2k->irq, device->device_id);
325 return rc;
326 }
327
328 change_state(device, NETIF_ACTIVE);
329
330 if (irc_service)
331 async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
332 }
333
334 return device->state;
335}
336
337int netif_stop_message(netif_device_t *device)
338{
339 if (device->state != NETIF_STOPPED) {
340 ne2k_t *ne2k = (ne2k_t *) device->specific;
341
342 ne2k_down(ne2k);
343 ipc_unregister_irq(ne2k->irq, device->device_id);
344 change_state(device, NETIF_STOPPED);
345 }
346
347 return EOK;
348}
349
350int netif_send_message(device_id_t device_id, packet_t *packet,
351 services_t sender)
352{
353 netif_device_t *device;
354 int rc = find_device(device_id, &device);
355 if (rc != EOK)
356 return rc;
357
358 if (device->state != NETIF_ACTIVE) {
359 netif_pq_release(packet_get_id(packet));
360 return EFORWARD;
361 }
362
363 ne2k_t *ne2k = (ne2k_t *) device->specific;
364
365 /*
366 * Process the packet queue
367 */
368
369 do {
370 packet_t *next = pq_detach(packet);
371 ne2k_send(ne2k, packet);
372 netif_pq_release(packet_get_id(packet));
373 packet = next;
374 } while (packet);
375
376 return EOK;
377}
378
379int netif_initialize(void)
380{
381 sysarg_t apic;
382 sysarg_t i8259;
383
384 if ((sysinfo_get_value("apic", &apic) == EOK) && (apic))
385 irc_service = SERVICE_APIC;
386 else if ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))
387 irc_service = SERVICE_I8259;
388
389 if (irc_service) {
390 while (irc_phone < 0) {
391 irc_phone = ipc_connect_me_to_blocking(PHONE_NS, irc_service,
392 0, 0);
393 }
394 }
395
396 async_set_interrupt_received(irq_handler);
397
398 sysarg_t phonehash;
399 return ipc_connect_to_me(PHONE_NS, SERVICE_DP8390, 0, 0, &phonehash);
400}
401
402int main(int argc, char *argv[])
403{
404 /* Start the module */
405 return netif_module_start();
406}
407
408/** @}
409 */
Note: See TracBrowser for help on using the repository browser.