iPXE
Functions | Variables
pcnet32.c File Reference
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <byteswap.h>
#include <errno.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/io.h>
#include <ipxe/iobuf.h>
#include <ipxe/malloc.h>
#include <ipxe/netdevice.h>
#include <ipxe/pci.h>
#include <ipxe/timer.h>
#include <mii.h>
#include "pcnet32.h"

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
static void pcnet32_wio_write_csr (unsigned long addr, int index, u16 val)
static u16 pcnet32_wio_read_bcr (unsigned long addr, int index)
static void pcnet32_wio_write_bcr (unsigned long addr, int index, u16 val)
static u16 pcnet32_wio_read_rap (unsigned long addr)
static void pcnet32_wio_write_rap (unsigned long addr, u16 val)
static void pcnet32_wio_reset (unsigned long addr)
static int pcnet32_wio_check (unsigned long addr)
static u16 pcnet32_dwio_read_csr (unsigned long addr, int index)
static void pcnet32_dwio_write_csr (unsigned long addr, int index, u16 val)
static u16 pcnet32_dwio_read_bcr (unsigned long addr, int index)
static void pcnet32_dwio_write_bcr (unsigned long addr, int index, u16 val)
static u16 pcnet32_dwio_read_rap (unsigned long addr)
static void pcnet32_dwio_write_rap (unsigned long addr, u16 val)
static void pcnet32_dwio_reset (unsigned long addr)
static int pcnet32_dwio_check (unsigned long addr)
static int pcnet32_mdio_read (struct net_device *netdev, int phy, int reg)
static void __unused pcnet32_mdio_write (struct net_device *netdev, int phy, int reg, int val)
static void pcnet32_refill_rx_ring (struct pcnet32_private *priv)
 pcnet32_refill_rx_ring - Allocates iobufs for every Rx descriptor that doesn't have one and isn't in use by the hardware
static int pcnet32_setup_rx_resources (struct pcnet32_private *priv)
 pcnet32_setup_rx_resources - allocate Rx resources (Descriptors)
static void pcnet32_free_rx_resources (struct pcnet32_private *priv)
static int pcnet32_setup_tx_resources (struct pcnet32_private *priv)
 pcnet32_setup_tx_resources - allocate Tx resources (Descriptors)
static void pcnet32_free_tx_resources (struct pcnet32_private *priv)
static int pcnet32_chip_detect (struct pcnet32_private *priv)
static int pcnet32_set_ops (struct pcnet32_private *priv)
 pcnet32_set_ops - Determines the ops used to access the registers
static void pcnet32_setup_init_block (struct pcnet32_private *priv)
 pcnet32_setup_init_block - setup the NICs initialization block
static void pcnet32_setup_probe_phy (struct pcnet32_private *priv)
 pcnet32_setup_probe_phy - go through all PHYs and see which one is present
static int pcnet32_setup_mac_addr (struct pcnet32_private *priv)
 pcnet32_setup_mac_addr - check for inconsistency between CSR12-14 and PROM addresses
static void pcnet32_setup_if_duplex (struct pcnet32_private *priv)
 pcnet32_setup_if_duplex - Sets the NICs used interface and duplex mode
static void pcnet32_hw_start (struct pcnet32_private *priv)
 pcnet32_hw_start - Starts up the NIC
static int pcnet32_open (struct net_device *netdev)
 open - Called when a network interface is made active
static int pcnet32_transmit (struct net_device *netdev, struct io_buffer *iobuf)
 transmit - Transmit a packet
static void pcnet32_process_tx_packets (struct net_device *netdev)
 pcnet32_process_tx_packets - Checks for successfully sent packets, reports them to iPXE with netdev_tx_complete()
static void pcnet32_process_rx_packets (struct net_device *netdev)
 pcnet32_process_rx_packets - Checks for received packets, reports them to iPXE with netdev_rx() or netdev_rx_err() if there was an error receiving the packet
static void pcnet32_poll (struct net_device *netdev)
 poll - Poll for received packets
static void pcnet32_close (struct net_device *netdev)
 close - Disable network interface
static void pcnet32_irq_enable (struct pcnet32_private *priv)
static void pcnet32_irq_disable (struct pcnet32_private *priv)
static void pcnet32_irq (struct net_device *netdev, int action)
 irq - enable or disable interrupts
static int pcnet32_probe (struct pci_device *pdev)
 probe - Initial configuration of NIC
static void pcnet32_remove (struct pci_device *pdev)
 remove - Device Removal Routine

Variables

static struct pcnet32_access pcnet32_wio
static struct pcnet32_access pcnet32_dwio
static struct net_device_operations pcnet32_operations
static struct pci_device_id pcnet32_nics []
struct pci_driver pcnet32_driver __pci_driver

Function Documentation

FILE_LICENCE ( GPL2_OR_LATER  )
static u16 pcnet32_wio_read_csr ( unsigned long  addr,
int  index 
) [static]

Definition at line 42 of file pcnet32.c.

References inw(), and outw().

Referenced by pcnet32_set_ops().

{
        outw ( index, addr + PCNET32_WIO_RAP );
        return inw ( addr + PCNET32_WIO_RDP );
}
static void pcnet32_wio_write_csr ( unsigned long  addr,
int  index,
u16  val 
) [static]

Definition at line 48 of file pcnet32.c.

References outw().

{
        outw ( index, addr + PCNET32_WIO_RAP );
        outw ( val, addr + PCNET32_WIO_RDP );
}
static u16 pcnet32_wio_read_bcr ( unsigned long  addr,
int  index 
) [static]

Definition at line 54 of file pcnet32.c.

References inw(), and outw().

{
        outw ( index, addr + PCNET32_WIO_RAP );
        return inw ( addr + PCNET32_WIO_BDP );
}
static void pcnet32_wio_write_bcr ( unsigned long  addr,
int  index,
u16  val 
) [static]

Definition at line 60 of file pcnet32.c.

References outw().

{
        outw ( index, addr + PCNET32_WIO_RAP );
        outw ( val, addr + PCNET32_WIO_BDP );
}
static u16 pcnet32_wio_read_rap ( unsigned long  addr) [static]

Definition at line 66 of file pcnet32.c.

References inw().

