Exemplo n.º 1
0
/*
 * Fires up the network interface. NIC interrupts
 * should have been disabled when calling this
 * function.
 *
 * \param mac Six byte unique MAC address.
 */
static int NicStart(phantom_device_t * dev, CONST uint8_t * mac)
{
    uint8_t i;

    if (NicReset(dev))
        return -1;

    /* Enable receiver. */
    nic_bs(3);
    nic_outlb(NIC_ERCV, 7);
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_RXEN);

    /* Enable transmitter and padding. */
    nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);

    /* Configure the PHY. */
    if (NicPhyConfig(dev))
        return -1;

    /* Set MAC address. */
    //printf("Set MAC %02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    nic_bs(1);
    for (i = 0; i < 6; i++)
        nic_outlb(NIC_IAR + i, mac[i]);
    //printf("OK\n");

    /* Enable interrupts. */
    nic_bs(2);
    nic_outlb(NIC_MSK, INT_ERCV | INT_RCV | INT_RX_OVRN);

    return 0;
}
/*!
 * \brief Initialize the NIC.
 *
 * \return 0 on success, -1 otherwise.
 */
int EtherInit(void)
{
    u_char i;

    /* NIC reset. */
    if (NicReset()) {
        return -1;
    }

    /* Enable receiver. */
    nic_bs(3);
    nic_outlb(NIC_ERCV, 7);
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_RXEN);

    /* Enable transmitter and padding. */
    nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);

    /* Configure the PHY. */
    if (NicPhyConfig()) {
        return -1;
    }

    /* Set MAC address. */
    nic_bs(1);
    for (i = 0; i < 6; i++) {
        nic_outlb(NIC_IAR + i, confnet.cdn_mac[i]);
    }
    return 0;
}
/*!
 * \brief Reset the Ethernet controller.
 *
 * \return 0 on success, -1 otherwise.
 */
int NicReset(void)
{
    /* Disable all interrupts. */
    nic_outlb(NIC_MSK, 0);

    /* MAC and PHY software reset. */
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_SOFT_RST);

    /* Enable Ethernet protocol handler. */
    nic_bs(1);
    nic_outw(NIC_CR, CR_EPH_EN);

    Delay(1);

    /* Disable transmit and receive. */
    nic_bs(0);
    nic_outw(NIC_RCR, 0);
    nic_outw(NIC_TCR, 0);

    /* Enable auto release. */
    nic_bs(1);
    nic_outw(NIC_CTR, CTR_AUTO_RELEASE);

    /* Reset MMU. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_RST);
    if (NicMmuWait(1000))
        return -1;

    return 0;
}
/*!
 * \brief Configure the internal PHY.
 *
 * Reset the PHY and initiate auto-negotiation.
 */
int NicPhyConfig(void)
{
    u_short phy_sor;
    u_short phy_sr;
    u_short phy_to;
    u_short mode;

    /* 
     * Reset the PHY and wait until this self clearing bit
     * becomes zero. We sleep 63 ms before each poll and
     * give up after 3 retries. 
     */
    NicPhyWrite(NIC_PHYCR, PHYCR_RST);
    for (phy_to = 0;; phy_to++) {
        Delay(1);
        if ((NicPhyRead(NIC_PHYCR) & PHYCR_RST) == 0)
            break;
        if (phy_to > 3) {
            return -1;
        }
    }
    Delay(1);

    /* Store PHY status output. */
    phy_sor = NicPhyRead(NIC_PHYSOR);

    /* Enable PHY interrupts. */
    NicPhyWrite(NIC_PHYMSK, PHYMSK_MLOSSSYN | PHYMSK_MCWRD | PHYMSK_MSSD |
                PHYMSK_MESD | PHYMSK_MRPOL | PHYMSK_MJAB | PHYMSK_MSPDDT | PHYMSK_MDPLDT);

    /* Set RPC register. */
    mode = RPCR_ANEG | RPCR_LEDA_PAT | RPCR_LEDB_PAT;
    nic_bs(0);
    nic_outw(NIC_RPCR, mode);

    /*
     * Advertise our capabilities, initiate auto negotiation
     * and wait until this has been completed.
     */
    NicPhyWrite(NIC_PHYANAD, PHYANAD_TX_FDX | PHYANAD_TX_HDX | PHYANAD_10FDX | PHYANAD_10_HDX | PHYANAD_CSMA);
    for (phy_to = 0, phy_sr = 0;; phy_to++) {
        /* Give up after long time wait. */
        if (phy_to >= 1024) {
            return -1;
        }
        /* Restart auto negotiation every 4 seconds or on failures. */
        if ((phy_to & 127) == 0 /* || (phy_sr & PHYSR_REM_FLT) != 0 */ ) {
            NicPhyWrite(NIC_PHYCR, PHYCR_ANEG_EN | PHYCR_ANEG_RST);
            Delay(2);
        }
        /* Check if link status detected. */
        phy_sr = NicPhyRead(NIC_PHYSR);
        if (phy_sr & PHYSR_ANEG_ACK)
            break;
        Delay(3);
    }
    return 0;
}
Exemplo n.º 5
0
/*!
 * \brief Reset the Ethernet controller.
 *
 * \return 0 on success, -1 otherwise.
 */
