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

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

avoid multiple overlapped interrupt request handling by handling interrupts one at a time
(using the Interrupt Mask Register)

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