{
        return inw ( addr + PCNET32_WIO_RAP );
}
static void pcnet32_wio_write_rap ( unsigned long  addr,
u16  val 
) [static]

Definition at line 71 of file pcnet32.c.

References outw().

{
        outw ( val, addr + PCNET32_WIO_RAP );
}
static void pcnet32_wio_reset ( unsigned long  addr) [static]

Definition at line 76 of file pcnet32.c.

References inw().

Referenced by pcnet32_close(), pcnet32_probe(), and pcnet32_remove().

{
        inw ( addr + PCNET32_WIO_RESET );
}
static int pcnet32_wio_check ( unsigned long  addr) [static]

Definition at line 81 of file pcnet32.c.

References inw(), and outw().

Referenced by pcnet32_set_ops().

{
        outw ( 88, addr + PCNET32_WIO_RAP );
        return ( inw ( addr + PCNET32_WIO_RAP ) == 88 );
}
static u16 pcnet32_dwio_read_csr ( unsigned long  addr,
int  index 
) [static]

Definition at line 97 of file pcnet32.c.

References inl(), and outl().

Referenced by pcnet32_set_ops().

{
        outl ( index, addr + PCNET32_DWIO_RAP );
        return ( inl ( addr + PCNET32_DWIO_RDP ) & 0xffff );
}
static void pcnet32_dwio_write_csr ( unsigned long  addr,
int  index,
u16  val 
) [static]

Definition at line 103 of file pcnet32.c.

References outl().

{
        outl ( index, addr + PCNET32_DWIO_RAP );
        outl ( val, addr + PCNET32_DWIO_RDP );
}
static u16 pcnet32_dwio_read_bcr ( unsigned long  addr,
int  index 
) [static]

Definition at line 109 of file pcnet32.c.

References inl(), and outl().

{
        outl ( index, addr + PCNET32_DWIO_RAP );
        return ( inl ( addr + PCNET32_DWIO_BDP ) & 0xffff );
}
static void pcnet32_dwio_write_bcr ( unsigned long  addr,
int  index,
u16  val 
) [static]

Definition at line 115 of file pcnet32.c.

References outl().

{
        outl ( index, addr + PCNET32_DWIO_RAP );
        outl ( val, addr + PCNET32_DWIO_BDP );
}
static u16 pcnet32_dwio_read_rap ( unsigned long  addr) [static]

Definition at line 121 of file pcnet32.c.

References inl().

{
        return ( inl ( addr + PCNET32_DWIO_RAP ) & 0xffff );
}
static void pcnet32_dwio_write_rap ( unsigned long  addr,
u16  val 
) [static]

Definition at line 126 of file pcnet32.c.

References outl().

{
        outl ( val, addr + PCNET32_DWIO_RAP );
}
static void pcnet32_dwio_reset ( unsigned long  addr) [static]

Definition at line 131 of file pcnet32.c.

References inl().

Referenced by pcnet32_set_ops().

{
        inl ( addr + PCNET32_DWIO_RESET );
}
static int pcnet32_dwio_check ( unsigned long  addr) [static]

Definition at line 136 of file pcnet32.c.

References inl(), and outl().

Referenced by pcnet32_set_ops().

{
        outl ( 88, addr + PCNET32_DWIO_RAP );
        return ( ( inl ( addr + PCNET32_DWIO_RAP ) & 0xffff ) == 88 );
}
static int pcnet32_mdio_read ( struct net_device netdev,
int  phy,
int  reg 
) [static]

Definition at line 154 of file pcnet32.c.

References ioaddr, priv, and net_device::priv.

Referenced by pcnet32_setup_probe_phy().

{
        struct pcnet32_private *priv = netdev->priv;
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        u16 val_out;

        if ( ! priv->mii )
                return 0;

        /* First, select PHY chip and the register we want to read */
        priv->a->write_bcr ( ioaddr, 33,
                ( ( phy & 0x1f ) << 5 ) | ( reg & 0x1f ) );

        /* Read the selected register's value */
        val_out = priv->a->read_bcr ( ioaddr, 34 );

        return val_out;
}
static void __unused pcnet32_mdio_write ( struct net_device netdev,
int  phy,
int  reg,
int  val 
) [static]

Definition at line 174 of file pcnet32.c.

References ioaddr, priv, and net_device::priv.

{
        struct pcnet32_private *priv = netdev->priv;
        unsigned long ioaddr = priv->pci_dev->ioaddr;

        if ( ! priv->mii )
                return;

        /* First, select PHY chip and the register we want to write to */
        priv->a->write_bcr ( ioaddr, 33,
                ( ( phy & 0x1f ) << 5 ) | ( reg & 0x1f ) );

        /* Write val to the selected register */
        priv->a->write_bcr ( ioaddr, 34, val );
}
static void pcnet32_refill_rx_ring ( struct pcnet32_private *  priv) [static]

pcnet32_refill_rx_ring - Allocates iobufs for every Rx descriptor that doesn't have one and isn't in use by the hardware

Parameters:
privDriver private structure

Definition at line 198 of file pcnet32.c.

References alloc_iob(), cpu_to_le16, cpu_to_le32, DBG, DBGP, DescOwn, le16_to_cpu, NULL, RX_RING_SIZE, status, virt_to_bus(), and wmb.

Referenced by pcnet32_process_rx_packets(), and pcnet32_setup_rx_resources().

{
        struct pcnet32_rx_desc *rx_curr_desc;
        u16 status;
        int i;

        DBGP ( "pcnet32_refill_rx_ring\n" );

        for ( i = 0; i < RX_RING_SIZE; i++ ) {
                rx_curr_desc = priv->rx_base + i;

                status = le16_to_cpu ( rx_curr_desc->status );

                /* Don't touch descriptors owned by the hardware */
                if ( status & DescOwn )
                        continue;

                /* Descriptors with iobufs still need to be processed */
                if ( priv->rx_iobuf[i] != NULL )
                        continue;

                /* If alloc_iob fails, try again later (next poll) */
                if ( ! ( priv->rx_iobuf[i] = alloc_iob ( PKT_BUF_SIZE ) ) ) {
                        DBG ( "Refill rx ring failed\n" );
                        break;
                }

                rx_curr_desc->base =
                        cpu_to_le32 ( virt_to_bus ( priv->rx_iobuf[i]->data ) );
                rx_curr_desc->buf_length = cpu_to_le16 ( -PKT_BUF_SIZE );
                rx_curr_desc->msg_length = rx_curr_desc->reserved = 0;

                /* Owner changes after the other status fields are set */
                wmb();
                rx_curr_desc->status = cpu_to_le16 ( DescOwn );
        }

}
static int pcnet32_setup_rx_resources ( struct pcnet32_private *  priv) [static]

pcnet32_setup_rx_resources - allocate Rx resources (Descriptors)

Parameters:
privDriver private structure
Return values:
rcReturns 0 on success, negative on failure

Definition at line 245 of file pcnet32.c.

References DBG, DBGP, ENOMEM, malloc_dma(), memset(), pcnet32_refill_rx_ring(), RX_RING_ALIGN, RX_RING_BYTES, and virt_to_bus().

Referenced by pcnet32_open().

{
        DBGP ( "pcnet32_setup_rx_resources\n" );

        priv->rx_base = malloc_dma ( RX_RING_BYTES, RX_RING_ALIGN );

        DBG ( "priv->rx_base = %#08lx\n", virt_to_bus ( priv->rx_base ) );

        if ( ! priv->rx_base ) {
                return -ENOMEM;
        }

        memset ( priv->rx_base, 0, RX_RING_BYTES );

        pcnet32_refill_rx_ring ( priv );

        priv->rx_curr = 0;

        return 0;
}
static void pcnet32_free_rx_resources ( struct pcnet32_private *  priv) [static]

Definition at line 267 of file pcnet32.c.

References DBGP, free_dma(), free_iob(), NULL, RX_RING_BYTES, and RX_RING_SIZE.

Referenced by pcnet32_close().

{
        int i;

        DBGP ( "pcnet32_free_rx_resources\n" );

        free_dma ( priv->rx_base, RX_RING_BYTES );

        for ( i = 0; i < RX_RING_SIZE; i++ ) {
                free_iob ( priv->rx_iobuf[i] );
                priv->rx_iobuf[i] = NULL;
        }
}
static int pcnet32_setup_tx_resources ( struct pcnet32_private *  priv) [static]

pcnet32_setup_tx_resources - allocate Tx resources (Descriptors)

Parameters:
privDriver private structure
Return values:
rcReturns 0 on success, negative on failure

Definition at line 289 of file pcnet32.c.

References DBG, DBGP, ENOMEM, malloc_dma(), memset(), TX_RING_ALIGN, TX_RING_BYTES, and virt_to_bus().

Referenced by pcnet32_open().

{
        DBGP ( "pcnet32_setup_tx_resources\n" );

        priv->tx_base = malloc_dma ( TX_RING_BYTES, TX_RING_ALIGN );

        if ( ! priv->tx_base ) {
                return -ENOMEM;
        }

        memset ( priv->tx_base, 0, TX_RING_BYTES );

        DBG ( "priv->tx_base = %#08lx\n", virt_to_bus ( priv->tx_base ) );

        priv->tx_curr = 0;
        priv->tx_fill_ctr = 0;
        priv->tx_tail = 0;

        return 0;
}
static void pcnet32_free_tx_resources ( struct pcnet32_private *  priv) [static]

Definition at line 311 of file pcnet32.c.

References DBGP, free_dma(), and TX_RING_BYTES.

Referenced by pcnet32_close(), and pcnet32_open().

{
        DBGP ( "pcnet32_free_tx_resources\n" );

        free_dma ( priv->tx_base, TX_RING_BYTES );
}
static int pcnet32_chip_detect ( struct pcnet32_private *  priv) [static]

Definition at line 319 of file pcnet32.c.

References DBG, ENODEV, ioaddr, media, mii, and rc.

Referenced by pcnet32_probe().

{
        int fdx, mii, fset;
        int media;
        int rc;
        unsigned long ioaddr;
        struct pcnet32_access *a;
        int chip_version;
        char *chipname;

        ioaddr = priv->pci_dev->ioaddr;
        a = priv->a;

        chip_version = a->read_csr ( ioaddr, 88 )
                | ( a->read_csr ( ioaddr, 89 ) << 16 );

        rc = -ENODEV;

        DBG ( "PCnet chip version is 0x%X\n", chip_version );
        if ( ( chip_version & 0xfff ) != 0x003 )
                goto err_unsupported;

        fdx = mii = fset = 0;
        chip_version = ( chip_version >> 12 ) & 0xffff;

        switch (chip_version) {
        case 0x2420:
                chipname = "PCnet/PCI 79C970";
                break;
        case 0x2430:
                /* 970 gives the wrong chip id back */
                chipname = "PCnet/PCI 79C970";
                break;
        case 0x2621:
                chipname = "PCnet/PCI II 79C970A";
                fdx = 1;
                break;
        case 0x2623:
                chipname = "PCnet/FAST 79C971";
                fdx = 1;
                mii = 1;
                fset = 1;
                break;
        case 0x2624:
                chipname = "PCnet/FAST+ 79C972";
                fdx = 1;
                mii = 1;
                fset = 1;
                break;
        case 0x2625:
                chipname = "PCnet/FAST III 79C973";
                fdx = 1;
                mii = 1;
                break;
        case 0x2626:
                chipname = "PCnet/Home 79C978";
                fdx = 1;
                /*
                 * This is based on specs published at www.amd.com. This section
                 * assumes that a NIC with a 79C978 wants to go into 1Mb HomePNA
                 * mode. The 79C978 can also go into standard ethernet, and
                 * there probably should be some sort of module option to select
                 * the mode by which the card should operate
                 */
                /* switch to home wiring mode */
                media = a->read_bcr(ioaddr, 49);

                DBG ( "media reset to %#x.\n", media );
                a->write_bcr(ioaddr, 49, media);
                break;
        case 0x2627:
                chipname = "PCnet/FAST III 79C975";
                fdx = 1;
                mii = 1;
                break;
        case 0x2628:
                chipname = "PCnet/PRO 79C976";
                fdx = 1;
                mii = 1;
                break;
        default:
                chipname = "UNKNOWN";
                DBG ( "PCnet version %#x, no PCnet32 chip.\n", chip_version );
                goto err_unsupported;
        }

        DBG ( "PCnet chipname %s\n", chipname );

        /*
         * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
         * starting until the packet is loaded. Strike one for reliability, lose
         * one for latency - although on PCI this isn't a big loss. Older chips
         * have FIFO's smaller than a packet, so you can't do this.
         * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn.
         */
        if (fset) {
                a->write_bcr ( ioaddr, 18,
                        ( a->read_bcr ( ioaddr, 18 ) | 0x0860 ) );
                a->write_csr ( ioaddr, 80, 0x0c00 );
        }

        priv->full_duplex = fdx;
        priv->mii = mii;

        return 0;

err_unsupported:
        return rc;
}
static int pcnet32_set_ops ( struct pcnet32_private *  priv) [static]