static int NicReset(phantom_device_t * dev)
{
#ifdef LANC111_RESET_BIT
    sbi(LANC111_RESET_DDR, LANC111_RESET_BIT);
    sbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
    NutDelay(WAIT100);
    cbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
    NutDelay(WAIT250);
    NutDelay(WAIT250);
#endif

    /* Disable all interrupts. */
    nic_outlb(NIC_MSK, 0);

    /* MAC and PHY software reset. */
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_SOFT_RST);

    /* Enable Ethernet protocol handler. */
    nic_bs(1);
    nic_outw(NIC_CR, CR_EPH_EN);

    NutDelay(10);

    /* Disable transmit and receive. */
    nic_bs(0);
    nic_outw(NIC_RCR, 0);
    nic_outw(NIC_TCR, 0);

    /* Enable auto release. */
    nic_bs(1);
    nic_outw(NIC_CTR, CTR_AUTO_RELEASE);

    /* Reset MMU. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_RST);
    if (NicMmuWait(dev,1000))
        return -1;

    return 0;
}
/*!
 * \brief Receive an Ethernet frame.
 *
 * \param tms  Return with timeout after the specified
 *             number of waiting loops. On a 14 Mhz ATmega
 *             this value represents approximately the number
 *             of milliseconds to wait.
 *
 * \return The number of bytes received, 0 on timeout 
 *         or -1 in case of a failure.
 */
int EtherInput(u_short type, u_short tms)
{
    register u_short fsw;
    register u_char *buf;
    u_short fbc;

    /* Check the fifo empty bit. If it is set, then there is 
       nothing in the receiver fifo. */
    nic_bs(2);
    while (tms--) {
        if ((nic_inw(NIC_FIFO) & 0x8000) == 0) {
            break;
        }
        MicroDelay(1000);
    }
    if (nic_inw(NIC_FIFO) & 0x8000) {
        return 0;
    }

    /* Inialize pointer register. */
    nic_outw(NIC_PTR, PTR_READ | PTR_RCV | PTR_AUTO_INCR);
    MicroDelay(1);

    /* Read status word and byte count. */
    fsw = nic_inw(NIC_DATA);
    fbc = nic_inw(NIC_DATA) - 3;

    /* Check for frame errors. */
    if ((fsw & 0xAC00) == 0) {
        DEBUG("\nRx(");
        DEBUGUSHORT(fbc);
        DEBUG(")");
        if(fbc > sizeof(rframe)) {
            fbc = sizeof(rframe);
        }
        /* Perform the read. */
        buf = (u_char *) & rframe;
        fsw = fbc;
        while (fsw--) {
            *buf++ = nic_inlb(NIC_DATA);
        }
    }
    else {
        fbc = -1;
    }

    /* Release the packet. */
    nic_outlb(NIC_MMUCR, MMU_TOP);

    return fbc;
}
Exemplo n.º 7
0
/*!
 * \brief Load a packet into the nic's transmit ring buffer.
 *
 * Interupts must have been disabled when calling this function.
 *
 * \param nb Network buffer structure containing the packet to be sent.
 *           The structure must have been allocated by a previous
 *           call NutNetBufAlloc(). This routine will automatically
 *           release the buffer in case of an error.
 *
 * \return 0 on success, -1 in case of any errors. Errors
 *         will automatically release the network buffer 
 *         structure.
 */
