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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 758f8d5 was acdb5bac, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Replace usage of bzero() with C standard memset().

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