欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

if_lan91cxx.c

eCos操作系统源码
C
第 1 页 / 共 4 页
字号:
        p->tx_queue_len = 1;        return 0; // OK    }#endif    default:        break;    }    return 1;}//// This routine is called to see if it is possible to send another packet.// It will return non-zero if a transmit is possible, zero otherwise.//static intlan91cxx_can_send(struct eth_drv_sc *sc){    struct lan91cxx_priv_data *cpd =        (struct lan91cxx_priv_data *)sc->driver_private;    int tcr;    DEBUG_FUNCTION();#ifndef LAN91CXX_IS_LAN91C111    // LINK_OK on 91C111 is just a general purpose input and may not    // have anything to do with the link.    if ((get_reg(sc, LAN91CXX_EPH_STATUS) & LAN91CXX_STATUS_LINK_OK) == 0) {	db_printf("no link\n");        return false;  // Link not connected    }#endif    CYG_ASSERT( cpd->within_send < 10, "can_send: Excess send recursions" );    cpd->within_send++;    tcr = get_reg(sc, LAN91CXX_TCR);    if ( 0 == (LAN91CXX_TCR_TXENA & tcr) ) {#if DEBUG & 1        db_printf("%s: ENGINE RESTART: tcr %x\n", __FUNCTION__, tcr );#endif        // Complete any outstanding activity:        if ( cpd->txbusy ) {            cpd->txbusy = 0;#if DEBUG & 9            db_printf("LAN91CXX - can_send, cleaning up pending TX\n" );#endif            (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, 0);        }        tcr |= LAN91CXX_TCR_TXENA;        put_reg(sc, LAN91CXX_TCR, tcr);    }    // This helps unstick deadly embraces.    lan91cxx_poll( sc ); // Deal with any outstanding rx state    cpd->within_send--;    return (cpd->txbusy == 0) && (0 == cpd->within_send);}//// This routine is called to send data to the hardware.static void lan91cxx_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,             int total_len, unsigned long key){    struct lan91cxx_priv_data *cpd =         (struct lan91cxx_priv_data *)sc->driver_private;    int i, len, plen, tcr;    unsigned short *sdata = NULL;    unsigned short ints, control;    cyg_uint16 packet, status;    DEBUG_FUNCTION();    INCR_STAT( tx_count );    // Worry about the TX engine stopping.    tcr = get_reg(sc, LAN91CXX_TCR);    if ( 0 == (LAN91CXX_TCR_TXENA & tcr) ) {#if DEBUG & 1        db_printf("%s: ENGINE RESTART: tcr %x\n", __FUNCTION__, tcr );#endif        tcr |= LAN91CXX_TCR_TXENA;        put_reg(sc, LAN91CXX_TCR, tcr);    }    // This helps unstick deadly embraces.    CYG_ASSERT( cpd->within_send < 10, "send: Excess send recursions" );    cpd->within_send++;    lan91cxx_poll( sc ); // Deal with any outstanding rx state    cpd->within_send--;    cpd->txbusy = 1;    cpd->txkey = key;    // Find packet length    plen = 0;    for (i = 0;  i < sg_len;  i++)        plen += sg_list[i].len;    CYG_ASSERT( plen == total_len, "sg data length mismatch" );    // Alloc new TX packet    do {        put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_alloc_for_tx#ifndef LAN91CXX_IS_LAN91C111		| ((plen >> 8) & 0x07)#endif	    );        i = 1024 * 1024;        do {            status = get_reg(sc, LAN91CXX_INTERRUPT);        } while (0 == (status & LAN91CXX_INTERRUPT_ALLOC_INT) && (--i > 0) );        if ( i )            packet = get_reg(sc, LAN91CXX_PNR);        else            packet = 0xffff;#if DEBUG & 1        db_printf("%s: allocated packet %04x\n", __FUNCTION__, packet);#endif        packet = packet >> 8;        if (packet & 0x80) {            // Hm.. Isn't this a dead end?#if DEBUG & 1            db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );#endif            // Not if we can make progress with what's filling memory.            lan91cxx_poll( sc ); // Deal with any outstanding state            continue;        }    } while (0);#if DEBUG & 4    db_printf("#####Tx packet allocated %x (previous %x)\n",                packet, cpd->txpacket);#endif    cpd->txpacket = packet;    put_reg(sc, LAN91CXX_PNR, packet);    // Note: Check FIFO state here before continuing?    put_reg(sc, LAN91CXX_POINTER, LAN91CXX_POINTER_AUTO_INCR | 0x0000);    // Pointer is now set, and the proper bank is selected for    // data writes.    // Prepare header:    put_data(sc, CYG_CPU_TO_LE16(0));        // reserve space for status word    // packet length (includes status, byte-count and control shorts)    put_data(sc, CYG_CPU_TO_LE16(0x7FE & (plen + 6)) ); // Always even, always < 15xx(dec)    // Put data into buffer    for (i = 0;  i < sg_len;  i++) {        sdata = (unsigned short *)sg_list[i].buf;        len = sg_list[i].len;        CYG_ASSERT(0 == (len & 1) || (i == (sg_len-1)), "odd length");        CYG_ASSERT( sdata, "No sg data pointer here" );        while(len >= sizeof(*sdata)) {            put_data(sc, *sdata++);            len -= sizeof(*sdata);        }    }    CYG_ASSERT( sdata, "No sg data pointer outside" );    // Lay down the control short unconditionally at the end.    // (or it might use random memory contents)    control = 0;    if ( 1 & plen ) {        // Need to set ODD flag and insert the data        unsigned char onebyte = *(unsigned char*)sdata;        control = onebyte;        control |= LAN91CXX_CONTROLBYTE_ODD;    }    control |= LAN91CXX_CONTROLBYTE_CRC; // Just in case...    put_data(sc, CYG_CPU_TO_LE16(control));    // Enqueue the packet    put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);    // Ack TX empty int and unmask it.    ints = get_reg(sc, LAN91CXX_INTERRUPT) & 0xff00;    put_reg(sc, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_SET_ACK);    put_reg(sc, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_SET_M);#if DEBUG & 1    ints = get_reg(sc, LAN91CXX_INTERRUPT);    db_printf("%s:END: ints at TX: %04x\n", __FUNCTION__, ints);#endif}static voidlan91cxx_TxEvent(struct eth_drv_sc *sc, int stat){    unsigned short packet, ints, tcr;    struct lan91cxx_priv_data *cpd =        (struct lan91cxx_priv_data *)sc->driver_private;    int success = 1;    DEBUG_FUNCTION();    INCR_STAT( tx_complete );    // Ack and mask TX interrupt set    ints = get_reg(sc, LAN91CXX_INTERRUPT) & 0xff00;    ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;    ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;    put_reg(sc, LAN91CXX_INTERRUPT, ints);    // Get number of completed packet and read the status word    packet = get_reg(sc, LAN91CXX_FIFO_PORTS);#if DEBUG & 1    db_printf("%s:START: fifo %04x ints %04x\n", __FUNCTION__, packet, ints);#endif#ifdef KEEP_STATISTICS    {        unsigned short reg;        reg = get_reg( sc, LAN91CXX_EPH_STATUS );                // Covering each bit in turn...        if ( reg & LAN91CXX_STATUS_TX_UNRN   ) INCR_STAT( tx_underrun );        //if ( reg & LAN91CXX_STATUS_LINK_OK ) INCR_STAT(  );        //if ( reg & LAN91CXX_STATUS_CTR_ROL ) INCR_STAT(  );        //if ( reg & LAN91CXX_STATUS_EXC_DEF ) INCR_STAT(  );        if ( reg & LAN91CXX_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );        if ( reg & LAN91CXX_STATUS_LATCOL    ) INCR_STAT( tx_late_collisions );        //if ( reg & LAN91CXX_STATUS_WAKEUP  ) INCR_STAT(  );        if ( reg & LAN91CXX_STATUS_TX_DEFR   ) INCR_STAT( tx_deferred );        //if ( reg & LAN91CXX_STATUS_LTX_BRD ) INCR_STAT(  );        if ( reg & LAN91CXX_STATUS_SQET      ) INCR_STAT( tx_sqetesterrors );        if ( reg & LAN91CXX_STATUS_16COL     ) INCR_STAT( tx_max_collisions );        //if ( reg & LAN91CXX_STATUS_LTX_MULT) INCR_STAT(  );        if ( reg & LAN91CXX_STATUS_MUL_COL   ) INCR_STAT( tx_mult_collisions );        if ( reg & LAN91CXX_STATUS_SNGL_COL  ) INCR_STAT( tx_single_collisions );        if ( reg & LAN91CXX_STATUS_TX_SUC    ) INCR_STAT( tx_good );        cpd->stats.tx_total_collisions =             cpd->stats.tx_late_collisions +             cpd->stats.tx_max_collisions +             cpd->stats.tx_mult_collisions +             cpd->stats.tx_single_collisions;        // We do not need to look in the Counter Register (LAN91CXX_COUNTER)        // because it just mimics the info we already have above.    }#endif // KEEP_STATISTICS    // We do not really care about Tx failure.  Ethernet is not a reliable    // medium.  But we do care about the TX engine stopping.    tcr = get_reg(sc, LAN91CXX_TCR);    if ( 0 == (LAN91CXX_TCR_TXENA & tcr) ) {#if DEBUG & 1        db_printf("%s: ENGINE RESTART: tcr %x ints %04x\n", __FUNCTION__, tcr, ints);#endif        tcr |= LAN91CXX_TCR_TXENA;        put_reg(sc, LAN91CXX_TCR, tcr);        success = 0; // And treat this as an error...    }    packet &= 0xff;    // It certainly appears that occasionally the tx fifo tells lies; we    // get the wrong packet number.  Freeing the one we allocated seems to    // give correct operation.#ifdef CYGPKG_INFRA_DEBUG    // Then we log, OOI, the number of times we get a bad packet number    // from the tx done fifo.    if (cpd->txpacket != packet )        lan91cxx_txfifo_bad++;    else        lan91cxx_txfifo_good++;#endif#if DEBUG & 4    db_printf("#####Tx packet freed %x (expected %x)\n", packet, cpd->txpacket );#endif    // and then free the packet    put_reg(sc, LAN91CXX_PNR, cpd->txpacket);    put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);    // Ack the TX int which is supposed to clear the packet from the TX    // completion queue.    ints = get_reg(sc, LAN91CXX_INTERRUPT) & 0xff00;    ints |= LAN91CXX_INTERRUPT_TX_FIFO_ACK;    put_reg(sc, LAN91CXX_INTERRUPT, ints);#if DEBUG & 1    // Hm... The free doesn't seem to have the desired effect?!?    ints = get_reg(sc, LAN91CXX_INTERRUPT);    packet = get_reg(sc, LAN91CXX_FIFO_PORTS);    db_printf("%s:END: fifo %04x ints %04x\n", __FUNCTION__, packet, ints);#endif    if ( cpd->txbusy ) {        cpd->txbusy = 0;        (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);    }}//// This function is called when a packet has been received.  Its job is// to prepare to unload the packet from the hardware.  Once the length of// the packet is known, the upper layer of the driver can be told.  When// the upper layer is ready to unload the packet, the internal function// 'lan91cxx_recv' will be called to actually fetch it from the hardware.//static voidlan91cxx_RxEvent(struct eth_drv_sc *sc){    struct lan91cxx_priv_data *cpd =         (struct lan91cxx_priv_data *)sc->driver_private;    unsigned short stat, len;#ifdef LAN91CXX_32BIT_RX    cyg_uint32 val;#endif    DEBUG_FUNCTION();    stat = get_reg(sc, LAN91CXX_FIFO_PORTS);#if DEBUG & 1    db_printf("RxEvent - FIFOs: 0x%04x\n", stat);#endif    if ( 0x8000 & stat ) {        // Then the Rx FIFO is empty#if DEBUG & 4        db_printf("#####RxEvent with empty fifo\n");#endif        return;    }    INCR_STAT( rx_count );#if DEBUG & 4    db_printf("#####Rx packet allocated %x (previous %x)\n",                0xff & (stat >> 8), cpd->rxpacket );#endif    // There is an Rx Packet ready    cpd->rxpacket = 0xff & (stat >> 8);    // Read status and (word) length    put_reg(sc, LAN91CXX_POINTER, (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |                                 LAN91CXX_POINTER_AUTO_INCR | 0x0000));#ifdef LAN91CXX_32BIT_RX    val = get_data(sc);    val = CYG_LE32_TO_CPU(val);    stat = val & 0xffff;    len = ((val >> 16) & 0xffff) - 6;   // minus header/footer words#else    stat = get_data(sc);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -