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

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

NIC no longer needs to support non-Ethernet frames.

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