Home | History | Annotate | Download | only in net
      1 /**************************************************************************
      2 Etherboot -  BOOTP/TFTP Bootstrap Program
      3 Bochs Pseudo NIC driver for Etherboot
      4 ***************************************************************************/
      5 
      6 /*
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License as
      9  * published by the Free Software Foundation; either version 2, or (at
     10  * your option) any later version.
     11  *
     12  * See pnic_api.h for an explanation of the Bochs Pseudo NIC.
     13  */
     14 
     15 FILE_LICENCE ( GPL2_OR_LATER );
     16 
     17 #include <stdint.h>
     18 #include <stdio.h>
     19 #include <gpxe/io.h>
     20 #include <errno.h>
     21 #include <gpxe/pci.h>
     22 #include <gpxe/if_ether.h>
     23 #include <gpxe/ethernet.h>
     24 #include <gpxe/iobuf.h>
     25 #include <gpxe/netdevice.h>
     26 
     27 #include "pnic_api.h"
     28 
     29 struct pnic {
     30 	unsigned short ioaddr;
     31 };
     32 
     33 /*
     34  * Utility functions: issue a PNIC command, retrieve result.  Use
     35  * pnic_command_quiet if you don't want failure codes to be
     36  * automatically printed.  Returns the PNIC status code.
     37  *
     38  * Set output_length to NULL only if you expect to receive exactly
     39  * output_max_length bytes, otherwise it'll complain that you didn't
     40  * get enough data (on the assumption that if you not interested in
     41  * discovering the output length then you're expecting a fixed amount
     42  * of data).
     43  */
     44 
     45 static uint16_t pnic_command_quiet ( struct pnic *pnic, uint16_t command,
     46 				     const void *input, uint16_t input_length,
     47 				     void *output, uint16_t output_max_length,
     48 				     uint16_t *output_length ) {
     49 	uint16_t status;
     50 	uint16_t _output_length;
     51 
     52 	if ( input != NULL ) {
     53 		/* Write input length */
     54 		outw ( input_length, pnic->ioaddr + PNIC_REG_LEN );
     55 		/* Write input data */
     56 		outsb ( pnic->ioaddr + PNIC_REG_DATA, input, input_length );
     57 	}
     58 	/* Write command */
     59 	outw ( command, pnic->ioaddr + PNIC_REG_CMD );
     60 	/* Retrieve status */
     61 	status = inw ( pnic->ioaddr + PNIC_REG_STAT );
     62 	/* Retrieve output length */
     63 	_output_length = inw ( pnic->ioaddr + PNIC_REG_LEN );
     64 	if ( output_length == NULL ) {
     65 		if ( _output_length != output_max_length ) {
     66 			printf ( "pnic_command %#hx: wrong data length "
     67 				 "returned (expected %d, got %d)\n", command,
     68 				 output_max_length, _output_length );
     69 		}
     70 	} else {
     71 		*output_length = _output_length;
     72 	}
     73 	if ( output != NULL ) {
     74 		if ( _output_length > output_max_length ) {
     75 			printf ( "pnic_command %#hx: output buffer too small "
     76 				 "(have %d, need %d)\n", command,
     77 				 output_max_length, _output_length );
     78 			_output_length = output_max_length;
     79 		}
     80 		/* Retrieve output data */
     81 		insb ( pnic->ioaddr + PNIC_REG_DATA, output, _output_length );
     82 	}
     83 	return status;
     84 }
     85 
     86 static uint16_t pnic_command ( struct pnic *pnic, uint16_t command,
     87 			       const void *input, uint16_t input_length,
     88 			       void *output, uint16_t output_max_length,
     89 			       uint16_t *output_length ) {
     90 	uint16_t status = pnic_command_quiet ( pnic, command,
     91 					       input, input_length,
     92 					       output, output_max_length,
     93 					       output_length );
     94 	if ( status == PNIC_STATUS_OK ) return status;
     95 	printf ( "PNIC command %#hx (len %#hx) failed with status %#hx\n",
     96 		 command, input_length, status );
     97 	return status;
     98 }
     99 
    100 /* Check API version matches that of NIC */
    101 static int pnic_api_check ( uint16_t api_version ) {
    102 	if ( api_version != PNIC_API_VERSION ) {
    103 		printf ( "Warning: API version mismatch! "
    104 			 "(NIC's is %d.%d, ours is %d.%d)\n",
    105 			 api_version >> 8, api_version & 0xff,
    106 			 PNIC_API_VERSION >> 8, PNIC_API_VERSION & 0xff );
    107 	}
    108 	if ( api_version < PNIC_API_VERSION ) {
    109 		printf ( "** You may need to update your copy of Bochs **\n" );
    110 	}
    111 	return ( api_version == PNIC_API_VERSION );
    112 }
    113 
    114 /**************************************************************************
    115 POLL - Wait for a frame
    116 ***************************************************************************/
    117 static void pnic_poll ( struct net_device *netdev ) {
    118 	struct pnic *pnic = netdev->priv;
    119 	struct io_buffer *iobuf;
    120 	uint16_t length;
    121 	uint16_t qlen;
    122 
    123 	/* Fetch all available packets */
    124 	while ( 1 ) {
    125 		if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
    126 				    &qlen, sizeof ( qlen ), NULL )
    127 		     != PNIC_STATUS_OK )
    128 			return;
    129 		if ( qlen == 0 )
    130 			return;
    131 		iobuf = alloc_iob ( ETH_FRAME_LEN );
    132 		if ( ! iobuf ) {
    133 			DBG ( "could not allocate buffer\n" );
    134 			netdev_rx_err ( netdev, NULL, -ENOMEM );
    135 			return;
    136 		}
    137 		if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
    138 				    iobuf->data, ETH_FRAME_LEN, &length )
    139 		     != PNIC_STATUS_OK ) {
    140 			netdev_rx_err ( netdev, iobuf, -EIO );
    141 			return;
    142 		}
    143 		iob_put ( iobuf, length );
    144 		netdev_rx ( netdev, iobuf );
    145 	}
    146 }
    147 
    148 /**************************************************************************
    149 TRANSMIT - Transmit a frame
    150 ***************************************************************************/
    151 static int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
    152 	struct pnic *pnic = netdev->priv;
    153 
    154 	/* Pad the packet */
    155 	iob_pad ( iobuf, ETH_ZLEN );
    156 
    157 	/* Send packet */
    158 	pnic_command ( pnic, PNIC_CMD_XMIT, iobuf->data, iob_len ( iobuf ),
    159 		       NULL, 0, NULL );
    160 
    161 	netdev_tx_complete ( netdev, iobuf );
    162 	return 0;
    163 }
    164 
    165 /**************************************************************************
    166 OPEN - Open network device
    167 ***************************************************************************/
    168 static int pnic_open ( struct net_device *netdev __unused ) {
    169 	/* Nothing to do */
    170 	return 0;
    171 }
    172 
    173 /**************************************************************************
    174 CLOSE - Close network device
    175 ***************************************************************************/
    176 static void pnic_close ( struct net_device *netdev __unused ) {
    177 	/* Nothing to do */
    178 }
    179 
    180 /**************************************************************************
    181 IRQ - Enable/disable interrupts
    182 ***************************************************************************/
    183 static void pnic_irq ( struct net_device *netdev, int enable ) {
    184 	struct pnic *pnic = netdev->priv;
    185 	uint8_t mask = ( enable ? 1 : 0 );
    186 
    187 	pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &mask, sizeof ( mask ),
    188 		       NULL, 0, NULL );
    189 }
    190 
    191 /**************************************************************************
    192 OPERATIONS TABLE
    193 ***************************************************************************/
    194 static struct net_device_operations pnic_operations = {
    195 	.open		= pnic_open,
    196 	.close		= pnic_close,
    197 	.transmit	= pnic_transmit,
    198 	.poll		= pnic_poll,
    199 	.irq   		= pnic_irq,
    200 };
    201 
    202 /**************************************************************************
    203 DISABLE - Turn off ethernet interface
    204 ***************************************************************************/
    205 static void pnic_remove ( struct pci_device *pci ) {
    206 	struct net_device *netdev = pci_get_drvdata ( pci );
    207 	struct pnic *pnic = netdev->priv;
    208 
    209 	unregister_netdev ( netdev );
    210 	pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
    211 	netdev_nullify ( netdev );
    212 	netdev_put ( netdev );
    213 }
    214 
    215 /**************************************************************************
    216 PROBE - Look for an adapter, this routine's visible to the outside
    217 ***************************************************************************/
    218 static int pnic_probe ( struct pci_device *pci,
    219 			const struct pci_device_id *id __unused ) {
    220 	struct net_device *netdev;
    221 	struct pnic *pnic;
    222 	uint16_t api_version;
    223 	uint16_t status;
    224 	int rc;
    225 
    226 	/* Allocate net device */
    227 	netdev = alloc_etherdev ( sizeof ( *pnic ) );
    228 	if ( ! netdev )
    229 		return -ENOMEM;
    230 	netdev_init ( netdev, &pnic_operations );
    231 	pnic = netdev->priv;
    232 	pci_set_drvdata ( pci, netdev );
    233 	netdev->dev = &pci->dev;
    234 	pnic->ioaddr = pci->ioaddr;
    235 
    236 	/* Fix up PCI device */
    237 	adjust_pci_device ( pci );
    238 
    239 	/* API version check */
    240 	status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
    241 				      &api_version,
    242 				      sizeof ( api_version ), NULL );
    243 	if ( status != PNIC_STATUS_OK ) {
    244 		printf ( "PNIC failed installation check, code %#hx\n",
    245 			 status );
    246 		rc = -EIO;
    247 		goto err;
    248 	}
    249 	pnic_api_check ( api_version );
    250 
    251 	/* Get MAC address */
    252 	status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
    253 				netdev->hw_addr, ETH_ALEN, NULL );
    254 
    255 	/* Mark as link up; PNIC has no concept of link state */
    256 	netdev_link_up ( netdev );
    257 
    258 	/* Register network device */
    259 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
    260 		goto err;
    261 
    262 	return 0;
    263 
    264  err:
    265 	/* Free net device */
    266 	netdev_nullify ( netdev );
    267 	netdev_put ( netdev );
    268 	return rc;
    269 }
    270 
    271 static struct pci_device_id pnic_nics[] = {
    272 /* genrules.pl doesn't let us use macros for PCI IDs...*/
    273 PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
    274 };
    275 
    276 struct pci_driver pnic_driver __pci_driver = {
    277 	.ids = pnic_nics,
    278 	.id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
    279 	.probe = pnic_probe,
    280 	.remove = pnic_remove,
    281 };
    282