iPXE
Functions | Variables
3c90x.c File Reference
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.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 <ipxe/nvs.h>
#include "3c90x.h"

Go to the source code of this file.

Functions

 FILE_LICENCE (BSD2)
static void a3c90x_internal_IssueCommand (int ioaddr, int cmd, int param)
 a3c90x_internal_IssueCommand: sends a command to the 3c90x card and waits for it's completion
static void a3c90x_internal_SetWindow (struct INF_3C90X *inf_3c90x, int window)
 a3c90x_internal_SetWindow: selects a register window set.
static void a3c90x_internal_WaitForEeprom (struct INF_3C90X *inf_3c90x)
static int a3c90x_internal_ReadEeprom (struct nvs_device *nvs, unsigned int address, void *data, size_t len)
 a3c90x_internal_ReadEeprom - nvs routine to read eeprom data We only support reading one word(2 byte).
static int a3c90x_internal_WriteEeprom (struct nvs_device *nvs __unused, unsigned int address __unused, const void *data __unused, size_t len __unused)
 a3c90x_internal_WriteEeprom - nvs routine to write eeprom data currently not implemented
static void a3c90x_internal_ReadEepromContents (struct INF_3C90X *inf_3c90x)
static void a3c90x_reset (struct INF_3C90X *inf_3c90x)
 a3c90x_reset: exported function that resets the card to its default state.
static int a3c90x_setup_tx_ring (struct INF_3C90X *p)
 a3c90x_setup_tx_ring - Allocates TX ring, initialize tx_desc values
static void a3c90x_process_tx_packets (struct net_device *netdev)
 a3c90x_process_tx_packets - Checks for successfully sent packets, reports them to iPXE with netdev_tx_complete();
static void a3c90x_free_tx_ring (struct INF_3C90X *p)
static int a3c90x_transmit (struct net_device *netdev, struct io_buffer *iob)
 a3c90x_transmit - Transmits a packet.
static void a3c90x_prepare_rx_desc (struct INF_3C90X *p, unsigned int index)
 a3c90x_prepare_rx_desc - fills the rx desc with initial data
static void a3c90x_refill_rx_ring (struct INF_3C90X *p)
 a3c90x_refill_rx_ring -checks every entry in the rx ring and reallocates them as necessary.
static int a3c90x_setup_rx_ring (struct INF_3C90X *p)
 a3c90x_setup_rx_ring - Allocates RX ring, initialize rx_desc values
static void a3c90x_free_rx_ring (struct INF_3C90X *p)
static void a3c90x_free_rx_iobuf (struct INF_3C90X *p)
static void a3c90x_process_rx_packets (struct net_device *netdev)
 a3c90x_process_rx_packets - Checks for received packets, reports them to iPXE with netdev_rx() or netdev_rx_err() if there was an error while receiving the packet
static void a3c90x_poll (struct net_device *netdev)
 a3c90x_poll - Routine that gets called periodically.
static void a3c90x_free_resources (struct INF_3C90X *p)
static void a3c90x_remove (struct pci_device *pci)
 a3c90x_remove - Routine to remove the card.
static void a3c90x_irq (struct net_device *netdev, int enable)
static void a3c90x_hw_start (struct net_device *netdev)
 a3c90x_hw_start - Initialize hardware, copy MAC address to NIC registers, set default receiver
static int a3c90x_open (struct net_device *netdev)
 a3c90x_open - Routine to initialize the card.
static void a3c90x_close (struct net_device *netdev)
 a3c90x_close - free()s TX and RX ring, disablex RX/TX, resets NIC
static int a3c90x_probe (struct pci_device *pci)
 a3c90x_probe: exported routine to probe for the 3c905 card.

Variables

static struct net_device_operations a3c90x_operations
static struct pci_device_id a3c90x_nics []
struct pci_driver a3c90x_driver __pci_driver

Function Documentation

FILE_LICENCE ( BSD2  )
static void a3c90x_internal_IssueCommand ( int  ioaddr,
int  cmd,
int  param 
) [static]

a3c90x_internal_IssueCommand: sends a command to the 3c90x card and waits for it's completion

Parameters:
ioaddrIOAddress of the NIC
cmdCommand to be issued
paramCommand parameter

Definition at line 70 of file 3c90x.c.

References DBG, DBG2, DBGP, inw(), outw(), and val.

Referenced by a3c90x_hw_start(), a3c90x_internal_SetWindow(), a3c90x_irq(), a3c90x_open(), a3c90x_poll(), a3c90x_prepare_rx_desc(), a3c90x_reset(), and a3c90x_transmit().

{
        unsigned int val = (cmd << 11) | param;
        int cnt = 0;

        DBGP("a3c90x_internal_IssueCommand\n");

        /* Send the cmd to the cmd register */
        outw(val, ioaddr + regCommandIntStatus_w);

        /* Wait for the cmd to complete */
        for (cnt = 0; cnt < 100000; cnt++) {
                if (inw(ioaddr + regCommandIntStatus_w) & INT_CMDINPROGRESS) {
                        continue;
                } else {
                        DBG2("Command 0x%04X finished in time. cnt = %d.\n", cmd, cnt);
                        return;
                }
        }

        DBG("Command 0x%04X DID NOT finish in time. cnt = %d.\n", cmd, cnt);
}
static void a3c90x_internal_SetWindow ( struct INF_3C90X *  inf_3c90x,
int  window 
) [static]