pcnet32_set_ops - Determines the ops used to access the registers

Parameters:
privDriver private structure
Return values:
rcReturns 0 on success, negative on failure

Definition at line 437 of file pcnet32.c.

References ENODEV, ioaddr, pcnet32_dwio, pcnet32_dwio_check(), pcnet32_dwio_read_csr(), pcnet32_dwio_reset(), pcnet32_wio, pcnet32_wio_check(), pcnet32_wio_read_csr(), and rc.

Referenced by pcnet32_probe().

{
        int rc;
        unsigned long ioaddr;

        ioaddr = priv->pci_dev->ioaddr;

        /* Check if CSR0 has its default value and perform a write / read
           in the RAP register to see if it works. Based on these results
           determine what mode the NIC is in (WIO / DWIO)
         */
        rc = -ENODEV;

        if ( pcnet32_wio_read_csr ( ioaddr, 0 ) == 4 &&
             pcnet32_wio_check ( ioaddr ) ) {
                priv->a = &pcnet32_wio;
        } else {
                pcnet32_dwio_reset ( ioaddr );
                if ( pcnet32_dwio_read_csr ( ioaddr, 0 ) == 4 &&
                     pcnet32_dwio_check ( ioaddr ) ) {
                        priv->a = &pcnet32_dwio;
                } else {
                        goto err_unsupported;
                }
        }

        return 0;

err_unsupported:
        return rc;
}
static void pcnet32_setup_init_block ( struct pcnet32_private *  priv) [static]

pcnet32_setup_init_block - setup the NICs initialization block

Parameters:
privDriver private structure
Return values:
rcReturns 0 on success, negative on failure

Definition at line 477 of file pcnet32.c.

References cpu_to_le16, cpu_to_le32, ETH_ALEN, virt_to_bus(), and wmb.

Referenced by pcnet32_open().

{
        int i;

        /* Configure the network port based on what we've established so far */
        priv->init_block.mode =
                cpu_to_le16 ( ( priv->options & PCNET32_PORT_PORTSEL ) << 7 );

        /* Setup RLEN and TLEN fields */
        priv->init_block.tlen_rlen =
                cpu_to_le16 ( ( PCNET32_LOG_RX_BUFFERS << 4 ) |
                              ( PCNET32_LOG_TX_BUFFERS << 12 ) );

        /* Fill in physical address */
        for ( i = 0; i < ETH_ALEN; i++)
                priv->init_block.phys_addr[i] = priv->netdev->hw_addr[i];

        /* No multicasting scheme, accept everything */
        priv->init_block.filter[0] = 0xffffffff;
        priv->init_block.filter[1] = 0xffffffff;

        priv->init_block.rx_ring =
                cpu_to_le32 ( virt_to_bus ( priv->rx_base ) );
        priv->init_block.tx_ring =
                cpu_to_le32 ( virt_to_bus ( priv->tx_base ) );

        /* Make sure all changes are visible */
        wmb();
}
static void pcnet32_setup_probe_phy ( struct pcnet32_private *  priv) [static]

pcnet32_setup_probe_phy - go through all PHYs and see which one is present

Parameters:
privDriver private structure

Definition at line 513 of file pcnet32.c.

References ioaddr, MII_PHYSID1, MII_PHYSID2, and pcnet32_mdio_read().

Referenced by pcnet32_probe().

{
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        unsigned int phycount = 0;
        int phy_id;
        int i;

        if ( priv->mii ) {
                phy_id = ( ( priv->a->read_bcr ( ioaddr, 33 ) ) >> 5 ) & 0x1f;
                for ( i = 0; i < PCNET32_MAX_PHYS; i++ ) {
                        unsigned short id1, id2;
                        id1 = pcnet32_mdio_read ( priv->netdev, i, MII_PHYSID1 );
                        if ( id1 == 0xffff )
                                continue;
                        id2 = pcnet32_mdio_read ( priv->netdev, i, MII_PHYSID2 );
                        if ( id2 == 0xffff )
                                continue;
                        if ( i == 31 && ( ( priv->chip_version + 1 ) & 0xfffe ) == 0x2624 )
                                continue;

                        phycount++;
                        phy_id = i;
                }
                priv->a->write_bcr ( ioaddr, 33, phy_id << 5 );
                if ( phycount > 1 )
                        priv->options |= PCNET32_PORT_MII;
        }
}
static int pcnet32_setup_mac_addr ( struct pcnet32_private *  priv) [static]

pcnet32_setup_mac_addr - check for inconsistency between CSR12-14 and PROM addresses

Parameters:
privDriver private structure

Definition at line 549 of file pcnet32.c.

References DBG, EADDRNOTAVAIL, ETH_ALEN, inb(), ioaddr, is_valid_ether_addr(), memcmp(), memcpy(), and val.

Referenced by pcnet32_probe().

