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

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ea788701 was ea788701, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Remove use of packet_t in NIC framework.

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