00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <byteswap.h>
00025 #include <string.h>
00026 #include <errno.h>
00027 #include <gpxe/if_ether.h>
00028 #include <gpxe/iobuf.h>
00029 #include <gpxe/tables.h>
00030 #include <gpxe/process.h>
00031 #include <gpxe/init.h>
00032 #include <gpxe/device.h>
00033 #include <gpxe/errortab.h>
00034 #include <gpxe/netdevice.h>
00035
00036
00037
00038
00039
00040
00041
00042
00043 struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
00044
00045
00046 static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
00047
00048
00049 #define EUNKNOWN_LINK_STATUS EINPROGRESS
00050
00051
00052 struct errortab netdev_errors[] __errortab = {
00053 { EUNKNOWN_LINK_STATUS, "Unknown" },
00054 };
00055
00056
00057
00058
00059
00060
00061 void netdev_link_down ( struct net_device *netdev ) {
00062
00063 switch ( netdev->link_rc ) {
00064 case 0:
00065 case -EUNKNOWN_LINK_STATUS:
00066 netdev->link_rc = -ENOTCONN;
00067 break;
00068 default:
00069
00070
00071
00072 break;
00073 }
00074 }
00075
00076
00077
00078
00079
00080
00081
00082 static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
00083 struct net_device_error *error;
00084 struct net_device_error *least_common_error;
00085 unsigned int i;
00086
00087
00088 if ( rc == 0 ) {
00089 stats->good++;
00090 return;
00091 }
00092
00093
00094 stats->bad++;
00095
00096
00097 least_common_error = &stats->errors[0];
00098 for ( i = 0 ; i < ( sizeof ( stats->errors ) /
00099 sizeof ( stats->errors[0] ) ) ; i++ ) {
00100 error = &stats->errors[i];
00101
00102 if ( error->rc == rc ) {
00103 error->count++;
00104 return;
00105 }
00106 if ( error->count < least_common_error->count )
00107 least_common_error = error;
00108 }
00109
00110
00111 least_common_error->rc = rc;
00112 least_common_error->count = 1;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
00126 int rc;
00127
00128 DBGC ( netdev, "NETDEV %p transmitting %p (%p+%zx)\n",
00129 netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
00130
00131 list_add_tail ( &iobuf->list, &netdev->tx_queue );
00132
00133 if ( ! netdev_is_open ( netdev ) ) {
00134 rc = -ENETUNREACH;
00135 goto err;
00136 }
00137
00138 if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 )
00139 goto err;
00140
00141 return 0;
00142
00143 err:
00144 netdev_tx_complete_err ( netdev, iobuf, rc );
00145 return rc;
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 void netdev_tx_complete_err ( struct net_device *netdev,
00158 struct io_buffer *iobuf, int rc ) {
00159
00160
00161 netdev_record_stat ( &netdev->tx_stats, rc );
00162 if ( rc == 0 ) {
00163 DBGC ( netdev, "NETDEV %p transmission %p complete\n",
00164 netdev, iobuf );
00165 } else {
00166 DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
00167 netdev, iobuf, strerror ( rc ) );
00168 }
00169
00170
00171 assert ( iobuf->list.next != NULL );
00172 assert ( iobuf->list.prev != NULL );
00173
00174
00175 list_del ( &iobuf->list );
00176 free_iob ( iobuf );
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) {
00188 struct io_buffer *iobuf;
00189
00190 list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
00191 netdev_tx_complete_err ( netdev, iobuf, rc );
00192 return;
00193 }
00194 }
00195
00196
00197
00198
00199
00200
00201 static void netdev_tx_flush ( struct net_device *netdev ) {
00202
00203
00204 while ( ! list_empty ( &netdev->tx_queue ) ) {
00205 netdev_tx_complete_next_err ( netdev, -ECANCELED );
00206 }
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
00219
00220 DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
00221 netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
00222
00223
00224 list_add_tail ( &iobuf->list, &netdev->rx_queue );
00225
00226
00227 netdev_record_stat ( &netdev->rx_stats, 0 );
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 void netdev_rx_err ( struct net_device *netdev,
00243 struct io_buffer *iobuf, int rc ) {
00244
00245 DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n",
00246 netdev, iobuf, strerror ( rc ) );
00247
00248
00249 free_iob ( iobuf );
00250
00251
00252 netdev_record_stat ( &netdev->rx_stats, rc );
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 void netdev_poll ( struct net_device *netdev ) {
00265
00266 if ( netdev_is_open ( netdev ) )
00267 netdev->op->poll ( netdev );
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) {
00280 struct io_buffer *iobuf;
00281
00282 list_for_each_entry ( iobuf, &netdev->rx_queue, list ) {
00283 list_del ( &iobuf->list );
00284 return iobuf;
00285 }
00286 return NULL;
00287 }
00288
00289
00290
00291
00292
00293
00294 static void netdev_rx_flush ( struct net_device *netdev ) {
00295 struct io_buffer *iobuf;
00296
00297
00298 while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
00299 netdev_rx_err ( netdev, iobuf, -ECANCELED );
00300 }
00301 }
00302
00303
00304
00305
00306
00307
00308 static void free_netdev ( struct refcnt *refcnt ) {
00309 struct net_device *netdev =
00310 container_of ( refcnt, struct net_device, refcnt );
00311
00312 netdev_tx_flush ( netdev );
00313 netdev_rx_flush ( netdev );
00314 clear_settings ( netdev_settings ( netdev ) );
00315 free ( netdev );
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 struct net_device * alloc_netdev ( size_t priv_size ) {
00327 struct net_device *netdev;
00328 size_t total_len;
00329
00330 total_len = ( sizeof ( *netdev ) + priv_size );
00331 netdev = zalloc ( total_len );
00332 if ( netdev ) {
00333 netdev->refcnt.free = free_netdev;
00334 netdev->link_rc = -EUNKNOWN_LINK_STATUS;
00335 INIT_LIST_HEAD ( &netdev->tx_queue );
00336 INIT_LIST_HEAD ( &netdev->rx_queue );
00337 netdev_settings_init ( netdev );
00338 netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
00339 }
00340 return netdev;
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 int register_netdev ( struct net_device *netdev ) {
00353 static unsigned int ifindex = 0;
00354 int rc;
00355
00356
00357 snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
00358 ifindex++ );
00359
00360
00361 netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
00362
00363
00364 if ( ( rc = register_settings ( netdev_settings ( netdev ),
00365 NULL ) ) != 0 ) {
00366 DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
00367 netdev, strerror ( rc ) );
00368 return rc;
00369 }
00370
00371
00372 netdev_get ( netdev );
00373 list_add_tail ( &netdev->list, &net_devices );
00374 DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n",
00375 netdev, netdev->name, netdev->dev->name,
00376 netdev_addr ( netdev ) );
00377
00378 return 0;
00379 }
00380
00381
00382
00383
00384
00385
00386
00387 int netdev_open ( struct net_device *netdev ) {
00388 int rc;
00389
00390
00391 if ( netdev->state & NETDEV_OPEN )
00392 return 0;
00393
00394 DBGC ( netdev, "NETDEV %p opening\n", netdev );
00395
00396
00397 if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
00398 return rc;
00399
00400
00401 netdev->state |= NETDEV_OPEN;
00402
00403
00404 list_add ( &netdev->open_list, &open_net_devices );
00405
00406 return 0;
00407 }
00408
00409
00410
00411
00412
00413
00414 void netdev_close ( struct net_device *netdev ) {
00415
00416
00417 if ( ! ( netdev->state & NETDEV_OPEN ) )
00418 return;
00419
00420 DBGC ( netdev, "NETDEV %p closing\n", netdev );
00421
00422
00423 netdev->op->close ( netdev );
00424
00425
00426 netdev_tx_flush ( netdev );
00427 netdev_rx_flush ( netdev );
00428
00429
00430 netdev->state &= ~NETDEV_OPEN;
00431
00432
00433 list_del ( &netdev->open_list );
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443 void unregister_netdev ( struct net_device *netdev ) {
00444
00445
00446 netdev_close ( netdev );
00447
00448
00449 unregister_settings ( netdev_settings ( netdev ) );
00450
00451
00452 list_del ( &netdev->list );
00453 netdev_put ( netdev );
00454 DBGC ( netdev, "NETDEV %p unregistered\n", netdev );
00455 }
00456
00457
00458
00459
00460
00461
00462 void netdev_irq ( struct net_device *netdev, int enable ) {
00463
00464
00465 netdev->op->irq ( netdev, enable );
00466
00467
00468 netdev->state &= ~NETDEV_IRQ_ENABLED;
00469 if ( enable )
00470 netdev->state |= NETDEV_IRQ_ENABLED;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 struct net_device * find_netdev ( const char *name ) {
00480 struct net_device *netdev;
00481
00482 list_for_each_entry ( netdev, &net_devices, list ) {
00483 if ( strcmp ( netdev->name, name ) == 0 )
00484 return netdev;
00485 }
00486
00487 return NULL;
00488 }
00489
00490
00491
00492
00493
00494
00495
00496
00497 struct net_device * find_netdev_by_location ( unsigned int bus_type,
00498 unsigned int location ) {
00499 struct net_device *netdev;
00500
00501 list_for_each_entry ( netdev, &net_devices, list ) {
00502 if ( ( netdev->dev->desc.bus_type == bus_type ) &&
00503 ( netdev->dev->desc.location == location ) )
00504 return netdev;
00505 }
00506
00507 return NULL;
00508 }
00509
00510
00511
00512
00513
00514
00515 struct net_device * last_opened_netdev ( void ) {
00516 struct net_device *netdev;
00517
00518 list_for_each_entry ( netdev, &open_net_devices, open_list ) {
00519 assert ( netdev_is_open ( netdev ) );
00520 return netdev;
00521 }
00522
00523 return NULL;
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
00540 struct net_protocol *net_protocol, const void *ll_dest ) {
00541 struct ll_protocol *ll_protocol = netdev->ll_protocol;
00542 int rc;
00543
00544
00545
00546
00547
00548
00549 netdev_poll ( netdev );
00550
00551
00552 if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, netdev->ll_addr,
00553 net_protocol->net_proto ) ) != 0 ) {
00554 free_iob ( iobuf );
00555 return rc;
00556 }
00557
00558
00559 return netdev_tx ( netdev, iobuf );
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
00572 uint16_t net_proto, const void *ll_source ) {
00573 struct net_protocol *net_protocol;
00574
00575
00576 for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
00577 if ( net_protocol->net_proto == net_proto )
00578 return net_protocol->rx ( iobuf, netdev, ll_source );
00579 }
00580
00581 DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n",
00582 netdev, ntohs ( net_proto ) );
00583 free_iob ( iobuf );
00584 return 0;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 static void net_step ( struct process *process __unused ) {
00596 struct net_device *netdev;
00597 struct io_buffer *iobuf;
00598 struct ll_protocol *ll_protocol;
00599 const void *ll_dest;
00600 const void *ll_source;
00601 uint16_t net_proto;
00602 int rc;
00603
00604
00605 list_for_each_entry ( netdev, &net_devices, list ) {
00606
00607
00608 netdev_poll ( netdev );
00609
00610
00611
00612
00613
00614
00615
00616 if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
00617
00618 DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n",
00619 netdev, iobuf, iobuf->data,
00620 iob_len ( iobuf ) );
00621
00622
00623 ll_protocol = netdev->ll_protocol;
00624 if ( ( rc = ll_protocol->pull ( netdev, iobuf,
00625 &ll_dest, &ll_source,
00626 &net_proto ) ) != 0 ) {
00627 free_iob ( iobuf );
00628 continue;
00629 }
00630
00631 net_rx ( iobuf, netdev, net_proto, ll_source );
00632 }
00633 }
00634 }
00635
00636
00637 struct process net_process __permanent_process = {
00638 .list = LIST_HEAD_INIT ( net_process.list ),
00639 .step = net_step,
00640 };