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

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

NIC does not need nic_device_id_t. Now it exists just inside net. Not sure if
we care to rename it since net is going away soon, anyway.

  • Property mode set to 100644
File size: 32.8 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 * This function is to be used only in the loopback driver. It's workaround
627 * for the situation when the frame does not contain ethernet address.
628 * The filtering is therefore not applied here.
629 *
630 * @param nic_data
631 * @param data Frame data
632 * @param size Frame size in bytes
633 */
634void nic_received_noneth_frame(nic_t *nic_data, void *data, size_t size)
635{
636 fibril_rwlock_write_lock(&nic_data->stats_lock);
637 nic_data->stats.receive_packets++;
638 nic_data->stats.receive_bytes += size;
639 fibril_rwlock_write_unlock(&nic_data->stats_lock);
640
641 nic_ev_received(nic_data->client_session, data, size);
642}
643
644/**
645 * Some NICs can receive multiple frames during single interrupt. These can
646 * send them in whole list of frames (actually nic_frame_t structures), then
647 * the list is deallocated and each frame is passed to the
648 * nic_received_packet function.
649 *
650 * @param nic_data
651 * @param frames List of received frames
652 */
653void nic_received_frame_list(nic_t *nic_data, nic_frame_list_t *frames)
654{
655 if (frames == NULL)
656 return;
657 while (!list_empty(frames)) {
658 nic_frame_t *frame =
659 list_get_instance(list_first(frames), nic_frame_t, link);
660
661 list_remove(&frame->link);
662 nic_received_frame(nic_data, frame);
663 }
664 nic_driver_release_frame_list(frames);
665}
666
667/** Allocate and initialize the driver data.
668 *
669 * @return Allocated structure or NULL.
670 *
671 */
672static nic_t *nic_create(void)
673{
674 nic_t *nic_data = malloc(sizeof(nic_t));
675 if (nic_data == NULL)
676 return NULL;
677
678 /* Force zero to all uninitialized fields (e.g. added in future) */
679 bzero(nic_data, sizeof(nic_t));
680 if (nic_rxc_init(&nic_data->rx_control) != EOK) {
681 free(nic_data);
682 return NULL;
683 }
684
685 if (nic_wol_virtues_init(&nic_data->wol_virtues) != EOK) {
686 free(nic_data);
687 return NULL;
688 }
689
690 nic_data->dev = NULL;
691 nic_data->fun = NULL;
692 nic_data->state = NIC_STATE_STOPPED;
693 nic_data->client_session = NULL;
694 nic_data->irc_session = NULL;
695 nic_data->poll_mode = NIC_POLL_IMMEDIATE;
696 nic_data->default_poll_mode = NIC_POLL_IMMEDIATE;
697 nic_data->send_frame = NULL;
698 nic_data->on_activating = NULL;
699 nic_data->on_going_down = NULL;
700 nic_data->on_stopping = NULL;
701 nic_data->specific = NULL;
702
703 fibril_rwlock_initialize(&nic_data->main_lock);
704 fibril_rwlock_initialize(&nic_data->stats_lock);
705 fibril_rwlock_initialize(&nic_data->rxc_lock);
706 fibril_rwlock_initialize(&nic_data->wv_lock);
707
708 bzero(&nic_data->mac, sizeof(nic_address_t));
709 bzero(&nic_data->default_mac, sizeof(nic_address_t));
710 bzero(&nic_data->stats, sizeof(nic_device_stats_t));
711
712 return nic_data;
713}
714
715/** Create NIC structure for the device and bind it to dev_fun_t
716 *
717 * The pointer to the created and initialized NIC structure will
718 * be stored in device->nic_data.
719 *
720 * @param device The NIC device structure
721 *
722 * @return Pointer to created nic_t structure or NULL
723 *
724 */
725nic_t *nic_create_and_bind(ddf_dev_t *device)
726{
727 assert(device);
728 assert(!device->driver_data);
729
730 nic_t *nic_data = nic_create();
731 if (!nic_data)
732 return NULL;
733
734 nic_data->dev = device;
735 device->driver_data = nic_data;
736
737 return nic_data;
738}
739
740/**
741 * Hangs up the phones in the structure, deallocates specific data and then
742 * the structure itself.
743 *
744 * @param data
745 */
746static void nic_destroy(nic_t *nic_data) {
747 if (nic_data->client_session != NULL) {
748 async_hangup(nic_data->client_session);
749 }
750
751 free(nic_data->specific);
752 free(nic_data);
753}
754
755/**
756 * Unbind and destroy nic_t stored in ddf_dev_t.nic_data.
757 * The ddf_dev_t.nic_data will be set to NULL, specific driver data will be
758 * destroyed.
759 *
760 * @param device The NIC device structure
761 */
762void nic_unbind_and_destroy(ddf_dev_t *device){
763 if (!device)
764 return;
765 if (!device->driver_data)
766 return;
767
768 nic_destroy((nic_t *) device->driver_data);
769 device->driver_data = NULL;
770 return;
771}
772
773/**
774 * Set information about current HW filtering.
775 * 1 ... Only those frames we want to receive are passed through HW
776 * 0 ... The HW filtering is imperfect
777 * -1 ... Don't change the setting
778 * Can be called only from the on_*_change handler.
779 *
780 * @param nic_data
781 * @param unicast_exact Unicast frames
782 * @param mcast_exact Multicast frames
783 * @param vlan_exact VLAN tags
784 */
785void nic_report_hw_filtering(nic_t *nic_data,
786 int unicast_exact, int multicast_exact, int vlan_exact)
787{
788 nic_rxc_hw_filtering(&nic_data->rx_control,
789 unicast_exact, multicast_exact, vlan_exact);
790}
791
792/**
793 * Computes hash for the address list based on standard multicast address
794 * hashing.
795 *
796 * @param address_list
797 * @param count
798 *
799 * @return Multicast hash
800 *
801 * @see multicast_hash
802 */
803uint64_t nic_mcast_hash(const nic_address_t *list, size_t count)
804{
805 return nic_rxc_mcast_hash(list, count);
806}
807
808/**
809 * Computes hash for multicast addresses currently set up in the RX multicast
810 * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
811 * Can be called only from the state change handlers (on_activating,
812 * on_going_down and on_stopping).
813 *
814 * @param nic_data
815 *
816 * @return Multicast hash
817 *
818 * @see multicast_hash
819 */
820uint64_t nic_query_mcast_hash(nic_t *nic_data)
821{
822 fibril_rwlock_read_lock(&nic_data->rxc_lock);
823 uint64_t hash = nic_rxc_multicast_get_hash(&nic_data->rx_control);
824 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
825 return hash;
826}
827
828/**
829 * Queries the current mode of unicast frames receiving.
830 * Can be called only from the on_*_change handler.
831 *
832 * @param nic_data
833 * @param mode The new unicast mode
834 * @param max_count Max number of addresses that can be written into the
835 * address_list.
836 * @param address_list List of MAC addresses or NULL.
837 * @param address_count Number of addresses in the list
838 */
839void nic_query_unicast(const nic_t *nic_data,
840 nic_unicast_mode_t *mode,
841 size_t max_count, nic_address_t *address_list, size_t *address_count)
842{
843 assert(mode != NULL);
844 nic_rxc_unicast_get_mode(&nic_data->rx_control, mode,
845 max_count, address_list, address_count);
846}
847
848/**
849 * Queries the current mode of multicast frames receiving.
850 * Can be called only from the on_*_change handler.
851 *
852 * @param nic_data
853 * @param mode The current multicast mode
854 * @param max_count Max number of addresses that can be written into the
855 * address_list.
856 * @param address_list List of MAC addresses or NULL.
857 * @param address_count Number of addresses in the list
858 */
859void nic_query_multicast(const nic_t *nic_data,
860 nic_multicast_mode_t *mode,
861 size_t max_count, nic_address_t *address_list, size_t *address_count)
862{
863 assert(mode != NULL);
864 nic_rxc_multicast_get_mode(&nic_data->rx_control, mode,
865 max_count, address_list, address_count);
866}
867
868/**
869 * Queries the current mode of broadcast frames receiving.
870 * Can be called only from the on_*_change handler.
871 *
872 * @param nic_data
873 * @param mode The new broadcast mode
874 */
875void nic_query_broadcast(const nic_t *nic_data,
876 nic_broadcast_mode_t *mode)
877{
878 assert(mode != NULL);
879 nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
880}
881
882/**
883 * Queries the current blocked source addresses.
884 * Can be called only from the on_*_change handler.
885 *
886 * @param nic_data
887 * @param max_count Max number of addresses that can be written into the
888 * address_list.
889 * @param address_list List of MAC addresses or NULL.
890 * @param address_count Number of addresses in the list
891 */
892void nic_query_blocked_sources(const nic_t *nic_data,
893 size_t max_count, nic_address_t *address_list, size_t *address_count)
894{
895 nic_rxc_blocked_sources_get(&nic_data->rx_control,
896 max_count, address_list, address_count);
897}
898
899/**
900 * Query mask used for filtering according to the VLAN tags.
901 * Can be called only from the on_*_change handler.
902 *
903 * @param nic_data
904 * @param mask Must be 512 bytes long
905 *
906 * @return EOK
907 * @return ENOENT
908 */
909int nic_query_vlan_mask(const nic_t *nic_data, nic_vlan_mask_t *mask)
910{
911 assert(mask);
912 return nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
913}
914
915/**
916 * Query maximum number of WOL virtues of specified type allowed on the device.
917 * Can be called only from add_device and on_wol_virtue_* handlers.
918 *
919 * @param nic_data
920 * @param type The type of the WOL virtues
921 *
922 * @return Maximal number of allowed virtues of this type. -1 means this type
923 * is not supported at all.
924 */
925int nic_query_wol_max_caps(const nic_t *nic_data, nic_wv_type_t type)
926{
927 return nic_data->wol_virtues.caps_max[type];
928}
929
930/**
931 * Sets maximum number of WOL virtues of specified type allowed on the device.
932 * Can be called only from add_device and on_wol_virtue_* handlers.
933 *
934 * @param nic_data
935 * @param type The type of the WOL virtues
936 * @param count Maximal number of allowed virtues of this type. -1 means
937 * this type is not supported at all.
938 */
939void nic_set_wol_max_caps(nic_t *nic_data, nic_wv_type_t type, int count)
940{
941 nic_data->wol_virtues.caps_max[type] = count;
942}
943
944/**
945 * @param nic_data
946 * @return The driver-specific structure for this NIC.
947 */
948void *nic_get_specific(nic_t *nic_data)
949{
950 return nic_data->specific;
951}
952
953/**
954 * @param nic_data
955 * @param specific The driver-specific structure for this NIC.
956 */
957void nic_set_specific(nic_t *nic_data, void *specific)
958{
959 nic_data->specific = specific;
960}
961
962/**
963 * You can call the function only from one of the state change handlers.
964 * @param nic_data
965 * @return Current state of the NIC, prior to the actually executed change
966 */
967nic_device_state_t nic_query_state(nic_t *nic_data)
968{
969 return nic_data->state;
970}
971
972/**
973 * @param nic_data
974 * @return DDF device associated with this NIC.
975 */
976ddf_dev_t *nic_get_ddf_dev(nic_t *nic_data)
977{
978 return nic_data->dev;
979}
980
981/**
982 * @param nic_data
983 * @return DDF function associated with this NIC.
984 */
985ddf_fun_t *nic_get_ddf_fun(nic_t *nic_data)
986{
987 return nic_data->fun;
988}
989
990/**
991 * @param nic_data
992 * @param fun
993 */
994void nic_set_ddf_fun(nic_t *nic_data, ddf_fun_t *fun)
995{
996 nic_data->fun = fun;
997}
998
999/**
1000 * @param dev DDF device associated with NIC
1001 * @return The associated NIC structure
1002 */
1003nic_t *nic_get_from_ddf_dev(ddf_dev_t *dev)
1004{
1005 return (nic_t *) dev->driver_data;
1006};
1007
1008/**
1009 * @param dev DDF function associated with NIC
1010 * @return The associated NIC structure
1011 */
1012nic_t *nic_get_from_ddf_fun(ddf_fun_t *fun)
1013{
1014 return (nic_t *) fun->driver_data;
1015};
1016
1017/**
1018 * Raises the send_packets and send_bytes in device statistics.
1019 *
1020 * @param nic_data
1021 * @param packets Number of received packets
1022 * @param bytes Number of received bytes
1023 */
1024void nic_report_send_ok(nic_t *nic_data, size_t packets, size_t bytes)
1025{
1026 fibril_rwlock_write_lock(&nic_data->stats_lock);
1027 nic_data->stats.send_packets += packets;
1028 nic_data->stats.send_bytes += bytes;
1029 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1030}
1031
1032/**
1033 * Raises total error counter (send_errors) and the concrete send error counter
1034 * determined by the cause argument.
1035 *
1036 * @param nic_data
1037 * @param cause The concrete error cause.
1038 */
1039void nic_report_send_error(nic_t *nic_data, nic_send_error_cause_t cause,
1040 unsigned count)
1041{
1042 if (count == 0)
1043 return;
1044
1045 fibril_rwlock_write_lock(&nic_data->stats_lock);
1046 nic_data->stats.send_errors += count;
1047 switch (cause) {
1048 case NIC_SEC_BUFFER_FULL:
1049 nic_data->stats.send_dropped += count;
1050 break;
1051 case NIC_SEC_ABORTED:
1052 nic_data->stats.send_aborted_errors += count;
1053 break;
1054 case NIC_SEC_CARRIER_LOST:
1055 nic_data->stats.send_carrier_errors += count;
1056 break;
1057 case NIC_SEC_FIFO_OVERRUN:
1058 nic_data->stats.send_fifo_errors += count;
1059 break;
1060 case NIC_SEC_HEARTBEAT:
1061 nic_data->stats.send_heartbeat_errors += count;
1062 break;
1063 case NIC_SEC_WINDOW_ERROR:
1064 nic_data->stats.send_window_errors += count;
1065 break;
1066 case NIC_SEC_OTHER:
1067 break;
1068 }
1069 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1070}
1071
1072/**
1073 * Raises total error counter (receive_errors) and the concrete receive error
1074 * counter determined by the cause argument.
1075 *
1076 * @param nic_data
1077 * @param cause The concrete error cause
1078 */
1079void nic_report_receive_error(nic_t *nic_data,
1080 nic_receive_error_cause_t cause, unsigned count)
1081{
1082 fibril_rwlock_write_lock(&nic_data->stats_lock);
1083 nic_data->stats.receive_errors += count;
1084 switch (cause) {
1085 case NIC_REC_BUFFER_FULL:
1086 nic_data->stats.receive_dropped += count;
1087 break;
1088 case NIC_REC_LENGTH:
1089 nic_data->stats.receive_length_errors += count;
1090 break;
1091 case NIC_REC_BUFFER_OVERFLOW:
1092 nic_data->stats.receive_dropped += count;
1093 break;
1094 case NIC_REC_CRC:
1095 nic_data->stats.receive_crc_errors += count;
1096 break;
1097 case NIC_REC_FRAME_ALIGNMENT:
1098 nic_data->stats.receive_frame_errors += count;
1099 break;
1100 case NIC_REC_FIFO_OVERRUN:
1101 nic_data->stats.receive_fifo_errors += count;
1102 break;
1103 case NIC_REC_MISSED:
1104 nic_data->stats.receive_missed_errors += count;
1105 break;
1106 case NIC_REC_OTHER:
1107 break;
1108 }
1109 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1110}
1111
1112/**
1113 * Raises the collisions counter in device statistics.
1114 */
1115void nic_report_collisions(nic_t *nic_data, unsigned count)
1116{
1117 fibril_rwlock_write_lock(&nic_data->stats_lock);
1118 nic_data->stats.collisions += count;
1119 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1120}
1121
1122/** Just wrapper for checking nonzero time interval
1123 *
1124 * @oaram t The interval to check
1125 * @returns Zero if the t is nonzero interval
1126 * @returns Nonzero if t is zero interval
1127 */
1128static int timeval_nonpositive(struct timeval t) {
1129 return (t.tv_sec <= 0) && (t.tv_usec <= 0);
1130}
1131
1132/** Main function of software period fibrill
1133 *
1134 * Just calls poll() in the nic->poll_period period
1135 *
1136 * @param data The NIC structure pointer
1137 *
1138 * @return 0, never reached
1139 */
1140static int period_fibril_fun(void *data)
1141{
1142 nic_t *nic = data;
1143 struct sw_poll_info *info = &nic->sw_poll_info;
1144 while (true) {
1145 fibril_rwlock_read_lock(&nic->main_lock);
1146 int run = info->run;
1147 int running = info->running;
1148 struct timeval remaining = nic->poll_period;
1149 fibril_rwlock_read_unlock(&nic->main_lock);
1150
1151 if (!running) {
1152 remaining.tv_sec = 5;
1153 remaining.tv_usec = 0;
1154 }
1155
1156 /* Wait the period (keep attention to overflows) */
1157 while (!timeval_nonpositive(remaining)) {
1158 suseconds_t wait = 0;
1159 if (remaining.tv_sec > 0) {
1160 time_t wait_sec = remaining.tv_sec;
1161 /* wait maximaly 5 seconds to get reasonable reaction time
1162 * when period is reset
1163 */
1164 if (wait_sec > 5)
1165 wait_sec = 5;
1166
1167 wait = (suseconds_t) wait_sec * 1000000;
1168
1169 remaining.tv_sec -= wait_sec;
1170 } else {
1171 wait = remaining.tv_usec;
1172
1173 if (wait > 5 * 1000000) {
1174 wait = 5 * 1000000;
1175 }
1176
1177 remaining.tv_usec -= wait;
1178 }
1179 async_usleep(wait);
1180
1181 /* Check if the period was not reset */
1182 if (info->run != run)
1183 break;
1184 }
1185
1186 /* Provide polling if the period finished */
1187 fibril_rwlock_read_lock(&nic->main_lock);
1188 if (info->running && info->run == run) {
1189 nic->on_poll_request(nic);
1190 }
1191 fibril_rwlock_read_unlock(&nic->main_lock);
1192 }
1193 return 0;
1194}
1195
1196/** Starts software periodic polling
1197 *
1198 * Reset to new period if the original period was running
1199 *
1200 * @param nic_data Nic data structure
1201 */
1202void nic_sw_period_start(nic_t *nic_data)
1203{
1204 /* Create the fibril if it is not crated */
1205 if (nic_data->sw_poll_info.fibril == 0) {
1206 nic_data->sw_poll_info.fibril = fibril_create(period_fibril_fun,
1207 nic_data);
1208 nic_data->sw_poll_info.running = 0;
1209 nic_data->sw_poll_info.run = 0;
1210
1211 /* Start fibril */
1212 fibril_add_ready(nic_data->sw_poll_info.fibril);
1213 }
1214
1215 /* Inform fibril about running with new period */
1216 nic_data->sw_poll_info.run = (nic_data->sw_poll_info.run + 1) % 100;
1217 nic_data->sw_poll_info.running = 1;
1218}
1219
1220/** Stops software periodic polling
1221 *
1222 * @param nic_data Nic data structure
1223 */
1224void nic_sw_period_stop(nic_t *nic_data)
1225{
1226 nic_data->sw_poll_info.running = 0;
1227}
1228
1229/** @}
1230 */
Note: See TracBrowser for help on using the repository browser.