a3c90x_internal_SetWindow: selects a register window set.

Parameters:
inf_3c90xprivate NIC data
windowwindow to be selected

Definition at line 99 of file 3c90x.c.

References a3c90x_internal_IssueCommand(), and DBGP.

Referenced by a3c90x_hw_start(), a3c90x_internal_ReadEeprom(), a3c90x_open(), and a3c90x_reset().

{
        DBGP("a3c90x_internal_SetWindow\n");
        /* Window already as set? */
        if (inf_3c90x->CurrentWindow == window)
                return;

        /* Issue the window command. */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                     cmdSelectRegisterWindow, window);
        inf_3c90x->CurrentWindow = window;

        return;
}
static void a3c90x_internal_WaitForEeprom ( struct INF_3C90X *  inf_3c90x) [static]

Definition at line 114 of file 3c90x.c.

References DBG, DBGP, inw(), and udelay().

Referenced by a3c90x_internal_ReadEeprom().

{
        int cnt = 0;

        DBGP("a3c90x_internal_WaitForEeprom\n");

        while (eepromBusy & inw(inf_3c90x->IOAddr + regEepromCommand_0_w)) {
                if (cnt == EEPROM_TIMEOUT) {
                        DBG("Read from eeprom failed: timeout\n");
                        return;
                }
                udelay(1);
                cnt++;
        }
}
static int a3c90x_internal_ReadEeprom ( struct nvs_device nvs,
unsigned int  address,
void *  data,
size_t  len 
) [static]

a3c90x_internal_ReadEeprom - nvs routine to read eeprom data We only support reading one word(2 byte).

The nvs subsystem will make sure that the routine will never be called with len != 2.

Parameters:
nvsnvs data.
addresseeprom address to read data from.
datadata is put here.
lennumber of bytes to read.

Definition at line 141 of file 3c90x.c.

References a3c90x_internal_SetWindow(), a3c90x_internal_WaitForEeprom(), assert, container_of, DBGP, dest, inw(), and outw().

Referenced by a3c90x_probe().

{
        unsigned short *dest = (unsigned short *) data;
        struct INF_3C90X *inf_3c90x =
            container_of(nvs, struct INF_3C90X, nvs);

        DBGP("a3c90x_internal_ReadEeprom\n");

        /* we support reading 2 bytes only */
        assert(len == 2);

        /* Select correct window */
        a3c90x_internal_SetWindow(inf_3c90x, winEepromBios0);

        /* set eepromRead bits in command sent to NIC */
        address += (inf_3c90x->is3c556 ? eepromRead_556 : eepromRead);

        a3c90x_internal_WaitForEeprom(inf_3c90x);
        /* send address to NIC */
        outw(address, inf_3c90x->IOAddr + regEepromCommand_0_w);
        a3c90x_internal_WaitForEeprom(inf_3c90x);

        /* read value */
        *dest = inw(inf_3c90x->IOAddr + regEepromData_0_w);

        return 0;
}
static int a3c90x_internal_WriteEeprom ( struct nvs_device *nvs  __unused,
unsigned int address  __unused,
const void *data  __unused,
size_t len  __unused 
) [static]

a3c90x_internal_WriteEeprom - nvs routine to write eeprom data currently not implemented

Parameters:
nvsnvs data.
addresseeprom address to read data from.
datadata is put here.
lennumber of bytes to read.

Definition at line 179 of file 3c90x.c.

References ENOTSUP.

Referenced by a3c90x_probe().

{
        return -ENOTSUP;
}
static void a3c90x_internal_ReadEepromContents ( struct INF_3C90X *  inf_3c90x) [static]

Definition at line 186 of file 3c90x.c.

References DBGP, and nvs_read().

Referenced by a3c90x_probe().

{
        int eeprom_size = (inf_3c90x->isBrev ? 0x20 : 0x17) * 2;

        DBGP("a3c90x_internal_ReadEepromContents\n");

        nvs_read(&inf_3c90x->nvs, 0, inf_3c90x->eeprom, eeprom_size);
}
static void a3c90x_reset ( struct INF_3C90X *  inf_3c90x) [static]

a3c90x_reset: exported function that resets the card to its default state.

This is so the Linux driver can re-set the card up the way it wants to. If CFG_3C90X_PRESERVE_XCVR is defined, then the reset will not alter the selected transceiver that we used to download the boot image.

Parameters:
inf_3c90xPrivate NIC data

Definition at line 204 of file 3c90x.c.

References a3c90x_internal_IssueCommand(), a3c90x_internal_SetWindow(), DBG2, DBGP, and outw().

Referenced by a3c90x_close(), a3c90x_open(), a3c90x_probe(), and a3c90x_remove().