static int NicPutPacket(NETBUF * nb)
{
    u_int16_t sz;
    uint8_t odd = 0;
    uint8_t imsk;

    //printf("[P]");
    /*
     * Calculate the number of bytes to be send. Do not send packets 
     * larger than the Ethernet maximum transfer unit. The MTU
     * consist of 1500 data bytes plus the 14 byte Ethernet header
     * plus 4 bytes CRC. We check the data bytes only.
     */
    if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETH_DATA_LEN)
        return -1;

    /* Disable all interrupts. */
    imsk = nic_inlb(NIC_MSK);
    nic_outlb(NIC_MSK, 0);

    /* Allocate packet buffer space. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_ALO);
    if (NicMmuWait(100))
        return -1;

    /* Enable interrupts including allocation success. */
    nic_outlb(NIC_MSK, imsk | INT_ALLOC);

    /* The MMU needs some time. Use it to calculate the byte count. */
    sz += nb->nb_dl.sz;
    sz += 6;
    if (sz & 1) {
        sz++;
        odd++;
    }

    /* Wait for allocation success. */
    while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
        if (NutEventWait(&maq, 125)) {
            nic_outlb(NIC_MMUCR, MMU_RST);
            NicMmuWait(1000);
            nic_outlb(NIC_MMUCR, MMU_ALO);
            if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
                if (NutEventWait(&maq, 125)) {
                    return -1;
                }
            }
        }
    }

    /* Disable interrupts. */
    imsk = nic_inlb(NIC_MSK);
    nic_outlb(NIC_MSK, 0);


    nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));

    nic_outw(NIC_PTR, 0x4000);

    /* Transfer control word. */
    nic_outlb(NIC_DATA, 0);
    nic_outlb(NIC_DATA, 0);

    /* Transfer the byte count. */
    nic_outw(NIC_DATA, sz);

    /* Transfer the Ethernet frame. */
    NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
    NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
    NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
    NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);

    if (odd)
        nic_outlb(NIC_DATA, 0);

    /* Transfer the control word. */
    nic_outw(NIC_DATA, 0);

    /* Enqueue packet. */
    if (NicMmuWait(100))
        return -1;
    nic_outlb(NIC_MMUCR, MMU_ENQ);

    /* Enable interrupts. */
    imsk |= INT_TX | INT_TX_EMPTY;
    nic_outlb(NIC_MSK, imsk);

    return 0;
}
Exemplo n.º 8
0
/*!
 * \brief Fetch the next packet out of the receive ring buffer.
 *
 * Nic interrupts must be disabled when calling this funtion.
 *
 */
static int NicGetPacket( struct phantom_device *dev, void *buf, int len )
{
    //NETBUF *nb = 0;
    //uint8_t *buf;
    u_int16_t f_status_word;
    u_int16_t fbytecount;

    /* Check the fifo empty bit. If it is set, then there is 
       nothing in the receiver fifo. */
    nic_bs(2);
    //if (nic_inw(NIC_FIFO) & 0x8000)
    //    return 0;

    // TODO cond/sem timed wait
    while(nic_inw(NIC_FIFO) & 0x8000)
        hal_sleep_msec(100);

    /* Inialize pointer register. */
    nic_outw(NIC_PTR, PTR_READ | PTR_RCV | PTR_AUTO_INCR);
    _NOP();
    _NOP();
    _NOP();
    _NOP();

    /* Read status word and byte count. */
    f_status_word = nic_inw(NIC_DATA);
    fbytecount = nic_inw(NIC_DATA);
    //printf("[SW=%04X,BC=%04X]", f_status_word, fbytecount);


    int ret = ERR_IO_ERROR;

    /* Check for frame errors. */
    if (f_status_word & 0xAC00) {
        //nb = (NETBUF *) 0xFFFF;
        ret = ERR_IO_ERROR;
    }
    /* Check the byte count. */
    else if (fbytecount < 66 || fbytecount > 1524) {
        //nb = (NETBUF *) 0xFFFF;
        ret = ERR_IO_ERROR;
    }
    else {
        /* 
         * Allocate a NETBUF. 
         * Hack alert: Rev A chips never set the odd frame indicator.
         */
        fbytecount -= 3;

        if( len < fbytecount )
            ret = ERR_VFS_INSUFFICIENT_BUF;
        else
        {
            NicRead( dev, buf, fbytecount);
            ret = fbytecount;
        }
    }

    /* Release the packet. */
    nic_outlb(NIC_MMUCR, MMU_TOP);

    return ret;
}
Exemplo n.º 9
0
/*
 * NIC interrupt entry.
 */
