Package org.jnode.driver.net._3c90x

Source Code of org.jnode.driver.net._3c90x._3c90xCore

/*
* $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._3c90x;

import java.util.ArrayList;
import java.util.Collection;
import javax.naming.NameNotFoundException;
import org.jnode.driver.Device;
import org.jnode.driver.DriverException;
import org.jnode.driver.bus.pci.PCIBaseAddress;
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.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.NumberUtils;
import org.jnode.util.TimeoutException;

/**
* @author epr
*/
public class _3c90xCore extends AbstractDeviceCore implements _3c90xConstants, IRQHandler, EthernetConstants {

    /**
     * Start of IO address space
     */
    private final int iobase;
    /**
     * IO address space
     */
    private final IOResource io;
    /**
     * IRQ
     */
    private final IRQResource irq;
    /**
     * My ethernet address
     */
    private EthernetAddress hwAddress;
    /**
     * The driver i'm a part of
     */
    private final _3c90xDriver driver;
    /**
     * My flags
     */
    private final _3c90xFlags flags;
    /**
     * Is a transmission active?
     */
    private boolean tx_active;
    /**
     * Active register window
     */
    private int reg_window = 0xff;
    /**
     * The receive buffer ring
     */
    private final _3c90xRxRing rxRing;
    /**
     * The transmit buffer
     */
    private final _3c90xTxBuffer txBuffer;
    /**
     * Is the device a B revision
     */
    private final boolean Brev;

    /**
     * Create a new instance
     *
     * @param flags
     */
    public _3c90xCore(_3c90xDriver driver, ResourceOwner owner, PCIDevice device, _3c90xFlags flags)
        throws DriverException, ResourceNotFreeException {
        final int irq = getIRQ(device, flags);
        this.driver = driver;
        this.flags = flags;
        this.tx_active = false;

        // Get the start of the IO address space
        this.iobase = getIOBase(device, flags);
        final int iolength = getIOLength(device, flags);
        final 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 {
            io = rm.claimIOResource(owner, iobase, iolength);
        } catch (ResourceNotFreeException ex) {
            this.irq.release();
            throw ex;
        }
        this.rxRing = new _3c90xRxRing(RX_FRAMES, rm);
        this.txBuffer = new _3c90xTxBuffer(rm);

        // Reset the device
        reset();

        // Determine Brev flag
        switch (readEEProm(0x03)) {
            case 0x9000:/** 10 Base TPO             **/
            case 0x9001:/** 10/100 T4               **/
            case 0x9050:/** 10/100 TPO              **/
            case 0x9051:/** 10 Base Combo           **/
                //case 0x9200: /** 3Com905C-TXM            **/
                Brev = false;
                break;

            case 0x9004:/** 10 Base TPO             **/
            case 0x9005:/** 10 Base Combo           **/
            case 0x9006:/** 10 Base TPO and Base2   **/
            case 0x900A:/** 10 Base FL              **/
            case 0x9055:/** 10/100 TPO              **/
            case 0x9056:/** 10/100 T4               **/
            case 0x905A:/** 10 Base FX              **/
            default:
                Brev = true;
                break;
        }

        // Read the eeprom
        final int[] eeprom = new int[0x21];
        for (int i = 0; i < 0x17; i++) {
            eeprom[i] = readEEProm(i);
            //Syslog.debug("eeprom[" + NumberUtils.hex(i, 2) + "]=" + NumberUtils.hex(eeprom[i], 4));
        }
        final byte[] hwAddrArr = new byte[ETH_ALEN];
        hwAddrArr[0] = (byte) (eeprom[0x0a] >> 8);
        hwAddrArr[1] = (byte) (eeprom[0x0a] & 0xFF);
        hwAddrArr[2] = (byte) (eeprom[0x0b] >> 8);
        hwAddrArr[3] = (byte) (eeprom[0x0b] & 0xFF);
        hwAddrArr[4] = (byte) (eeprom[0x0c] >> 8);
        hwAddrArr[5] = (byte) (eeprom[0x0c] & 0xFF);
        this.hwAddress = new EthernetAddress(hwAddrArr, 0);

        log.debug("Found " + flags.getName() + " IRQ=" + irq + ", IOBase=0x" +
                NumberUtils.hex(iobase) + ", MAC Address=" + hwAddress);
    }