{
        int i;
        u8 promaddr[ETH_ALEN];
        unsigned long ioaddr = priv->pci_dev->ioaddr;

        /* In most chips, after a chip reset, the ethernet address is read from
         * the station address PROM at the base address and programmed into the
         * "Physical Address Registers" CSR12-14.
         * As a precautionary measure, we read the PROM values and complain if
         * they disagree with the CSRs.  If they miscompare, and the PROM addr
         * is valid, then the PROM addr is used.
         */
        for ( i = 0; i < 3; i++ ) {
                unsigned int val;
                val = priv->a->read_csr ( ioaddr, i + 12 ) & 0x0ffff;
                /* There may be endianness issues here. */
                priv->netdev->hw_addr[2 * i] = val & 0x0ff;
                priv->netdev->hw_addr[2 * i + 1] = ( val >> 8 ) & 0x0ff;
        }

        for ( i = 0; i < ETH_ALEN; i++ )
                promaddr[i] = inb ( ioaddr + i );

        if ( memcmp ( promaddr, priv->netdev->hw_addr, ETH_ALEN ) ||
             ! is_valid_ether_addr ( priv->netdev->hw_addr ) ) {
                if ( is_valid_ether_addr ( promaddr ) ) {
                        DBG ( "CSR address is invalid, using PROM addr\n" );
                        memcpy ( priv->netdev->hw_addr, promaddr, ETH_ALEN );
                }
        }

        /* If ethernet address is not valid, return error */
        if ( ! is_valid_ether_addr ( priv->netdev->hw_addr ) )
                return -EADDRNOTAVAIL;

        return 0;
}
static void pcnet32_setup_if_duplex ( struct pcnet32_private *  priv) [static]

pcnet32_setup_if_duplex - Sets the NICs used interface and duplex mode

Parameters:
privDriver private structure

Definition at line 594 of file pcnet32.c.

References ioaddr, pci_read_config_word(), PCI_SUBSYSTEM_ID, PCI_SUBSYSTEM_VENDOR_ID, and val.

Referenced by pcnet32_open().

{
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        u16 val;

        /* Set/Reset autoselect bit */
        val = priv->a->read_bcr ( ioaddr, 2 ) & ~2;
        if ( priv->options & PCNET32_PORT_ASEL )
                val |= 2;
        priv->a->write_bcr ( ioaddr, 2, val );

        /* Handle full duplex setting */
        if ( priv->full_duplex ) {
                val = priv->a->read_bcr ( ioaddr, 9 ) & ~3;
                if ( priv->options & PCNET32_PORT_FD ) {
                        val |= 1;
                        if ( priv->options == ( PCNET32_PORT_FD | PCNET32_PORT_AUI ) )
                                val |= 2;
                } else if ( priv->options & PCNET32_PORT_ASEL ) {
                        /* Workaround of xSeries 250, on for 79C975 only */
                        if ( priv->chip_version == 0x2627 )
                                val |= 3;
                }
                priv->a->write_bcr ( ioaddr, 9, val );
        }

        /* Set/Reset GPSI bit in test register */
        val = priv->a->read_csr ( ioaddr, 124 ) & ~0x10;
        if ( ( priv->options & PCNET32_PORT_PORTSEL ) == PCNET32_PORT_GPSI )
                val |= 0x10;
        priv->a->write_bcr ( ioaddr, 124, val );

        /* Allied Telesyn AT are 100Mbit only and do not negotiate */
        u16 subsys_vend_id, subsys_dev_id;
        pci_read_config_word ( priv->pci_dev,
                               PCI_SUBSYSTEM_VENDOR_ID,
                               &subsys_vend_id );
        pci_read_config_word ( priv->pci_dev,
                               PCI_SUBSYSTEM_ID,
                               &subsys_dev_id );
        if ( subsys_vend_id == PCI_VENDOR_ID_AT &&
             ( ( subsys_dev_id == PCI_SUBDEVICE_ID_AT_2700FX ) ||
               ( subsys_dev_id == PCI_SUBDEVICE_ID_AT_2701FX ) ) ) {
                priv->options = PCNET32_PORT_FD | PCNET32_PORT_100;
        }

        if ( priv->mii && ! ( priv->options & PCNET32_PORT_ASEL ) ) {
                /* Disable Auto Negotiation, set 10Mbps, HD */
                val = priv->a->read_bcr ( ioaddr, 32 ) & ~0x38;
                if ( priv->options & PCNET32_PORT_FD )
                        val |= 0x10;
                if ( priv->options & PCNET32_PORT_100 )
                        val |= 0x08;
                priv->a->write_bcr ( ioaddr, 32, val );
        } else if ( priv->options & PCNET32_PORT_ASEL ) {
                /* 79C970 chips do not have the BCR32 register */
                if ( ( priv->chip_version != 0x2420 ) &&
                     ( priv->chip_version != 0x2621 ) ) {
                        /* Enable Auto Negotiation, setup, disable FD */
                        val = priv->a->read_bcr ( ioaddr, 32 ) & ~0x98;
                        val |= 0x20;
                        priv->a->write_bcr ( ioaddr, 32, val );
                }
        }
}
static void pcnet32_hw_start ( struct pcnet32_private *  priv) [static]

pcnet32_hw_start - Starts up the NIC

Parameters:
privDriver private structure

Definition at line 666 of file pcnet32.c.

References ioaddr.

Referenced by pcnet32_open().

{
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        int i;

        /* Begin initialization procedure */
        priv->a->write_csr ( ioaddr, 0, Init );

        /* Wait for the initialization to be done */
        i = 0;
        while ( i++ < 100 )
                if ( priv->a->read_csr ( ioaddr, 0 ) & InitDone )
                        break;

        /* Start the chip */
        priv->a->write_csr ( ioaddr, 0, Strt );
}
static int pcnet32_open ( struct net_device netdev) [static]

open - Called when a network interface is made active

Parameters:
netdevNetwork device
Return values:
rcReturn status code, 0 on success, negative value on failure

Definition at line 691 of file pcnet32.c.

References DBG, ioaddr, netdev_priv(), pcnet32_free_tx_resources(), pcnet32_hw_start(), pcnet32_setup_if_duplex(), pcnet32_setup_init_block(), pcnet32_setup_rx_resources(), pcnet32_setup_tx_resources(), priv, rc, val, and virt_to_bus().