{
        DBGP("a3c90x_reset\n");
        /* Send the reset command to the card */
        DBG2("3c90x: Issuing RESET\n");

        /* reset of the receiver on B-revision cards re-negotiates the link
         * takes several seconds (a computer eternity), so we don't reset
         * it here.
         */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                     cmdGlobalReset,
                                     globalResetMaskNetwork);

        /* global reset command resets station mask, non-B revision cards
         * require explicit reset of values
         */
        a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
        outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 0);
        outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 2);
        outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 4);

        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0);
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0);

        /* enable rxComplete and txComplete indications */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                     cmdSetIndicationEnable,
                                     INT_TXCOMPLETE | INT_UPCOMPLETE);

        /* acknowledge any pending status flags */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                     cmdAcknowledgeInterrupt, 0x661);

        return;
}
static int a3c90x_setup_tx_ring ( struct INF_3C90X *  p) [static]

a3c90x_setup_tx_ring - Allocates TX ring, initialize tx_desc values

Parameters:
pPrivate NIC data
Return values:
Returns0 on success, negative on failure

Definition at line 248 of file 3c90x.c.

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

Referenced by a3c90x_open().

{
        DBGP("a3c90x_setup_tx_ring\n");
        p->tx_ring =
            malloc_dma(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN);

        if (!p->tx_ring) {
                DBG("Could not allocate TX-ring\n");
                return -ENOMEM;
        }

        memset(p->tx_ring, 0, TX_RING_SIZE * sizeof(struct TXD));
        p->tx_cur = 0;
        p->tx_cnt = 0;
        p->tx_tail = 0;

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

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

Parameters:
netdevNetwork device info

Definition at line 273 of file 3c90x.c.

References DBG2, DBGP, inl(), iob_len(), netdev_priv(), netdev_tx_complete(), TX_RING_SIZE, and virt_to_bus().

Referenced by a3c90x_poll().

{
        struct INF_3C90X *p = netdev_priv(netdev);
        unsigned int downlist_ptr;

        DBGP("a3c90x_process_tx_packets\n");

        DBG2("    tx_cnt: %d\n", p->tx_cnt);

        while (p->tx_tail != p->tx_cur) {

                downlist_ptr = inl(p->IOAddr + regDnListPtr_l);

                DBG2("    downlist_ptr: %#08x\n", downlist_ptr);
                DBG2("    tx_tail: %d tx_cur: %d\n", p->tx_tail, p->tx_cur);

                /* NIC is currently working on this tx desc */
                if(downlist_ptr == virt_to_bus(p->tx_ring + p->tx_tail))
                        return;

                netdev_tx_complete(netdev, p->tx_iobuf[p->tx_tail]);

                DBG2("transmitted packet\n");
                DBG2("    size: %zd\n", iob_len(p->tx_iobuf[p->tx_tail]));

                p->tx_tail = (p->tx_tail + 1) % TX_RING_SIZE;
                p->tx_cnt--;
        }
}
static void a3c90x_free_tx_ring ( struct INF_3C90X *  p) [static]

Definition at line 303 of file 3c90x.c.

References DBGP, free_dma(), NULL, and TX_RING_SIZE.

Referenced by a3c90x_free_resources().

{
        DBGP("a3c90x_free_tx_ring\n");

        free_dma(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD));
        p->tx_ring = NULL;
        /* io_buffers are free()ed by netdev_tx_complete[,_err]() */
}
static int a3c90x_transmit ( struct net_device netdev,
struct io_buffer iob 
) [static]

a3c90x_transmit - Transmits a packet.

Parameters:
netdevNetwork device info
iobio_buffer containing the data to be send
Return values:
Returns0 on success, negative on failure

Definition at line 320 of file 3c90x.c.

References a3c90x_internal_IssueCommand(), io_buffer::data, DBG, DBGP, ENOBUFS, inl(), iob_len(), len, netdev_priv(), outl(), TX_RING_SIZE, and virt_to_bus().

{
        struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
        struct TXD *tx_cur_desc;
        struct TXD *tx_prev_desc;

        unsigned int len;
        unsigned int downlist_ptr;

        DBGP("a3c90x_transmit\n");

        if (inf_3c90x->tx_cnt == TX_RING_SIZE) {
                DBG("TX-Ring overflow\n");
                return -ENOBUFS;
        }

        inf_3c90x->tx_iobuf[inf_3c90x->tx_cur] = iob;
        tx_cur_desc = inf_3c90x->tx_ring + inf_3c90x->tx_cur;

        tx_prev_desc = inf_3c90x->tx_ring +
            (((inf_3c90x->tx_cur + TX_RING_SIZE) - 1) % TX_RING_SIZE);

        len = iob_len(iob);

        /* Setup the DPD (download descriptor) */
        tx_cur_desc->DnNextPtr = 0;

        /* FrameStartHeader differs in 90x and >= 90xB
         * It contains the packet length in 90x and a round up boundary and
         * packet ID for 90xB and 90xC. Disable packet length round-up on the
         * later revisions.
         */
        tx_cur_desc->FrameStartHeader =
            fshTxIndicate | (inf_3c90x->isBrev ? fshRndupDefeat : len);

        tx_cur_desc->DataAddr = virt_to_bus(iob->data);
        tx_cur_desc->DataLength = len | downLastFrag;

        /* We have to stall the download engine, so the NIC won't access the
         * tx descriptor while we modify it. There is a way around this
         * from revision B and upwards. To stay compatible with older revisions
         * we don't use it here.
         */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl,
                                     dnStall);

        tx_prev_desc->DnNextPtr = virt_to_bus(tx_cur_desc);

        downlist_ptr = inl(inf_3c90x->IOAddr + regDnListPtr_l);
        if (downlist_ptr == 0) {
                /* currently no DownList, sending a new one */
                outl(virt_to_bus(tx_cur_desc),
                     inf_3c90x->IOAddr + regDnListPtr_l);
        }

        /* End Stall */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl,
                                     dnUnStall);

        inf_3c90x->tx_cur = (inf_3c90x->tx_cur + 1) % TX_RING_SIZE;
        inf_3c90x->tx_cnt++;

        return 0;
}
static void a3c90x_prepare_rx_desc ( struct INF_3C90X *  p,
unsigned int  index 
) [static]