    /**
     * Gets the ethernet address of this device
     */
    public HardwareAddress getHwAddress() {
        return hwAddress;
    }

    /**
     * Initialize the device
     */
    public synchronized void initialize() {
        // First reset the device
        reset();

        // Now initialize our buffers
        rxRing.initialize();

        /** Program the MAC address into the station address registers **/
        setWindow(winAddressing2);
        final int a0 = ((hwAddress.get(1) & 0xFF) << 8) | (hwAddress.get(0) & 0xFF);
        final int a1 = ((hwAddress.get(3) & 0xFF) << 8) | (hwAddress.get(2) & 0xFF);
        final int a2 = ((hwAddress.get(5) & 0xFF) << 8) | (hwAddress.get(4) & 0xFF);
        setReg16(regStationAddress_2_3w + 0, a0);
        setReg16(regStationAddress_2_3w + 2, a1);
        setReg16(regStationAddress_2_3w + 4, a2);
        setReg16(regStationMask_2_3w + 0, 0);
        setReg16(regStationMask_2_3w + 2, 0);
        setReg16(regStationMask_2_3w + 4, 0);

        // Determine the link type
        final ArrayList<String> connectors = new ArrayList<String>();
        final int linktype = determineLinkType(connectors);
        log.debug("Found connectors " + connectors);

        /** enable DC converter for 10-Base-T **/
        if (linktype == 0x0003) {
            issueCommand(cmdEnableDcConverter, 0, 0);
        }

        /** Set the link to the type we just determined. **/
        setWindow(winTxRxOptions3);
        int cfg = getReg32(regInternalConfig_3_l);
        cfg &= ~(0xF << 20);
        cfg |= (linktype << 20);
        setReg32(regInternalConfig_3_l, cfg);
        //log.debug("Setting linktype to 0x" + NumberUtils.hex(linktype));

        /** Now that we set the xcvr type, reset the Tx and Rx, re-enable. **/
        issueCommand(cmdTxReset, 0x00, 10);
        while ((getReg16(regCommandIntStatus_w) & INT_CMDINPROGRESS) != 0) {
            /* loop */
        }

        if (!Brev) {
            setReg8(regTxFreeThresh_b, 0x01);
        }

        issueCommand(cmdTxEnable, 0, 0);

        /**
         ** reset of the receiver on B-revision cards re-negotiates the link
         ** takes several seconds (a computer eternity)
         **/
        if (Brev) {
            issueCommand(cmdRxReset, 0x04, 10);
        } else {
            issueCommand(cmdRxReset, 0x00, 10);
        }
        while ((getReg16(regCommandIntStatus_w) & INT_CMDINPROGRESS) != 0) {
            /* loop */
        }

        /** Set the RX filter = receive only individual pkts & bcast. **/
        issueCommand(cmdSetRxFilter, 0x01 + 0x04, 0);
        //issueCommand(cmdSetRxFilter, 0x1F, 0);
        issueCommand(cmdRxEnable, 0, 0);
        setReg32(regUpListPtr_l, rxRing.getFirstUPDAddress().toInt());

        /**
         ** set Indication and Interrupt flags , acknowledge any IRQ's
         **/
        final int intMask =
                INT_HOSTERROR | INT_TXCOMPLETE | INT_RXCOMPLETE | INT_UPDATESTATS | INT_LINKEVENT |
                        INT_UPCOMPLETE | INT_INTREQUESTED;
        issueCommand(cmdSetInterruptEnable, /*0x7FF*/intMask, 0);
        issueCommand(cmdSetIndicationEnable, 0x7FF, 0);
        issueCommand(cmdAcknowledgeInterrupt, 0x661, 0);

        log.debug("initialize done");
    }

