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

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

Create DDF functions manually.

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