a3c90x_prepare_rx_desc - fills the rx desc with initial data

Parameters:
pNIC private data
indexIndex for rx_iobuf and rx_ring array

Definition at line 393 of file 3c90x.c.

References a3c90x_internal_IssueCommand(), DBG2, DBGP, index, RX_BUF_SIZE, and virt_to_bus().

Referenced by a3c90x_refill_rx_ring().

{
        DBGP("a3c90x_prepare_rx_desc\n");
        DBG2("Populating rx_desc %d\n", index);

        /* We have to stall the upload engine, so the NIC won't access the
         * rx descriptor while we modify it. There is a way around this
         * from revision B and upwards. To stay compatible with older revisions
         * we don't use it here.
         */
        a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upStall);

        p->rx_ring[index].DataAddr = virt_to_bus(p->rx_iobuf[index]->data);
        p->rx_ring[index].DataLength = RX_BUF_SIZE | upLastFrag;
        p->rx_ring[index].UpPktStatus = 0;

        /* unstall upload engine */
        a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upUnStall);
}
static void a3c90x_refill_rx_ring ( struct INF_3C90X *  p) [static]

a3c90x_refill_rx_ring -checks every entry in the rx ring and reallocates them as necessary.

Then it calls a3c90x_prepare_rx_desc to fill the rx desc with initial data.

Parameters:
pNIC private data

Definition at line 420 of file 3c90x.c.

References a3c90x_prepare_rx_desc(), alloc_iob(), DBG, DBGP, NULL, RX_BUF_SIZE, RX_RING_SIZE, and status.

Referenced by a3c90x_process_rx_packets(), and a3c90x_setup_rx_ring().

{
        int i;
        unsigned int status;
        struct RXD *rx_cur_desc;

        DBGP("a3c90x_refill_rx_ring\n");

        for (i = 0; i < RX_RING_SIZE; i++) {
                rx_cur_desc = p->rx_ring + i;
                status = rx_cur_desc->UpPktStatus;

                /* only refill used descriptor */
                if (!(status & upComplete))
                        continue;

                /* we still need to process this descriptor */
                if (p->rx_iobuf[i] != NULL)
                        continue;

                p->rx_iobuf[i] = alloc_iob(RX_BUF_SIZE);
                if (p->rx_iobuf[i] == NULL) {
                        DBG("alloc_iob() failed\n");
                        break;
                }

                a3c90x_prepare_rx_desc(p, i);
        }
}
static int a3c90x_setup_rx_ring ( struct INF_3C90X *  p) [static]

a3c90x_setup_rx_ring - Allocates RX ring, initialize rx_desc values

Parameters:
pPrivate NIC data
Return values:
Returns0 on success, negative on failure

Definition at line 457 of file 3c90x.c.

References a3c90x_refill_rx_ring(), DBG, DBGP, ENOMEM, malloc_dma(), NULL, RX_RING_ALIGN, RX_RING_SIZE, and virt_to_bus().

Referenced by a3c90x_open().

{
        int i;

        DBGP("a3c90x_setup_rx_ring\n");

        p->rx_ring =
            malloc_dma(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN);

        if (!p->rx_ring) {
                DBG("Could not allocate RX-ring\n");
                return -ENOMEM;
        }

        p->rx_cur = 0;

        for (i = 0; i < RX_RING_SIZE; i++) {
                p->rx_ring[i].UpNextPtr =
                    virt_to_bus(p->rx_ring + (i + 1));

                /* these are needed so refill_rx_ring initializes the ring */
                p->rx_ring[i].UpPktStatus = upComplete;
                p->rx_iobuf[i] = NULL;
        }

        /* Loop the ring */
        p->rx_ring[i - 1].UpNextPtr = virt_to_bus(p->rx_ring);

        a3c90x_refill_rx_ring(p);

        return 0;
}
static void a3c90x_free_rx_ring ( struct INF_3C90X *  p) [static]

Definition at line 490 of file 3c90x.c.

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

Referenced by a3c90x_free_resources().

