iPXE
snpnet.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  */
00019 
00020 FILE_LICENCE ( GPL2_OR_LATER );
00021 
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <errno.h>
00026 #include <ipxe/iobuf.h>
00027 #include <ipxe/netdevice.h>
00028 #include <ipxe/ethernet.h>
00029 #include <ipxe/vsprintf.h>
00030 #include <ipxe/efi/efi.h>
00031 #include <ipxe/efi/Protocol/SimpleNetwork.h>
00032 #include <ipxe/efi/efi_driver.h>
00033 #include <ipxe/efi/efi_utils.h>
00034 #include "snpnet.h"
00035 
00036 /** @file
00037  *
00038  * SNP NIC driver
00039  *
00040  */
00041 
00042 /** An SNP NIC */
00043 struct snp_nic {
00044         /** EFI device */
00045         struct efi_device *efidev;
00046         /** Simple network protocol */
00047         EFI_SIMPLE_NETWORK_PROTOCOL *snp;
00048         /** Generic device */
00049         struct device dev;
00050 
00051         /** Maximum packet size
00052          *
00053          * This is calculated as the sum of MediaHeaderSize and
00054          * MaxPacketSize, and may therefore be an overestimate.
00055          */
00056         size_t mtu;
00057 
00058         /** Current transmit buffer */
00059         struct io_buffer *txbuf;
00060         /** Current receive buffer */
00061         struct io_buffer *rxbuf;
00062 };
00063 
00064 /** Maximum number of received packets per poll */
00065 #define SNP_RX_QUOTA 4
00066 
00067 /**
00068  * Format SNP MAC address (for debugging)
00069  *
00070  * @v mac               MAC address
00071  * @v len               Length of MAC address
00072  * @ret text            MAC address as text
00073  */
00074 static const char * snpnet_mac_text ( EFI_MAC_ADDRESS *mac, size_t len ) {
00075         static char buf[ sizeof ( *mac ) * 3 /* "xx:" or "xx\0" */ ];
00076         size_t used = 0;
00077         unsigned int i;
00078 
00079         for ( i = 0 ; i < len ; i++ ) {
00080                 used += ssnprintf ( &buf[used], ( sizeof ( buf ) - used ),
00081                                     "%s%02x", ( used ? ":" : "" ),
00082                                     mac->Addr[i] );
00083         }
00084         return buf;
00085 }
00086 
00087 /**
00088  * Dump SNP mode information (for debugging)
00089  *
00090  * @v netdev            Network device
00091  */
00092 static void snpnet_dump_mode ( struct net_device *netdev ) {
00093         struct snp_nic *snp = netdev_priv ( netdev );
00094         EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode;
00095         size_t mac_len = mode->HwAddressSize;
00096         unsigned int i;
00097 
00098         /* Do nothing unless debugging is enabled */
00099         if ( ! DBG_EXTRA )
00100                 return;
00101 
00102         DBGC2 ( snp, "SNP %s st %d type %d hdr %d pkt %d rxflt %#x/%#x%s "
00103                 "nvram %d acc %d mcast %d/%d\n", netdev->name, mode->State,
00104                 mode->IfType, mode->MediaHeaderSize, mode->MaxPacketSize,
00105                 mode->ReceiveFilterSetting, mode->ReceiveFilterMask,
00106                 ( mode->MultipleTxSupported ? " multitx" : "" ),
00107                 mode->NvRamSize, mode->NvRamAccessSize,
00108                 mode->MCastFilterCount, mode->MaxMCastFilterCount );
00109         DBGC2 ( snp, "SNP %s hw %s", netdev->name,
00110                 snpnet_mac_text ( &mode->PermanentAddress, mac_len ) );
00111         DBGC2 ( snp, " addr %s%s",
00112                 snpnet_mac_text ( &mode->CurrentAddress, mac_len ),
00113                 ( mode->MacAddressChangeable ? "" : "(f)" ) );
00114         DBGC2 ( snp, " bcast %s\n",
00115                 snpnet_mac_text ( &mode->BroadcastAddress, mac_len ) );
00116         for ( i = 0 ; i < mode->MCastFilterCount ; i++ ) {
00117                 DBGC2 ( snp, "SNP %s mcast %s\n", netdev->name,
00118                         snpnet_mac_text ( &mode->MCastFilter[i], mac_len ) );
00119         }
00120         DBGC2 ( snp, "SNP %s media %s\n", netdev->name,
00121                 ( mode->MediaPresentSupported ?
00122                   ( mode->MediaPresent ? "present" : "not present" ) :
00123                   "presence not supported" ) );
00124 }
00125 
00126 /**
00127  * Check link state
00128  *
00129  * @v netdev            Network device
00130  */
00131 static void snpnet_check_link ( struct net_device *netdev ) {
00132         struct snp_nic *snp = netdev_priv ( netdev );
00133         EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode;
00134 
00135         /* Do nothing unless media presence detection is supported */
00136         if ( ! mode->MediaPresentSupported )
00137                 return;
00138 
00139         /* Report any link status change */
00140         if ( mode->MediaPresent && ( ! netdev_link_ok ( netdev ) ) ) {
00141                 netdev_link_up ( netdev );
00142         } else if ( ( ! mode->MediaPresent ) && netdev_link_ok ( netdev ) ) {
00143                 netdev_link_down ( netdev );
00144         }
00145 }
00146 
00147 /**
00148  * Transmit packet
00149  *
00150  * @v netdev            Network device
00151  * @v iobuf             I/O buffer
00152  * @ret rc              Return status code
00153  */
00154 static int snpnet_transmit ( struct net_device *netdev,
00155                              struct io_buffer *iobuf ) {
00156         struct snp_nic *snp = netdev_priv ( netdev );
00157         EFI_STATUS efirc;
00158         int rc;
00159 
00160         /* Defer the packet if there is already a transmission in progress */
00161         if ( snp->txbuf ) {
00162                 netdev_tx_defer ( netdev, iobuf );
00163                 return 0;
00164         }
00165 
00166         /* Transmit packet */
00167         if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ),
00168                                             iobuf->data, NULL, NULL,
00169                                             NULL ) ) != 0 ) {
00170                 rc = -EEFI ( efirc );
00171                 DBGC ( snp, "SNP %s could not transmit: %s\n",
00172                        netdev->name, strerror ( rc ) );
00173                 return rc;
00174         }
00175         snp->txbuf = iobuf;
00176 
00177         return 0;
00178 }
00179 
00180 /**
00181  * Poll for completed packets
00182  *
00183  * @v netdev            Network device
00184  */
00185 static void snpnet_poll_tx ( struct net_device *netdev ) {
00186         struct snp_nic *snp = netdev->priv;
00187         struct io_buffer *iobuf;
00188         UINT32 irq;
00189         VOID *txbuf;
00190         EFI_STATUS efirc;
00191         int rc;
00192 
00193         /* Get status */
00194         txbuf = NULL;
00195         if ( ( efirc = snp->snp->GetStatus ( snp->snp, &irq, &txbuf ) ) != 0 ) {
00196                 rc = -EEFI ( efirc );
00197                 DBGC ( snp, "SNP %s could not get status: %s\n",
00198                        netdev->name, strerror ( rc ) );
00199                 netdev_rx_err ( netdev, NULL, rc );
00200                 return;
00201         }
00202 
00203         /* Do nothing unless we have a completion */
00204         if ( ! txbuf )
00205                 return;
00206 
00207         /* Sanity check */
00208         if ( ! snp->txbuf ) {
00209                 DBGC ( snp, "SNP %s reported spurious TX completion\n",
00210                        netdev->name );
00211                 netdev_tx_err ( netdev, NULL, -EPIPE );
00212                 return;
00213         }
00214 
00215         /* Complete transmission */
00216         iobuf = snp->txbuf;
00217         snp->txbuf = NULL;
00218         netdev_tx_complete ( netdev, iobuf );
00219 }
00220 
00221 /**
00222  * Poll for received packets
00223  *
00224  * @v netdev            Network device
00225  */
00226 static void snpnet_poll_rx ( struct net_device *netdev ) {
00227         struct snp_nic *snp = netdev->priv;
00228         UINTN len;
00229         unsigned int quota;
00230         EFI_STATUS efirc;
00231         int rc;
00232 
00233         /* Retrieve up to SNP_RX_QUOTA packets */
00234         for ( quota = SNP_RX_QUOTA ; quota ; quota-- ) {
00235 
00236                 /* Allocate buffer, if required */
00237                 if ( ! snp->rxbuf ) {
00238                         snp->rxbuf = alloc_iob ( snp->mtu );
00239                         if ( ! snp->rxbuf ) {
00240                                 /* Leave for next poll */
00241                                 break;
00242                         }
00243                 }
00244 
00245                 /* Receive packet */
00246                 len = iob_tailroom ( snp->rxbuf );
00247                 if ( ( efirc = snp->snp->Receive ( snp->snp, NULL, &len,
00248                                                    snp->rxbuf->data, NULL,
00249                                                    NULL, NULL ) ) != 0 ) {
00250 
00251                         /* EFI_NOT_READY is just the usual "no packet"
00252                          * status indication; ignore it.
00253                          */
00254                         if ( efirc == EFI_NOT_READY )
00255                                 break;
00256 
00257                         /* Anything else is an error */
00258                         rc = -EEFI ( efirc );
00259                         DBGC ( snp, "SNP %s could not receive: %s\n",
00260                                netdev->name, strerror ( rc ) );
00261                         netdev_rx_err ( netdev, NULL, rc );
00262                         break;
00263                 }
00264 
00265                 /* Hand off to network stack */
00266                 iob_put ( snp->rxbuf, len );
00267                 netdev_rx ( netdev, snp->rxbuf );
00268                 snp->rxbuf = NULL;
00269         }
00270 }
00271 
00272 /**
00273  * Poll for completed packets
00274  *
00275  * @v netdev            Network device
00276  */
00277 static void snpnet_poll ( struct net_device *netdev ) {
00278 
00279         /* Process any TX completions */
00280         snpnet_poll_tx ( netdev );
00281 
00282         /* Process any RX completions */
00283         snpnet_poll_rx ( netdev );
00284 
00285         /* Check for link state changes */
00286         snpnet_check_link ( netdev );
00287 }
00288 
00289 /**
00290  * Set receive filters
00291  *
00292  * @v netdev            Network device
00293  * @ret rc              Return status code
00294  */
00295 static int snpnet_rx_filters ( struct net_device *netdev ) {
00296         struct snp_nic *snp = netdev->priv;
00297         UINT32 filters[] = {
00298                 snp->snp->Mode->ReceiveFilterMask,
00299                 ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
00300                   EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
00301                   EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ),
00302                 ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
00303                   EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ),
00304                 ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST ),
00305         };
00306         unsigned int i;
00307         EFI_STATUS efirc;
00308         int rc;
00309 
00310         /* Try possible receive filters in turn */
00311         for ( i = 0; i < ( sizeof ( filters ) / sizeof ( filters[0] ) ); i++ ) {
00312                 efirc = snp->snp->ReceiveFilters ( snp->snp, filters[i],
00313                                                    0, TRUE, 0, NULL );
00314                 if ( efirc == 0 )
00315                         return 0;
00316                 rc = -EEFI ( efirc );
00317                 DBGC ( snp, "SNP %s could not set receive filters %#02x (have "
00318                        "%#02x): %s\n", netdev->name, filters[i],
00319                        snp->snp->Mode->ReceiveFilterSetting, strerror ( rc ) );
00320         }
00321 
00322         return rc;
00323 }
00324 
00325 /**
00326  * Open network device
00327  *
00328  * @v netdev            Network device
00329  * @ret rc              Return status code
00330  */
00331 static int snpnet_open ( struct net_device *netdev ) {
00332         struct snp_nic *snp = netdev->priv;
00333         EFI_MAC_ADDRESS *mac = ( ( void * ) netdev->ll_addr );
00334         EFI_STATUS efirc;
00335         int rc;
00336 
00337         /* Try setting MAC address (before initialising) */
00338         if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){
00339                 rc = -EEFI ( efirc );
00340                 DBGC ( snp, "SNP %s could not set station address before "
00341                        "initialising: %s\n", netdev->name, strerror ( rc ) );
00342                 /* Ignore error */
00343         }
00344 
00345         /* Initialise NIC */
00346         if ( ( efirc = snp->snp->Initialize ( snp->snp, 0, 0 ) ) != 0 ) {
00347                 rc = -EEFI ( efirc );
00348                 snpnet_dump_mode ( netdev );
00349                 DBGC ( snp, "SNP %s could not initialise: %s\n",
00350                        netdev->name, strerror ( rc ) );
00351                 return rc;
00352         }
00353 
00354         /* Try setting MAC address (after initialising) */
00355         if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){
00356                 rc = -EEFI ( efirc );
00357                 DBGC ( snp, "SNP %s could not set station address after "
00358                        "initialising: %s\n", netdev->name, strerror ( rc ) );
00359                 /* Ignore error */
00360         }
00361 
00362         /* Set receive filters */
00363         if ( ( rc = snpnet_rx_filters ( netdev ) ) != 0 ) {
00364                 /* Ignore error */
00365         }
00366 
00367         /* Dump mode information (for debugging) */
00368         snpnet_dump_mode ( netdev );
00369 
00370         return 0;
00371 }
00372 
00373 /**
00374  * Close network device
00375  *
00376  * @v netdev            Network device
00377  */
00378 static void snpnet_close ( struct net_device *netdev ) {
00379         struct snp_nic *snp = netdev->priv;
00380         EFI_STATUS efirc;
00381         int rc;
00382 
00383         /* Shut down NIC */
00384         if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) {
00385                 rc = -EEFI ( efirc );
00386                 DBGC ( snp, "SNP %s could not shut down: %s\n",
00387                        netdev->name, strerror ( rc ) );
00388                 /* Nothing we can do about this */
00389         }
00390 
00391         /* Discard transmit buffer, if applicable */
00392         if ( snp->txbuf ) {
00393                 netdev_tx_complete_err ( netdev, snp->txbuf, -ECANCELED );
00394                 snp->txbuf = NULL;
00395         }
00396 
00397         /* Discard receive buffer, if applicable */
00398         if ( snp->rxbuf ) {
00399                 free_iob ( snp->rxbuf );
00400                 snp->rxbuf = NULL;
00401         }
00402 }
00403 
00404 /** SNP network device operations */
00405 static struct net_device_operations snpnet_operations = {
00406         .open = snpnet_open,
00407         .close = snpnet_close,
00408         .transmit = snpnet_transmit,
00409         .poll = snpnet_poll,
00410 };
00411 
00412 /**
00413  * Attach driver to device
00414  *
00415  * @v efidev            EFI device
00416  * @ret rc              Return status code
00417  */
00418 int snpnet_start ( struct efi_device *efidev ) {
00419         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00420         EFI_HANDLE device = efidev->device;
00421         EFI_SIMPLE_NETWORK_MODE *mode;
00422         struct net_device *netdev;
00423         struct snp_nic *snp;
00424         void *interface;
00425         EFI_STATUS efirc;
00426         int rc;
00427 
00428         /* Open SNP protocol */
00429         if ( ( efirc = bs->OpenProtocol ( device,
00430                                           &efi_simple_network_protocol_guid,
00431                                           &interface, efi_image_handle, device,
00432                                           ( EFI_OPEN_PROTOCOL_BY_DRIVER |
00433                                             EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
00434                 rc = -EEFI ( efirc );
00435                 DBGC ( device, "SNP %s cannot open SNP protocol: %s\n",
00436                        efi_handle_name ( device ), strerror ( rc ) );
00437                 DBGC_EFI_OPENERS ( device, device,
00438                                    &efi_simple_network_protocol_guid );
00439                 goto err_open_protocol;
00440         }
00441 
00442         /* Allocate and initialise structure */
00443         netdev = alloc_etherdev ( sizeof ( *snp ) );
00444         if ( ! netdev ) {
00445                 rc = -ENOMEM;
00446                 goto err_alloc;
00447         }
00448         netdev_init ( netdev, &snpnet_operations );
00449         snp = netdev->priv;
00450         snp->efidev = efidev;
00451         snp->snp = interface;
00452         mode = snp->snp->Mode;
00453         efidev_set_drvdata ( efidev, netdev );
00454 
00455         /* Populate underlying device information */
00456         efi_device_info ( device, "SNP", &snp->dev );
00457         snp->dev.driver_name = "SNP";
00458         snp->dev.parent = &efidev->dev;
00459         list_add ( &snp->dev.siblings, &efidev->dev.children );
00460         INIT_LIST_HEAD ( &snp->dev.children );
00461         netdev->dev = &snp->dev;
00462 
00463         /* Bring to the Started state */
00464         if ( ( mode->State == EfiSimpleNetworkStopped ) &&
00465              ( ( efirc = snp->snp->Start ( snp->snp ) ) != 0 ) ) {
00466                 rc = -EEFI ( efirc );
00467                 DBGC ( device, "SNP %s could not start: %s\n",
00468                        efi_handle_name ( device ), strerror ( rc ) );
00469                 goto err_start;
00470         }
00471         if ( ( mode->State == EfiSimpleNetworkInitialized ) &&
00472              ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
00473                 rc = -EEFI ( efirc );
00474                 DBGC ( device, "SNP %s could not shut down: %s\n",
00475                        efi_handle_name ( device ), strerror ( rc ) );
00476                 goto err_shutdown;
00477         }
00478 
00479         /* Populate network device parameters */
00480         if ( mode->HwAddressSize != netdev->ll_protocol->hw_addr_len ) {
00481                 DBGC ( device, "SNP %s has invalid hardware address length "
00482                        "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
00483                 rc = -ENOTSUP;
00484                 goto err_hw_addr_len;
00485         }
00486         memcpy ( netdev->hw_addr, &mode->PermanentAddress,
00487                  netdev->ll_protocol->hw_addr_len );
00488         if ( mode->HwAddressSize != netdev->ll_protocol->ll_addr_len ) {
00489                 DBGC ( device, "SNP %s has invalid link-layer address length "
00490                        "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
00491                 rc = -ENOTSUP;
00492                 goto err_ll_addr_len;
00493         }
00494         memcpy ( netdev->ll_addr, &mode->CurrentAddress,
00495                  netdev->ll_protocol->ll_addr_len );
00496         snp->mtu = ( snp->snp->Mode->MaxPacketSize +
00497                      snp->snp->Mode->MediaHeaderSize );
00498 
00499         /* Register network device */
00500         if ( ( rc = register_netdev ( netdev ) ) != 0 )
00501                 goto err_register_netdev;
00502         DBGC ( device, "SNP %s registered as %s\n",
00503                efi_handle_name ( device ), netdev->name );
00504 
00505         /* Set initial link state */
00506         if ( snp->snp->Mode->MediaPresentSupported ) {
00507                 snpnet_check_link ( netdev );
00508         } else {
00509                 netdev_link_up ( netdev );
00510         }
00511 
00512         return 0;
00513 
00514         unregister_netdev ( netdev );
00515  err_register_netdev:
00516  err_ll_addr_len:
00517  err_hw_addr_len:
00518  err_shutdown:
00519  err_start:
00520         list_del ( &snp->dev.siblings );
00521         netdev_nullify ( netdev );
00522         netdev_put ( netdev );
00523  err_alloc:
00524         bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
00525                             efi_image_handle, device );
00526  err_open_protocol:
00527         return rc;
00528 }
00529 
00530 /**
00531  * Detach driver from device
00532  *
00533  * @v efidev            EFI device
00534   */
00535 void snpnet_stop ( struct efi_device *efidev ) {
00536         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00537         struct net_device *netdev = efidev_get_drvdata ( efidev );
00538         struct snp_nic *snp = netdev->priv;
00539         EFI_HANDLE device = efidev->device;
00540         EFI_STATUS efirc;
00541         int rc;
00542 
00543         /* Unregister network device */
00544         unregister_netdev ( netdev );
00545 
00546         /* Stop SNP protocol */
00547         if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) {
00548                 rc = -EEFI ( efirc );
00549                 DBGC ( device, "SNP %s could not stop: %s\n",
00550                        efi_handle_name ( device ), strerror ( rc ) );
00551                 /* Nothing we can do about this */
00552         }
00553 
00554         /* Free network device */
00555         list_del ( &snp->dev.siblings );
00556         netdev_nullify ( netdev );
00557         netdev_put ( netdev );
00558 
00559         /* Close SNP protocol */
00560         bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
00561                             efi_image_handle, device );
00562 }