    /**
     * Disable the device
     */
    public synchronized void disable() {
        reset();
    }

    /**
     * Release all resources
     */
    public void release() {
        io.release();
        log.debug("irq.release");
        irq.release();
        log.debug("end of release");
    }

    /**
     * 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);

        //final int txStatus = getReg8(regTxStatus_b);
        //log.debug("Waiting for transmit txStatus=0x" + NumberUtils.hex(txStatus, 2));

        // Wait until we can start transmitting
        final long start = System.currentTimeMillis();
        while (tx_active) {
            final long now = System.currentTimeMillis();
            if (now - start > timeout) {
                throw new TimeoutException("Timeout in claiming transmitter");
            }
            wait(timeout);
        }
        tx_active = true;
        //log.debug("Going for transmit");

        txBuffer.initialize(buf);

        // Stall the download engine
        issueCommand(cmdStallCtl, 2, 1);

        // Set the address of the txBuffer
        setReg32(regDnListPtr_l, txBuffer.getFirstDPDAddress().toInt());

        // UnStall the download engine
        issueCommand(cmdStallCtl, 3, 1);
        //log.debug("Leaving transmit txStatus=0x" + NumberUtils.hex(getReg8(regTxStatus_b), 2));
    }

    /**
     * @see org.jnode.system.resource.IRQHandler#handleInterrupt(int)
     */
    public synchronized void handleInterrupt(int irq) {

        int intStatus = getReg16(regCommandIntStatus_w);
        int loops = 0;
        while ((intStatus & ~INT_WINDOWNUMBER) != 0) {
            //log.debug("IntStatus flags on " + flags.getName() + ": 0x" + NumberUtils.hex(intStatus, 4));
            loops++;
            if (loops > MAX_SERVICE) {
                log.error("Too much work in intterupt, IntStatus=0x" + NumberUtils.hex(intStatus));
                //issueCommand(cmdAcknowledgeInterrupt, intStatus & ~INT_WINDOWNUMBER, 0);
                return;
            }
            if ((intStatus & INT_TXCOMPLETE) != 0) {
                //log.debug("TxComplete on " + flags.getName());
                processTxComplete();
            } else if ((intStatus & INT_UPDATESTATS) != 0) {
                log.debug("UpdateStats on " + flags.getName());
                processUpdateStats();
            } else if ((intStatus & INT_LINKEVENT) != 0) {
                //log.debug("LinkEvent on " + flags.getName());
                processLinkEvent();
            } else if ((intStatus & INT_UPCOMPLETE) != 0) {
                //log.debug("UpComplete on " + flags.getName());
                processUpComplete();
            } else if ((intStatus & INT_INTERRUPTLATCH) != 0) {
                issueCommand(cmdAcknowledgeInterrupt, INT_INTERRUPTLATCH, 0);
            } else {
                log.debug("Unknown IntStatus flags set on " + flags.getName() + ": IntStatus=0x" +
                        NumberUtils.hex(intStatus, 4));
                issueCommand(cmdAcknowledgeInterrupt, intStatus & ~INT_WINDOWNUMBER, 0);
            }
            intStatus = getReg16(regCommandIntStatus_w);
        }

        //issueCommand(cmdAcknowledgeInterrupt, INT_INTERRUPTLATCH, 0);

        //log.debug("Done IRQ on " + flags.getName() + ": 0x" + NumberUtils.hex(intStatus, 4));
    }

    /**
     * Process a TxComplete interrupt
     */
    private final void processTxComplete() {
        tx_active = false;
        notifyAll();
        setReg8(regTxStatus_b, 0xFF); // Ack TxComplete, by writing any value
    }

    /**
     * Process an UpdateStats interrupt
     */
    private final void processUpdateStats() {
        // TODO Implement update stats
    }

    /**
     * Process a LinkEvent interrupt
     */
    private final void processLinkEvent() {
        // Read IntStatusAuto ack. the interrupt
        //getReg16(regIntStatusAuto_w);
        issueCommand(cmdAcknowledgeInterrupt, 0x02, 0);
        //issueCommand(cmdRxEnable, 0, 0);
    }