{
        DBGP("a3c90x_free_rx_ring\n");

        free_dma(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD));
        p->rx_ring = NULL;
}
static void a3c90x_free_rx_iobuf ( struct INF_3C90X *  p) [static]

Definition at line 498 of file 3c90x.c.

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

Referenced by a3c90x_free_resources().

{
        int i;

        DBGP("a3c90x_free_rx_iobuf\n");

        for (i = 0; i < RX_RING_SIZE; i++) {
                free_iob(p->rx_iobuf[i]);
                p->rx_iobuf[i] = NULL;
        }
}
static void a3c90x_process_rx_packets ( struct net_device netdev) [static]

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

Parameters:
netdevNetwork device info

Definition at line 517 of file 3c90x.c.

References a3c90x_refill_rx_ring(), DBG, DBG2, DBGP, EINVAL, iob_put, netdev_priv(), netdev_rx(), netdev_rx_err(), NULL, and RX_RING_SIZE.

Referenced by a3c90x_poll().

{
        int i;
        unsigned int rx_status;
        struct INF_3C90X *p = netdev_priv(netdev);
        struct RXD *rx_cur_desc;

        DBGP("a3c90x_process_rx_packets\n");

        for (i = 0; i < RX_RING_SIZE; i++) {
                rx_cur_desc = p->rx_ring + p->rx_cur;
                rx_status = rx_cur_desc->UpPktStatus;

                if (!(rx_status & upComplete) && !(rx_status & upError))
                        break;

                if (p->rx_iobuf[p->rx_cur] == NULL)
                        break;

                if (rx_status & upError) {
                        DBG("Corrupted packet received: %#x\n", rx_status);
                        netdev_rx_err(netdev, p->rx_iobuf[p->rx_cur],
                                      -EINVAL);
                } else {
                        /* if we're here, we've got good packet */
                        int packet_len;

                        packet_len = rx_status & 0x1FFF;
                        iob_put(p->rx_iobuf[p->rx_cur], packet_len);

                        DBG2("received packet\n");
                        DBG2("    size: %d\n", packet_len);

                        netdev_rx(netdev, p->rx_iobuf[p->rx_cur]);
                }

                p->rx_iobuf[p->rx_cur] = NULL;  /* invalidate rx desc */
                p->rx_cur = (p->rx_cur + 1) % RX_RING_SIZE;
        }
        a3c90x_refill_rx_ring(p);

}
static void a3c90x_poll ( struct net_device netdev) [static]

a3c90x_poll - Routine that gets called periodically.

Here we hanle transmitted and received packets. We could also check the link status from time to time, which we currently don't do.

Parameters:
netdevNetwork device info

Definition at line 568 of file 3c90x.c.

References a3c90x_internal_IssueCommand(), a3c90x_process_rx_packets(), a3c90x_process_tx_packets(), DBG2, DBGP, inw(), netdev_priv(), and outb().

{
        struct INF_3C90X *p = netdev_priv(netdev);
        uint16_t raw_status, int_status;

        DBGP("a3c90x_poll\n");

        raw_status = inw(p->IOAddr + regCommandIntStatus_w);
        int_status = (raw_status & 0x0FFF);

        if ( int_status == 0 )
                return;

        a3c90x_internal_IssueCommand(p->IOAddr, cmdAcknowledgeInterrupt,
                                     int_status);

        if (int_status & INT_TXCOMPLETE)
                outb(0x00, p->IOAddr + regTxStatus_b);

        DBG2("poll: status = %#04x\n", raw_status);

        a3c90x_process_tx_packets(netdev);

        a3c90x_process_rx_packets(netdev);
}
static void a3c90x_free_resources ( struct INF_3C90X *  p) [static]

Definition at line 596 of file 3c90x.c.

References a3c90x_free_rx_iobuf(), a3c90x_free_rx_ring(), a3c90x_free_tx_ring(), and DBGP.

Referenced by a3c90x_close(), and a3c90x_open().

{
        DBGP("a3c90x_free_resources\n");

        a3c90x_free_tx_ring(p);
        a3c90x_free_rx_ring(p);
        a3c90x_free_rx_iobuf(p);
}
static void a3c90x_remove ( struct pci_device pci) [static]

a3c90x_remove - Routine to remove the card.

Unregisters the NIC from iPXE, disables RX/TX and resets the card.

Parameters:
pciPCI device info

Definition at line 611 of file 3c90x.c.

References a3c90x_reset(), DBGP, netdev, netdev_nullify(), netdev_priv(), netdev_put(), outw(), pci_get_drvdata(), and unregister_netdev().

{
        struct net_device *netdev = pci_get_drvdata(pci);
        struct INF_3C90X *inf_3c90x = netdev_priv(netdev);

        DBGP("a3c90x_remove\n");

        a3c90x_reset(inf_3c90x);

        /* Disable the receiver and transmitter. */
        outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
        outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);

        unregister_netdev(netdev);
        netdev_nullify(netdev);
        netdev_put(netdev);
}
static void a3c90x_irq ( struct net_device netdev,
int  enable 
) [static]

Definition at line 629 of file 3c90x.c.

References a3c90x_internal_IssueCommand(), DBGP, and netdev_priv().

