Package org.jnode.driver.net.lance

Source Code of org.jnode.driver.net.lance.LanceCore

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.driver.net.lance;

import java.security.PrivilegedExceptionAction;
import javax.naming.NameNotFoundException;
import org.jnode.driver.DriverException;
import org.jnode.driver.bus.pci.PCIBaseAddress;
import org.jnode.driver.bus.pci.PCIConstants;
import org.jnode.driver.bus.pci.PCIDevice;
import org.jnode.driver.bus.pci.PCIHeaderType0;
import org.jnode.driver.net.NetworkException;
import org.jnode.driver.net.ethernet.spi.Flags;
import org.jnode.driver.net.spi.AbstractDeviceCore;
import org.jnode.naming.InitialNaming;
import org.jnode.net.HardwareAddress;
import org.jnode.net.SocketBuffer;
import org.jnode.net.ethernet.EthernetAddress;
import org.jnode.net.ethernet.EthernetConstants;
import org.jnode.system.resource.IOResource;
import org.jnode.system.resource.IRQHandler;
import org.jnode.system.resource.IRQResource;
import org.jnode.system.resource.ResourceManager;
import org.jnode.system.resource.ResourceNotFreeException;
import org.jnode.system.resource.ResourceOwner;
import org.jnode.util.AccessControllerUtils;
import org.jnode.util.NumberUtils;
import org.jnode.util.TimeoutException;