    /**
     * Process an UpComplete interrupt
     */
    private final void processUpComplete() {
        // Read all packets
        final int nrFrames = rxRing.getNrFrames();

        // Stall uploading first
        issueCommand(cmdStallCtl, 0x00, 1);

        for (int i = 0; i < nrFrames; i++) {
            final int pktStatus = rxRing.getPktStatus(i);
            if (pktStatus != 0) {
                //log.debug("PktStatus[" + NumberUtils.hex(i, 2) + "]=0x" + NumberUtils.hex(pktStatus));
                if ((pktStatus & upComplete) != 0) {
                    final SocketBuffer skbuf = rxRing.getPacket(i);
                    try {
                        //log.debug("Read packet at index 0x" + NumberUtils.hex(i));
                        driver.onReceive(skbuf);
                    } catch (NetworkException ex) {
                        log.debug("Error in onReceive", ex);
                    } finally {
                        rxRing.setPktStatus(i, 0);
                    }
                }
            }
        }

        // UnStall uploading
        issueCommand(cmdStallCtl, 0x01, 0);

        // Ack interrupt
        issueCommand(cmdAcknowledgeInterrupt, INT_UPCOMPLETE, 0);
    }

    /**
     * Reset this device
     */
    private void reset() {
        issueCommand(cmdGlobalReset, 0xff, 10);

        /** global reset command resets station mask, non-B revision cards
         ** require explicit reset of values
         **/
        setWindow(winAddressing2);
        setReg16(regStationAddress_2_3w + 0, 0);
        setReg16(regStationAddress_2_3w + 2, 0);
        setReg16(regStationAddress_2_3w + 4, 0);

        /** Issue transmit reset, wait for command completion **/
        issueCommand(cmdTxReset, 0, 10);
        issueCommand(cmdRxReset, 0, 10);
        issueCommand(cmdSetInterruptEnable, 0, 0);
        /** enable rxComplete and txComplete **/
        issueCommand(cmdSetIndicationEnable, 0x0014, 0);
        /** acknowledge any pending status flags **/
        issueCommand(cmdAcknowledgeInterrupt, 0x661, 0);
    }