{
        struct INF_3C90X *p = netdev_priv(netdev);

        DBGP("a3c90x_irq\n");

        if (enable == 0) {
                /* disable interrupts */
                a3c90x_internal_IssueCommand(p->IOAddr,
                                             cmdSetInterruptEnable, 0);
        } else {
                a3c90x_internal_IssueCommand(p->IOAddr,
                                             cmdSetInterruptEnable,
                                             INT_TXCOMPLETE |
                                             INT_UPCOMPLETE);
                a3c90x_internal_IssueCommand(p->IOAddr,
                                             cmdAcknowledgeInterrupt,
                                             0x661);
        }
}
static void a3c90x_hw_start ( struct net_device netdev) [static]

a3c90x_hw_start - Initialize hardware, copy MAC address to NIC registers, set default receiver

Definition at line 654 of file 3c90x.c.

References a3c90x_internal_IssueCommand(), a3c90x_internal_SetWindow(), cfg, DBG, DBG2, DBGP, ETH_ALEN, inl(), inw(), net_device::ll_addr, netdev_priv(), outb(), outl(), and outw().

Referenced by a3c90x_open().

{
        int i, c;
        unsigned int cfg;
        unsigned int mopt;
        unsigned short linktype;
        struct INF_3C90X *inf_3c90x = netdev_priv(netdev);

        DBGP("a3c90x_hw_start\n");

        /* 3C556: Invert MII power */
        if (inf_3c90x->is3c556) {
                unsigned int tmp;
                a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
                tmp = inw(inf_3c90x->IOAddr + regResetOptions_2_w);
                tmp |= 0x4000;
                outw(tmp, inf_3c90x->IOAddr + regResetOptions_2_w);
        }

        /* Copy MAC address into the NIC registers */
        a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
        for (i = 0; i < ETH_ALEN; i++)
                outb(netdev->ll_addr[i],
                     inf_3c90x->IOAddr + regStationAddress_2_3w + i);
        for (i = 0; i < ETH_ALEN; i++)
                outb(0, inf_3c90x->IOAddr + regStationMask_2_3w + i);

        /* Read the media options register, print a message and set default
        * xcvr.
        *
        * Uses Media Option command on B revision, Reset Option on non-B
        * revision cards -- same register address
        */
        a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3);
        mopt = inw(inf_3c90x->IOAddr + regResetMediaOptions_3_w);

        /* mask out VCO bit that is defined as 10baseFL bit on B-rev cards */
        if (!inf_3c90x->isBrev) {
                mopt &= 0x7F;
        }

        DBG2("Connectors present: ");
        c = 0;
        linktype = 0x0008;
        if (mopt & 0x01) {
                DBG2("%s100Base-T4", (c++) ? ", " : "");
                linktype = linkMII;
        }
        if (mopt & 0x04) {
                DBG2("%s100Base-FX", (c++) ? ", " : "");
                linktype = link100BaseFX;
        }
        if (mopt & 0x10) {
                DBG2("%s10Base-2", (c++) ? ", " : "");
                linktype = link10Base2;
        }
        if (mopt & 0x20) {
                DBG2("%sAUI", (c++) ? ", " : "");
                linktype = linkAUI;
        }
        if (mopt & 0x40) {
                DBG2("%sMII", (c++) ? ", " : "");
                linktype = linkMII;
        }
        if ((mopt & 0xA) == 0xA) {
                DBG2("%s10Base-T / 100Base-TX", (c++) ? ", " : "");
                linktype = linkAutoneg;
        } else if ((mopt & 0xA) == 0x2) {
                DBG2("%s100Base-TX", (c++) ? ", " : "");
                linktype = linkAutoneg;
        } else if ((mopt & 0xA) == 0x8) {
                DBG2("%s10Base-T", (c++) ? ", " : "");
                linktype = linkAutoneg;
        }
        DBG2(".\n");

        /* Determine transceiver type to use, depending on value stored in
        * eeprom 0x16
        */
        if (inf_3c90x->isBrev) {
                if ((inf_3c90x->eeprom[0x16] & 0xFF00) == XCVR_MAGIC) {
                        /* User-defined */
                        linktype = inf_3c90x->eeprom[0x16] & 0x000F;
                }
        } else {
                /* I don't know what MII MAC only mode is!!! */
                if (linktype == linkExternalMII) {
                        if (inf_3c90x->isBrev)
                                DBG("WARNING: MII External MAC Mode only supported on B-revision " "cards!!!!\nFalling Back to MII Mode\n");
                        linktype = linkMII;
                }
        }

        /* enable DC converter for 10-Base-T */
        if (linktype == link10Base2) {
                a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                             cmdEnableDcConverter, 0);
        }

        /* Set the link to the type we just determined. */
        a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3);
        cfg = inl(inf_3c90x->IOAddr + regInternalConfig_3_l);
        cfg &= ~(0xF << 20);
        cfg |= (linktype << 20);

        DBG2("Setting internal cfg register: 0x%08X (linktype: 0x%02X)\n",
            cfg, linktype);

        outl(cfg, inf_3c90x->IOAddr + regInternalConfig_3_l);

        /* Now that we set the xcvr type, reset the Tx and Rx */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxReset, 0x00);

        if (!inf_3c90x->isBrev)
                outb(0x01, inf_3c90x->IOAddr + regTxFreeThresh_b);

        /* Set the RX filter = receive only individual pkts & multicast & bcast. */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdSetRxFilter,
                                     0x01 + 0x02 + 0x04);


        /*
        * set Indication and Interrupt flags , acknowledge any IRQ's
        */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                     cmdSetInterruptEnable,
         INT_TXCOMPLETE | INT_UPCOMPLETE);
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                     cmdSetIndicationEnable,
         INT_TXCOMPLETE | INT_UPCOMPLETE);
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
                                     cmdAcknowledgeInterrupt, 0x661);
}
static int a3c90x_open ( struct net_device netdev) [static]

