⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_lancepci.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
#if DEBUG & 9    db_printf("Lancepci-control:done\n");#endif    CYGACC_CALL_IF_DELAY_US(50000);	// let VMware get a tick    return res;}//// 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 intlancepci_can_send(struct eth_drv_sc *sc){    struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;    DEBUG_FUNCTION();    return (0 == cpd->txbusy);}//// This routine is called to send data to the hardware.static voidlancepci_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,            int total_len, unsigned long key){    struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;    int i, len, plen, ring_entry;    cyg_uint8* sdata = NULL;    cyg_uint8 *d, *buf, *txd;    cyg_uint16 ints;    cyg_uint32 b;    DEBUG_FUNCTION();    INCR_STAT( tx_count );    cpd->txbusy = 1; cpd->txbusyh=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" );    // Get next TX descriptor    ring_entry = cpd->tx_ring_free;    do {        if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {            // Is this a dead end? Probably is.#if DEBUG & 1            db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );#endif            continue;        }        cpd->tx_ring_free++;        cpd->tx_ring_owned++;        if (cpd->tx_ring_free == cpd->tx_ring_cnt)            cpd->tx_ring_free = 0;    } while (0);    txd = cpd->tx_ring + ring_entry*LANCE_TD_SIZE;    buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;    CYG_ASSERT(0 == (_SU32(txd, LANCE_TD_PTR) & LANCE_TD_PTR_OWN),               "TX descriptor not free");#if DEBUG & 4    db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",                txd, buf);#endif    // Put data into buffer    d = buf;    for (i = 0;  i < sg_len;  i++) {        sdata = (cyg_uint8 *)sg_list[i].buf;        len = sg_list[i].len;        CYG_ASSERT( sdata, "No sg data pointer here" );        while(len--)            *d++ = *sdata++;    }    CYG_ASSERT( sdata, "No sg data pointer outside" );#if DEBUG & 1    db_printf("CSCR %04x\n", get_reg(sc, LANCE_CSR_CSCR));#endif    _SU16(txd, LANCE_TD_LEN) = (-plen);    _SU16(txd, LANCE_TD_MISC) = 0;    HAL_PCI_CPU_TO_BUS(buf, (cyg_uint8 *)b);    _SU32(txd, LANCE_TD_PTR) = ((b & LANCE_TD_PTR_MASK)                                | LANCE_TD_PTR_OWN | LANCE_TD_PTR_STP | LANCE_TD_PTR_ENP);#if DEBUG & 1    db_printf("Last TX: LEN %04x MISC %04x PTR %08x\n",                _SU16(txd, LANCE_TD_LEN),                _SU16(txd, LANCE_TD_MISC),                _SU32(txd, LANCE_TD_PTR));#endif    // This delay seems to be necessary on some platforms    // (Malta 5kc for example).    // Why it is needed is not clear, but removing it or    // reducing it cause transmission failures in RedBoot (at least).    CYGACC_CALL_IF_DELAY_US(100);    // Set transmit demand    ints = get_reg(sc, LANCE_CSR_CSCR);    ints &= LANCE_CSR_CSCR_EV_MASK;    ints |= LANCE_CSR_CSCR_TDMD;    put_reg(sc, LANCE_CSR_CSCR, ints);#if DEBUG & 1    ints = get_reg(sc, LANCE_CSR_CSCR);    db_printf("%s:END: ints at TX: 0x%04x\n", __FUNCTION__, ints);#endif    // This is another mystery delay like the one above. This one is    // even stranger, since waiting here at the _end_ of the function    // should have no effect.    CYGACC_CALL_IF_DELAY_US(200);}static voidlancepci_TxEvent(struct eth_drv_sc *sc, int stat){     struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;    int success = 1;    cyg_uint8 *txd;    cyg_uint16 ints;    cyg_uint32 pkt_stat;    DEBUG_FUNCTION();    if (0 == cpd->tx_ring_owned) {#if DEBUG & 1        db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);#endif        return;    }    INCR_STAT( tx_complete );    txd = cpd->tx_ring + cpd->tx_ring_alloc*LANCE_TD_SIZE;    pkt_stat = _SU32(txd, LANCE_TD_PTR);    if (pkt_stat & LANCE_TD_PTR_OWN) {#if DEBUG & 1        db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);#endif        // first dirty ring entry not freed - wtf?    }    if (pkt_stat & LANCE_TD_PTR_ERR) {        // We had an error. Tell the stack.        success = 0;#if DEBUG & 1        db_printf("%s: TX failure, retrying...\n", __FUNCTION__);#endif    }    cpd->tx_ring_alloc++;    if (cpd->tx_ring_alloc == cpd->tx_ring_cnt)        cpd->tx_ring_alloc = 0;    cpd->tx_ring_owned--;#if FIXME#ifdef KEEP_STATISTICS    {        cyg_uint16 reg;        reg = get_reg( sc, LANCE_CSR_CSCR );        // Covering each bit in turn...        if ( reg & LANCE_STATUS_TX_UNRN   ) INCR_STAT( tx_underrun );        //if ( reg & LANCE_STATUS_LINK_OK ) INCR_STAT(  );        //if ( reg & LANCE_STATUS_CTR_ROL ) INCR_STAT(  );        //if ( reg & LANCE_STATUS_EXC_DEF ) INCR_STAT(  );        if ( reg & LANCE_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );        if ( reg & LANCE_STATUS_LATCOL    ) INCR_STAT( tx_late_collisions );        //if ( reg & LANCE_STATUS_WAKEUP  ) INCR_STAT(  );        if ( reg & LANCE_STATUS_TX_DEFR   ) INCR_STAT( tx_deferred );        //if ( reg & LANCE_STATUS_LTX_BRD ) INCR_STAT(  );        if ( reg & LANCE_STATUS_SQET      ) INCR_STAT( tx_sqetesterrors );        if ( reg & LANCE_STATUS_16COL     ) INCR_STAT( tx_max_collisions );        //if ( reg & LANCE_STATUS_LTX_MULT) INCR_STAT(  );        if ( reg & LANCE_STATUS_MUL_COL   ) INCR_STAT( tx_mult_collisions );        if ( reg & LANCE_STATUS_SNGL_COL  ) INCR_STAT( tx_single_collisions );        if ( reg & LANCE_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 (LANCE_COUNTER)        // because it just mimics the info we already have above.    }#endif // KEEP_STATISTICS#endif // FIXME    // Ack the TX int which clears the packet from the TX completion    // queue.    ints = get_reg(sc, LANCE_CSR_CSCR);    ints |= LANCE_CSR_CSCR_TINT;    put_reg(sc, LANCE_CSR_CSCR, ints);#if DEBUG & 4    db_printf("#####Tx packet freed 0x%08x\n", txd );#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// 'lancepci_recv' will be called to actually fetch it from the hardware.//static voidlancepci_RxEvent(struct eth_drv_sc *sc){    struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;    cyg_uint8 *rxd;    cyg_uint32 rstat;    cyg_uint16 ints, len;    DEBUG_FUNCTION();    ints = get_reg(sc, LANCE_CSR_CSCR);#if DEBUG & 1    db_printf("RxEvent - CSR: 0x%04x\n", ints);#endif    while (1) {        // Get state of next (supposedly) full ring entry        cpd->rxpacket = cpd->rx_ring_next;        rxd = cpd->rx_ring + cpd->rxpacket*LANCE_RD_SIZE;        rstat = _SU32(rxd, LANCE_RD_PTR);        // Keep going until we hit an entry that is owned by the        // controller.        if (rstat & LANCE_RD_PTR_OWN) {#if DEBUG & 1            int i;            for (i = 0; i < cpd->rx_ring_cnt; i++) {                rxd = cpd->rx_ring + i*LANCE_RD_SIZE;                rstat = _SU32(rxd, LANCE_RD_PTR);                if (!(rstat & LANCE_RD_PTR_OWN)) {                    int i;                    cyg_uint32 rstat;                    cyg_uint16 mlen, blen;                    cyg_uint8* rxd;                    db_printf("%s: Inconsistent RX state\n", __FUNCTION__);                    for (i = 0; i < cpd->rx_ring_cnt; i++) {                        rxd = cpd->rx_ring + i*LANCE_RD_SIZE;                        rstat = _SU32(rxd, LANCE_RD_PTR);                        blen = _SU16(rxd, LANCE_RD_BLEN);                        mlen = _SU16(rxd, LANCE_RD_MLEN);                        db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);                    }                }            }#endif            break;        }#if DEBUG & 4        db_printf("#####Rx packet at index %d\n", cpd->rxpacket);#endif        // Increment counts        INCR_STAT( rx_count );        cpd->rx_ring_next++;        if (cpd->rx_ring_next == cpd->rx_ring_cnt) cpd->rx_ring_next = 0;        len = _SU16(rxd, LANCE_RD_MLEN);#ifdef KEEP_STATISTICS        //if ( rstat & LANCE_RD_PTR_FRAM ) INCR_STAT( rx_frame_errors );        //if ( rstat & LANCE_RD_PTR_OFLO ) INCR_STAT(  );        if ( rstat & LANCE_RD_PTR_CRC ) INCR_STAT( rx_crc_errors );        //if ( rstat & LANCE_RD_PTR_BUFF ) INCR_STAT(  );#endif // KEEP_STATISTICS        if (0 == (rstat & LANCE_RD_PTR_ERR)) {            // It's OK            INCR_STAT( rx_good );#if DEBUG & 1            db_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);#endif            // Check for bogusly short packets; can happen in promisc            // mode: Asserted against and checked by upper layer            // driver.#ifdef CYGPKG_NET            if ( len > sizeof( struct ether_header ) )                // then it is acceptable; offer the data to the network stack#endif                (sc->funs->eth_drv->recv)(sc, len);        } else {            // Not OK for one reason or another...#if DEBUG & 1            db_printf("RxEvent - No RX bit: stat: 0x%08x, len: 0x%04x\n",                        rstat, len);#endif        }        // Free packet (clear all status flags, and set OWN)        _SU32(rxd, LANCE_RD_PTR) &= LANCE_RD_PTR_MASK;        _SU32(rxd, LANCE_RD_PTR) |= LANCE_RD_PTR_OWN;    }    // Ack RX interrupt set    ints = get_reg(sc, LANCE_CSR_CSCR);    ints &= LANCE_CSR_CSCR_EV_MASK;    ints |= LANCE_CSR_CSCR_RINT;    put_reg(sc, LANCE_CSR_CSCR, ints);}//// This function is called as a result of the "eth_drv_recv()" call above.// Its job is to actually fetch data for a packet from the hardware once// memory buffers have been allocated for the packet.  Note that the buffers// may come in pieces, using a scatter-gather list.  This allows for more// efficient processing in the upper layers of the stack.//static voidlancepci_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){    struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;    int i, mlen=0, plen;    cyg_uint8 *data, *rxd, *buf;    DEBUG_FUNCTION();    rxd = cpd->rx_ring + cpd->rxpacket*LANCE_RD_SIZE;    buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;    INCR_STAT( rx_deliver );    plen = _SU16(rxd, LANCE_RD_MLEN);    for (i = 0;  i < sg_len;  i++) {        data = (cyg_uint8*)sg_list[i].buf;        mlen = sg_list[i].len;#if DEBUG & 1        db_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);#endif        if (data) {            while (mlen > 0) {                *data++ = *buf++;                mlen--;                plen--;            }        }    }}static voidlancepci_poll(struct eth_drv_sc *sc){    cyg_uint16 event;    struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;//  DEBUG_FUNCTION();    while (1) {        // Get the (unmasked) requests	if (cpd->event) {	    event=cpd->event;	    cpd->event=0;	}	else            event = get_reg(sc, LANCE_CSR_CSCR);        if (!((LANCE_CSR_CSCR_ERR|LANCE_CSR_CSCR_INTR) & event))            break;        if (event & LANCE_CSR_CSCR_RINT) {            lancepci_RxEvent(sc);        }        else if (event & LANCE_CSR_CSCR_TINT) {	    cpd->txbusyh=0;		// again , for polled mode            lancepci_TxEvent(sc, event);        }        else if (event & LANCE_CSR_CSCR_MISS) {#if DEBUG & 1            int i;            cyg_uint32 rstat;            cyg_uint16 mlen, blen;            cyg_uint8* rxd;            struct lancepci_priv_data *cpd =                (struct lancepci_priv_data *)sc->driver_private;            db_printf("%s: Ran out of RX buffers (%04x)\n", __FUNCTION__, event);            for (i = 0; i < cpd->rx_ring_cnt; i++) {                rxd = cpd->rx_ring + i*LANCE_TD_SIZE;                rstat = _SU32(rxd, LANCE_RD_PTR);                blen = _SU16(rxd, LANCE_RD_BLEN);                mlen = _SU16(rxd, LANCE_RD_MLEN);                db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);            }#endif            event &= LANCE_CSR_CSCR_EV_MASK;            event |= LANCE_CSR_CSCR_MISS;            put_reg(sc, LANCE_CSR_CSCR, event);        }        else {#if DEBUG & 1            db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);#endif            put_reg(sc, LANCE_CSR_CSCR, event);        }    }}// EOF if_lancepci.c

⌨️ 快捷键说明

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