    /**
     * Gets the first IO-Address used by the given device
     *
     * @param device
     * @param flags
     */
    protected final int getIOBase(Device device, _3c90xFlags flags) throws DriverException {
        final PCIHeaderType0 config = ((PCIDevice) device).getConfig().asHeaderType0();
        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");
        }
        return addrs[0].getIOBase();
    }

    /**
     * Gets the number of IO-Addresses used by the given device
     *
     * @param device
     * @param flags
     */
    protected int getIOLength(Device device, _3c90xFlags flags) throws DriverException {
        final PCIHeaderType0 config = ((PCIDevice) device).getConfig().asHeaderType0();
        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");
        }
        return addrs[0].getSize();
    }

    /**
     * Gets the IRQ used by the given device
     *
     * @param device
     * @param flags
     */
    protected int getIRQ(Device device, _3c90xFlags flags) throws DriverException {
        final PCIHeaderType0 config = ((PCIDevice) device).getConfig().asHeaderType0();
        return config.getInterruptLine();
    }

    /**
     * Determine which connectors are physically available on the device.
     * Determine the link type based on that.
     *
     * @param connectors
     */
    private final int determineLinkType(Collection<String> connectors) {
        /** 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
         **/
        setWindow(winTxRxOptions3);
        int mopt = getReg16(regResetMediaOptions_3_w);

        /* mask out VCO bit that is defined as 10baseFL bit on B-rev cards */
        if (!Brev) {
            mopt &= 0x7F;
        }
        //log.debug("mopt=0x" + NumberUtils.hex(mopt));

        int linktype = 0x0008;
        if ((mopt & 0x01) != 0) {
            connectors.add("100Base-T4");
            linktype = 0x0006;
        }
        if ((mopt & 0x04) != 0) {
            connectors.add("100Base-FX");
            linktype = 0x0005;
        }
        if ((mopt & 0x10) != 0) {
            connectors.add("10Base-2");
            linktype = 0x0003;
        }
        if ((mopt & 0x20) != 0) {
            connectors.add("AUI");
            linktype = 0x0001;
        }
        if ((mopt & 0x40) != 0) {
            connectors.add("MII");
            linktype = 0x0006;
        }
        if ((mopt & 0xA) == 0xA) {
            connectors.add("10Base-T / 100Base-TX");
            linktype = 0x0008;
        } else if ((mopt & 0xA) == 0x2) {
            connectors.add("100Base-TX");
            linktype = 0x0008;
        } else if ((mopt & 0xA) == 0x8) {
            connectors.add("10Base-T");
            linktype = 0x0008;
        }

        return linktype;
    }

    /**
     * Execute a command on the NIC
     *
     * @param command
     * @param param
     */
    private final void issueCommand(int command, int param, long sleep) {
        // Calculate the complete command + param value
        final int v = (command << 11) | (param & 0x7FF);
        // Wait for the previous command to complete
        while ((getReg16(regCommandIntStatus_w) & INT_CMDINPROGRESS) != 0) {
            /* loop */
        }
        // Send the command
        setReg16(regCommandIntStatus_w, v);
        if (sleep > 0) {
            // Sleep for long commands
            try {
                Thread.sleep(sleep);
            } catch (InterruptedException ex) {
                // Ignore
            }
        }
        // Wait for the command to complete
        int loops = 0;
        while ((getReg16(regCommandIntStatus_w) & INT_CMDINPROGRESS) != 0) {
            /* loop */
            loops++;
        }
        //log.debug("Loops=" + loops + ", cmd=0x" + NumberUtils.hex(v));
    }

    /**
     * Read data from the serial eeprom
     *
     * @param address
     */
    private int readEEProm(int address) {
        /** Select correct window **/
        setWindow(winEepromBios0);

        /** Make sure the eeprom isn't busy **/
        while (((1 << 15) & getReg16(regEepromCommand_0_w)) != 0) {
            /* Loop */
        }

        /** Read the value. **/
        setReg16(regEepromCommand_0_w, address + ((0x02) << 6));
        try {
            Thread.sleep(2);
        } catch (InterruptedException ex) {
            // Ignore
        }
        while (((1 << 15) & getReg16(regEepromCommand_0_w)) != 0) {
            /* Loop */
        }

        return getReg16(regEepromData_0_w) & 0xFFFF;
    }

    /**
     * Sets the current register window
     *
     * @param w
     */
    private final void setWindow(int w) {
        if (reg_window != w) {
            issueCommand(cmdSelectRegisterWindow, w, 0);
            reg_window = w;
        }
    }

    /**
     * Reads a 8-bit NIC register
     * @param reg
     */
    /*private final int getReg8(int reg) {
         return io.inPortByte(iobase + reg);
     }*/

    /**
     * Reads a 16-bit NIC register
     *
     * @param reg
     */
    private final int getReg16(int reg) {
        return io.inPortWord(iobase + reg);
    }

    /**
     * Reads a 32-bit NIC register
     *
     * @param reg
     */
    private final int getReg32(int reg) {
        return io.inPortDword(iobase + reg);
    }

    /**
     * Writes a 8-bit NIC register
     *
     * @param reg
     * @param value
     */
    private final void setReg8(int reg, int value) {
        io.outPortByte(iobase + reg, value);
    }

    /**
     * Writes a 16-bit NIC register
     *
     * @param reg
     * @param value
     */
    private final void setReg16(int reg, int value) {
        io.outPortWord(iobase + reg, value);
    }

    /**
     * Writes a 32-bit NIC register
     *
     * @param reg
     * @param value
     */
    private final void setReg32(int reg, int value) {
        io.outPortDword(iobase + reg, value);
    }
}
TOP

Related Classes of org.jnode.driver.net._3c90x._3c90xCore

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.