a3c90x_open - Routine to initialize the card.

Initialize hardware, allocate TX and RX ring, send RX ring address to the NIC.

Parameters:
netdevNetwork device info
Return values:
Returns0 on success, negative on failure

Definition at line 796 of file 3c90x.c.

References a3c90x_free_resources(), a3c90x_hw_start(), a3c90x_internal_IssueCommand(), a3c90x_internal_SetWindow(), a3c90x_reset(), a3c90x_setup_rx_ring(), a3c90x_setup_tx_ring(), DBG, DBGP, error, netdev_priv(), outl(), rc, RX_BUF_SIZE, and virt_to_bus().

{
        int rc;
        struct INF_3C90X *inf_3c90x = netdev_priv(netdev);

        DBGP("a3c90x_open\n");

        a3c90x_hw_start(netdev);

        rc = a3c90x_setup_tx_ring(inf_3c90x);
        if (rc != 0) {
                DBG("Error setting up TX Ring\n");
                goto error;
        }

        rc = a3c90x_setup_rx_ring(inf_3c90x);
        if (rc != 0) {
                DBG("Error setting up RX Ring\n");
                goto error;
        }

        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl, upStall);

        /* send rx_ring address to NIC */
        outl(virt_to_bus(inf_3c90x->rx_ring),
             inf_3c90x->IOAddr + regUpListPtr_l);

        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl, upUnStall);

        /* set maximum allowed receive packet length */
        a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3);
        outl(RX_BUF_SIZE, inf_3c90x->IOAddr + regMaxPktSize_3_w);

        /* enable packet transmission and reception */
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0);
        a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0);

        return 0;

      error:
        a3c90x_free_resources(inf_3c90x);
        a3c90x_reset(inf_3c90x);
        return rc;
}
static void a3c90x_close ( struct net_device netdev) [static]

a3c90x_close - free()s TX and RX ring, disablex RX/TX, resets NIC

Parameters:
netdevNetwork device info

Definition at line 846 of file 3c90x.c.

References a3c90x_free_resources(), a3c90x_reset(), DBGP, netdev_priv(), and outw().

{
        struct INF_3C90X *inf_3c90x = netdev_priv(netdev);

        DBGP("a3c90x_close\n");

        a3c90x_reset(inf_3c90x);
        outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
        outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
        a3c90x_free_resources(inf_3c90x);
}
static int a3c90x_probe ( struct pci_device pci) [static]

a3c90x_probe: exported routine to probe for the 3c905 card.

If this routine is called, the pci functions did find the card. We read the eeprom here and get the MAC address. Initialization is done in a3c90x_open().

Parameters:
pciPCI device info @ pci_id PCI device IDs
Return values:
rcReturns 0 on success, negative on failure

Definition at line 877 of file 3c90x.c.

References a3c90x_internal_ReadEeprom(), a3c90x_internal_ReadEepromContents(), a3c90x_internal_WriteEeprom(), a3c90x_reset(), adjust_pci_device(), alloc_etherdev(), DBG, DBG2, DBGP, pci_device::dev, net_device::dev, pci_device::device, EINVAL, ENOMEM, net_device::hw_addr, pci_device::ioaddr, memset(), netdev, netdev_init(), netdev_link_up(), netdev_priv(), netdev_put(), pci_set_drvdata(), rc, register_netdev(), and pci_device::vendor.

