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

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

Allow multiple tasks to register for loc category change events.
Open NIC devices via location service, discover using category change events.
Eliminate device_added driver entry point.
loc_service_get_name() should return fully qualified service name.

  • Property mode set to 100644
File size: 33.2 KB
Line 
1/*
2 * Copyright (c) 2011 Radim Vansa
3 * Copyright (c) 2011 Jiri Michalec
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
31 * @addtogroup libnic
32 * @{
33 */
34/**
35 * @file
36 * @brief Internal implementation of general NIC operations
37 */
38
39#include <assert.h>
40#include <fibril_synch.h>
41#include <ns.h>
42#include <stdio.h>
43#include <str_error.h>
44#include <ipc/services.h>
45#include <ipc/ns.h>
46#include <ipc/irc.h>
47#include <sysinfo.h>
48#include <as.h>
49#include <devman.h>
50#include <ddf/interrupt.h>
51#include <net_interface.h>
52#include <ops/nic.h>
53#include <errno.h>
54
55#include "nic_driver.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->connect_to_nil)
110 iface->connect_to_nil = nic_connect_to_nil_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 the NET and IRQ services. 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 NET or IRC service cannot be connected.
434 */
435int nic_connect_to_services(nic_t *nic_data)
436{
437 /* NET service */
438 nic_data->net_session = service_connect_blocking(EXCHANGE_SERIALIZE,
439 SERVICE_NETWORKING, 0, 0);
440 if (nic_data->net_session == NULL)
441 return errno;
442
443 /* IRC service */
444 sysarg_t apic;
445 sysarg_t i8259;
446 services_t irc_service = -1;
447 if (((sysinfo_get_value("apic", &apic) == EOK) && (apic)) ||
448 ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
449 irc_service = SERVICE_IRC;
450 else
451 return EINVAL;
452
453 nic_data->irc_session = service_connect_blocking(EXCHANGE_SERIALIZE,
454 irc_service, 0, 0);
455 if (nic_data->irc_session == NULL)
456 return errno;
457
458 return EOK;
459}
460
461/** Inform the NICF about poll mode
462 *
463 * @param nic_data The controller data
464 * @param mode
465 * @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
466 * @return EOK
467 * @return EINVAL
468 */
469int nic_report_poll_mode(nic_t *nic_data, nic_poll_mode_t mode,
470 struct timeval *period)
471{
472 int rc = EOK;
473 fibril_rwlock_write_lock(&nic_data->main_lock);
474 nic_data->poll_mode = mode;
475 nic_data->default_poll_mode = mode;
476 if (mode == NIC_POLL_PERIODIC) {
477 if (period) {
478 memcpy(&nic_data->default_poll_period, period, sizeof (struct timeval));
479 memcpy(&nic_data->poll_period, period, sizeof (struct timeval));
480 } else {
481 rc = EINVAL;
482 }
483 }
484 fibril_rwlock_write_unlock(&nic_data->main_lock);
485 return rc;
486}
487
488/** Inform the NICF about device's MAC adress.
489 *
490 * @return EOK On success
491 *
492 */
493int nic_report_address(nic_t *nic_data, const nic_address_t *address)
494{
495 assert(nic_data);
496
497 if (address->address[0] & 1)
498 return EINVAL;
499
500 fibril_rwlock_write_lock(&nic_data->main_lock);
501
502 /* Notify NIL layer (and uppper) if bound - not in add_device */
503 if (nic_data->nil_session != NULL) {
504 int rc = nil_addr_changed_msg(nic_data->nil_session,
505 nic_data->device_id, address);
506 if (rc != EOK) {
507 fibril_rwlock_write_unlock(&nic_data->main_lock);
508 return rc;
509 }
510 }
511
512 fibril_rwlock_write_lock(&nic_data->rxc_lock);
513
514 /*
515 * The initial address (all zeroes) shouldn't be
516 * there and we will ignore that error -- in next
517 * calls this should not happen.
518 */
519 int rc = nic_rxc_set_addr(&nic_data->rx_control,
520 &nic_data->mac, address);
521
522 /* For the first time also record the default MAC */
523 if (MAC_IS_ZERO(nic_data->default_mac.address)) {
524 assert(MAC_IS_ZERO(nic_data->mac.address));
525 memcpy(&nic_data->default_mac, address, sizeof(nic_address_t));
526 }
527
528 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
529
530 if ((rc != EOK) && (rc != ENOENT)) {
531 fibril_rwlock_write_unlock(&nic_data->main_lock);
532 return rc;
533 }
534
535 memcpy(&nic_data->mac, address, sizeof(nic_address_t));
536
537 fibril_rwlock_write_unlock(&nic_data->main_lock);
538
539 return EOK;
540}
541
542/**
543 * Used to obtain devices MAC address.
544 *
545 * The main lock should be locked, otherwise the inconsistent address
546 * can be returend.
547 *
548 * @param nic_data The controller data
549 * @param address The output for address.
550 */
551void nic_query_address(nic_t *nic_data, nic_address_t *addr) {
552 if (!addr)
553 return;
554 if (!nic_data)
555 memset(addr, 0, sizeof(nic_address_t));
556
557 memcpy(addr, &nic_data->mac, sizeof(nic_address_t));
558};
559
560/**
561 * The busy flag can be set to 1 only in the send_frame handler, to 0 it can
562 * be set anywhere.
563 *
564 * @param nic_data
565 * @param busy
566 */
567void nic_set_tx_busy(nic_t *nic_data, int busy)
568{
569 /*
570 * When the function is called in send_frame handler the main lock is
571 * locked so no race can happen.
572 * Otherwise, when it is unexpectedly set to 0 (even with main lock held
573 * by other fibril) it cannot crash anything.
574 */
575 nic_data->tx_busy = busy;
576}
577
578/**
579 * This is the function that the driver should call when it receives a frame.
580 * The frame is checked by filters and then sent up to the NIL layer or
581 * discarded. The frame is released.
582 *
583 * @param nic_data
584 * @param frame The received frame
585 */
586void nic_received_frame(nic_t *nic_data, nic_frame_t *frame)
587{
588 /* Note: this function must not lock main lock, because loopback driver
589 * calls it inside send_frame handler (with locked main lock) */
590 fibril_rwlock_read_lock(&nic_data->rxc_lock);
591 nic_frame_type_t frame_type;
592 int check = nic_rxc_check(&nic_data->rx_control, frame->data,
593 frame->size, &frame_type);
594 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
595 /* Update statistics */
596 fibril_rwlock_write_lock(&nic_data->stats_lock);
597
598 if (nic_data->state == NIC_STATE_ACTIVE && check) {
599 nic_data->stats.receive_packets++;
600 nic_data->stats.receive_bytes += frame->size;
601 switch (frame_type) {
602 case NIC_FRAME_MULTICAST:
603 nic_data->stats.receive_multicast++;
604 break;
605 case NIC_FRAME_BROADCAST:
606 nic_data->stats.receive_broadcast++;
607 break;
608 default:
609 break;
610 }
611 fibril_rwlock_write_unlock(&nic_data->stats_lock);
612 nil_received_msg(nic_data->nil_session, nic_data->device_id,
613 frame->data, frame->size);
614 } else {
615 switch (frame_type) {
616 case NIC_FRAME_UNICAST:
617 nic_data->stats.receive_filtered_unicast++;
618 break;
619 case NIC_FRAME_MULTICAST:
620 nic_data->stats.receive_filtered_multicast++;
621 break;
622 case NIC_FRAME_BROADCAST:
623 nic_data->stats.receive_filtered_broadcast++;
624 break;
625 }
626 fibril_rwlock_write_unlock(&nic_data->stats_lock);
627 }
628 nic_release_frame(nic_data, frame);
629}
630
631/**
632 * This function is to be used only in the loopback driver. It's workaround
633 * for the situation when the frame does not contain ethernet address.
634 * The filtering is therefore not applied here.
635 *
636 * @param nic_data
637 * @param data Frame data
638 * @param size Frame size in bytes
639 */
640void nic_received_noneth_frame(nic_t *nic_data, void *data, size_t size)
641{
642 fibril_rwlock_write_lock(&nic_data->stats_lock);
643 nic_data->stats.receive_packets++;
644 nic_data->stats.receive_bytes += size;
645 fibril_rwlock_write_unlock(&nic_data->stats_lock);
646
647 nil_received_msg(nic_data->nil_session, nic_data->device_id,
648 data, size);
649}
650
651/**
652 * Some NICs can receive multiple frames during single interrupt. These can
653 * send them in whole list of frames (actually nic_frame_t structures), then
654 * the list is deallocated and each frame is passed to the
655 * nic_received_packet function.
656 *
657 * @param nic_data
658 * @param frames List of received frames
659 */
660void nic_received_frame_list(nic_t *nic_data, nic_frame_list_t *frames)
661{
662 if (frames == NULL)
663 return;
664 while (!list_empty(frames)) {
665 nic_frame_t *frame =
666 list_get_instance(list_first(frames), nic_frame_t, link);
667
668 list_remove(&frame->link);
669 nic_received_frame(nic_data, frame);
670 }
671 nic_driver_release_frame_list(frames);
672}
673
674/** Allocate and initialize the driver data.
675 *
676 * @return Allocated structure or NULL.
677 *
678 */
679static nic_t *nic_create(void)
680{
681 nic_t *nic_data = malloc(sizeof(nic_t));
682 if (nic_data == NULL)
683 return NULL;
684
685 /* Force zero to all uninitialized fields (e.g. added in future) */
686 bzero(nic_data, sizeof(nic_t));
687 if (nic_rxc_init(&nic_data->rx_control) != EOK) {
688 free(nic_data);
689 return NULL;
690 }
691
692 if (nic_wol_virtues_init(&nic_data->wol_virtues) != EOK) {
693 free(nic_data);
694 return NULL;
695 }
696
697 nic_data->dev = NULL;
698 nic_data->fun = NULL;
699 nic_data->device_id = NIC_DEVICE_INVALID_ID;
700 nic_data->state = NIC_STATE_STOPPED;
701 nic_data->net_session = NULL;
702 nic_data->nil_session = NULL;
703 nic_data->irc_session = NULL;
704 nic_data->poll_mode = NIC_POLL_IMMEDIATE;
705 nic_data->default_poll_mode = NIC_POLL_IMMEDIATE;
706 nic_data->send_frame = NULL;
707 nic_data->on_activating = NULL;
708 nic_data->on_going_down = NULL;
709 nic_data->on_stopping = NULL;
710 nic_data->specific = NULL;
711
712 fibril_rwlock_initialize(&nic_data->main_lock);
713 fibril_rwlock_initialize(&nic_data->stats_lock);
714 fibril_rwlock_initialize(&nic_data->rxc_lock);
715 fibril_rwlock_initialize(&nic_data->wv_lock);
716
717 bzero(&nic_data->mac, sizeof(nic_address_t));
718 bzero(&nic_data->default_mac, sizeof(nic_address_t));
719 bzero(&nic_data->stats, sizeof(nic_device_stats_t));
720
721 return nic_data;
722}
723
724/** Create NIC structure for the device and bind it to dev_fun_t
725 *
726 * The pointer to the created and initialized NIC structure will
727 * be stored in device->nic_data.
728 *
729 * @param device The NIC device structure
730 *
731 * @return Pointer to created nic_t structure or NULL
732 *
733 */
734nic_t *nic_create_and_bind(ddf_dev_t *device)
735{
736 assert(device);
737 assert(!device->driver_data);
738
739 nic_t *nic_data = nic_create();
740 if (!nic_data)
741 return NULL;
742
743 nic_data->dev = device;
744 device->driver_data = nic_data;
745
746 return nic_data;
747}
748
749/**
750 * Hangs up the phones in the structure, deallocates specific data and then
751 * the structure itself.
752 *
753 * @param data
754 */
755static void nic_destroy(nic_t *nic_data) {
756 if (nic_data->net_session != NULL) {
757 async_hangup(nic_data->net_session);
758 }
759
760 if (nic_data->nil_session != NULL) {
761 async_hangup(nic_data->nil_session);
762 }
763
764 free(nic_data->specific);
765 free(nic_data);
766}
767
768/**
769 * Unbind and destroy nic_t stored in ddf_dev_t.nic_data.
770 * The ddf_dev_t.nic_data will be set to NULL, specific driver data will be
771 * destroyed.
772 *
773 * @param device The NIC device structure
774 */
775void nic_unbind_and_destroy(ddf_dev_t *device){
776 if (!device)
777 return;
778 if (!device->driver_data)
779 return;
780
781 nic_destroy((nic_t *) device->driver_data);
782 device->driver_data = NULL;
783 return;
784}
785
786/**
787 * Set information about current HW filtering.
788 * 1 ... Only those frames we want to receive are passed through HW
789 * 0 ... The HW filtering is imperfect
790 * -1 ... Don't change the setting
791 * Can be called only from the on_*_change handler.
792 *
793 * @param nic_data
794 * @param unicast_exact Unicast frames
795 * @param mcast_exact Multicast frames
796 * @param vlan_exact VLAN tags
797 */
798void nic_report_hw_filtering(nic_t *nic_data,
799 int unicast_exact, int multicast_exact, int vlan_exact)
800{
801 nic_rxc_hw_filtering(&nic_data->rx_control,
802 unicast_exact, multicast_exact, vlan_exact);
803}
804
805/**
806 * Computes hash for the address list based on standard multicast address
807 * hashing.
808 *
809 * @param address_list
810 * @param count
811 *
812 * @return Multicast hash
813 *
814 * @see multicast_hash
815 */
816uint64_t nic_mcast_hash(const nic_address_t *list, size_t count)
817{
818 return nic_rxc_mcast_hash(list, count);
819}
820
821/**
822 * Computes hash for multicast addresses currently set up in the RX multicast
823 * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
824 * Can be called only from the state change handlers (on_activating,
825 * on_going_down and on_stopping).
826 *
827 * @param nic_data
828 *
829 * @return Multicast hash
830 *
831 * @see multicast_hash
832 */
833uint64_t nic_query_mcast_hash(nic_t *nic_data)
834{
835 fibril_rwlock_read_lock(&nic_data->rxc_lock);
836 uint64_t hash = nic_rxc_multicast_get_hash(&nic_data->rx_control);
837 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
838 return hash;
839}
840
841/**
842 * Queries the current mode of unicast frames receiving.
843 * Can be called only from the on_*_change handler.
844 *
845 * @param nic_data
846 * @param mode The new unicast mode
847 * @param max_count Max number of addresses that can be written into the
848 * address_list.
849 * @param address_list List of MAC addresses or NULL.
850 * @param address_count Number of addresses in the list
851 */
852void nic_query_unicast(const nic_t *nic_data,
853 nic_unicast_mode_t *mode,
854 size_t max_count, nic_address_t *address_list, size_t *address_count)
855{
856 assert(mode != NULL);
857 nic_rxc_unicast_get_mode(&nic_data->rx_control, mode,
858 max_count, address_list, address_count);
859}
860
861/**
862 * Queries the current mode of multicast frames receiving.
863 * Can be called only from the on_*_change handler.
864 *
865 * @param nic_data
866 * @param mode The current multicast mode
867 * @param max_count Max number of addresses that can be written into the
868 * address_list.
869 * @param address_list List of MAC addresses or NULL.
870 * @param address_count Number of addresses in the list
871 */
872void nic_query_multicast(const nic_t *nic_data,
873 nic_multicast_mode_t *mode,
874 size_t max_count, nic_address_t *address_list, size_t *address_count)
875{
876 assert(mode != NULL);
877 nic_rxc_multicast_get_mode(&nic_data->rx_control, mode,
878 max_count, address_list, address_count);
879}
880
881/**
882 * Queries the current mode of broadcast frames receiving.
883 * Can be called only from the on_*_change handler.
884 *
885 * @param nic_data
886 * @param mode The new broadcast mode
887 */
888void nic_query_broadcast(const nic_t *nic_data,
889 nic_broadcast_mode_t *mode)
890{
891 assert(mode != NULL);
892 nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
893}
894
895/**
896 * Queries the current blocked source addresses.
897 * Can be called only from the on_*_change handler.
898 *
899 * @param nic_data
900 * @param max_count Max number of addresses that can be written into the
901 * address_list.
902 * @param address_list List of MAC addresses or NULL.
903 * @param address_count Number of addresses in the list
904 */
905void nic_query_blocked_sources(const nic_t *nic_data,
906 size_t max_count, nic_address_t *address_list, size_t *address_count)
907{
908 nic_rxc_blocked_sources_get(&nic_data->rx_control,
909 max_count, address_list, address_count);
910}
911
912/**
913 * Query mask used for filtering according to the VLAN tags.
914 * Can be called only from the on_*_change handler.
915 *
916 * @param nic_data
917 * @param mask Must be 512 bytes long
918 *
919 * @return EOK
920 * @return ENOENT
921 */
922int nic_query_vlan_mask(const nic_t *nic_data, nic_vlan_mask_t *mask)
923{
924 assert(mask);
925 return nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
926}
927
928/**
929 * Query maximum number of WOL virtues of specified type allowed on the device.
930 * Can be called only from add_device and on_wol_virtue_* handlers.
931 *
932 * @param nic_data
933 * @param type The type of the WOL virtues
934 *
935 * @return Maximal number of allowed virtues of this type. -1 means this type
936 * is not supported at all.
937 */
938int nic_query_wol_max_caps(const nic_t *nic_data, nic_wv_type_t type)
939{
940 return nic_data->wol_virtues.caps_max[type];
941}
942
943/**
944 * Sets maximum number of WOL virtues of specified type allowed on the device.
945 * Can be called only from add_device and on_wol_virtue_* handlers.
946 *
947 * @param nic_data
948 * @param type The type of the WOL virtues
949 * @param count Maximal number of allowed virtues of this type. -1 means
950 * this type is not supported at all.
951 */
952void nic_set_wol_max_caps(nic_t *nic_data, nic_wv_type_t type, int count)
953{
954 nic_data->wol_virtues.caps_max[type] = count;
955}
956
957/**
958 * @param nic_data
959 * @return The driver-specific structure for this NIC.
960 */
961void *nic_get_specific(nic_t *nic_data)
962{
963 return nic_data->specific;
964}
965
966/**
967 * @param nic_data
968 * @param specific The driver-specific structure for this NIC.
969 */
970void nic_set_specific(nic_t *nic_data, void *specific)
971{
972 nic_data->specific = specific;
973}
974
975/**
976 * You can call the function only from one of the state change handlers.
977 * @param nic_data
978 * @return Current state of the NIC, prior to the actually executed change
979 */
980nic_device_state_t nic_query_state(nic_t *nic_data)
981{
982 return nic_data->state;
983}
984
985/**
986 * @param nic_data
987 * @return DDF device associated with this NIC.
988 */
989ddf_dev_t *nic_get_ddf_dev(nic_t *nic_data)
990{
991 return nic_data->dev;
992}
993
994/**
995 * @param nic_data
996 * @return DDF function associated with this NIC.
997 */
998ddf_fun_t *nic_get_ddf_fun(nic_t *nic_data)
999{
1000 return nic_data->fun;
1001}
1002
1003/**
1004 * @param nic_data
1005 * @param fun
1006 */
1007void nic_set_ddf_fun(nic_t *nic_data, ddf_fun_t *fun)
1008{
1009 nic_data->fun = fun;
1010}
1011
1012/**
1013 * @param dev DDF device associated with NIC
1014 * @return The associated NIC structure
1015 */
1016nic_t *nic_get_from_ddf_dev(ddf_dev_t *dev)
1017{
1018 return (nic_t *) dev->driver_data;
1019};
1020
1021/**
1022 * @param dev DDF function associated with NIC
1023 * @return The associated NIC structure
1024 */
1025nic_t *nic_get_from_ddf_fun(ddf_fun_t *fun)
1026{
1027 return (nic_t *) fun->driver_data;
1028};
1029
1030/**
1031 * Raises the send_packets and send_bytes in device statistics.
1032 *
1033 * @param nic_data
1034 * @param packets Number of received packets
1035 * @param bytes Number of received bytes
1036 */
1037void nic_report_send_ok(nic_t *nic_data, size_t packets, size_t bytes)
1038{
1039 fibril_rwlock_write_lock(&nic_data->stats_lock);
1040 nic_data->stats.send_packets += packets;
1041 nic_data->stats.send_bytes += bytes;
1042 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1043}
1044
1045/**
1046 * Raises total error counter (send_errors) and the concrete send error counter
1047 * determined by the cause argument.
1048 *
1049 * @param nic_data
1050 * @param cause The concrete error cause.
1051 */
1052void nic_report_send_error(nic_t *nic_data, nic_send_error_cause_t cause,
1053 unsigned count)
1054{
1055 if (count == 0)
1056 return;
1057
1058 fibril_rwlock_write_lock(&nic_data->stats_lock);
1059 nic_data->stats.send_errors += count;
1060 switch (cause) {
1061 case NIC_SEC_BUFFER_FULL:
1062 nic_data->stats.send_dropped += count;
1063 break;
1064 case NIC_SEC_ABORTED:
1065 nic_data->stats.send_aborted_errors += count;
1066 break;
1067 case NIC_SEC_CARRIER_LOST:
1068 nic_data->stats.send_carrier_errors += count;
1069 break;
1070 case NIC_SEC_FIFO_OVERRUN:
1071 nic_data->stats.send_fifo_errors += count;
1072 break;
1073 case NIC_SEC_HEARTBEAT:
1074 nic_data->stats.send_heartbeat_errors += count;
1075 break;
1076 case NIC_SEC_WINDOW_ERROR:
1077 nic_data->stats.send_window_errors += count;
1078 break;
1079 case NIC_SEC_OTHER:
1080 break;
1081 }
1082 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1083}
1084
1085/**
1086 * Raises total error counter (receive_errors) and the concrete receive error
1087 * counter determined by the cause argument.
1088 *
1089 * @param nic_data
1090 * @param cause The concrete error cause
1091 */
1092void nic_report_receive_error(nic_t *nic_data,
1093 nic_receive_error_cause_t cause, unsigned count)
1094{
1095 fibril_rwlock_write_lock(&nic_data->stats_lock);
1096 nic_data->stats.receive_errors += count;
1097 switch (cause) {
1098 case NIC_REC_BUFFER_FULL:
1099 nic_data->stats.receive_dropped += count;
1100 break;
1101 case NIC_REC_LENGTH:
1102 nic_data->stats.receive_length_errors += count;
1103 break;
1104 case NIC_REC_BUFFER_OVERFLOW:
1105 nic_data->stats.receive_dropped += count;
1106 break;
1107 case NIC_REC_CRC:
1108 nic_data->stats.receive_crc_errors += count;
1109 break;
1110 case NIC_REC_FRAME_ALIGNMENT:
1111 nic_data->stats.receive_frame_errors += count;
1112 break;
1113 case NIC_REC_FIFO_OVERRUN:
1114 nic_data->stats.receive_fifo_errors += count;
1115 break;
1116 case NIC_REC_MISSED:
1117 nic_data->stats.receive_missed_errors += count;
1118 break;
1119 case NIC_REC_OTHER:
1120 break;
1121 }
1122 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1123}
1124
1125/**
1126 * Raises the collisions counter in device statistics.
1127 */
1128void nic_report_collisions(nic_t *nic_data, unsigned count)
1129{
1130 fibril_rwlock_write_lock(&nic_data->stats_lock);
1131 nic_data->stats.collisions += count;
1132 fibril_rwlock_write_unlock(&nic_data->stats_lock);
1133}
1134
1135/** Just wrapper for checking nonzero time interval
1136 *
1137 * @oaram t The interval to check
1138 * @returns Zero if the t is nonzero interval
1139 * @returns Nonzero if t is zero interval
1140 */
1141static int timeval_nonpositive(struct timeval t) {
1142 return (t.tv_sec <= 0) && (t.tv_usec <= 0);
1143}
1144
1145/** Main function of software period fibrill
1146 *
1147 * Just calls poll() in the nic->poll_period period
1148 *
1149 * @param data The NIC structure pointer
1150 *
1151 * @return 0, never reached
1152 */
1153static int period_fibril_fun(void *data)
1154{
1155 nic_t *nic = data;
1156 struct sw_poll_info *info = &nic->sw_poll_info;
1157 while (true) {
1158 fibril_rwlock_read_lock(&nic->main_lock);
1159 int run = info->run;
1160 int running = info->running;
1161 struct timeval remaining = nic->poll_period;
1162 fibril_rwlock_read_unlock(&nic->main_lock);
1163
1164 if (!running) {
1165 remaining.tv_sec = 5;
1166 remaining.tv_usec = 0;
1167 }
1168
1169 /* Wait the period (keep attention to overflows) */
1170 while (!timeval_nonpositive(remaining)) {
1171 suseconds_t wait = 0;
1172 if (remaining.tv_sec > 0) {
1173 time_t wait_sec = remaining.tv_sec;
1174 /* wait maximaly 5 seconds to get reasonable reaction time
1175 * when period is reset
1176 */
1177 if (wait_sec > 5)
1178 wait_sec = 5;
1179
1180 wait = (suseconds_t) wait_sec * 1000000;
1181
1182 remaining.tv_sec -= wait_sec;
1183 } else {
1184 wait = remaining.tv_usec;
1185
1186 if (wait > 5 * 1000000) {
1187 wait = 5 * 1000000;
1188 }
1189
1190 remaining.tv_usec -= wait;
1191 }
1192 async_usleep(wait);
1193
1194 /* Check if the period was not reset */
1195 if (info->run != run)
1196 break;
1197 }
1198
1199 /* Provide polling if the period finished */
1200 fibril_rwlock_read_lock(&nic->main_lock);
1201 if (info->running && info->run == run) {
1202 nic->on_poll_request(nic);
1203 }
1204 fibril_rwlock_read_unlock(&nic->main_lock);
1205 }
1206 return 0;
1207}
1208
1209/** Starts software periodic polling
1210 *
1211 * Reset to new period if the original period was running
1212 *
1213 * @param nic_data Nic data structure
1214 */
1215void nic_sw_period_start(nic_t *nic_data)
1216{
1217 /* Create the fibril if it is not crated */
1218 if (nic_data->sw_poll_info.fibril == 0) {
1219 nic_data->sw_poll_info.fibril = fibril_create(period_fibril_fun,
1220 nic_data);
1221 nic_data->sw_poll_info.running = 0;
1222 nic_data->sw_poll_info.run = 0;
1223
1224 /* Start fibril */
1225 fibril_add_ready(nic_data->sw_poll_info.fibril);
1226 }
1227
1228 /* Inform fibril about running with new period */
1229 nic_data->sw_poll_info.run = (nic_data->sw_poll_info.run + 1) % 100;
1230 nic_data->sw_poll_info.running = 1;
1231}
1232
1233/** Stops software periodic polling
1234 *
1235 * @param nic_data Nic data structure
1236 */
1237void nic_sw_period_stop(nic_t *nic_data)
1238{
1239 nic_data->sw_poll_info.running = 0;
1240}
1241
1242/** @}
1243 */
Note: See TracBrowser for help on using the repository browser.