Add memtest support.
[syslinux-debian/hramrach.git] / gpxe / src / net / netdevice.c
blobee0d0b72b7927553945ab5edc1f60ab8fa230a41
1 /*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 FILE_LICENCE ( GPL2_OR_LATER );
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <byteswap.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <gpxe/if_ether.h>
28 #include <gpxe/iobuf.h>
29 #include <gpxe/tables.h>
30 #include <gpxe/process.h>
31 #include <gpxe/init.h>
32 #include <gpxe/device.h>
33 #include <gpxe/errortab.h>
34 #include <gpxe/netdevice.h>
36 /** @file
38 * Network device management
42 /** List of network devices */
43 struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
45 /** List of open network devices, in reverse order of opening */
46 static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
48 /** Default link status code */
49 #define EUNKNOWN_LINK_STATUS EINPROGRESS
51 /** Human-readable message for the default link status */
52 struct errortab netdev_errors[] __errortab = {
53 { EUNKNOWN_LINK_STATUS, "Unknown" },
56 /**
57 * Mark network device as having link down
59 * @v netdev Network device
61 void netdev_link_down ( struct net_device *netdev ) {
63 switch ( netdev->link_rc ) {
64 case 0:
65 case -EUNKNOWN_LINK_STATUS:
66 netdev->link_rc = -ENOTCONN;
67 break;
68 default:
69 /* Avoid clobbering a more detailed link status code,
70 * if one is already set.
72 break;
76 /**
77 * Record network device statistic
79 * @v stats Network device statistics
80 * @v rc Status code
82 static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
83 struct net_device_error *error;
84 struct net_device_error *least_common_error;
85 unsigned int i;
87 /* If this is not an error, just update the good counter */
88 if ( rc == 0 ) {
89 stats->good++;
90 return;
93 /* Update the bad counter */
94 stats->bad++;
96 /* Locate the appropriate error record */
97 least_common_error = &stats->errors[0];
98 for ( i = 0 ; i < ( sizeof ( stats->errors ) /
99 sizeof ( stats->errors[0] ) ) ; i++ ) {
100 error = &stats->errors[i];
101 /* Update matching record, if found */
102 if ( error->rc == rc ) {
103 error->count++;
104 return;
106 if ( error->count < least_common_error->count )
107 least_common_error = error;
110 /* Overwrite the least common error record */
111 least_common_error->rc = rc;
112 least_common_error->count = 1;
116 * Transmit raw packet via network device
118 * @v netdev Network device
119 * @v iobuf I/O buffer
120 * @ret rc Return status code
122 * Transmits the packet via the specified network device. This
123 * function takes ownership of the I/O buffer.
125 int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
126 int rc;
128 DBGC ( netdev, "NETDEV %p transmitting %p (%p+%zx)\n",
129 netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
131 list_add_tail ( &iobuf->list, &netdev->tx_queue );
133 if ( ! ( netdev->state & NETDEV_OPEN ) ) {
134 rc = -ENETUNREACH;
135 goto err;
138 if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 )
139 goto err;
141 return 0;
143 err:
144 netdev_tx_complete_err ( netdev, iobuf, rc );
145 return rc;
149 * Complete network transmission
151 * @v netdev Network device
152 * @v iobuf I/O buffer
153 * @v rc Packet status code
155 * The packet must currently be in the network device's TX queue.
157 void netdev_tx_complete_err ( struct net_device *netdev,
158 struct io_buffer *iobuf, int rc ) {
160 /* Update statistics counter */
161 netdev_record_stat ( &netdev->tx_stats, rc );
162 if ( rc == 0 ) {
163 DBGC ( netdev, "NETDEV %p transmission %p complete\n",
164 netdev, iobuf );
165 } else {
166 DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
167 netdev, iobuf, strerror ( rc ) );
170 /* Catch data corruption as early as possible */
171 assert ( iobuf->list.next != NULL );
172 assert ( iobuf->list.prev != NULL );
174 /* Dequeue and free I/O buffer */
175 list_del ( &iobuf->list );
176 free_iob ( iobuf );
180 * Complete network transmission
182 * @v netdev Network device
183 * @v rc Packet status code
185 * Completes the oldest outstanding packet in the TX queue.
187 void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) {
188 struct io_buffer *iobuf;
190 list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
191 netdev_tx_complete_err ( netdev, iobuf, rc );
192 return;
197 * Flush device's transmit queue
199 * @v netdev Network device
201 static void netdev_tx_flush ( struct net_device *netdev ) {
203 /* Discard any packets in the TX queue */
204 while ( ! list_empty ( &netdev->tx_queue ) ) {
205 netdev_tx_complete_next_err ( netdev, -ECANCELED );
210 * Add packet to receive queue
212 * @v netdev Network device
213 * @v iobuf I/O buffer, or NULL
215 * The packet is added to the network device's RX queue. This
216 * function takes ownership of the I/O buffer.
218 void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
220 DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
221 netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
223 /* Enqueue packet */
224 list_add_tail ( &iobuf->list, &netdev->rx_queue );
226 /* Update statistics counter */
227 netdev_record_stat ( &netdev->rx_stats, 0 );
231 * Discard received packet
233 * @v netdev Network device
234 * @v iobuf I/O buffer, or NULL
235 * @v rc Packet status code
237 * The packet is discarded and an RX error is recorded. This function
238 * takes ownership of the I/O buffer. @c iobuf may be NULL if, for
239 * example, the net device wishes to report an error due to being
240 * unable to allocate an I/O buffer.
242 void netdev_rx_err ( struct net_device *netdev,
243 struct io_buffer *iobuf, int rc ) {
245 DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n",
246 netdev, iobuf, strerror ( rc ) );
248 /* Discard packet */
249 free_iob ( iobuf );
251 /* Update statistics counter */
252 netdev_record_stat ( &netdev->rx_stats, rc );
256 * Poll for completed and received packets on network device
258 * @v netdev Network device
260 * Polls the network device for completed transmissions and received
261 * packets. Any received packets will be added to the RX packet queue
262 * via netdev_rx().
264 void netdev_poll ( struct net_device *netdev ) {
266 if ( netdev->state & NETDEV_OPEN )
267 netdev->op->poll ( netdev );
271 * Remove packet from device's receive queue
273 * @v netdev Network device
274 * @ret iobuf I/O buffer, or NULL
276 * Removes the first packet from the device's RX queue and returns it.
277 * Ownership of the packet is transferred to the caller.
279 struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) {
280 struct io_buffer *iobuf;
282 list_for_each_entry ( iobuf, &netdev->rx_queue, list ) {
283 list_del ( &iobuf->list );
284 return iobuf;
286 return NULL;
290 * Flush device's receive queue
292 * @v netdev Network device
294 static void netdev_rx_flush ( struct net_device *netdev ) {
295 struct io_buffer *iobuf;
297 /* Discard any packets in the RX queue */
298 while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
299 netdev_rx_err ( netdev, iobuf, -ECANCELED );
304 * Free network device
306 * @v refcnt Network device reference counter
308 static void free_netdev ( struct refcnt *refcnt ) {
309 struct net_device *netdev =
310 container_of ( refcnt, struct net_device, refcnt );
312 netdev_tx_flush ( netdev );
313 netdev_rx_flush ( netdev );
314 clear_settings ( netdev_settings ( netdev ) );
315 free ( netdev );
319 * Allocate network device
321 * @v priv_size Size of private data area (net_device::priv)
322 * @ret netdev Network device, or NULL
324 * Allocates space for a network device and its private data area.
326 struct net_device * alloc_netdev ( size_t priv_size ) {
327 struct net_device *netdev;
328 size_t total_len;
330 total_len = ( sizeof ( *netdev ) + priv_size );
331 netdev = zalloc ( total_len );
332 if ( netdev ) {
333 netdev->refcnt.free = free_netdev;
334 netdev->link_rc = -EUNKNOWN_LINK_STATUS;
335 INIT_LIST_HEAD ( &netdev->tx_queue );
336 INIT_LIST_HEAD ( &netdev->rx_queue );
337 netdev_settings_init ( netdev );
338 netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
340 return netdev;
344 * Register network device
346 * @v netdev Network device
347 * @ret rc Return status code
349 * Gives the network device a name and adds it to the list of network
350 * devices.
352 int register_netdev ( struct net_device *netdev ) {
353 static unsigned int ifindex = 0;
354 int rc;
356 /* Create device name */
357 snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
358 ifindex++ );
360 /* Set initial link-layer address */
361 netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
363 /* Register per-netdev configuration settings */
364 if ( ( rc = register_settings ( netdev_settings ( netdev ),
365 NULL ) ) != 0 ) {
366 DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
367 netdev, strerror ( rc ) );
368 return rc;
371 /* Add to device list */
372 netdev_get ( netdev );
373 list_add_tail ( &netdev->list, &net_devices );
374 DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n",
375 netdev, netdev->name, netdev->dev->name,
376 netdev_addr ( netdev ) );
378 return 0;
382 * Open network device
384 * @v netdev Network device
385 * @ret rc Return status code
387 int netdev_open ( struct net_device *netdev ) {
388 int rc;
390 /* Do nothing if device is already open */
391 if ( netdev->state & NETDEV_OPEN )
392 return 0;
394 DBGC ( netdev, "NETDEV %p opening\n", netdev );
396 /* Open the device */
397 if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
398 return rc;
400 /* Mark as opened */
401 netdev->state |= NETDEV_OPEN;
403 /* Add to head of open devices list */
404 list_add ( &netdev->open_list, &open_net_devices );
406 return 0;
410 * Close network device
412 * @v netdev Network device
414 void netdev_close ( struct net_device *netdev ) {
416 /* Do nothing if device is already closed */
417 if ( ! ( netdev->state & NETDEV_OPEN ) )
418 return;
420 DBGC ( netdev, "NETDEV %p closing\n", netdev );
422 /* Close the device */
423 netdev->op->close ( netdev );
425 /* Flush TX and RX queues */
426 netdev_tx_flush ( netdev );
427 netdev_rx_flush ( netdev );
429 /* Mark as closed */
430 netdev->state &= ~NETDEV_OPEN;
432 /* Remove from open devices list */
433 list_del ( &netdev->open_list );
437 * Unregister network device
439 * @v netdev Network device
441 * Removes the network device from the list of network devices.
443 void unregister_netdev ( struct net_device *netdev ) {
445 /* Ensure device is closed */
446 netdev_close ( netdev );
448 /* Unregister per-netdev configuration settings */
449 unregister_settings ( netdev_settings ( netdev ) );
451 /* Remove from device list */
452 list_del ( &netdev->list );
453 netdev_put ( netdev );
454 DBGC ( netdev, "NETDEV %p unregistered\n", netdev );
457 /** Enable or disable interrupts
459 * @v netdev Network device
460 * @v enable Interrupts should be enabled
462 void netdev_irq ( struct net_device *netdev, int enable ) {
463 netdev->op->irq ( netdev, enable );
467 * Get network device by name
469 * @v name Network device name
470 * @ret netdev Network device, or NULL
472 struct net_device * find_netdev ( const char *name ) {
473 struct net_device *netdev;
475 list_for_each_entry ( netdev, &net_devices, list ) {
476 if ( strcmp ( netdev->name, name ) == 0 )
477 return netdev;
480 return NULL;
484 * Get network device by PCI bus:dev.fn address
486 * @v bus_type Bus type
487 * @v location Bus location
488 * @ret netdev Network device, or NULL
490 struct net_device * find_netdev_by_location ( unsigned int bus_type,
491 unsigned int location ) {
492 struct net_device *netdev;
494 list_for_each_entry ( netdev, &net_devices, list ) {
495 if ( ( netdev->dev->desc.bus_type == bus_type ) &&
496 ( netdev->dev->desc.location == location ) )
497 return netdev;
500 return NULL;
504 * Get most recently opened network device
506 * @ret netdev Most recently opened network device, or NULL
508 struct net_device * last_opened_netdev ( void ) {
509 struct net_device *netdev;
511 list_for_each_entry ( netdev, &open_net_devices, open_list ) {
512 assert ( netdev->state & NETDEV_OPEN );
513 return netdev;
516 return NULL;
520 * Transmit network-layer packet
522 * @v iobuf I/O buffer
523 * @v netdev Network device
524 * @v net_protocol Network-layer protocol
525 * @v ll_dest Destination link-layer address
526 * @ret rc Return status code
528 * Prepends link-layer headers to the I/O buffer and transmits the
529 * packet via the specified network device. This function takes
530 * ownership of the I/O buffer.
532 int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
533 struct net_protocol *net_protocol, const void *ll_dest ) {
534 struct ll_protocol *ll_protocol = netdev->ll_protocol;
535 int rc;
537 /* Force a poll on the netdevice to (potentially) clear any
538 * backed-up TX completions. This is needed on some network
539 * devices to avoid excessive losses due to small TX ring
540 * sizes.
542 netdev_poll ( netdev );
544 /* Add link-layer header */
545 if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, netdev->ll_addr,
546 net_protocol->net_proto ) ) != 0 ) {
547 free_iob ( iobuf );
548 return rc;
551 /* Transmit packet */
552 return netdev_tx ( netdev, iobuf );
556 * Process received network-layer packet
558 * @v iobuf I/O buffer
559 * @v netdev Network device
560 * @v net_proto Network-layer protocol, in network-byte order
561 * @v ll_source Source link-layer address
562 * @ret rc Return status code
564 int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
565 uint16_t net_proto, const void *ll_source ) {
566 struct net_protocol *net_protocol;
568 /* Hand off to network-layer protocol, if any */
569 for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
570 if ( net_protocol->net_proto == net_proto )
571 return net_protocol->rx ( iobuf, netdev, ll_source );
574 DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n",
575 netdev, ntohs ( net_proto ) );
576 free_iob ( iobuf );
577 return 0;
581 * Single-step the network stack
583 * @v process Network stack process
585 * This polls all interfaces for received packets, and processes
586 * packets from the RX queue.
588 static void net_step ( struct process *process __unused ) {
589 struct net_device *netdev;
590 struct io_buffer *iobuf;
591 struct ll_protocol *ll_protocol;
592 const void *ll_dest;
593 const void *ll_source;
594 uint16_t net_proto;
595 int rc;
597 /* Poll and process each network device */
598 list_for_each_entry ( netdev, &net_devices, list ) {
600 /* Poll for new packets */
601 netdev_poll ( netdev );
603 /* Process at most one received packet. Give priority
604 * to getting packets out of the NIC over processing
605 * the received packets, because we advertise a window
606 * that assumes that we can receive packets from the
607 * NIC faster than they arrive.
609 if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
611 DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n",
612 netdev, iobuf, iobuf->data,
613 iob_len ( iobuf ) );
615 /* Remove link-layer header */
616 ll_protocol = netdev->ll_protocol;
617 if ( ( rc = ll_protocol->pull ( netdev, iobuf,
618 &ll_dest, &ll_source,
619 &net_proto ) ) != 0 ) {
620 free_iob ( iobuf );
621 continue;
624 net_rx ( iobuf, netdev, net_proto, ll_source );
629 /** Networking stack process */
630 struct process net_process __permanent_process = {
631 .list = LIST_HEAD_INIT ( net_process.list ),
632 .step = net_step,