2 * Copyright (c) 2011 Radim Vansa
3 * Copyright (c) 2011 Jiri Michalec
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
36 * @brief Internal implementation of general NIC operations
40 #include <fibril_synch.h>
43 #include <str_error.h>
46 #include <ddf/interrupt.h>
50 #include "nic_driver.h"
54 #define NIC_GLOBALS_MAX_CACHE_SIZE 16
56 nic_globals_t nic_globals
;
59 * Initializes libraries required for NIC framework - logger
61 * @param name Name of the device/driver (used in logging)
63 errno_t
nic_driver_init(const char *name
)
65 list_initialize(&nic_globals
.frame_list_cache
);
66 nic_globals
.frame_list_cache_size
= 0;
67 list_initialize(&nic_globals
.frame_cache
);
68 nic_globals
.frame_cache_size
= 0;
69 fibril_mutex_initialize(&nic_globals
.lock
);
72 snprintf(buffer
, 256, "drv/" DEVICE_CATEGORY_NIC
"/%s", name
);
77 /** Fill in the default implementations for device options and NIC interface.
83 void nic_driver_implement(driver_ops_t
*driver_ops
, ddf_dev_ops_t
*dev_ops
,
88 dev_ops
->open
= nic_open_impl
;
90 dev_ops
->close
= nic_close_impl
;
91 if (!dev_ops
->interfaces
[NIC_DEV_IFACE
])
92 dev_ops
->interfaces
[NIC_DEV_IFACE
] = iface
;
93 if (!dev_ops
->default_handler
)
94 dev_ops
->default_handler
= nic_default_handler_impl
;
98 if (!iface
->get_state
)
99 iface
->get_state
= nic_get_state_impl
;
100 if (!iface
->set_state
)
101 iface
->set_state
= nic_set_state_impl
;
102 if (!iface
->send_frame
)
103 iface
->send_frame
= nic_send_frame_impl
;
104 if (!iface
->callback_create
)
105 iface
->callback_create
= nic_callback_create_impl
;
106 if (!iface
->get_address
)
107 iface
->get_address
= nic_get_address_impl
;
108 if (!iface
->get_stats
)
109 iface
->get_stats
= nic_get_stats_impl
;
110 if (!iface
->unicast_get_mode
)
111 iface
->unicast_get_mode
= nic_unicast_get_mode_impl
;
112 if (!iface
->unicast_set_mode
)
113 iface
->unicast_set_mode
= nic_unicast_set_mode_impl
;
114 if (!iface
->multicast_get_mode
)
115 iface
->multicast_get_mode
= nic_multicast_get_mode_impl
;
116 if (!iface
->multicast_set_mode
)
117 iface
->multicast_set_mode
= nic_multicast_set_mode_impl
;
118 if (!iface
->broadcast_get_mode
)
119 iface
->broadcast_get_mode
= nic_broadcast_get_mode_impl
;
120 if (!iface
->broadcast_set_mode
)
121 iface
->broadcast_set_mode
= nic_broadcast_set_mode_impl
;
122 if (!iface
->blocked_sources_get
)
123 iface
->blocked_sources_get
= nic_blocked_sources_get_impl
;
124 if (!iface
->blocked_sources_set
)
125 iface
->blocked_sources_set
= nic_blocked_sources_set_impl
;
126 if (!iface
->vlan_get_mask
)
127 iface
->vlan_get_mask
= nic_vlan_get_mask_impl
;
128 if (!iface
->vlan_set_mask
)
129 iface
->vlan_set_mask
= nic_vlan_set_mask_impl
;
130 if (!iface
->wol_virtue_add
)
131 iface
->wol_virtue_add
= nic_wol_virtue_add_impl
;
132 if (!iface
->wol_virtue_remove
)
133 iface
->wol_virtue_remove
= nic_wol_virtue_remove_impl
;
134 if (!iface
->wol_virtue_probe
)
135 iface
->wol_virtue_probe
= nic_wol_virtue_probe_impl
;
136 if (!iface
->wol_virtue_list
)
137 iface
->wol_virtue_list
= nic_wol_virtue_list_impl
;
138 if (!iface
->wol_virtue_get_caps
)
139 iface
->wol_virtue_get_caps
= nic_wol_virtue_get_caps_impl
;
140 if (!iface
->poll_get_mode
)
141 iface
->poll_get_mode
= nic_poll_get_mode_impl
;
142 if (!iface
->poll_set_mode
)
143 iface
->poll_set_mode
= nic_poll_set_mode_impl
;
144 if (!iface
->poll_now
)
145 iface
->poll_now
= nic_poll_now_impl
;
150 * Setup send frame handler. This MUST be called in the add_device handler
151 * if the nic_send_message_impl function is used for sending messages (filled
152 * as send_message member of the nic_iface_t structure). The function must not
153 * be called anywhere else.
156 * @param sffunc Function handling the send_frame request
158 void nic_set_send_frame_handler(nic_t
*nic_data
, send_frame_handler sffunc
)
160 nic_data
->send_frame
= sffunc
;
164 * Setup event handlers for transitions between driver states.
165 * This function can be called only in the add_device handler.
167 * @param on_activating Called when device is going to the ACTIVE state.
168 * @param on_going_down Called when device is going to the DOWN state.
169 * @param on_stopping Called when device is going to the STOP state.
171 void nic_set_state_change_handlers(nic_t
*nic_data
,
172 state_change_handler on_activating
, state_change_handler on_going_down
,
173 state_change_handler on_stopping
)
175 nic_data
->on_activating
= on_activating
;
176 nic_data
->on_going_down
= on_going_down
;
177 nic_data
->on_stopping
= on_stopping
;
181 * Setup event handlers for changing the filtering modes.
182 * This function can be called only in the add_device handler.
185 * @param on_unicast_mode_change
186 * @param on_multicast_mode_change
187 * @param on_broadcast_mode_change
188 * @param on_blocked_sources_change
189 * @param on_vlan_mask_change
191 void nic_set_filtering_change_handlers(nic_t
*nic_data
,
192 unicast_mode_change_handler on_unicast_mode_change
,
193 multicast_mode_change_handler on_multicast_mode_change
,
194 broadcast_mode_change_handler on_broadcast_mode_change
,
195 blocked_sources_change_handler on_blocked_sources_change
,
196 vlan_mask_change_handler on_vlan_mask_change
)
198 nic_data
->on_unicast_mode_change
= on_unicast_mode_change
;
199 nic_data
->on_multicast_mode_change
= on_multicast_mode_change
;
200 nic_data
->on_broadcast_mode_change
= on_broadcast_mode_change
;
201 nic_data
->on_blocked_sources_change
= on_blocked_sources_change
;
202 nic_data
->on_vlan_mask_change
= on_vlan_mask_change
;
206 * Setup filters for WOL virtues add and removal.
207 * This function can be called only in the add_device handler. Both handlers
208 * must be set or none of them.
210 * @param on_wv_add Called when a virtue is added
211 * @param on_wv_remove Called when a virtue is removed
213 void nic_set_wol_virtue_change_handlers(nic_t
*nic_data
,
214 wol_virtue_add_handler on_wv_add
, wol_virtue_remove_handler on_wv_remove
)
216 assert(on_wv_add
!= NULL
&& on_wv_remove
!= NULL
);
217 nic_data
->on_wol_virtue_add
= on_wv_add
;
218 nic_data
->on_wol_virtue_remove
= on_wv_remove
;
222 * Setup poll handlers.
223 * This function can be called only in the add_device handler.
225 * @param on_poll_mode_change Called when the mode is about to be changed
226 * @param on_poll_request Called when poll request is triggered
228 void nic_set_poll_handlers(nic_t
*nic_data
,
229 poll_mode_change_handler on_poll_mode_change
, poll_request_handler on_poll_req
)
231 nic_data
->on_poll_mode_change
= on_poll_mode_change
;
232 nic_data
->on_poll_request
= on_poll_req
;
236 * Connect to the parent's driver and get HW resources list in parsed format.
237 * Note: this function should be called only from add_device handler, therefore
238 * we don't need to use locks.
241 * @param[out] resources Parsed lists of resources.
243 * @return EOK or an error code
245 errno_t
nic_get_resources(nic_t
*nic_data
, hw_res_list_parsed_t
*resources
)
247 ddf_dev_t
*dev
= nic_data
->dev
;
248 async_sess_t
*parent_sess
;
250 /* Connect to the parent's driver. */
251 parent_sess
= ddf_dev_parent_sess_get(dev
);
252 if (parent_sess
== NULL
)
255 return hw_res_get_list_parsed(parent_sess
, resources
, 0);
260 * @param nic_data The NIC driver data
261 * @param size Frame size in bytes
262 * @return pointer to allocated frame if success, NULL otherwise
264 nic_frame_t
*nic_alloc_frame(nic_t
*nic_data
, size_t size
)
267 fibril_mutex_lock(&nic_globals
.lock
);
268 if (nic_globals
.frame_cache_size
> 0) {
269 link_t
*first
= list_first(&nic_globals
.frame_cache
);
271 nic_globals
.frame_cache_size
--;
272 frame
= list_get_instance(first
, nic_frame_t
, link
);
273 fibril_mutex_unlock(&nic_globals
.lock
);
275 fibril_mutex_unlock(&nic_globals
.lock
);
276 frame
= malloc(sizeof(nic_frame_t
));
280 link_initialize(&frame
->link
);
283 frame
->data
= malloc(size
);
284 if (frame
->data
== NULL
) {
295 * @param nic_data The driver data
296 * @param frame The frame to release
298 void nic_release_frame(nic_t
*nic_data
, nic_frame_t
*frame
)
303 if (frame
->data
!= NULL
) {
309 fibril_mutex_lock(&nic_globals
.lock
);
310 if (nic_globals
.frame_cache_size
>= NIC_GLOBALS_MAX_CACHE_SIZE
) {
311 fibril_mutex_unlock(&nic_globals
.lock
);
314 list_prepend(&frame
->link
, &nic_globals
.frame_cache
);
315 nic_globals
.frame_cache_size
++;
316 fibril_mutex_unlock(&nic_globals
.lock
);
321 * Allocate a new frame list
323 * @return New frame list or NULL on error.
325 nic_frame_list_t
*nic_alloc_frame_list(void)
327 nic_frame_list_t
*frames
;
328 fibril_mutex_lock(&nic_globals
.lock
);
330 if (nic_globals
.frame_list_cache_size
> 0) {
332 list_get_instance(list_first(&nic_globals
.frame_list_cache
),
333 nic_frame_list_t
, head
);
334 list_remove(&frames
->head
);
335 list_initialize(frames
);
336 nic_globals
.frame_list_cache_size
--;
337 fibril_mutex_unlock(&nic_globals
.lock
);
339 fibril_mutex_unlock(&nic_globals
.lock
);
341 frames
= malloc(sizeof (nic_frame_list_t
));
343 list_initialize(frames
);
349 static void nic_driver_release_frame_list(nic_frame_list_t
*frames
)
353 fibril_mutex_lock(&nic_globals
.lock
);
354 if (nic_globals
.frame_list_cache_size
>= NIC_GLOBALS_MAX_CACHE_SIZE
) {
355 fibril_mutex_unlock(&nic_globals
.lock
);
358 list_prepend(&frames
->head
, &nic_globals
.frame_list_cache
);
359 nic_globals
.frame_list_cache_size
++;
360 fibril_mutex_unlock(&nic_globals
.lock
);
365 * Append a frame to the frame list
367 * @param frames Frame list
368 * @param frame Appended frame
370 void nic_frame_list_append(nic_frame_list_t
*frames
,
373 assert(frame
!= NULL
&& frames
!= NULL
);
374 list_append(&frame
->link
, frames
);
377 /** Get the polling mode information from the device
379 * The main lock should be locked, otherwise the inconsistency between
380 * mode and period can occure.
382 * @param nic_data The controller data
383 * @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
384 * @return Current polling mode of the controller
386 nic_poll_mode_t
nic_query_poll_mode(nic_t
*nic_data
, struct timeval
*period
)
389 *period
= nic_data
->poll_period
;
390 return nic_data
->poll_mode
;
393 /** Inform the NICF about poll mode
395 * @param nic_data The controller data
397 * @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
401 errno_t
nic_report_poll_mode(nic_t
*nic_data
, nic_poll_mode_t mode
,
402 struct timeval
*period
)
405 fibril_rwlock_write_lock(&nic_data
->main_lock
);
406 nic_data
->poll_mode
= mode
;
407 nic_data
->default_poll_mode
= mode
;
408 if (mode
== NIC_POLL_PERIODIC
) {
410 memcpy(&nic_data
->default_poll_period
, period
, sizeof (struct timeval
));
411 memcpy(&nic_data
->poll_period
, period
, sizeof (struct timeval
));
416 fibril_rwlock_write_unlock(&nic_data
->main_lock
);
420 /** Inform the NICF about device's MAC adress.
422 * @return EOK On success
425 errno_t
nic_report_address(nic_t
*nic_data
, const nic_address_t
*address
)
429 if (address
->address
[0] & 1)
432 fibril_rwlock_write_lock(&nic_data
->main_lock
);
434 /* Notify NIL layer (and uppper) if bound - not in add_device */
435 if (nic_data
->client_session
!= NULL
) {
436 errno_t rc
= nic_ev_addr_changed(nic_data
->client_session
,
440 fibril_rwlock_write_unlock(&nic_data
->main_lock
);
445 fibril_rwlock_write_lock(&nic_data
->rxc_lock
);
448 * The initial address (all zeroes) shouldn't be
449 * there and we will ignore that error -- in next
450 * calls this should not happen.
452 errno_t rc
= nic_rxc_set_addr(&nic_data
->rx_control
,
453 &nic_data
->mac
, address
);
455 /* For the first time also record the default MAC */
456 if (MAC_IS_ZERO(nic_data
->default_mac
.address
)) {
457 assert(MAC_IS_ZERO(nic_data
->mac
.address
));
458 memcpy(&nic_data
->default_mac
, address
, sizeof(nic_address_t
));
461 fibril_rwlock_write_unlock(&nic_data
->rxc_lock
);
463 if ((rc
!= EOK
) && (rc
!= ENOENT
)) {
464 fibril_rwlock_write_unlock(&nic_data
->main_lock
);
468 memcpy(&nic_data
->mac
, address
, sizeof(nic_address_t
));
470 fibril_rwlock_write_unlock(&nic_data
->main_lock
);
476 * Used to obtain devices MAC address.
478 * The main lock should be locked, otherwise the inconsistent address
481 * @param nic_data The controller data
482 * @param address The output for address.
484 void nic_query_address(nic_t
*nic_data
, nic_address_t
*addr
) {
488 memcpy(addr
, &nic_data
->mac
, sizeof(nic_address_t
));
492 * The busy flag can be set to 1 only in the send_frame handler, to 0 it can
498 void nic_set_tx_busy(nic_t
*nic_data
, int busy
)
501 * When the function is called in send_frame handler the main lock is
502 * locked so no race can happen.
503 * Otherwise, when it is unexpectedly set to 0 (even with main lock held
504 * by other fibril) it cannot crash anything.
506 nic_data
->tx_busy
= busy
;
510 * This is the function that the driver should call when it receives a frame.
511 * The frame is checked by filters and then sent up to the NIL layer or
512 * discarded. The frame is released.
515 * @param frame The received frame
517 void nic_received_frame(nic_t
*nic_data
, nic_frame_t
*frame
)
519 /* Note: this function must not lock main lock, because loopback driver
520 * calls it inside send_frame handler (with locked main lock) */
521 fibril_rwlock_read_lock(&nic_data
->rxc_lock
);
522 nic_frame_type_t frame_type
;
523 bool check
= nic_rxc_check(&nic_data
->rx_control
, frame
->data
,
524 frame
->size
, &frame_type
);
525 fibril_rwlock_read_unlock(&nic_data
->rxc_lock
);
526 /* Update statistics */
527 fibril_rwlock_write_lock(&nic_data
->stats_lock
);
529 if (nic_data
->state
== NIC_STATE_ACTIVE
&& check
) {
530 nic_data
->stats
.receive_packets
++;
531 nic_data
->stats
.receive_bytes
+= frame
->size
;
532 switch (frame_type
) {
533 case NIC_FRAME_MULTICAST
:
534 nic_data
->stats
.receive_multicast
++;
536 case NIC_FRAME_BROADCAST
:
537 nic_data
->stats
.receive_broadcast
++;
542 fibril_rwlock_write_unlock(&nic_data
->stats_lock
);
543 nic_ev_received(nic_data
->client_session
, frame
->data
,
546 switch (frame_type
) {
547 case NIC_FRAME_UNICAST
:
548 nic_data
->stats
.receive_filtered_unicast
++;
550 case NIC_FRAME_MULTICAST
:
551 nic_data
->stats
.receive_filtered_multicast
++;
553 case NIC_FRAME_BROADCAST
:
554 nic_data
->stats
.receive_filtered_broadcast
++;
557 fibril_rwlock_write_unlock(&nic_data
->stats_lock
);
559 nic_release_frame(nic_data
, frame
);
563 * Some NICs can receive multiple frames during single interrupt. These can
564 * send them in whole list of frames (actually nic_frame_t structures), then
565 * the list is deallocated and each frame is passed to the
566 * nic_received_packet function.
569 * @param frames List of received frames
571 void nic_received_frame_list(nic_t
*nic_data
, nic_frame_list_t
*frames
)
575 while (!list_empty(frames
)) {
577 list_get_instance(list_first(frames
), nic_frame_t
, link
);
579 list_remove(&frame
->link
);
580 nic_received_frame(nic_data
, frame
);
582 nic_driver_release_frame_list(frames
);
585 /** Allocate and initialize the driver data.
587 * @return Allocated structure or NULL.
590 static nic_t
*nic_create(ddf_dev_t
*dev
)
592 nic_t
*nic_data
= ddf_dev_data_alloc(dev
, sizeof(nic_t
));
593 if (nic_data
== NULL
)
596 /* Force zero to all uninitialized fields (e.g. added in future) */
597 if (nic_rxc_init(&nic_data
->rx_control
) != EOK
) {
601 if (nic_wol_virtues_init(&nic_data
->wol_virtues
) != EOK
) {
605 nic_data
->dev
= NULL
;
606 nic_data
->fun
= NULL
;
607 nic_data
->state
= NIC_STATE_STOPPED
;
608 nic_data
->client_session
= NULL
;
609 nic_data
->poll_mode
= NIC_POLL_IMMEDIATE
;
610 nic_data
->default_poll_mode
= NIC_POLL_IMMEDIATE
;
611 nic_data
->send_frame
= NULL
;
612 nic_data
->on_activating
= NULL
;
613 nic_data
->on_going_down
= NULL
;
614 nic_data
->on_stopping
= NULL
;
615 nic_data
->specific
= NULL
;
617 fibril_rwlock_initialize(&nic_data
->main_lock
);
618 fibril_rwlock_initialize(&nic_data
->stats_lock
);
619 fibril_rwlock_initialize(&nic_data
->rxc_lock
);
620 fibril_rwlock_initialize(&nic_data
->wv_lock
);
622 memset(&nic_data
->mac
, 0, sizeof(nic_address_t
));
623 memset(&nic_data
->default_mac
, 0, sizeof(nic_address_t
));
624 memset(&nic_data
->stats
, 0, sizeof(nic_device_stats_t
));
629 /** Create NIC structure for the device and bind it to dev_fun_t
631 * The pointer to the created and initialized NIC structure will
632 * be stored in device->nic_data.
634 * @param device The NIC device structure
636 * @return Pointer to created nic_t structure or NULL
639 nic_t
*nic_create_and_bind(ddf_dev_t
*device
)
641 nic_t
*nic_data
= nic_create(device
);
645 nic_data
->dev
= device
;
651 * Hangs up the phones in the structure, deallocates specific data and then
652 * the structure itself.
656 static void nic_destroy(nic_t
*nic_data
)
658 free(nic_data
->specific
);
662 * Unbind and destroy nic_t stored in ddf_dev_t.nic_data.
663 * The ddf_dev_t.nic_data will be set to NULL, specific driver data will be
666 * @param device The NIC device structure
668 void nic_unbind_and_destroy(ddf_dev_t
*device
)
670 nic_destroy(nic_get_from_ddf_dev(device
));
675 * Set information about current HW filtering.
676 * 1 ... Only those frames we want to receive are passed through HW
677 * 0 ... The HW filtering is imperfect
678 * -1 ... Don't change the setting
679 * Can be called only from the on_*_change handler.
682 * @param unicast_exact Unicast frames
683 * @param mcast_exact Multicast frames
684 * @param vlan_exact VLAN tags
686 void nic_report_hw_filtering(nic_t
*nic_data
,
687 int unicast_exact
, int multicast_exact
, int vlan_exact
)
689 nic_rxc_hw_filtering(&nic_data
->rx_control
,
690 unicast_exact
, multicast_exact
, vlan_exact
);
694 * Computes hash for the address list based on standard multicast address
697 * @param address_list
700 * @return Multicast hash
702 * @see multicast_hash
704 uint64_t nic_mcast_hash(const nic_address_t
*list
, size_t count
)
706 return nic_rxc_mcast_hash(list
, count
);
710 * Computes hash for multicast addresses currently set up in the RX multicast
711 * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
712 * Can be called only from the state change handlers (on_activating,
713 * on_going_down and on_stopping).
717 * @return Multicast hash
719 * @see multicast_hash
721 uint64_t nic_query_mcast_hash(nic_t
*nic_data
)
723 fibril_rwlock_read_lock(&nic_data
->rxc_lock
);
724 uint64_t hash
= nic_rxc_multicast_get_hash(&nic_data
->rx_control
);
725 fibril_rwlock_read_unlock(&nic_data
->rxc_lock
);
730 * Queries the current mode of unicast frames receiving.
731 * Can be called only from the on_*_change handler.
734 * @param mode The new unicast mode
735 * @param max_count Max number of addresses that can be written into the
737 * @param address_list List of MAC addresses or NULL.
738 * @param address_count Number of addresses in the list
740 void nic_query_unicast(const nic_t
*nic_data
,
741 nic_unicast_mode_t
*mode
,
742 size_t max_count
, nic_address_t
*address_list
, size_t *address_count
)
744 assert(mode
!= NULL
);
745 nic_rxc_unicast_get_mode(&nic_data
->rx_control
, mode
,
746 max_count
, address_list
, address_count
);
750 * Queries the current mode of multicast frames receiving.
751 * Can be called only from the on_*_change handler.
754 * @param mode The current multicast mode
755 * @param max_count Max number of addresses that can be written into the
757 * @param address_list List of MAC addresses or NULL.
758 * @param address_count Number of addresses in the list
760 void nic_query_multicast(const nic_t
*nic_data
,
761 nic_multicast_mode_t
*mode
,
762 size_t max_count
, nic_address_t
*address_list
, size_t *address_count
)
764 assert(mode
!= NULL
);
765 nic_rxc_multicast_get_mode(&nic_data
->rx_control
, mode
,
766 max_count
, address_list
, address_count
);
770 * Queries the current mode of broadcast frames receiving.
771 * Can be called only from the on_*_change handler.
774 * @param mode The new broadcast mode
776 void nic_query_broadcast(const nic_t
*nic_data
,
777 nic_broadcast_mode_t
*mode
)
779 assert(mode
!= NULL
);
780 nic_rxc_broadcast_get_mode(&nic_data
->rx_control
, mode
);
784 * Queries the current blocked source addresses.
785 * Can be called only from the on_*_change handler.
788 * @param max_count Max number of addresses that can be written into the
790 * @param address_list List of MAC addresses or NULL.
791 * @param address_count Number of addresses in the list
793 void nic_query_blocked_sources(const nic_t
*nic_data
,
794 size_t max_count
, nic_address_t
*address_list
, size_t *address_count
)
796 nic_rxc_blocked_sources_get(&nic_data
->rx_control
,
797 max_count
, address_list
, address_count
);
801 * Query mask used for filtering according to the VLAN tags.
802 * Can be called only from the on_*_change handler.
805 * @param mask Must be 512 bytes long
810 errno_t
nic_query_vlan_mask(const nic_t
*nic_data
, nic_vlan_mask_t
*mask
)
813 return nic_rxc_vlan_get_mask(&nic_data
->rx_control
, mask
);
817 * Query maximum number of WOL virtues of specified type allowed on the device.
818 * Can be called only from add_device and on_wol_virtue_* handlers.
821 * @param type The type of the WOL virtues
823 * @return Maximal number of allowed virtues of this type. -1 means this type
824 * is not supported at all.
826 int nic_query_wol_max_caps(const nic_t
*nic_data
, nic_wv_type_t type
)
828 return nic_data
->wol_virtues
.caps_max
[type
];
832 * Sets maximum number of WOL virtues of specified type allowed on the device.
833 * Can be called only from add_device and on_wol_virtue_* handlers.
836 * @param type The type of the WOL virtues
837 * @param count Maximal number of allowed virtues of this type. -1 means
838 * this type is not supported at all.
840 void nic_set_wol_max_caps(nic_t
*nic_data
, nic_wv_type_t type
, int count
)
842 nic_data
->wol_virtues
.caps_max
[type
] = count
;
847 * @return The driver-specific structure for this NIC.
849 void *nic_get_specific(nic_t
*nic_data
)
851 return nic_data
->specific
;
856 * @param specific The driver-specific structure for this NIC.
858 void nic_set_specific(nic_t
*nic_data
, void *specific
)
860 nic_data
->specific
= specific
;
864 * You can call the function only from one of the state change handlers.
866 * @return Current state of the NIC, prior to the actually executed change
868 nic_device_state_t
nic_query_state(nic_t
*nic_data
)
870 return nic_data
->state
;
875 * @return DDF device associated with this NIC.
877 ddf_dev_t
*nic_get_ddf_dev(nic_t
*nic_data
)
879 return nic_data
->dev
;
884 * @return DDF function associated with this NIC.
886 ddf_fun_t
*nic_get_ddf_fun(nic_t
*nic_data
)
888 return nic_data
->fun
;
895 void nic_set_ddf_fun(nic_t
*nic_data
, ddf_fun_t
*fun
)
901 * @param dev DDF device associated with NIC
902 * @return The associated NIC structure
904 nic_t
*nic_get_from_ddf_dev(ddf_dev_t
*dev
)
906 return (nic_t
*) ddf_dev_data_get(dev
);
910 * @param dev DDF function associated with NIC
911 * @return The associated NIC structure
913 nic_t
*nic_get_from_ddf_fun(ddf_fun_t
*fun
)
915 return (nic_t
*) ddf_dev_data_get(ddf_fun_get_dev(fun
));
919 * Raises the send_packets and send_bytes in device statistics.
922 * @param packets Number of received packets
923 * @param bytes Number of received bytes
925 void nic_report_send_ok(nic_t
*nic_data
, size_t packets
, size_t bytes
)
927 fibril_rwlock_write_lock(&nic_data
->stats_lock
);
928 nic_data
->stats
.send_packets
+= packets
;
929 nic_data
->stats
.send_bytes
+= bytes
;
930 fibril_rwlock_write_unlock(&nic_data
->stats_lock
);
934 * Raises total error counter (send_errors) and the concrete send error counter
935 * determined by the cause argument.
938 * @param cause The concrete error cause.
940 void nic_report_send_error(nic_t
*nic_data
, nic_send_error_cause_t cause
,
946 fibril_rwlock_write_lock(&nic_data
->stats_lock
);
947 nic_data
->stats
.send_errors
+= count
;
949 case NIC_SEC_BUFFER_FULL
:
950 nic_data
->stats
.send_dropped
+= count
;
952 case NIC_SEC_ABORTED
:
953 nic_data
->stats
.send_aborted_errors
+= count
;
955 case NIC_SEC_CARRIER_LOST
:
956 nic_data
->stats
.send_carrier_errors
+= count
;
958 case NIC_SEC_FIFO_OVERRUN
:
959 nic_data
->stats
.send_fifo_errors
+= count
;
961 case NIC_SEC_HEARTBEAT
:
962 nic_data
->stats
.send_heartbeat_errors
+= count
;
964 case NIC_SEC_WINDOW_ERROR
:
965 nic_data
->stats
.send_window_errors
+= count
;
970 fibril_rwlock_write_unlock(&nic_data
->stats_lock
);
974 * Raises total error counter (receive_errors) and the concrete receive error
975 * counter determined by the cause argument.
978 * @param cause The concrete error cause
980 void nic_report_receive_error(nic_t
*nic_data
,
981 nic_receive_error_cause_t cause
, unsigned count
)
983 fibril_rwlock_write_lock(&nic_data
->stats_lock
);
984 nic_data
->stats
.receive_errors
+= count
;
986 case NIC_REC_BUFFER_FULL
:
987 nic_data
->stats
.receive_dropped
+= count
;
990 nic_data
->stats
.receive_length_errors
+= count
;
992 case NIC_REC_BUFFER_OVERFLOW
:
993 nic_data
->stats
.receive_dropped
+= count
;
996 nic_data
->stats
.receive_crc_errors
+= count
;
998 case NIC_REC_FRAME_ALIGNMENT
:
999 nic_data
->stats
.receive_frame_errors
+= count
;
1001 case NIC_REC_FIFO_OVERRUN
:
1002 nic_data
->stats
.receive_fifo_errors
+= count
;
1004 case NIC_REC_MISSED
:
1005 nic_data
->stats
.receive_missed_errors
+= count
;
1010 fibril_rwlock_write_unlock(&nic_data
->stats_lock
);
1014 * Raises the collisions counter in device statistics.
1016 void nic_report_collisions(nic_t
*nic_data
, unsigned count
)
1018 fibril_rwlock_write_lock(&nic_data
->stats_lock
);
1019 nic_data
->stats
.collisions
+= count
;
1020 fibril_rwlock_write_unlock(&nic_data
->stats_lock
);
1023 /** Just wrapper for checking nonzero time interval
1025 * @oaram t The interval to check
1026 * @returns Zero if the t is nonzero interval
1027 * @returns Nonzero if t is zero interval
1029 static int timeval_nonpositive(struct timeval t
) {
1030 return (t
.tv_sec
<= 0) && (t
.tv_usec
<= 0);
1033 /** Main function of software period fibrill
1035 * Just calls poll() in the nic->poll_period period
1037 * @param data The NIC structure pointer
1039 * @return 0, never reached
1041 static errno_t
period_fibril_fun(void *data
)
1044 struct sw_poll_info
*info
= &nic
->sw_poll_info
;
1046 fibril_rwlock_read_lock(&nic
->main_lock
);
1047 int run
= info
->run
;
1048 int running
= info
->running
;
1049 struct timeval remaining
= nic
->poll_period
;
1050 fibril_rwlock_read_unlock(&nic
->main_lock
);
1053 remaining
.tv_sec
= 5;
1054 remaining
.tv_usec
= 0;
1057 /* Wait the period (keep attention to overflows) */
1058 while (!timeval_nonpositive(remaining
)) {
1059 suseconds_t wait
= 0;
1060 if (remaining
.tv_sec
> 0) {
1061 time_t wait_sec
= remaining
.tv_sec
;
1062 /* wait maximaly 5 seconds to get reasonable reaction time
1063 * when period is reset
1068 wait
= (suseconds_t
) wait_sec
* 1000000;
1070 remaining
.tv_sec
-= wait_sec
;
1072 wait
= remaining
.tv_usec
;
1074 if (wait
> 5 * 1000000) {
1078 remaining
.tv_usec
-= wait
;
1082 /* Check if the period was not reset */
1083 if (info
->run
!= run
)
1087 /* Provide polling if the period finished */
1088 fibril_rwlock_read_lock(&nic
->main_lock
);
1089 if (info
->running
&& info
->run
== run
) {
1090 nic
->on_poll_request(nic
);
1092 fibril_rwlock_read_unlock(&nic
->main_lock
);
1097 /** Starts software periodic polling
1099 * Reset to new period if the original period was running
1101 * @param nic_data Nic data structure
1103 void nic_sw_period_start(nic_t
*nic_data
)
1105 /* Create the fibril if it is not crated */
1106 if (nic_data
->sw_poll_info
.fibril
== 0) {
1107 nic_data
->sw_poll_info
.fibril
= fibril_create(period_fibril_fun
,
1109 nic_data
->sw_poll_info
.running
= 0;
1110 nic_data
->sw_poll_info
.run
= 0;
1113 fibril_add_ready(nic_data
->sw_poll_info
.fibril
);
1116 /* Inform fibril about running with new period */
1117 nic_data
->sw_poll_info
.run
= (nic_data
->sw_poll_info
.run
+ 1) % 100;
1118 nic_data
->sw_poll_info
.running
= 1;
1121 /** Stops software periodic polling
1123 * @param nic_data Nic data structure
1125 void nic_sw_period_stop(nic_t
*nic_data
)
1127 nic_data
->sw_poll_info
.running
= 0;