/**
* This is the DeviceCore for LANCE and PCnet 32 compatable ethernet PCI drivers.
* <p/>
* The current implementation was specificaly designed for the AMD PCnet-PCI II
* Ethernet Controller (Am79C970A), but should work for other AMD PCnet PCI devices.
* The driver is based on information in the following specification from AMD.
* http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/19436.pdf
* <p/>
* Specificaly the following assumptions were made:
* - Device supports Software Style 2 (PCnet-PCI) which defines the layout of the initialaztion
* block and the descriptor rings.
* <p/>
* Note: It should be easy to expand this driver to remove these assuptions.
*
* @author Chirs Cole
*/
public class LanceCore extends AbstractDeviceCore implements IRQHandler, LanceConstants,
        EthernetConstants {

    // This is the number of descriptors for the receive and transmit rings
    // Note: Valid numbers are 2^x where x is 0..8 (1, 2, 4, 8, 16, .., 512)
    private static final int RX_DESCRIPTOR_LENGTH = 4;
    private static final int TX_DESCRIPTOR_LENGTH = 4;

    /**
     * Device Driver
     */
    private final LanceDriver driver;
   
    /**
     * Start of IO address space
     */
    private final int iobase;
   
    /**
     * IO address space resource
     */
    private final IOResource ioResource;
    private final IOAccess io;
   
    /**
     * IRQ resource
     */
    private final IRQResource irq;
   
    /**
     * My ethernet address
     */
    private EthernetAddress hwAddress;
   
    /**
     * Flags for the specific device found
     */
    private final LanceFlags flags;
   
    /**
     * Manager for receive and transmit rings as well as data buffers
     */
    private final BufferManager bufferManager;

    /**
     * Create a new instance and allocate all resources
     *
     * @throws ResourceNotFreeException
     */
    public LanceCore(LanceDriver driver, ResourceOwner owner, PCIDevice device, Flags flags)
        throws ResourceNotFreeException, DriverException {
        this.driver = driver;
        this.flags = (LanceFlags) flags;

        final PCIHeaderType0 config = device.getConfig().asHeaderType0();
        final int irq = config.getInterruptLine();

        final PCIBaseAddress[] addrs = config.getBaseAddresses();
        if (addrs.length < 1) {
            throw new DriverException("Cannot find iobase: not base addresses");
        }
        if (!addrs[0].isIOSpace()) {
            throw new DriverException("Cannot find iobase: first address is not I/O");
        }

        // Get the start of the IO address space
        iobase = addrs[0].getIOBase();
        final int iolength = addrs[0].getSize();
        log.debug("Found Lance IOBase: 0x" + NumberUtils.hex(iobase) + ", length: " + iolength);
        ResourceManager rm;
        try {
            rm = InitialNaming.lookup(ResourceManager.NAME);
        } catch (NameNotFoundException ex) {
            throw new DriverException("Cannot find ResourceManager");
        }
        this.irq = rm.claimIRQ(owner, irq, this, true);
        try {
            ioResource = claimPorts(rm, owner, iobase, iolength);
        } catch (ResourceNotFreeException ex) {
            this.irq.release();
            throw ex;
        }

        // Determine the type of IO access (Word or DWord)
        io = getIOAccess();
        log.debug("IO Access set to " + io.getType());

        // Set the flags based on the version of the device found
        setFlags();

        // Load the hw address
        this.hwAddress = loadHWAddress();

        log.info("Found " + this.flags.getChipName() + " at 0x" + NumberUtils.hex(iobase, 4) +
                " with MAC Address " + hwAddress);

        // Create rx & tx descriptor rings, initdata and databuffers
        this.bufferManager =
                new BufferManager(RX_DESCRIPTOR_LENGTH, TX_DESCRIPTOR_LENGTH,
                        CSR15_DRX | CSR15_DTX, hwAddress, 0, rm, owner);

        // Enable device to become a bus master on the PCI bus.
        config.setCommand(config.getCommand() | PCIConstants.PCI_COMMAND_MASTER);
    }

    private IOAccess getIOAccess() {
        // reset
        ioResource.inPortWord(iobase + WIO_RESET);
        ioResource.outPortWord(iobase + WIO_RAP, 0);
        if (ioResource.inPortWord(iobase + WIO_RDP) == 4) {
            ioResource.outPortWord(iobase + WIO_RAP, 88);
            if (ioResource.inPortWord(iobase + WIO_RAP) == 88) {
                return new WordIOAccess(ioResource, iobase);
            }
        }

        ioResource.inPortDword(iobase + DWIO_RESET);
        ioResource.outPortDword(iobase + DWIO_RAP, 0);
        if (ioResource.inPortDword(iobase + DWIO_RDP) == 4) {
            ioResource.outPortDword(iobase + DWIO_RAP, 88);
            if ((ioResource.inPortDword(iobase + DWIO_RAP) & 0xFFFF) == 88) {
                return new DWordIOAccess(ioResource, iobase);
            }
        }
        return null;
    }

    /**
     * Initialize this device.
     */
    public void initialize() {
        // reset the chip
        io.reset();

        // Set the Software Style to mode 2 (PCnet-PCI)
        // Note: this may not be compatable with older lance controllers (non PCnet)
        io.setBCR(20, 2);

        // TODO the device should be setup based on the flags for the chip version
        // Auto select port
        io.setBCR(2, BCR2_ASEL);
        // Enable full duplex
        io.setBCR(9, BCR9_FDEN);
        io.setCSR(4, CSR4_DMAPLUS | CSR4_APAD_XMT);
        io.setCSR(5, CSR5_LTINTEN | CSR5_SINTE | CSR5_SLPINTE | CSR5_EXDINTE | CSR5_MPINTE);

        // Set the address of the Initialization Block
        final int iaddr = bufferManager.getInitDataAddressAs32Bit();
        io.setCSR(1, iaddr & 0xFFFF);
        io.setCSR(2, (iaddr >> 16) & 0xFFFF);

        // Initialize the device with the Initialization Block and enable interrupts
        io.setCSR(0, CSR0_INIT | CSR0_IENA);
    }

    /**
     * Disable this device
     */
    public void disable() {
        io.reset();
        io.setCSR(0, CSR0_STOP);
    }

    /**
     * Release all resources
     */
    public void release() {
        ioResource.release();
        irq.release();
    }

    /**
     * Gets the hardware address of this card.
     */
    public HardwareAddress getHwAddress() {
        return hwAddress;
    }

    /**
     * Read the hardware address
     */
    private final EthernetAddress loadHWAddress() {
        final byte[] addr = new byte[ETH_ALEN];
        for (int i = 0; i < addr.length; i++) {
            addr[i] = (byte) ioResource.inPortByte(iobase + R_ETH_ADDR_OFFSET + i);
        }
        return new EthernetAddress(addr, 0);
    }

    private final void setFlags() {
        int chipVersion = io.getCSR(88) | (io.getCSR(89) << 16);
        chipVersion = (chipVersion >> 12) & 0xffff;

        flags.setForVersion(chipVersion);
    }

    /**
     * Transmit the given buffer
     *
     * @param buf
     * @param timeout
     * @throws InterruptedException
     * @throws TimeoutException
     */
    public synchronized void transmit(SocketBuffer buf, HardwareAddress destination, long timeout)
        throws InterruptedException, TimeoutException {
        // Set the source address
        hwAddress.writeTo(buf, 6);

        // debug dump for investigating VWWare 3 network problems
        // dumpDebugInfo();

        // ask buffer manager to send out the data
        bufferManager.transmit(buf);

        // force the device to poll current transmit descriptor for new data
        io.setCSR(0, io.getCSR(0) | CSR0_TDMD);
    }

    /**
     * @see org.jnode.system.resource.IRQHandler#handleInterrupt(int)
     */
    public void handleInterrupt(int irq) {
        while ((io.getCSR(0) & CSR0_INTR) != 0) {
            final int csr0 = io.getCSR(0);
            final int csr4 = io.getCSR(4);
            final int csr5 = io.getCSR(5);

            io.setCSR(0, csr0);
            io.setCSR(4, csr4);
            io.setCSR(5, csr5);

            // check if interrupt is due to Initialization Done
            if ((csr0 & CSR0_IDON) != 0) {
                log.info(flags.getChipName() + " Initialization Complete");

                // Now enable RX/TX
                io.setCSR(15, 0);

                // assert the Start and clear Initialization Done (IDON) flag
                // Note: there are reported errors due to setting IDON here but I have not seen any
                io.setCSR(0, CSR0_STRT | CSR0_IENA | CSR0_IDON);
            }

            // check if interrupt is due to Transmition Interrupt
            if ((csr0 & CSR0_TINT) != 0) {
                //log.debug("Transmition Interrupt");
            }

            // check if interrupt is due to Receive Interrupt
            if ((csr0 & CSR0_RINT) != 0) {
                //log.debug("Receive Interrupt");
                rxProcess();
            }

            // check if interrupt is due an error
            if ((csr0 & CSR0_ERR) != 0) {
                log.debug("Error Interrupt");

                // check if interrupt is due to Memory Error
                if ((csr0 & CSR0_MERR) != 0) {
                    log.debug("Memory Error");
                }

                // check if interrupt is due to Missed Frame
                if ((csr0 & CSR0_MISS) != 0) {
                    log.debug("Missed Frame");
                }

                // check if interrupt is due to Collision Error
                if ((csr0 & CSR0_CERR) != 0) {
                    log.debug("Collision Error");
                }

                // check if interrupt is due to a Bable transmitter time-out
                if ((csr0 & CSR0_BABL) != 0) {
                    log.debug("Bable transmitter time-out");
                }
            }

            // check if interrupt is due to a Missed Frame Counter Overflow
            if ((csr4 & CSR4_MFCO) == CSR4_MFCO) {
                log.debug("Missed Frame Counter Overflow");
            }

            // check if interrupt is due to a User Interrupt
            if ((csr4 & CSR4_UINT) == CSR4_UINT) {
                log.debug("User Interrupt");
            }

            // check if interrupt is due to a Receive Collision Counter Overflow
            if ((csr4 & CSR4_RCVCCO) == CSR4_RCVCCO) {
                log.debug("Receive Collision Counter Overflow");
            }

            // check if interrupt is due to a Transmit Start
            if ((csr4 & CSR4_TXSTRT) == CSR4_TXSTRT) {
                log.debug("Transmit Start");
            }

            // check if interrupt is due to a Jabber Error
            if ((csr4 & CSR4_JAB) == CSR4_JAB) {
                log.debug("Jabber Error");
            }

            // check if interrupt is due to a Jabber Error
            if ((csr4 & CSR4_JAB) == CSR4_JAB) {
                log.debug("Jabber Error");
            }

            // check if interrupt is due to a System Interrupt
            if ((csr5 & CSR5_SINT) == CSR5_SINT) {
                log.debug("System Interrupt");
            }

            // check if interrupt is due to a Sleep Interrupt
            if ((csr5 & CSR5_SLPINT) == CSR5_SLPINT) {
                log.debug("Sleep Interrupt");
            }

            // check if interrupt is due to a Excessive Deferral Interrupt
            if ((csr5 & CSR5_EXDINT) == CSR5_EXDINT) {
                log.debug("Excessive Deferral Interrupt");
            }

            // check if interrupt is due to a Magic Packet Interrupt
            if ((csr5 & CSR5_MPINT) == CSR5_MPINT) {
                log.debug("Magic Packet Interrupt");
            }

        }
    }

    private void rxProcess() {
        SocketBuffer skbuf;

        while ((skbuf = bufferManager.getPacket()) != null) {
            try {
                if (skbuf != null)
                    driver.onReceive(skbuf);
            } catch (NetworkException e) {
                // FIXME
                e.printStackTrace();
            } finally {
                // FIXME
            }
        }
    }

    private IOResource claimPorts(final ResourceManager rm, final ResourceOwner owner,
            final int low, final int length) throws ResourceNotFreeException, DriverException {
        try {
            return AccessControllerUtils.doPrivileged(new PrivilegedExceptionAction<IOResource>() {
                public IOResource run() throws ResourceNotFreeException {
                    return rm.claimIOResource(owner, low, length);
                }
            });
        } catch (ResourceNotFreeException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new DriverException("Unknown exception", ex);
        }

    }

    final void dumpDebugInfo() {
        log.debug("Debug Dump");
        log.debug("CSR0 = " + io.getCSR(0));

        // stop the device so we can read all registers
        io.setCSR(0, CSR0_STOP);

        bufferManager.dumpData(log);

        int validVMWareLanceRegs[] = {
            0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 30, 31, 58, 76, 77, 80,
            82, 88, 89, 112, 124};

        for (int validVMWareLanceReg : validVMWareLanceRegs) {
            int csr_val = io.getCSR(validVMWareLanceReg);
            log.debug("CSR" + validVMWareLanceReg + " : " + NumberUtils.hex(csr_val, 4));
        }

        // try to start again, not sure if this works?
        io.setCSR(0, CSR0_STRT);
    }
}
TOP

Related Classes of org.jnode.driver.net.lance.LanceCore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.