source: mainline/uspace/lib/nic/src/nic_driver.c@ 612af1a0

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

networking fixes

  • use sysarg_t for packet_id_t to avoid potential overflow
  • fix the confusion in the order of arguments for nil_received_msg(), this fixes the strange ping timeout on 127.0.0.1
  • Property mode set to 100644
File size: 36.2 KB
Line 
1/*
2 * Copyright (c) 2011 Radim Vansa
3 * Copyright (c) 2011 Jiri Michalec
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/**
31 * @addtogroup libnic
32 * @{
33 */
34/**
35 * @file
36 * @brief Internal implementation of general NIC operations
37 */
38
39#include <assert.h>
40#include <fibril_synch.h>
41#include <ns.h>
42#include <stdio.h>
43#include <str_error.h>
44#include <ipc/services.h>
45#include <ipc/ns.h>
46#include <ipc/irc.h>
47#include <sysinfo.h>
48
49#include <devman.h>
50#include <ddf/interrupt.h>
51#include <net_interface.h>
52#include <ops/nic.h>
53#include <packet_client.h>
54#include <packet_remote.h>
55#include <net/packet_header.h>
56#include <errno.h>
57
58#include "nic_driver.h"
59#include "nic_impl.h"
60
61#define NIC_GLOBALS_MAX_CACHE_SIZE 16
62
63nic_globals_t nic_globals;
64
65/**
66 * Initializes libraries required for NIC framework - logger, packet manager
67 *
68 * @param name Name of the device/driver (used in logging)
69 */
70int nic_driver_init(const char *name)
71{
72 list_initialize(&nic_globals.frame_list_cache);
73 nic_globals.frame_list_cache_size = 0;
74 list_initialize(&nic_globals.frame_cache);
75 nic_globals.frame_cache_size = 0;
76 fibril_mutex_initialize(&nic_globals.lock);
77
78 char buffer[256];
79 snprintf(buffer, 256, "drv/" DEVICE_CATEGORY_NIC "/%s", name);
80
81 /* Initialize packet manager */
82 return pm_init();
83}
84
85/**
86 * Fill in the default implementations for device options and NIC interface.
87 *
88 * @param driver_ops
89 * @param dev_ops
90 * @param iface
91 */
92void nic_driver_implement(driver_ops_t *driver_ops, ddf_dev_ops_t *dev_ops,
93 nic_iface_t *iface)
94{
95 if (driver_ops) {
96 if (!driver_ops->device_added)
97 driver_ops->device_added = nic_device_added_impl;
98 }
99
100 if (dev_ops) {
101 if (!dev_ops->open)
102 dev_ops->open = nic_open_impl;
103 if (!dev_ops->close)
104 dev_ops->close = nic_close_impl;
105 if (!dev_ops->interfaces[NIC_DEV_IFACE])
106 dev_ops->interfaces[NIC_DEV_IFACE] = iface;
107 if (!dev_ops->default_handler)
108 dev_ops->default_handler = nic_default_handler_impl;
109 }
110
111 if (iface) {
112 if (!iface->get_state)
113 iface->get_state = nic_get_state_impl;
114 if (!iface->set_state)
115 iface->set_state = nic_set_state_impl;
116 if (!iface->send_message)
117 iface->send_message = nic_send_message_impl;
118 if (!iface->connect_to_nil)
119 iface->connect_to_nil = nic_connect_to_nil_impl;
120 if (!iface->get_address)
121 iface->get_address = nic_get_address_impl;
122 if (!iface->get_stats)
123 iface->get_stats = nic_get_stats_impl;
124 if (!iface->unicast_get_mode)
125 iface->unicast_get_mode = nic_unicast_get_mode_impl;
126 if (!iface->unicast_set_mode)
127 iface->unicast_set_mode = nic_unicast_set_mode_impl;
128 if (!iface->multicast_get_mode)
129 iface->multicast_get_mode = nic_multicast_get_mode_impl;
130 if (!iface->multicast_set_mode)
131 iface->multicast_set_mode = nic_multicast_set_mode_impl;
132 if (!iface->broadcast_get_mode)
133 iface->broadcast_get_mode = nic_broadcast_get_mode_impl;
134 if (!iface->broadcast_set_mode)
135 iface->broadcast_set_mode = nic_broadcast_set_mode_impl;
136 if (!iface->blocked_sources_get)
137 iface->blocked_sources_get = nic_blocked_sources_get_impl;
138 if (!iface->blocked_sources_set)
139 iface->blocked_sources_set = nic_blocked_sources_set_impl;
140 if (!iface->vlan_get_mask)
141 iface->vlan_get_mask = nic_vlan_get_mask_impl;
142 if (!iface->vlan_set_mask)
143 iface->vlan_set_mask = nic_vlan_set_mask_impl;
144 if (!iface->wol_virtue_add)
145 iface->wol_virtue_add = nic_wol_virtue_add_impl;
146 if (!iface->wol_virtue_remove)
147 iface->wol_virtue_remove = nic_wol_virtue_remove_impl;
148 if (!iface->wol_virtue_probe)
149 iface->wol_virtue_probe = nic_wol_virtue_probe_impl;
150 if (!iface->wol_virtue_list)
151 iface->wol_virtue_list = nic_wol_virtue_list_impl;
152 if (!iface->wol_virtue_get_caps)
153 iface->wol_virtue_get_caps = nic_wol_virtue_get_caps_impl;
154 if (!iface->poll_get_mode)
155 iface->poll_get_mode = nic_poll_get_mode_impl;
156 if (!iface->poll_set_mode)
157 iface->poll_set_mode = nic_poll_set_mode_impl;
158 if (!iface->poll_now)
159 iface->poll_now = nic_poll_now_impl;
160 }
161}
162
163/**
164 * Setup write packet handler. This MUST be called in the add_device handler
165 * if the nic_send_message_impl function is used for sending messages (filled
166 * as send_message member of the nic_iface_t structure). The function must not
167 * be called anywhere else.
168 *
169 * @param nic_data
170 * @param wpfunc Function handling the write_packet request
171 */
172void nic_set_write_packet_handler(nic_t *nic_data, write_packet_handler wpfunc)
173{
174 nic_data->write_packet = wpfunc;
175}
176
177/**
178 * Setup event handlers for transitions between driver states.
179 * This function can be called only in the add_device handler.
180 *
181 * @param on_activating Called when device is going to the ACTIVE state.
182 * @param on_going_down Called when device is going to the DOWN state.
183 * @param on_stopping Called when device is going to the STOP state.
184 */
185void nic_set_state_change_handlers(nic_t *nic_data,
186 state_change_handler on_activating, state_change_handler on_going_down,
187 state_change_handler on_stopping)
188{
189 nic_data->on_activating = on_activating;
190 nic_data->on_going_down = on_going_down;
191 nic_data->on_stopping = on_stopping;
192}
193
194/**
195 * Setup event handlers for changing the filtering modes.
196 * This function can be called only in the add_device handler.
197 *
198 * @param nic_data
199 * @param on_unicast_mode_change
200 * @param on_multicast_mode_change
201 * @param on_broadcast_mode_change
202 * @param on_blocked_sources_change
203 * @param on_vlan_mask_change
204 */
205void nic_set_filtering_change_handlers(nic_t *nic_data,
206 unicast_mode_change_handler on_unicast_mode_change,
207 multicast_mode_change_handler on_multicast_mode_change,
208 broadcast_mode_change_handler on_broadcast_mode_change,
209 blocked_sources_change_handler on_blocked_sources_change,
210 vlan_mask_change_handler on_vlan_mask_change)
211{
212 nic_data->on_unicast_mode_change = on_unicast_mode_change;
213 nic_data->on_multicast_mode_change = on_multicast_mode_change;
214 nic_data->on_broadcast_mode_change = on_broadcast_mode_change;
215 nic_data->on_blocked_sources_change = on_blocked_sources_change;
216 nic_data->on_vlan_mask_change = on_vlan_mask_change;
217}
218
219/**
220 * Setup filters for WOL virtues add and removal.
221 * This function can be called only in the add_device handler. Both handlers
222 * must be set or none of them.
223 *
224 * @param on_wv_add Called when a virtue is added
225 * @param on_wv_remove Called when a virtue is removed
226 */
227void nic_set_wol_virtue_change_handlers(nic_t *nic_data,
228 wol_virtue_add_handler on_wv_add, wol_virtue_remove_handler on_wv_remove)
229{
230 assert(on_wv_add != NULL && on_wv_remove != NULL);
231 nic_data->on_wol_virtue_add = on_wv_add;
232 nic_data->on_wol_virtue_remove = on_wv_remove;
233}
234
235/**
236 * Setup poll handlers.
237 * This function can be called only in the add_device handler.
238 *
239 * @param on_poll_mode_change Called when the mode is about to be changed
240 * @param on_poll_request Called when poll request is triggered
241 */
242void nic_set_poll_handlers(nic_t *nic_data,
243 poll_mode_change_handler on_poll_mode_change, poll_request_handler on_poll_req)
244{
245 nic_data->on_poll_mode_change = on_poll_mode_change;
246 nic_data->on_poll_request = on_poll_req;
247}
248
249/**
250 * Connect to the parent's driver and get HW resources list in parsed format.
251 * Note: this function should be called only from add_device handler, therefore
252 * we don't need to use locks.
253 *
254 * @param nic_data
255 * @param[out] resources Parsed lists of resources.
256 *
257 * @return EOK or negative error code
258 */
259int nic_get_resources(nic_t *nic_data, hw_res_list_parsed_t *resources)
260{
261 ddf_dev_t *dev = nic_data->dev;
262
263 /* Connect to the parent's driver. */
264 dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
265 dev->handle, IPC_FLAG_BLOCKING);
266 if (dev->parent_sess == NULL)
267 return EPARTY;
268
269 return hw_res_get_list_parsed(nic_data->dev->parent_sess, resources, 0);
270}
271
272/**
273 * Just a wrapper over the packet_get_1_remote function
274 */
275packet_t *nic_alloc_packet(nic_t *nic_data, size_t data_size)
276{
277 return packet_get_1_remote(nic_data->net_session, data_size);
278}
279
280
281/**
282 * Just a wrapper over the pq_release_remote function
283 */
284void nic_release_packet(nic_t *nic_data, packet_t *packet)
285{
286 pq_release_remote(nic_data->net_session, packet_get_id(packet));
287}
288
289/** Allocate frame and packet
290 *
291 * @param nic_data The NIC driver data
292 * @param packet_size Size of packet
293 * @param offload_size Size of packet offload
294 * @return pointer to allocated frame if success, NULL otherwise
295 */
296nic_frame_t *nic_alloc_frame(nic_t *nic_data, size_t packet_size)
297{
298 nic_frame_t *frame;
299 fibril_mutex_lock(&nic_globals.lock);
300 if (nic_globals.frame_cache_size > 0) {
301 link_t *first = list_first(&nic_globals.frame_cache);
302 list_remove(first);
303 nic_globals.frame_cache_size--;
304 frame = list_get_instance(first, nic_frame_t, link);
305 fibril_mutex_unlock(&nic_globals.lock);
306 } else {
307 fibril_mutex_unlock(&nic_globals.lock);
308 frame = malloc(sizeof(nic_frame_t));
309 if (!frame)
310 return NULL;
311
312 link_initialize(&frame->link);
313 }
314
315 packet_t *packet = nic_alloc_packet(nic_data, packet_size);
316 if (!packet) {
317 free(frame);
318 return NULL;
319 }
320
321 frame->packet = packet;
322 return frame;
323}
324
325/** Release frame
326 *
327 * @param nic_data The driver data
328 * @param frame The frame to release
329 */
330void nic_release_frame(nic_t *nic_data, nic_frame_t *frame)
331{
332 if (!frame)
333 return;
334 if (frame->packet != NULL) {
335 nic_release_packet(nic_data, frame->packet);
336 }
337 fibril_mutex_lock(&nic_globals.lock);
338 if (nic_globals.frame_cache_size >= NIC_GLOBALS_MAX_CACHE_SIZE) {
339 fibril_mutex_unlock(&nic_globals.lock);
340 free(frame);
341 } else {
342 list_prepend(&frame->link, &nic_globals.frame_cache);
343 nic_globals.frame_cache_size++;
344 fibril_mutex_unlock(&nic_globals.lock);
345 }
346}
347
348/**
349 * Allocate a new frame list
350 *
351 * @return New frame list or NULL on error.
352 */
353nic_frame_list_t *nic_alloc_frame_list(void)
354{
355 nic_frame_list_t *frames;
356 fibril_mutex_lock(&nic_globals.lock);
357
358 if (nic_globals.frame_list_cache_size > 0) {
359 frames =
360 list_get_instance(list_first(&nic_globals.frame_list_cache),
361 nic_frame_list_t, head);
362 list_remove(&frames->head);
363 list_initialize(frames);
364 nic_globals.frame_list_cache_size--;
365 fibril_mutex_unlock(&nic_globals.lock);
366 } else {
367 fibril_mutex_unlock(&nic_globals.lock);
368
369 frames = malloc(sizeof (nic_frame_list_t));
370 if (frames != NULL)
371 list_initialize(frames);
372 }
373
374 return frames;
375}
376
377static void nic_driver_release_frame_list(nic_frame_list_t *frames)
378{
379 if (!frames)
380 return;
381 fibril_mutex_lock(&nic_globals.lock);
382 if (nic_globals.frame_list_cache_size >= NIC_GLOBALS_MAX_CACHE_SIZE) {
383 fibril_mutex_unlock(&nic_globals.lock);
384 free(frames);
385 } else {
386 list_prepend(&frames->head, &nic_globals.frame_list_cache);
387 nic_globals.frame_list_cache_size++;
388 fibril_mutex_unlock(&nic_globals.lock);
389 }
390}
391
392/**
393 * Append a frame to the frame list
394 *
395 * @param frames Frame list
396 * @param frame Appended frame
397 */
398void nic_frame_list_append(nic_frame_list_t *frames,
399 nic_frame_t *frame)
400{
401 assert(frame != NULL && frames != NULL);
402 list_append(&frame->link, frames);
403}
404
405
406/**
407 * Enable interrupts for this driver.
408 *
409 * @param nic_data
410 * @param irq The IRQ number for this device
411 */
412void nic_enable_interrupt(nic_t *nic_data, int irq)
413{
414 async_exch_t *exch = async_exchange_begin(nic_data->irc_session);
415 async_msg_1(exch, IRC_ENABLE_INTERRUPT, irq);
416 async_exchange_end(exch);
417}
418
419/**
420 * Disable interrupts for this driver.
421 *
422 * @param nic_data
423 * @param irq The IRQ number for this device
424 */
425void nic_disable_interrupt(nic_t *nic_data, int irq)
426{
427 async_exch_t *exch = async_exchange_begin(nic_data->irc_session);
428 async_msg_1(exch, IRC_CLEAR_INTERRUPT, irq);
429 async_exchange_end(exch);
430}
431
432/** Get the polling mode information from the device
433 *
434 * The main lock should be locked, otherwise the inconsistency between
435 * mode and period can occure.
436 *
437 * @param nic_data The controller data
438 * @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
439 * @return Current polling mode of the controller
440 */
441nic_poll_mode_t nic_query_poll_mode(nic_t *nic_data, struct timeval *period)
442{
443 if (period)
444 *period = nic_data->poll_period;
445 return nic_data->poll_mode;
446};
447
448/**
449 * Connect to the NET and IRQ services. This function should be called only from
450 * the add_device handler, thus no locking is required.
451 *
452 * @param nic_data
453 *
454 * @return EOK If connection was successful.
455 * @return EINVAL If the IRC service cannot be determined.
456 * @return EREFUSED If NET or IRC service cannot be connected.
457 */
458int nic_connect_to_services(nic_t *nic_data)
459{
460 /* NET service */
461 nic_data->net_session = service_connect_blocking(EXCHANGE_SERIALIZE,
462 SERVICE_NETWORKING, 0, 0);
463 if (nic_data->net_session == NULL)
464 return errno;
465
466 /* IRC service */
467 sysarg_t apic;
468 sysarg_t i8259;
469 services_t irc_service = -1;
470 if (((sysinfo_get_value("apic", &apic) == EOK) && (apic)) ||
471 ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
472 irc_service = SERVICE_IRC;
473 else
474 return EINVAL;
475
476 nic_data->irc_session = service_connect_blocking(EXCHANGE_SERIALIZE,
477 irc_service, 0, 0);
478 if (nic_data->irc_session == NULL)
479 return errno;
480
481 return EOK;
482}
483
484/** Notify the NET service that the device is ready
485 *
486 * @param nic NICF structure
487 *
488 * @return EOK on success
489 *
490 */
491int nic_ready(nic_t *nic)
492{
493 fibril_rwlock_read_lock(&nic->main_lock);
494
495 async_sess_t *session = nic->net_session;
496 devman_handle_t handle = nic->dev->handle;
497
498 fibril_rwlock_read_unlock(&nic->main_lock);
499
500 if (session == NULL)
501 return EINVAL;
502
503 return net_driver_ready(session, handle);
504}
505
506/** Inform the NICF about poll mode
507 *
508 * @param nic_data The controller data
509 * @param mode
510 * @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
511 * @return EOK
512 * @return EINVAL
513 */
514int nic_report_poll_mode(nic_t *nic_data, nic_poll_mode_t mode,
515 struct timeval *period)
516{
517 int rc = EOK;
518 fibril_rwlock_write_lock(&nic_data->main_lock);
519 nic_data->poll_mode = mode;
520 nic_data->default_poll_mode = mode;
521 if (mode == NIC_POLL_PERIODIC) {
522 if (period) {
523 memcpy(&nic_data->default_poll_period, period, sizeof (struct timeval));
524 memcpy(&nic_data->poll_period, period, sizeof (struct timeval));
525 } else {
526 rc = EINVAL;
527 }
528 }
529 fibril_rwlock_write_unlock(&nic_data->main_lock);
530 return rc;
531}
532
533/** Inform the NICF about device's MAC adress.
534 *
535 * @return EOK On success
536 *
537 */
538int nic_report_address(nic_t *nic_data, const nic_address_t *address)
539{
540 assert(nic_data);
541
542 if (address->address[0] & 1)
543 return EINVAL;
544
545 fibril_rwlock_write_lock(&nic_data->main_lock);
546
547 /* Notify NIL layer (and uppper) if bound - not in add_device */
548 if (nic_data->nil_session != NULL) {
549 int rc = nil_addr_changed_msg(nic_data->nil_session,
550 nic_data->device_id, address);
551 if (rc != EOK) {
552 fibril_rwlock_write_unlock(&nic_data->main_lock);
553 return rc;
554 }
555 }
556
557 fibril_rwlock_write_lock(&nic_data->rxc_lock);
558
559 /*
560 * The initial address (all zeroes) shouldn't be
561 * there and we will ignore that error -- in next
562 * calls this should not happen.
563 */
564 int rc = nic_rxc_set_addr(&nic_data->rx_control,
565 &nic_data->mac, address);
566
567 /* For the first time also record the default MAC */
568 if (MAC_IS_ZERO(nic_data->default_mac.address)) {
569 assert(MAC_IS_ZERO(nic_data->mac.address));
570 memcpy(&nic_data->default_mac, address, sizeof(nic_address_t));
571 }
572
573 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
574
575 if ((rc != EOK) && (rc != ENOENT)) {
576 fibril_rwlock_write_unlock(&nic_data->main_lock);
577 return rc;
578 }
579
580 memcpy(&nic_data->mac, address, sizeof(nic_address_t));
581
582 fibril_rwlock_write_unlock(&nic_data->main_lock);
583
584 return EOK;
585}
586
587/**
588 * Used to obtain devices MAC address.
589 *
590 * The main lock should be locked, otherwise the inconsistent address
591 * can be returend.
592 *
593 * @param nic_data The controller data
594 * @param address The output for address.
595 */
596void nic_query_address(nic_t *nic_data, nic_address_t *addr) {
597 if (!addr)
598 return;
599 if (!nic_data)
600 memset(addr, 0, sizeof(nic_address_t));
601
602 memcpy(addr, &nic_data->mac, sizeof(nic_address_t));
603};
604
605/**
606 * The busy flag can be set to 1 only in the write_packet handler, to 0 it can
607 * be set anywhere.
608 *
609 * @param nic_data
610 * @param busy
611 */
612void nic_set_tx_busy(nic_t *nic_data, int busy)
613{
614 /*
615 * When the function is called in write_packet handler the main lock is
616 * locked so no race can happen.
617 * Otherwise, when it is unexpectedly set to 0 (even with main lock held
618 * by other fibril) it cannot crash anything.
619 */
620 nic_data->tx_busy = busy;
621}
622
623/**
624 * Provided for correct naming conventions.
625 * The packet is checked by filters and then sent up to the NIL layer or
626 * discarded, the frame is released.
627 *
628 * @param nic_data
629 * @param frame The frame containing received packet
630 */
631void nic_received_frame(nic_t *nic_data, nic_frame_t *frame)
632{
633 nic_received_packet(nic_data, frame->packet);
634 frame->packet = NULL;
635 nic_release_frame(nic_data, frame);
636}
637
638/**
639 * This is the function that the driver should call when it receives a packet.
640 * The packet is checked by filters and then sent up to the NIL layer or
641 * discarded.
642 *
643 * @param nic_data
644 * @param packet The received packet
645 */
646void nic_received_packet(nic_t *nic_data, packet_t *packet)
647{
648 /* Note: this function must not lock main lock, because loopback driver
649 * calls it inside write_packet handler (with locked main lock) */
650 packet_id_t pid = packet_get_id(packet);
651
652 fibril_rwlock_read_lock(&nic_data->rxc_lock);
653 nic_frame_type_t frame_type;
654 int check = nic_rxc_check(&nic_data->rx_control, packet, &frame_type);
655 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
656 /* Update statistics */
657 fibril_rwlock_write_lock(&nic_data->stats_lock);
658 /* Both sending message up and releasing packet are atomic IPC calls */
659 if (nic_data->state == NIC_STATE_ACTIVE && check) {
660 nic_data->stats.receive_packets++;
661 nic_data->stats.receive_bytes += packet_get_data_length(packet);
662 switch (frame_type) {
663 case NIC_FRAME_MULTICAST:
664 nic_data->stats.receive_multicast++;
665 break;
666 case NIC_FRAME_BROADCAST:
667 nic_data->stats.receive_broadcast++;
668 break;
669 default:
670 break;
671 }
672 fibril_rwlock_write_unlock(&nic_data->stats_lock);
673 nil_received_msg(nic_data->nil_session, nic_data->device_id, pid);
674 } else {
675 switch (frame_type) {
676 case NIC_FRAME_UNICAST:
677 nic_data->stats.receive_filtered_unicast++;
678 break;
679 case NIC_FRAME_MULTICAST:
680 nic_data->stats.receive_filtered_multicast++;
681 break;
682 case NIC_FRAME_BROADCAST:
683 nic_data->stats.receive_filtered_broadcast++;
684 break;
685 }
686 fibril_rwlock_write_unlock(&nic_data->stats_lock);
687 nic_release_packet(nic_data, packet);
688 }
689}
690
691/**
692 * This function is to be used only in the loopback driver. It's workaround
693 * for the situation when the packet does not contain ethernet address.
694 * The filtering is therefore not applied here.
695 *
696 * @param nic_data
697 * @param packet
698 */
699void nic_received_noneth_packet(nic_t *nic_data, packet_t *packet)
700{
701 fibril_rwlock_write_lock(&nic_data->stats_lock);
702 nic_data->stats.receive_packets++;
703 nic_data->stats.receive_bytes += packet_get_data_length(packet);
704 fibril_rwlock_write_unlock(&nic_data->stats_lock);
705
706 nil_received_msg(nic_data->nil_session, nic_data->device_id,
707 packet_get_id(packet));
708}
709
710/**
711 * Some NICs can receive multiple packets during single interrupt. These can
712 * send them in whole list of frames (actually nic_frame_t structures), then
713 * the list is deallocated and each packet is passed to the
714 * nic_received_packet function.
715 *
716 * @param nic_data
717 * @param frames List of received frames
718 */
719void nic_received_frame_list(nic_t *nic_data, nic_frame_list_t *frames)
720{
721 if (frames == NULL)
722 return;
723 while (!list_empty(frames)) {
724 nic_frame_t *frame =
725 list_get_instance(list_first(frames), nic_frame_t, link);
726
727 list_remove(&frame->link);
728 nic_received_packet(nic_data, frame->packet);
729 frame->packet = NULL;
730 nic_release_frame(nic_data, frame);
731 }
732 nic_driver_release_frame_list(frames);
733}
734
735/** Allocate and initialize the driver data.
736 *
737 * @return Allocated structure or NULL.
738 *
739 */
740static nic_t *nic_create(void)
741{
742 nic_t *nic_data = malloc(sizeof(nic_t));
743 if (nic_data == NULL)
744 return NULL;
745
746 /* Force zero to all uninitialized fields (e.g. added in future) */
747 bzero(nic_data, sizeof(nic_t));
748 if (nic_rxc_init(&nic_data->rx_control) != EOK) {
749 free(nic_data);
750 return NULL;
751 }
752
753 if (nic_wol_virtues_init(&nic_data->wol_virtues) != EOK) {
754 free(nic_data);
755 return NULL;
756 }
757
758 nic_data->dev = NULL;
759 nic_data->fun = NULL;
760 nic_data->device_id = NIC_DEVICE_INVALID_ID;
761 nic_data->state = NIC_STATE_STOPPED;
762 nic_data->net_session = NULL;
763 nic_data->nil_session = NULL;
764 nic_data->irc_session = NULL;
765 nic_data->poll_mode = NIC_POLL_IMMEDIATE;
766 nic_data->default_poll_mode = NIC_POLL_IMMEDIATE;
767 nic_data->write_packet = NULL;
768 nic_data->on_activating = NULL;
769 nic_data->on_going_down = NULL;
770 nic_data->on_stopping = NULL;
771 nic_data->specific = NULL;
772
773 fibril_rwlock_initialize(&nic_data->main_lock);
774 fibril_rwlock_initialize(&nic_data->stats_lock);
775 fibril_rwlock_initialize(&nic_data->rxc_lock);
776 fibril_rwlock_initialize(&nic_data->wv_lock);
777
778 bzero(&nic_data->mac, sizeof(nic_address_t));
779 bzero(&nic_data->default_mac, sizeof(nic_address_t));
780 bzero(&nic_data->stats, sizeof(nic_device_stats_t));
781
782 return nic_data;
783}
784
785/** Create NIC structure for the device and bind it to dev_fun_t
786 *
787 * The pointer to the created and initialized NIC structure will
788 * be stored in device->nic_data.
789 *
790 * @param device The NIC device structure
791 *
792 * @return Pointer to created nic_t structure or NULL
793 *
794 */
795nic_t *nic_create_and_bind(ddf_dev_t *device)
796{
797 assert(device);
798 assert(!device->driver_data);
799
800 nic_t *nic_data = nic_create();
801 if (!nic_data)
802 return NULL;
803
804 nic_data->dev = device;
805 device->driver_data = nic_data;
806
807 return nic_data;
808}
809
810/**
811 * Hangs up the phones in the structure, deallocates specific data and then
812 * the structure itself.
813 *
814 * @param data
815 */
816static void nic_destroy(nic_t *nic_data) {
817 if (nic_data->net_session != NULL) {
818 async_hangup(nic_data->net_session);
819 }
820
821 if (nic_data->nil_session != NULL) {
822 async_hangup(nic_data->nil_session);
823 }
824
825 free(nic_data->specific);
826 free(nic_data);
827}
828
829/**
830 * Unbind and destroy nic_t stored in ddf_dev_t.nic_data.
831 * The ddf_dev_t.nic_data will be set to NULL, specific driver data will be
832 * destroyed.
833 *
834 * @param device The NIC device structure
835 */
836void nic_unbind_and_destroy(ddf_dev_t *device){
837 if (!device)
838 return;
839 if (!device->driver_data)
840 return;
841
842 nic_destroy((nic_t *) device->driver_data);
843 device->driver_data = NULL;
844 return;
845}
846
847/**
848 * Creates an exposed DDF function for the device, named "port0".
849 * Device options are set as this function's options. The function is bound
850 * (see ddf_fun_bind) and then registered to the DEVICE_CATEGORY_NIC class.
851 * Note: this function should be called only from add_device handler, therefore
852 * we don't need to use locks.
853 *
854 * @param nic_data The NIC structure
855 * @param ops Device options for the DDF function.
856 */
857int nic_register_as_ddf_fun(nic_t *nic_data, ddf_dev_ops_t *ops)
858{
859 int rc;
860 assert(nic_data);
861
862 nic_data->fun = ddf_fun_create(nic_data->dev, fun_exposed, "port0");
863 if (nic_data->fun == NULL)
864 return ENOMEM;
865
866 nic_data->fun->ops = ops;
867 nic_data->fun->driver_data = nic_data;
868
869 rc = ddf_fun_bind(nic_data->fun);
870 if (rc != EOK) {
871 ddf_fun_destroy(nic_data->fun);
872 return rc;
873 }
874
875 rc = ddf_fun_add_to_category(nic_data->fun, DEVICE_CATEGORY_NIC);
876 if (rc != EOK) {
877 ddf_fun_destroy(nic_data->fun);
878 return rc;
879 }
880
881 return EOK;
882}
883
884/**
885 * Set information about current HW filtering.
886 * 1 ... Only those frames we want to receive are passed through HW
887 * 0 ... The HW filtering is imperfect
888 * -1 ... Don't change the setting
889 * Can be called only from the on_*_change handler.
890 *
891 * @param nic_data
892 * @param unicast_exact Unicast frames
893 * @param mcast_exact Multicast frames
894 * @param vlan_exact VLAN tags
895 */
896void nic_report_hw_filtering(nic_t *nic_data,
897 int unicast_exact, int multicast_exact, int vlan_exact)
898{
899 nic_rxc_hw_filtering(&nic_data->rx_control,
900 unicast_exact, multicast_exact, vlan_exact);
901}
902
903/**
904 * Computes hash for the address list based on standard multicast address
905 * hashing.
906 *
907 * @param address_list
908 * @param count
909 *
910 * @return Multicast hash
911 *
912 * @see multicast_hash
913 */
914uint64_t nic_mcast_hash(const nic_address_t *list, size_t count)
915{
916 return nic_rxc_mcast_hash(list, count);
917}
918
919/**
920 * Computes hash for multicast addresses currently set up in the RX multicast
921 * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
922 * Can be called only from the state change handlers (on_activating,
923 * on_going_down and on_stopping).
924 *
925 * @param nic_data
926 *
927 * @return Multicast hash
928 *
929 * @see multicast_hash
930 */
931uint64_t nic_query_mcast_hash(nic_t *nic_data)
932{
933 fibril_rwlock_read_lock(&nic_data->rxc_lock);
934 uint64_t hash = nic_rxc_multicast_get_hash(&nic_data->rx_control);
935 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
936 return hash;
937}
938
939/**
940 * Queries the current mode of unicast frames receiving.
941 * Can be called only from the on_*_change handler.
942 *
943 * @param nic_data
944 * @param mode The new unicast mode
945 * @param max_count Max number of addresses that can be written into the
946 * address_list.
947 * @param address_list List of MAC addresses or NULL.
948 * @param address_count Number of addresses in the list
949 */
950void nic_query_unicast(const nic_t *nic_data,
951 nic_unicast_mode_t *mode,
952 size_t max_count, nic_address_t *address_list, size_t *address_count)
953{
954 assert(mode != NULL);
955 nic_rxc_unicast_get_mode(&nic_data->rx_control, mode,
956 max_count, address_list, address_count);
957}
958
959/**
960 * Queries the current mode of multicast frames receiving.
961 * Can be called only from the on_*_change handler.
962 *
963 * @param nic_data
964 * @param mode The current multicast mode
965 * @param max_count Max number of addresses that can be written into the
966 * address_list.
967 * @param address_list List of MAC addresses or NULL.
968 * @param address_count Number of addresses in the list
969 */
970void nic_query_multicast(const nic_t *nic_data,
971 nic_multicast_mode_t *mode,
972 size_t max_count, nic_address_t *address_list, size_t *address_count)
973{
974 assert(mode != NULL);
975 nic_rxc_multicast_get_mode(&nic_data->rx_control, mode,
976 max_count, address_list, address_count);
977}
978
979/**
980 * Queries the current mode of broadcast frames receiving.
981 * Can be called only from the on_*_change handler.
982 *
983 * @param nic_data
984 * @param mode The new broadcast mode
985 */
986void nic_query_broadcast(const nic_t *nic_data,
987 nic_broadcast_mode_t *mode)
988{
989 assert(mode != NULL);
990 nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
991}
992
993/**
994 * Queries the current blocked source addresses.
995 * Can be called only from the on_*_change handler.
996 *
997 * @param nic_data
998 * @param max_count Max number of addresses that can be written into the
999 * address_list.
1000 * @param address_list List of MAC addresses or NULL.
1001 * @param address_count Number of addresses in the list
1002 */
1003void nic_query_blocked_sources(const nic_t *nic_data,
1004 size_t max_count, nic_address_t *address_list, size_t *address_count)
1005{
1006 nic_rxc_blocked_sources_get(&nic_data->rx_control,
1007 max_count, address_list, address_count);
1008}
1009
1010/**
1011 * Query mask used for filtering according to the VLAN tags.
1012 * Can be called only from the on_*_change handler.
1013 *
1014 * @param nic_data
1015 * @param mask Must be 512 bytes long
1016 *
1017 * @return EOK
1018 * @return ENOENT
1019 */
1020int nic_query_vlan_mask(const nic_t *nic_data, nic_vlan_mask_t *mask)
1021{
1022 assert(mask);
1023 return nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
1024}
1025
1026/**
1027 * Query maximum number of WOL virtues of specified type allowed on the device.
1028 * Can be called only from add_device and on_wol_virtue_* handlers.
1029 *
1030 * @param nic_data
1031 * @param type The type of the WOL virtues
1032 *
1033 * @return Maximal number of allowed virtues of this type. -1 means this type
1034 * is not supported at all.
1035 */
1036int nic_query_wol_max_caps(const nic_t *nic_data, nic_wv_type_t type)
1037{
1038 return nic_data->wol_virtues.caps_max[type];
1039}
1040
1041/**
1042 * Sets maximum number of WOL virtues of specified type allowed on the device.
1043 * Can be called only from add_device and on_wol_virtue_* handlers.
1044 *
1045 * @param nic_data
1046 * @param type The type of the WOL virtues
1047 * @param count Maximal number of allowed virtues of this type. -1 means
1048 * this type is not supported at all.
1049 */
1050void nic_set_wol_max_caps(nic_t *nic_data, nic_wv_type_t type, int count)
1051{
1052 nic_data->wol_virtues.caps_max[type] = count;
1053}
1054
1055/**
1056 * @param nic_data
1057 * @return The driver-specific structure for this NIC.
1058 */
1059void *nic_get_specific(nic_t *nic_data)
1060{
1061 return nic_data->specific;
1062}
1063
1064/**
1065 * @param nic_data
1066 * @param specific The driver-specific structure for this NIC.
1067 */
1068void nic_set_specific(nic_t *nic_data, void *specific)
1069{
1070 nic_data->specific = specific;
1071}
1072
1073/**
1074 * You can call the function only from one of the state change handlers.
1075 * @param nic_data
1076 * @return Current state of the NIC, prior to the actually executed change
1077 */
1078nic_device_state_t nic_query_state(nic_t *nic_data)
1079{
1080 return nic_data->state;
1081}
1082
1083/**
1084 * @param nic_data
1085 * @return DDF device associated with this NIC.
1086 */
1087ddf_dev_t *nic_get_ddf_dev(nic_t *nic_data)
1088{
1089 return nic_data->dev;
1090}
1091
1092/**
1093 * @param nic_data
1094 * @return DDF function associated with this NIC.
1095 */
1096ddf_fun_t *nic_get_ddf_fun(nic_t *nic_data)
1097{
1098 return nic_data->fun;
1099}
1100
1101/**
1102 * @param dev DDF device associated with NIC
1103 * @return The associated NIC structure
1104 */
1105nic_t *nic_get_from_ddf_dev(ddf_dev_t *dev)
1106{
1107 return (nic_t *) dev->driver_data;
1108};
1109
1110/**
1111 * @param dev DDF function associated with NIC
1112 * @return The associated NIC structure
1113 */
1114nic_t *nic_get_from_ddf_fun(ddf_fun_t *fun)
1115{
1116 return (nic_t *) fun->driver_data;
1117};
1118
1119/**
1120 * Raises the send_packets and send_bytes in device statistics.
1121 *
1122 * @param nic_data
1123 * @param packets Number of received packets
1124 * @param bytes Number of received bytes
1125 */
1126void nic_report_send_ok(nic_t *nic_data, size_t packets, size_t bytes)
1127{
1128 fibril_rwlock_write_lock(&nic_data->stats_lock);
1129 nic_data->stats.send_packets += packets;
1130 nic_data->stats.send_bytes += bytes;
1131 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1132}
1133
1134/**
1135 * Raises total error counter (send_errors) and the concrete send error counter
1136 * determined by the cause argument.
1137 *
1138 * @param nic_data
1139 * @param cause The concrete error cause.
1140 */
1141void nic_report_send_error(nic_t *nic_data, nic_send_error_cause_t cause,
1142 unsigned count)
1143{
1144 if (count == 0)
1145 return;
1146
1147 fibril_rwlock_write_lock(&nic_data->stats_lock);
1148 nic_data->stats.send_errors += count;
1149 switch (cause) {
1150 case NIC_SEC_BUFFER_FULL:
1151 nic_data->stats.send_dropped += count;
1152 break;
1153 case NIC_SEC_ABORTED:
1154 nic_data->stats.send_aborted_errors += count;
1155 break;
1156 case NIC_SEC_CARRIER_LOST:
1157 nic_data->stats.send_carrier_errors += count;
1158 break;
1159 case NIC_SEC_FIFO_OVERRUN:
1160 nic_data->stats.send_fifo_errors += count;
1161 break;
1162 case NIC_SEC_HEARTBEAT:
1163 nic_data->stats.send_heartbeat_errors += count;
1164 break;
1165 case NIC_SEC_WINDOW_ERROR:
1166 nic_data->stats.send_window_errors += count;
1167 break;
1168 case NIC_SEC_OTHER:
1169 break;
1170 }
1171 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1172}
1173
1174/**
1175 * Raises total error counter (receive_errors) and the concrete receive error
1176 * counter determined by the cause argument.
1177 *
1178 * @param nic_data
1179 * @param cause The concrete error cause
1180 */
1181void nic_report_receive_error(nic_t *nic_data,
1182 nic_receive_error_cause_t cause, unsigned count)
1183{
1184 fibril_rwlock_write_lock(&nic_data->stats_lock);
1185 nic_data->stats.receive_errors += count;
1186 switch (cause) {
1187 case NIC_REC_BUFFER_FULL:
1188 nic_data->stats.receive_dropped += count;
1189 break;
1190 case NIC_REC_LENGTH:
1191 nic_data->stats.receive_length_errors += count;
1192 break;
1193 case NIC_REC_BUFFER_OVERFLOW:
1194 nic_data->stats.receive_dropped += count;
1195 break;
1196 case NIC_REC_CRC:
1197 nic_data->stats.receive_crc_errors += count;
1198 break;
1199 case NIC_REC_FRAME_ALIGNMENT:
1200 nic_data->stats.receive_frame_errors += count;
1201 break;
1202 case NIC_REC_FIFO_OVERRUN:
1203 nic_data->stats.receive_fifo_errors += count;
1204 break;
1205 case NIC_REC_MISSED:
1206 nic_data->stats.receive_missed_errors += count;
1207 break;
1208 case NIC_REC_OTHER:
1209 break;
1210 }
1211 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1212}
1213
1214/**
1215 * Raises the collisions counter in device statistics.
1216 */
1217void nic_report_collisions(nic_t *nic_data, unsigned count)
1218{
1219 fibril_rwlock_write_lock(&nic_data->stats_lock);
1220 nic_data->stats.collisions += count;
1221 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1222}
1223
1224/** Just wrapper for checking nonzero time interval
1225 *
1226 * @oaram t The interval to check
1227 * @returns Zero if the t is nonzero interval
1228 * @returns Nonzero if t is zero interval
1229 */
1230static int timeval_nonpositive(struct timeval t) {
1231 return (t.tv_sec <= 0) && (t.tv_usec <= 0);
1232}
1233
1234/** Main function of software period fibrill
1235 *
1236 * Just calls poll() in the nic->poll_period period
1237 *
1238 * @param data The NIC structure pointer
1239 *
1240 * @return 0, never reached
1241 */
1242static int period_fibril_fun(void *data)
1243{
1244 nic_t *nic = data;
1245 struct sw_poll_info *info = &nic->sw_poll_info;
1246 while (true) {
1247 fibril_rwlock_read_lock(&nic->main_lock);
1248 int run = info->run;
1249 int running = info->running;
1250 struct timeval remaining = nic->poll_period;
1251 fibril_rwlock_read_unlock(&nic->main_lock);
1252
1253 if (!running) {
1254 remaining.tv_sec = 5;
1255 remaining.tv_usec = 0;
1256 }
1257
1258 /* Wait the period (keep attention to overflows) */
1259 while (!timeval_nonpositive(remaining)) {
1260 suseconds_t wait = 0;
1261 if (remaining.tv_sec > 0) {
1262 time_t wait_sec = remaining.tv_sec;
1263 /* wait maximaly 5 seconds to get reasonable reaction time
1264 * when period is reset
1265 */
1266 if (wait_sec > 5)
1267 wait_sec = 5;
1268
1269 wait = (suseconds_t) wait_sec * 1000000;
1270
1271 remaining.tv_sec -= wait_sec;
1272 } else {
1273 wait = remaining.tv_usec;
1274
1275 if (wait > 5 * 1000000) {
1276 wait = 5 * 1000000;
1277 }
1278
1279 remaining.tv_usec -= wait;
1280 }
1281 async_usleep(wait);
1282
1283 /* Check if the period was not reset */
1284 if (info->run != run)
1285 break;
1286 }
1287
1288 /* Provide polling if the period finished */
1289 fibril_rwlock_read_lock(&nic->main_lock);
1290 if (info->running && info->run == run) {
1291 nic->on_poll_request(nic);
1292 }
1293 fibril_rwlock_read_unlock(&nic->main_lock);
1294 }
1295 return 0;
1296}
1297
1298/** Starts software periodic polling
1299 *
1300 * Reset to new period if the original period was running
1301 *
1302 * @param nic_data Nic data structure
1303 */
1304void nic_sw_period_start(nic_t *nic_data)
1305{
1306 /* Create the fibril if it is not crated */
1307 if (nic_data->sw_poll_info.fibril == 0) {
1308 nic_data->sw_poll_info.fibril = fibril_create(period_fibril_fun,
1309 nic_data);
1310 nic_data->sw_poll_info.running = 0;
1311 nic_data->sw_poll_info.run = 0;
1312
1313 /* Start fibril */
1314 fibril_add_ready(nic_data->sw_poll_info.fibril);
1315 }
1316
1317 /* Inform fibril about running with new period */
1318 nic_data->sw_poll_info.run = (nic_data->sw_poll_info.run + 1) % 100;
1319 nic_data->sw_poll_info.running = 1;
1320}
1321
1322/** Stops software periodic polling
1323 *
1324 * @param nic_data Nic data structure
1325 */
1326void nic_sw_period_stop(nic_t *nic_data)
1327{
1328 nic_data->sw_poll_info.running = 0;
1329}
1330
1331// FIXME: Later
1332#if 0
1333
1334/** Lock packet for DMA usage
1335 *
1336 * @param packet
1337 * @return physical address of packet
1338 */
1339void *nic_dma_lock_packet(packet_t *packet)
1340{
1341 void *phys_addr;
1342 size_t locked;
1343 int rc = dma_lock(packet, &phys_addr, 1, &locked);
1344 if (rc != EOK)
1345 return NULL;
1346
1347 assert(locked == 1);
1348 return phys_addr;
1349}
1350
1351/** Unlock packet after DMA usage
1352 *
1353 * @param packet
1354 */
1355void nic_dma_unlock_packet(packet_t *packet)
1356{
1357 size_t unlocked;
1358 int rc = dma_unlock(packet, 1, &unlocked);
1359 if (rc != EOK)
1360 return;
1361
1362 assert(unlocked == 1);
1363}
1364
1365#endif
1366
1367/** @}
1368 */
Note: See TracBrowser for help on using the repository browser.