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

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

cstyle (no change in functionality)

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