{
        struct pcnet32_private *priv = netdev_priv ( netdev );
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        int rc;
        u16 val;

        /* Setup TX and RX descriptors */
        if ( ( rc = pcnet32_setup_tx_resources ( priv ) ) != 0 ) {
                DBG ( "Error setting up TX resources\n" );
                goto err_setup_tx;
        }

        if ( ( rc = pcnet32_setup_rx_resources ( priv ) ) != 0 ) {
                DBG ( "Error setting up RX resources\n" );
                goto err_setup_rx;
        }

        /* Reset the chip */
        priv->a->reset ( ioaddr );

        /* Switch pcnet32 to 32bit mode */
        priv->a->write_bcr ( ioaddr, 20, PCNET32_SWSTYLE_PCNET32 );

        /* Setup the interface and duplex mode */
        pcnet32_setup_if_duplex ( priv );

        /* Disable interrupts */
        val = priv->a->read_csr ( ioaddr, 3 );
        val |= BablMask | MissFrameMask | RxIntMask | TxIntMask | InitDoneMask;
        priv->a->write_csr ( ioaddr, 3, val );

        /* Setup initialization block */
        pcnet32_setup_init_block ( priv );

        /* Fill in the address of the initialization block */
        priv->a->write_csr ( ioaddr, 1,
                ( virt_to_bus ( &priv->init_block ) ) & 0xffff );
        priv->a->write_csr ( ioaddr, 2,
                ( virt_to_bus ( &priv->init_block ) ) >> 16 );

        /* Enable Auto-Pad, disable interrupts */
        priv->a->write_csr ( ioaddr, 4, 0x0915 );

        pcnet32_hw_start ( priv );

        return 0;

err_setup_rx:
        pcnet32_free_tx_resources ( priv );
err_setup_tx:
        priv->a->reset( priv->pci_dev->ioaddr );
        return rc;
}
static int pcnet32_transmit ( struct net_device netdev,
struct io_buffer iobuf 
) [static]

transmit - Transmit a packet

Parameters:
netdevNetwork device
iobufI/O buffer
Return values:
rcReturns 0 on success, negative on failure

Definition at line 755 of file pcnet32.c.

References cpu_to_le16, cpu_to_le32, io_buffer::data, DBG, DBGP, DescOwn, ENOTSUP, ioaddr, iob_len(), netdev_priv(), priv, TX_RING_SIZE, virt_to_bus(), and wmb.

{
        struct pcnet32_private *priv = netdev_priv ( netdev );
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        uint32_t tx_len = iob_len ( iobuf );
        struct pcnet32_tx_desc *tx_curr_desc;

        DBGP ( "pcnet32_transmit\n" );

        if ( priv->tx_fill_ctr == TX_RING_SIZE ) {
                DBG ( "Tx overflow\n" );
                return -ENOTSUP;
        }

        priv->tx_iobuf[priv->tx_curr] = iobuf;

        tx_curr_desc = priv->tx_base + priv->tx_curr;

        /* Configure current descriptor to transmit packet */
        tx_curr_desc->length = cpu_to_le16 ( -tx_len );
        tx_curr_desc->misc = 0x00000000;
        tx_curr_desc->base = cpu_to_le32 ( virt_to_bus ( iobuf->data ) );

        /* Owner changes after the other status fields are set */
        wmb();
        tx_curr_desc->status =
                cpu_to_le16 ( DescOwn | StartOfPacket | EndOfPacket );

        /* Trigger an immediate send poll */
        priv->a->write_csr ( ioaddr, 0,
                ( priv->irq_enabled ? IntEnable : 0 ) | TxDemand );

        /* Point to the next free descriptor */
        priv->tx_curr = ( priv->tx_curr + 1 ) % TX_RING_SIZE;

        /* Increment number of tx descriptors in use */
        priv->tx_fill_ctr++;

        return 0;
}
static void pcnet32_process_tx_packets ( struct net_device netdev) [static]

pcnet32_process_tx_packets - Checks for successfully sent packets, reports them to iPXE with netdev_tx_complete()

Parameters:
netdevNetwork device

Definition at line 803 of file pcnet32.c.

References DBG, DBGP, DescOwn, le16_to_cpu, memset(), netdev_priv(), netdev_tx_complete(), priv, status, TX_RING_SIZE, and virt_to_bus().

Referenced by pcnet32_poll().

{
        struct pcnet32_private *priv = netdev_priv ( netdev );
        struct pcnet32_tx_desc *tx_curr_desc;

        DBGP ( "pcnet32_process_tx_packets\n" );

        while ( priv->tx_tail != priv->tx_curr ) {
                tx_curr_desc = priv->tx_base + priv->tx_tail;

                u16 status = le16_to_cpu ( tx_curr_desc->status );

                DBG ( "Before OWN bit check, status: %#08x\n", status );

                /* Skip this descriptor if hardware still owns it */
                if ( status & DescOwn )
                        break;

                DBG ( "Transmitted packet.\n" );
                DBG ( "priv->tx_fill_ctr= %d\n", priv->tx_fill_ctr );
                DBG ( "priv->tx_tail    = %d\n", priv->tx_tail );
                DBG ( "priv->tx_curr    = %d\n", priv->tx_curr );
                DBG ( "tx_curr_desc     = %#08lx\n", virt_to_bus ( tx_curr_desc ) );

                /* This packet is ready for completion */
                netdev_tx_complete ( netdev, priv->tx_iobuf[priv->tx_tail]);

                /* Clear the descriptor */
                memset ( tx_curr_desc, 0, sizeof(*tx_curr_desc) );

                /* Reduce the number of tx descriptors in use */
                priv->tx_fill_ctr--;

                /* Go to next available descriptor */
                priv->tx_tail = ( priv->tx_tail + 1 ) % TX_RING_SIZE;
        }
}
static void pcnet32_process_rx_packets ( struct net_device netdev) [static]

pcnet32_process_rx_packets - Checks for received packets, reports them to iPXE with netdev_rx() or netdev_rx_err() if there was an error receiving the packet

Parameters:
netdevNetwork device

Definition at line 849 of file pcnet32.c.

References DBG, DBGP, DescOwn, EINVAL, iob_put, le16_to_cpu, le32_to_cpu, len, memset(), netdev_priv(), netdev_rx(), netdev_rx_err(), NULL, pcnet32_refill_rx_ring(), priv, rmb, RX_RING_SIZE, status, and virt_to_bus().

Referenced by pcnet32_poll().

