Annotation of qemu/roms/ipxe/src/drivers/net/pnic.c, revision 1.1

1.1     ! root        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 <ipxe/io.h>
        !            20: #include <errno.h>
        !            21: #include <ipxe/pci.h>
        !            22: #include <ipxe/if_ether.h>
        !            23: #include <ipxe/ethernet.h>
        !            24: #include <ipxe/iobuf.h>
        !            25: #include <ipxe/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:        struct net_device *netdev;
        !           220:        struct pnic *pnic;
        !           221:        uint16_t api_version;
        !           222:        uint16_t status;
        !           223:        int rc;
        !           224: 
        !           225:        /* Allocate net device */
        !           226:        netdev = alloc_etherdev ( sizeof ( *pnic ) );
        !           227:        if ( ! netdev )
        !           228:                return -ENOMEM;
        !           229:        netdev_init ( netdev, &pnic_operations );
        !           230:        pnic = netdev->priv;
        !           231:        pci_set_drvdata ( pci, netdev );
        !           232:        netdev->dev = &pci->dev;
        !           233:        pnic->ioaddr = pci->ioaddr;
        !           234: 
        !           235:        /* Fix up PCI device */
        !           236:        adjust_pci_device ( pci );
        !           237:        
        !           238:        /* API version check */
        !           239:        status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
        !           240:                                      &api_version,
        !           241:                                      sizeof ( api_version ), NULL );
        !           242:        if ( status != PNIC_STATUS_OK ) {
        !           243:                printf ( "PNIC failed installation check, code %#hx\n",
        !           244:                         status );
        !           245:                rc = -EIO;
        !           246:                goto err;
        !           247:        }
        !           248:        pnic_api_check ( api_version );
        !           249: 
        !           250:        /* Get MAC address */
        !           251:        status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
        !           252:                                netdev->hw_addr, ETH_ALEN, NULL );
        !           253: 
        !           254:        /* Register network device */
        !           255:        if ( ( rc = register_netdev ( netdev ) ) != 0 )
        !           256:                goto err;
        !           257: 
        !           258:        /* Mark as link up; PNIC has no concept of link state */
        !           259:        netdev_link_up ( netdev );
        !           260: 
        !           261:        return 0;
        !           262: 
        !           263:  err:
        !           264:        /* Free net device */
        !           265:        netdev_nullify ( netdev );
        !           266:        netdev_put ( netdev );
        !           267:        return rc;
        !           268: }
        !           269: 
        !           270: static struct pci_device_id pnic_nics[] = {
        !           271: /* genrules.pl doesn't let us use macros for PCI IDs...*/
        !           272: PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
        !           273: };
        !           274: 
        !           275: struct pci_driver pnic_driver __pci_driver = {
        !           276:        .ids = pnic_nics,
        !           277:        .id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
        !           278:        .probe = pnic_probe,
        !           279:        .remove = pnic_remove,
        !           280: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.