static void NicInterrupt(void *arg)
{
    phantom_device_t * dev = arg;

    uint8_t isr;
    uint8_t imr;
    lanc111_nic_t *ni = (lanc111_nic_t *) ((NUTDEVICE *) arg)->dev_dcb;


    ni->ni_interrupts++;

    /* Read the interrupt mask and disable all interrupts. */
    nic_bs(2);
    imr = nic_inlb(NIC_MSK);
    nic_outlb(NIC_MSK, 0);

    /* Read the interrupt status and acknowledge all interrupts. */
    isr = nic_inlb(NIC_IST);
    //printf("\n!%02X-%02X ", isr, imr);
    isr &= imr;

    /*
     * If this is a transmit interrupt, then a packet has been sent. 
     * So we can clear the transmitter busy flag and wake up the 
     * transmitter thread.
     */
    if (isr & INT_TX_EMPTY) {
        nic_outlb(NIC_ACK, INT_TX_EMPTY);
        imr &= ~INT_TX_EMPTY;
    }
    /* Transmit error. */
    else if (isr & INT_TX) {
        /* re-enable transmit */
        nic_bs(0);
        nic_outw(NIC_TCR, nic_inlb(NIC_TCR) | TCR_TXENA);
        nic_bs(2);
        nic_outlb(NIC_ACK, INT_TX);
        /* kill the packet */
        nic_outlb(NIC_MMUCR, MMU_PKT);
    }


    /*
     * If this is a receive interrupt, then wake up the receiver 
     * thread.
     */
    if (isr & INT_RX_OVRN) {
        nic_outlb(NIC_ACK, INT_RX_OVRN);
        //nic_outlb(NIC_MMUCR, MMU_TOP);
        NutEventPostFromIrq(&ni->ni_rx_rdy);
    }
    if (isr & INT_ERCV) {
        nic_outlb(NIC_ACK, INT_ERCV);
        NutEventPostFromIrq(&ni->ni_rx_rdy);
    }
    if (isr & INT_RCV) {
        nic_outlb(NIC_ACK, INT_RCV);
        imr &= ~INT_RCV;
        NutEventPostFromIrq(&ni->ni_rx_rdy);
    }

    if (isr & INT_ALLOC) {
        imr &= ~INT_ALLOC;
        NutEventPostFromIrq(&maq);
    }
    //printf(" -%02X-%02X- ", nic_inlb(NIC_IST), inb(PINE) & 0x20);
    nic_outlb(NIC_MSK, imr);
}
Exemplo n.º 10
0
/*!
 * \brief Configure the internal PHY.
 *
 * Reset the PHY and initiate auto-negotiation.
 */