{
        struct pcnet32_private *priv = netdev_priv ( netdev );
        struct pcnet32_rx_desc *rx_curr_desc;
        u16 status;
        u32 len;
        int i;

        DBGP ( "pcnet32_process_rx_packets\n" );

        for ( i = 0; i < RX_RING_SIZE; i++ ) {
                rx_curr_desc = priv->rx_base + priv->rx_curr;

                status = le16_to_cpu ( rx_curr_desc->status );
                rmb();

                DBG ( "Before OWN bit check, status: %#08x\n", status );

                /* Skip this descriptor if hardware still owns it */
                if ( status & DescOwn )
                        break;

                /* We own the descriptor, but it has not been refilled yet */
                if ( priv->rx_iobuf[priv->rx_curr] == NULL )
                        break;

                DBG ( "Received packet.\n" );
                DBG ( "priv->rx_curr    = %d\n", priv->rx_curr );
                DBG ( "rx_len           = %d\n",
                      ( le32_to_cpu ( rx_curr_desc->msg_length ) & 0xfff ) - 4 );
                DBG ( "rx_curr_desc     = %#08lx\n",
                      virt_to_bus ( rx_curr_desc ) );

                /* Check ERR bit */
                if ( status & 0x4000 ) {
                        netdev_rx_err ( netdev, priv->rx_iobuf[priv->rx_curr],
                                        -EINVAL );
                        DBG ( "Corrupted packet received!\n");
                } else {
                        /* Adjust size of the iobuf to reflect received data */
                        len = ( le32_to_cpu ( rx_curr_desc->msg_length ) & 0xfff ) - 4;
                        iob_put ( priv->rx_iobuf[priv->rx_curr], len );

                        /* Add this packet to the receive queue */
                        netdev_rx ( netdev, priv->rx_iobuf[priv->rx_curr] );
                }

                /* Invalidate iobuf and descriptor */
                priv->rx_iobuf[priv->rx_curr] = NULL;
                memset ( rx_curr_desc, 0, sizeof(*rx_curr_desc) );

                /* Point to the next free descriptor */
                priv->rx_curr = ( priv->rx_curr + 1 ) % RX_RING_SIZE;
        }

        /* Allocate new iobufs where needed */
        pcnet32_refill_rx_ring ( priv );
}
static void pcnet32_poll ( struct net_device netdev) [static]

poll - Poll for received packets

Parameters:
netdevNetwork device

Definition at line 914 of file pcnet32.c.

References DBG, DBGP, ioaddr, netdev_priv(), pcnet32_process_rx_packets(), pcnet32_process_tx_packets(), priv, and status.

{
        struct pcnet32_private *priv = netdev_priv ( netdev );
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        u16 status;

        DBGP ( "pcnet32_poll\n" );

        status = priv->a->read_csr ( ioaddr, 0 );

        /* Clear interrupts */
        priv->a->write_csr ( ioaddr, 0, status );

        DBG ( "pcnet32_poll: mask = %#04x, status = %#04x\n",
                priv->a->read_csr ( ioaddr, 3 ), status );

        /* Return when RINT or TINT are not set */
        if ( ( status & 0x0500 ) == 0x0000 )
                return;

        /* Process transmitted packets */
        pcnet32_process_tx_packets ( netdev );

        /* Process received packets */
        pcnet32_process_rx_packets ( netdev );
}
static void pcnet32_close ( struct net_device netdev) [static]

close - Disable network interface

Parameters:
netdevnetwork interface device structure

Definition at line 947 of file pcnet32.c.

References DBGP, ioaddr, netdev_priv(), pcnet32_free_rx_resources(), pcnet32_free_tx_resources(), pcnet32_wio_reset(), and priv.

{
        struct pcnet32_private *priv = netdev_priv ( netdev );
        unsigned long ioaddr = priv->pci_dev->ioaddr;

        DBGP ( "pcnet32_close\n" );

        /* Reset the chip */
        pcnet32_wio_reset ( ioaddr );

        /* Stop the PCNET32 - it occasionally polls memory if we don't */
        priv->a->write_csr ( ioaddr, 0, Stop );

        /* Switch back to 16bit mode to avoid problems with dumb
         * DOS packet driver after a warm reboot */
        priv->a->write_bcr ( ioaddr, 20, PCNET32_SWSTYLE_LANCE );

        pcnet32_free_rx_resources ( priv );
        pcnet32_free_tx_resources ( priv );
}
static void pcnet32_irq_enable ( struct pcnet32_private *  priv) [static]

Definition at line 968 of file pcnet32.c.

References DBGP, ioaddr, and val.

Referenced by pcnet32_irq().

{
        unsigned long ioaddr = priv->pci_dev->ioaddr;
        u16 val;

        DBGP ( "pcnet32_irq_enable\n" );

        /* Enable TINT and RINT masks */
        val = priv->a->read_csr ( ioaddr, 3 );
        val &= ~( RxIntMask | TxIntMask );
        priv->a->write_csr ( ioaddr, 3, val );

        /* Enable interrupts */
        priv->a->write_csr ( ioaddr, 0, IntEnable );

        priv->irq_enabled = 1;
}
static void pcnet32_irq_disable ( struct pcnet32_private *  priv) [static]

Definition at line 986 of file pcnet32.c.

References DBGP, and ioaddr.

Referenced by pcnet32_irq().

{
        unsigned long ioaddr = priv->pci_dev->ioaddr;

        DBGP ( "pcnet32_irq_disable\n" );

        priv->a->write_csr ( ioaddr, 0, 0x0000 );

        priv->irq_enabled = 0;
}
static void pcnet32_irq ( struct net_device netdev,
int  action 
) [static]

irq - enable or disable interrupts

Parameters:
netdevnetwork adapter
actionrequested interrupt action

Definition at line 1004 of file pcnet32.c.

References DBGP, netdev_priv(), pcnet32_irq_disable(), pcnet32_irq_enable(), and priv.

{
        struct pcnet32_private *priv = netdev_priv ( netdev );

        DBGP ( "pcnet32_irq\n" );

        switch ( action ) {
        case 0:
                pcnet32_irq_disable ( priv );
                break;
        default:
                pcnet32_irq_enable ( priv );
                break;
        }
}
static int pcnet32_probe ( struct pci_device pdev) [static]

probe - Initial configuration of NIC

Parameters:
pdevPCI device
entPCI IDs
Return values:
rcReturn status code

Definition at line 1037 of file pcnet32.c.

