iPXE
pnic.c
Go to the documentation of this file.
00001 /**************************************************************************
00002 Etherboot -  BOOTP/TFTP Bootstrap Program
00003 Bochs Pseudo NIC driver for Etherboot
00004 ***************************************************************************/
00005 
00006 /*
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License as
00009  * published by the Free Software Foundation; either version 2 of the
00010  * License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00020  * 02110-1301, USA.
00021  *
00022  * See pnic_api.h for an explanation of the Bochs Pseudo NIC.
00023  */
00024 
00025 FILE_LICENCE ( GPL2_OR_LATER );
00026 
00027 #include <stdint.h>
00028 #include <stdio.h>
00029 #include <ipxe/io.h>
00030 #include <errno.h>
00031 #include <ipxe/pci.h>
00032 #include <ipxe/if_ether.h>
00033 #include <ipxe/ethernet.h>
00034 #include <ipxe/iobuf.h>
00035 #include <ipxe/netdevice.h>
00036 
00037 #include "pnic_api.h"
00038 
00039 struct pnic {
00040         unsigned short ioaddr;
00041 };
00042 
00043 /* 
00044  * Utility functions: issue a PNIC command, retrieve result.  Use
00045  * pnic_command_quiet if you don't want failure codes to be
00046  * automatically printed.  Returns the PNIC status code.
00047  * 
00048  * Set output_length to NULL only if you expect to receive exactly
00049  * output_max_length bytes, otherwise it'll complain that you didn't
00050  * get enough data (on the assumption that if you not interested in
00051  * discovering the output length then you're expecting a fixed amount
00052  * of data).
00053  */
00054 
00055 static uint16_t pnic_command_quiet ( struct pnic *pnic, uint16_t command,
00056                                      const void *input, uint16_t input_length,
00057                                      void *output, uint16_t output_max_length,
00058                                      uint16_t *output_length ) {
00059         uint16_t status;
00060         uint16_t _output_length;
00061 
00062         if ( input != NULL ) {
00063                 /* Write input length */
00064                 outw ( input_length, pnic->ioaddr + PNIC_REG_LEN );
00065                 /* Write input data */
00066                 outsb ( pnic->ioaddr + PNIC_REG_DATA, input, input_length );
00067         }
00068         /* Write command */
00069         outw ( command, pnic->ioaddr + PNIC_REG_CMD );
00070         /* Retrieve status */
00071         status = inw ( pnic->ioaddr + PNIC_REG_STAT );
00072         /* Retrieve output length */
00073         _output_length = inw ( pnic->ioaddr + PNIC_REG_LEN );
00074         if ( output_length == NULL ) {
00075                 if ( _output_length != output_max_length ) {
00076                         printf ( "pnic_command %#hx: wrong data length "
00077                                  "returned (expected %d, got %d)\n", command,
00078                                  output_max_length, _output_length );
00079                 }
00080         } else {
00081                 *output_length = _output_length;
00082         }
00083         if ( output != NULL ) {
00084                 if ( _output_length > output_max_length ) {
00085                         printf ( "pnic_command %#hx: output buffer too small "
00086                                  "(have %d, need %d)\n", command,
00087                                  output_max_length, _output_length );
00088                         _output_length = output_max_length;
00089                 }
00090                 /* Retrieve output data */
00091                 insb ( pnic->ioaddr + PNIC_REG_DATA, output, _output_length );
00092         }
00093         return status;
00094 }
00095 
00096 static uint16_t pnic_command ( struct pnic *pnic, uint16_t command,
00097                                const void *input, uint16_t input_length,
00098                                void *output, uint16_t output_max_length,
00099                                uint16_t *output_length ) {
00100         uint16_t status = pnic_command_quiet ( pnic, command,
00101                                                input, input_length,
00102                                                output, output_max_length,
00103                                                output_length );
00104         if ( status == PNIC_STATUS_OK ) return status;
00105         printf ( "PNIC command %#hx (len %#hx) failed with status %#hx\n",
00106                  command, input_length, status );
00107         return status;
00108 }
00109 
00110 /* Check API version matches that of NIC */
00111 static int pnic_api_check ( uint16_t api_version ) {
00112         if ( api_version != PNIC_API_VERSION ) {
00113                 printf ( "Warning: API version mismatch! "
00114                          "(NIC's is %d.%d, ours is %d.%d)\n",
00115                          api_version >> 8, api_version & 0xff,
00116                          PNIC_API_VERSION >> 8, PNIC_API_VERSION & 0xff );
00117         }
00118         if ( api_version < PNIC_API_VERSION ) {
00119                 printf ( "** You may need to update your copy of Bochs **\n" );
00120         }
00121         return ( api_version == PNIC_API_VERSION );
00122 }
00123 
00124 /**************************************************************************
00125 POLL - Wait for a frame
00126 ***************************************************************************/
00127 static void pnic_poll ( struct net_device *netdev ) {
00128         struct pnic *pnic = netdev->priv;
00129         struct io_buffer *iobuf;
00130         uint16_t length;
00131         uint16_t qlen;
00132 
00133         /* Fetch all available packets */
00134         while ( 1 ) {
00135                 if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
00136                                     &qlen, sizeof ( qlen ), NULL )
00137                      != PNIC_STATUS_OK )
00138                         return;
00139                 if ( qlen == 0 )
00140                         return;
00141                 iobuf = alloc_iob ( ETH_FRAME_LEN );
00142                 if ( ! iobuf ) {
00143                         DBG ( "could not allocate buffer\n" );
00144                         netdev_rx_err ( netdev, NULL, -ENOMEM );
00145                         return;
00146                 }
00147                 if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
00148                                     iobuf->data, ETH_FRAME_LEN, &length )
00149                      != PNIC_STATUS_OK ) {
00150                         netdev_rx_err ( netdev, iobuf, -EIO );
00151                         return;
00152                 }
00153                 iob_put ( iobuf, length );
00154                 netdev_rx ( netdev, iobuf );
00155         }
00156 }
00157 
00158 /**************************************************************************
00159 TRANSMIT - Transmit a frame
00160 ***************************************************************************/
00161 static int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
00162         struct pnic *pnic = netdev->priv;
00163 
00164         /* Pad the packet */
00165         iob_pad ( iobuf, ETH_ZLEN );
00166 
00167         /* Send packet */
00168         pnic_command ( pnic, PNIC_CMD_XMIT, iobuf->data, iob_len ( iobuf ),
00169                        NULL, 0, NULL );
00170 
00171         netdev_tx_complete ( netdev, iobuf );
00172         return 0;
00173 }
00174 
00175 /**************************************************************************
00176 OPEN - Open network device
00177 ***************************************************************************/
00178 static int pnic_open ( struct net_device *netdev __unused ) {
00179         /* Nothing to do */
00180         return 0;
00181 }
00182 
00183 /**************************************************************************
00184 CLOSE - Close network device
00185 ***************************************************************************/
00186 static void pnic_close ( struct net_device *netdev __unused ) {
00187         /* Nothing to do */
00188 }
00189 
00190 /**************************************************************************
00191 IRQ - Enable/disable interrupts
00192 ***************************************************************************/
00193 static void pnic_irq ( struct net_device *netdev, int enable ) {
00194         struct pnic *pnic = netdev->priv;
00195         uint8_t mask = ( enable ? 1 : 0 );
00196         
00197         pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &mask, sizeof ( mask ),
00198                        NULL, 0, NULL );
00199 }
00200 
00201 /**************************************************************************
00202 OPERATIONS TABLE
00203 ***************************************************************************/
00204 static struct net_device_operations pnic_operations = {
00205         .open           = pnic_open,
00206         .close          = pnic_close,
00207         .transmit       = pnic_transmit,
00208         .poll           = pnic_poll,
00209         .irq            = pnic_irq,
00210 };
00211 
00212 /**************************************************************************
00213 DISABLE - Turn off ethernet interface
00214 ***************************************************************************/
00215 static void pnic_remove ( struct pci_device *pci ) {
00216         struct net_device *netdev = pci_get_drvdata ( pci );
00217         struct pnic *pnic = netdev->priv;
00218 
00219         unregister_netdev ( netdev );
00220         pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
00221         netdev_nullify ( netdev );
00222         netdev_put ( netdev );
00223 }
00224 
00225 /**************************************************************************
00226 PROBE - Look for an adapter, this routine's visible to the outside
00227 ***************************************************************************/
00228 static int pnic_probe ( struct pci_device *pci ) {
00229         struct net_device *netdev;
00230         struct pnic *pnic;
00231         uint16_t api_version;
00232         uint16_t status;
00233         int rc;
00234 
00235         /* Allocate net device */
00236         netdev = alloc_etherdev ( sizeof ( *pnic ) );
00237         if ( ! netdev )
00238                 return -ENOMEM;
00239         netdev_init ( netdev, &pnic_operations );
00240         pnic = netdev->priv;
00241         pci_set_drvdata ( pci, netdev );
00242         netdev->dev = &pci->dev;
00243         pnic->ioaddr = pci->ioaddr;
00244 
00245         /* Fix up PCI device */
00246         adjust_pci_device ( pci );
00247         
00248         /* API version check */
00249         status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
00250                                       &api_version,
00251                                       sizeof ( api_version ), NULL );
00252         if ( status != PNIC_STATUS_OK ) {
00253                 printf ( "PNIC failed installation check, code %#hx\n",
00254                          status );
00255                 rc = -EIO;
00256                 goto err;
00257         }
00258         pnic_api_check ( api_version );
00259 
00260         /* Get MAC address */
00261         status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
00262                                 netdev->hw_addr, ETH_ALEN, NULL );
00263 
00264         /* Register network device */
00265         if ( ( rc = register_netdev ( netdev ) ) != 0 )
00266                 goto err;
00267 
00268         /* Mark as link up; PNIC has no concept of link state */
00269         netdev_link_up ( netdev );
00270 
00271         return 0;
00272 
00273  err:
00274         /* Free net device */
00275         netdev_nullify ( netdev );
00276         netdev_put ( netdev );
00277         return rc;
00278 }
00279 
00280 static struct pci_device_id pnic_nics[] = {
00281 /* genrules.pl doesn't let us use macros for PCI IDs...*/
00282 PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
00283 };
00284 
00285 struct pci_driver pnic_driver __pci_driver = {
00286         .ids = pnic_nics,
00287         .id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
00288         .probe = pnic_probe,
00289         .remove = pnic_remove,
00290 };