{

        struct net_device *netdev;
        struct INF_3C90X *inf_3c90x;
        unsigned char *HWAddr;
        int rc;

        DBGP("a3c90x_probe\n");

        if (pci->ioaddr == 0)
                return -EINVAL;

        netdev = alloc_etherdev(sizeof(*inf_3c90x));
        if (!netdev)
                return -ENOMEM;

        netdev_init(netdev, &a3c90x_operations);
        pci_set_drvdata(pci, netdev);
        netdev->dev = &pci->dev;

        inf_3c90x = netdev_priv(netdev);
        memset(inf_3c90x, 0, sizeof(*inf_3c90x));

        adjust_pci_device(pci);

        inf_3c90x->is3c556 = (pci->device == 0x6055);
        inf_3c90x->IOAddr = pci->ioaddr;
        inf_3c90x->CurrentWindow = winNone;

        inf_3c90x->isBrev = 1;
        switch (pci->device) {
        case 0x9000:            /* 10 Base TPO             */
        case 0x9001:            /* 10/100 T4               */
        case 0x9050:            /* 10/100 TPO              */
        case 0x9051:            /* 10 Base Combo           */
                inf_3c90x->isBrev = 0;
                break;
        }

        DBG2("[3c90x]: found NIC(0x%04X, 0x%04X), isBrev=%d, is3c556=%d\n",
            pci->vendor, pci->device, inf_3c90x->isBrev,
            inf_3c90x->is3c556);

        /* initialize nvs device */
        inf_3c90x->nvs.word_len_log2 = 1;       /* word */
        inf_3c90x->nvs.size = (inf_3c90x->isBrev ? 0x20 : 0x17);
        inf_3c90x->nvs.block_size = 1;
        inf_3c90x->nvs.read = a3c90x_internal_ReadEeprom;
        inf_3c90x->nvs.write = a3c90x_internal_WriteEeprom;

        /* reset NIC before accessing any data from it */
        a3c90x_reset(inf_3c90x);

        /* load eeprom contents to inf_3c90x->eeprom */
        a3c90x_internal_ReadEepromContents(inf_3c90x);

        HWAddr = netdev->hw_addr;

        /* Retrieve the Hardware address */
        HWAddr[0] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] >> 8;
        HWAddr[1] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] & 0xFF;
        HWAddr[2] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] >> 8;
        HWAddr[3] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] & 0xFF;
        HWAddr[4] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] >> 8;
        HWAddr[5] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] & 0xFF;

        if ((rc = register_netdev(netdev)) != 0) {
                DBG("3c90x: register_netdev() failed\n");
                netdev_put(netdev);
                return rc;
        }

        /* we don't handle linkstates yet, so we're always up */
        netdev_link_up(netdev);

        return 0;
}

Variable Documentation

Initial value:
 {
        .open = a3c90x_open,
        .close = a3c90x_close,
        .poll = a3c90x_poll,
        .transmit = a3c90x_transmit,
        .irq = a3c90x_irq,
}

Definition at line 858 of file 3c90x.c.

struct pci_device_id a3c90x_nics[] [static]
Initial value:
 {

        PCI_ROM(0x10b7, 0x6055, "3c556", "3C556", 0),   
        PCI_ROM(0x10b7, 0x9000, "3c905-tpo", "3Com900-TPO", 0), 
        PCI_ROM(0x10b7, 0x9001, "3c905-t4", "3Com900-Combo", 0),        
        PCI_ROM(0x10b7, 0x9050, "3c905-tpo100", "3Com905-TX", 0),       
        PCI_ROM(0x10b7, 0x9051, "3c905-combo", "3Com905-T4", 0),        

        PCI_ROM(0x10b7, 0x9004, "3c905b-tpo", "3Com900B-TPO", 0),       
        PCI_ROM(0x10b7, 0x9005, "3c905b-combo", "3Com900B-Combo", 0),   
        PCI_ROM(0x10b7, 0x9006, "3c905b-tpb2", "3Com900B-2/T", 0),      
        PCI_ROM(0x10b7, 0x900a, "3c905b-fl", "3Com900B-FL", 0), 
        PCI_ROM(0x10b7, 0x9055, "3c905b-tpo100", "3Com905B-TX", 0),     
        PCI_ROM(0x10b7, 0x9056, "3c905b-t4", "3Com905B-T4", 0), 
        PCI_ROM(0x10b7, 0x9058, "3c905b-9058", "3Com905B-9058", 0),     
        PCI_ROM(0x10b7, 0x905a, "3c905b-fx", "3Com905B-FL", 0), 

        PCI_ROM(0x10b7, 0x9200, "3c905c-tpo", "3Com905C-TXM", 0),       
        PCI_ROM(0x10b7, 0x9202, "3c920b-emb-ati", "3c920B-EMB-WNM (ATI Radeon 9100 IGP)", 0),   
        PCI_ROM(0x10b7, 0x9210, "3c920b-emb-wnm", "3Com20B-EMB WNM", 0),
        PCI_ROM(0x10b7, 0x9800, "3c980", "3Com980-Cyclone", 0), 
        PCI_ROM(0x10b7, 0x9805, "3c9805", "3Com9805", 0),       
        PCI_ROM(0x10b7, 0x7646, "3csoho100-tx", "3CSOHO100-TX", 0),     
        PCI_ROM(0x10b7, 0x4500, "3c450", "3Com450 HomePNA Tornado", 0),
        PCI_ROM(0x10b7, 0x1201, "3c982a", "3Com982A", 0),
        PCI_ROM(0x10b7, 0x1202, "3c982b", "3Com982B", 0),
}

Definition at line 956 of file 3c90x.c.

struct pci_driver a3c90x_driver __pci_driver
Initial value:
 {
        .ids = a3c90x_nics,
        .id_count = (sizeof(a3c90x_nics) / sizeof(a3c90x_nics[0])),
        .probe = a3c90x_probe,
        .remove = a3c90x_remove,
}

Definition at line 984 of file 3c90x.c.