References adjust_pci_device(), alloc_etherdev(), DBG, DBGP, pci_device::dev, net_device::dev, pci_device_id::device, ENOMEM, eth_ntoa(), net_device::hw_addr, pci_device::id, ioaddr, pci_device::ioaddr, pci_device_id::name, netdev, netdev_init(), netdev_link_up(), netdev_priv(), netdev_put(), pci_set_drvdata(), pcnet32_chip_detect(), pcnet32_set_ops(), pcnet32_setup_mac_addr(), pcnet32_setup_probe_phy(), pcnet32_wio_reset(), priv, rc, register_netdev(), and pci_device_id::vendor.

{
        struct net_device *netdev;
        struct pcnet32_private *priv;
        unsigned long ioaddr;
        int rc;

        DBGP ( "pcnet32_probe\n" );

        DBG ( "Found %s, vendor = %#04x, device = %#04x\n",
                pdev->id->name, pdev->id->vendor, pdev->id->device );

        /* Allocate our private data */
        netdev = alloc_etherdev ( sizeof ( *priv ) );
        if ( ! netdev ) {
                rc = -ENOMEM;
                goto err_alloc_etherdev;
        }

        /* Link our operations to the netdev struct */
        netdev_init ( netdev, &pcnet32_operations );

        /* Link the PCI device to the netdev struct */
        pci_set_drvdata ( pdev, netdev );
        netdev->dev = &pdev->dev;

        /* Get a reference to our private data */
        priv = netdev_priv ( netdev );

        /* We'll need these set up for the rest of the routines */
        priv->pci_dev = pdev;
        priv->netdev = netdev;

        ioaddr = pdev->ioaddr;

        /* Only use irqs under UNDI */
        priv->irq_enabled = 0;

        /* Reset the chip */
        pcnet32_wio_reset ( ioaddr );

        if ( ( rc = pcnet32_set_ops ( priv ) ) != 0 ) {
                DBG ( "Setting driver operations failed\n");
                goto err_set_ops;
        }

        if ( ( rc = pcnet32_chip_detect ( priv ) ) != 0 ) {
                DBG ( "pcnet32_chip_detect failed\n" );
                goto err_chip_detect;
        }

        /* Enter bus mastering mode */
        adjust_pci_device ( pdev );

        /* Verify and get MAC address */
        if ( ( rc = pcnet32_setup_mac_addr ( priv ) ) != 0 ) {
                DBG ( "Setting MAC address failed\n" );
                goto err_mac_addr;
        }

        DBG ( "IO Addr 0x%lX, MAC Addr %s\n", ioaddr,
                eth_ntoa ( netdev->hw_addr ) );

        priv->options = PCNET32_PORT_ASEL;

        /* Detect special T1/E1 WAN card by checking for MAC address */
        if ( netdev->hw_addr[0] == 0x00 &&
             netdev->hw_addr[1] == 0xE0 &&
             netdev->hw_addr[2] == 0x75 )
                priv->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;

        /* Probe the PHY so we can check link state and speed */
        pcnet32_setup_probe_phy ( priv );

        if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
                DBG ( "Error registering netdev\n" );
                goto err_register;
        }

        netdev_link_up ( netdev );

        return 0;

err_register:
        netdev_put ( netdev );
err_chip_detect:
err_set_ops:
err_alloc_etherdev:
err_mac_addr:
        return rc;
}
static void pcnet32_remove ( struct pci_device pdev) [static]

remove - Device Removal Routine

Parameters:
pdevPCI device information struct

Definition at line 1135 of file pcnet32.c.

References DBGP, ioaddr, pci_device::ioaddr, netdev, netdev_nullify(), netdev_put(), pci_get_drvdata(), pcnet32_wio_reset(), and unregister_netdev().

{
        struct net_device *netdev = pci_get_drvdata ( pdev );
        unsigned long ioaddr = pdev->ioaddr;

        DBGP ( "pcnet32_remove\n" );

        /* Reset the chip */
        pcnet32_wio_reset ( ioaddr );

        unregister_netdev ( netdev );
        netdev_nullify ( netdev );
        netdev_put ( netdev );
}

Variable Documentation

struct pcnet32_access pcnet32_wio [static]
Initial value:
 {
        .read_csr       = pcnet32_wio_read_csr,
        .write_csr      = pcnet32_wio_write_csr,
        .read_bcr       = pcnet32_wio_read_bcr,
        .write_bcr      = pcnet32_wio_write_bcr,
        .read_rap       = pcnet32_wio_read_rap,
        .write_rap      = pcnet32_wio_write_rap,
        .reset          = pcnet32_wio_reset,
}

Definition at line 87 of file pcnet32.c.

Referenced by pcnet32_set_ops().

struct pcnet32_access pcnet32_dwio [static]
Initial value:
 {
        .read_csr       = pcnet32_dwio_read_csr,
        .write_csr      = pcnet32_dwio_write_csr,
        .read_bcr       = pcnet32_dwio_read_bcr,
        .write_bcr      = pcnet32_dwio_write_bcr,
        .read_rap       = pcnet32_dwio_read_rap,
        .write_rap      = pcnet32_dwio_write_rap,
        .reset          = pcnet32_dwio_reset,
}

Definition at line 143 of file pcnet32.c.

Referenced by pcnet32_set_ops().

Initial value:
 {
        .open           = pcnet32_open,
        .transmit       = pcnet32_transmit,
        .poll           = pcnet32_poll,
        .close          = pcnet32_close,
        .irq            = pcnet32_irq,
}

Definition at line 1020 of file pcnet32.c.

struct pci_device_id pcnet32_nics[] [static]
Initial value:
 {
        PCI_ROM(0x1022, 0x2000, "pcnet32", "AMD PCnet/PCI", 0),
        PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD PCNet FAST III", 0),
        PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD PCnet/HomePNA", 0),
}

Definition at line 1150 of file pcnet32.c.

struct pci_driver pcnet32_driver __pci_driver
Initial value:
 {
        .ids            = pcnet32_nics,
        .id_count       = ARRAY_SIZE ( pcnet32_nics ),
        .probe          = pcnet32_probe,
        .remove         = pcnet32_remove,
}

Definition at line 1156 of file pcnet32.c.