static int NicPhyConfig(phantom_device_t * dev)
{
    u_int16_t phy_sor;
    u_int16_t phy_sr;
    u_int16_t phy_to;
    u_int16_t mode;

    /* 
     * Reset the PHY and wait until this self clearing bit
     * becomes zero. We sleep 63 ms before each poll and
     * give up after 3 retries. 
     */
    //printf("Reset PHY..");
    NicPhyWrite(dev, NIC_PHYCR, PHYCR_RST);
    for (phy_to = 0;; phy_to++) {
        NutSleep(63);
        if ((NicPhyRead(dev, NIC_PHYCR) & PHYCR_RST) == 0)
            break;
        if (phy_to > 3)
            return -1;
    }
    //printf("OK\n");

    /* Store PHY status output. */
    phy_sor = NicPhyRead(dev, NIC_PHYSOR);

    /* Enable PHY interrupts. */
    NicPhyWrite(dev, NIC_PHYMSK, PHYMSK_MLOSSSYN | PHYMSK_MCWRD | PHYMSK_MSSD |
                PHYMSK_MESD | PHYMSK_MRPOL | PHYMSK_MJAB | PHYMSK_MSPDDT | PHYMSK_MDPLDT);

    /* Set RPC register. */
    mode = RPCR_ANEG | RPCR_LEDA_PAT | RPCR_LEDB_PAT;
    nic_bs(0);
    nic_outw(NIC_RPCR, mode);

#ifdef NIC_FIXED
    /* Disable link. */
    phy_sr = NicPhyRead(NIC_PHYCFR1);
    NicPhyWrite(NIC_PHYCFR1, phy_sr | 0x8000);
    NutSleep(63);

    /* Set fixed capabilities. */
    NicPhyWrite(NIC_PHYCR, NIC_FIXED);
    nic_bs(0);
    nic_outw(NIC_RPCR, mode);

    /* Enable link. */
    phy_sr = NicPhyRead(NIC_PHYCFR1);
    NicPhyWrite(NIC_PHYCFR1, phy_sr & ~0x8000);
    phy_sr = NicPhyRead(NIC_PHYCFR1);

#else
    /*
     * Advertise our capabilities, initiate auto negotiation
     * and wait until this has been completed.
     */
    //printf("Negotiate..");
    NicPhyWrite(dev, NIC_PHYANAD, PHYANAD_TX_FDX | PHYANAD_TX_HDX | PHYANAD_10FDX | PHYANAD_10_HDX | PHYANAD_CSMA);
    NutSleep(63);
    for (phy_to = 0, phy_sr = 0;; phy_to++) {
        /* Give up after 10 seconds. */
        if (phy_to >= 1024)
            return -1;
        /* Restart auto negotiation every 4 seconds or on failures. */
        if ((phy_to & 127) == 0 /* || (phy_sr & PHYSR_REM_FLT) != 0 */ ) {
            NicPhyWrite(dev, NIC_PHYCR, PHYCR_ANEG_EN | PHYCR_ANEG_RST);
            //printf("Restart..");
            NutSleep(63);
        }
        /* Check if we are done. */
        phy_sr = NicPhyRead(dev, NIC_PHYSR);
        //printf("[SR %04X]", phy_sr);
        if (phy_sr & PHYSR_ANEG_ACK)
            break;
        NutSleep(63);
    }
    //printf("OK\n");
#endif

    return 0;
}
/*!
 * \brief Send an Ethernet frame.
 *
 * \param dmac Destination MAC address.
 * \param type Frame type.
 * \param len  Frame size.
 *
 * \return 0 on success, -1 otherwise.
 */
int EtherOutput(const u_char * dmac, u_short type, u_short len)
{
    ETHERHDR *eh;
    u_char *cp;

    /*
     * Set the Ethernet header.
     */
    if (type == ETHERTYPE_ARP) {
        cp = (u_char *) & arpframe;
    } else {
        cp = (u_char *) & sframe;
    }
    eh = (ETHERHDR *)cp;
    memcpy_(eh->ether_shost, confnet.cdn_mac, 6);
    memcpy_(eh->ether_dhost, dmac, 6);
    eh->ether_type = type;

    /*
     * The total packet length includes 
     * - status word (2 bytes)
     * - byte count (2 bytes)
     * - destination address (6 bytes)
     * - source address (6 bytes)
     * - Ethernet type (2 bytes)
     * - data bytes (variable)
     * - control word (2 bytes)
     * Thus we add 20 to the number of data bytes. We didn't
     * manage to get an odd number of bytes transmitted, so
     * add another byte.
     */
    if((len += 20) & 1) {
        len++;
    }

    DEBUG(" Tx(");
    DEBUGUSHORT(len);
    DEBUG(")");

    /* Allocate transmit packet buffer space. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_ALO);
    if (NicMmuWait(100)) {
        return -1;
    }

    /*
     * An allocation error might appear when incoming packets occupy 
     * all the buffer. Reset the MMU to release all memory. This is
     * very drastic, but OK for our sequential boot loader.
     */
    if ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
        DEBUG("[MMURST]");
        nic_outlb(NIC_MMUCR, MMU_RST);
        NicMmuWait(1000);
        nic_outlb(NIC_MMUCR, MMU_ALO);
        if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
            return -1;
        }
    }

    /* 
     * Read the number of the allcocated packet from the allocation 
     * result register and write it to the packet number register.
     */
    nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));

    /*
     * Initially set the pointer register address to 2 and enable
     * auto increment. The first two bytes will be used by the CSMA 
     * to store the status word upon transmit completion. 
     */
    nic_outw(NIC_PTR, PTR_AUTO_INCR | 2);

    /* 
     * Transfer the byte count and the data bytes.
     */
    nic_outw(NIC_DATA, len);
    while (len--) {
        nic_outlb(NIC_DATA, *cp);
        cp++;
    }
    
    /* 
     * Transfer the control word. As stated above, we never succeeded
     * in sending an odd number of bytes.
     */
    nic_outw(NIC_DATA, 0);

    /* Enqueue packet. */
    NicMmuWait(100);
    nic_outlb(NIC_MMUCR, MMU_ENQ);

    return 0;
}