if_rhine.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,320 行 · 第 1/3 页

C
1,320
字号
    // This MII read forces the MIISR to get updated    (void) rhine_read_MII(cpd, cpd->phys_id, MII_BMSR);    HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_MIISR, stat);    if (stat & RHINE_MIISR_LNKFL) {#if DEBUG & 1        diag_printf("*** Link failure\n");#endif        return false;  // Link not connected    }    return (cpd->txbusy == 0);}//// This routine is called to send data to the hardware.static void rhine_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,             int total_len, unsigned long key){    struct rhine_priv_data *cpd =         (struct rhine_priv_data *)sc->driver_private;    int i, len, plen, ring_entry;    cyg_uint8* sdata = NULL;    cyg_uint8 *d, *buf, *txd;    cyg_uint16 status;    cyg_uint8 cr0;    DEBUG_FUNCTION();    INCR_STAT( tx_count );    // Worry about the engine stopping.    HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR0, status);    if ( 0 == (RHINE_CR0_STRT & status) ) {#if DEBUG & 1        diag_printf("%s: ENGINE RESTART: status %04x\n", __FUNCTION__, status);#endif        status &= ~RHINE_CR0_STOP;        status |= RHINE_CR0_STRT;        HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, status);    }    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" );        // 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            diag_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*RHINE_TD_SIZE;    buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;    CYG_ASSERT(0 == (_SU32(txd, RHINE_TDES0) & RHINE_TDES0_OWN),               "TX descriptor not free");#if DEBUG & 4    diag_printf("##Tx descriptor index %d TDES %08x buffer %08x\n",                 ring_entry, 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" );        // Annoyingly the chip doesn't pad to minimal packet size, so do    // that by steam    if (plen < 60) {        plen = 60;#if DEBUG & 4        diag_printf("Padded %d bytes packet to 60 bytes\n", plen);#endif    }            CYG_ASSERT( (plen & RHINE_TDES1_TLNG_mask) == plen, "packet too long");    CYG_ASSERT( (plen & RHINE_TDES1_TLNG_mask) >= 60, "packet too short");    _SU32(txd, RHINE_TDES1) &= ~RHINE_TDES1_TLNG_mask;    _SU32(txd, RHINE_TDES1) |= plen;    _SU32(txd, RHINE_TDES0) = RHINE_TDES0_OWN;#if DEBUG & 1 // FIXME    diag_printf("Before TX: Desc (@0x%08lx) %08x %08x %08x %08x\n Next (@0x%08lx) %08x %08x %08x %08x\n",                (unsigned long) txd,                _SU32(txd, RHINE_TDES0), _SU32(txd, RHINE_TDES1),                _SU32(txd, RHINE_TDES2), _SU32(txd, RHINE_TDES3),                (  (unsigned long)txd)+0x10,                _SU32(txd, (0x10+RHINE_TDES0)), _SU32(txd, (0x10+RHINE_TDES1)),                _SU32(txd,(0x10+ RHINE_TDES2)), _SU32(txd,(0x10+ RHINE_TDES3)));#endif    // Ack TX empty int    HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_PTX);    // Set transmit demand    HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR0, cr0);    cr0 |= RHINE_CR0_TDMD;    HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, cr0);#if DEBUG & 1    HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_ISR, status);    diag_printf("%s:END: ints at TX: %04x\n", __FUNCTION__, status);#endif}static voidrhine_TxEvent(struct eth_drv_sc *sc, int stat){     struct rhine_priv_data *cpd =        (struct rhine_priv_data *)sc->driver_private;    int success = 1;    cyg_uint8 *txd;    cyg_uint8 status;    DEBUG_FUNCTION();    INCR_STAT( tx_complete );    txd = cpd->tx_ring + cpd->tx_ring_alloc*RHINE_TD_SIZE;#if DEBUG & 4    diag_printf("##Tx packet %d freed %08x %08x!\n", cpd->tx_ring_alloc, txd, _SU32(txd, RHINE_TDES0) );#endif    if ((_SU32(txd, RHINE_TDES0) & RHINE_TDES0_OWN)) {#if DEBUG & 1        diag_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);#endif        // first dirty ring entry not freed - wtf?    }    cpd->tx_ring_alloc++;    if (cpd->tx_ring_alloc == cpd->tx_ring_cnt)        cpd->tx_ring_alloc = 0;    cpd->tx_ring_owned--;#ifdef KEEP_STATISTICS    {        cyg_uint32 reg = _SU32(txd, RHINE_TDES0);        int collisions;        // Covering each bit in turn...        if ( reg & RHINE_TDES0_TXOK ) INCR_STAT( tx_good );        if ( reg & RHINE_TDES0_CRS ) INCR_STAT( tx_carrier_loss );        if ( reg & RHINE_TDES0_OWC ) INCR_STAT( tx_late_collisions );        if ( reg & RHINE_TDES0_ABT ) INCR_STAT( tx_max_collisions );        if ( reg & RHINE_TDES0_DFR ) INCR_STAT( tx_deferred );        collisions = ((reg & RHINE_TDES0_NCR_mask) >> RHINE_TDES0_NCR_shift);        if (1 == collisions)            INCR_STAT( tx_single_collisions );        else if (1 < collisions)            INCR_STAT( tx_mult_collisions );        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;    }#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.    HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR0, status);    if ( 0 == (RHINE_CR0_STRT & status) ) {#if DEBUG & 1        diag_printf("%s: ENGINE RESTART: status %04x\n", __FUNCTION__, status);#endif        status &= ~RHINE_CR0_STOP;        status |= RHINE_CR0_STRT;        HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, status);        success = 0; // And treat this as an error...    }    if ( cpd->txbusy ) {        cpd->txbusy = 0;        (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);    }    // Ack TX interrupt set    HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_PTX);}//// 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// 'rhine_recv' will be called to actually fetch it from the hardware.//static voidrhine_RxEvent(struct eth_drv_sc *sc){    struct rhine_priv_data *cpd =         (struct rhine_priv_data *)sc->driver_private;    cyg_uint8 *rxd;    cyg_uint32 rstat;    cyg_uint16 ints, len, mask;    DEBUG_FUNCTION();    HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_ISR, ints);#if DEBUG & 1    diag_printf("RxEvent - CSR: 0x%04x\n", ints);#endif    if ( 0 == (RHINE_ISR_PRX & ints) )        // Then there's no RX event pending        return;    // Mask interrupt    HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_IMR, mask);    mask &= ~RHINE_IMR_PRX;    HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_IMR, mask);    while (1) {        // Get state of next (supposedly) full ring entry        cpd->rxpacket = cpd->rx_ring_next;        rxd = cpd->rx_ring + cpd->rxpacket*RHINE_RD_SIZE;        rstat = _SU32(rxd, RHINE_RDES0);        // Keep going until we hit an entry that is owned by the        // controller.        if (rstat & RHINE_RDES0_OWN) {#ifdef CYGDBG_USE_ASSERTS            // Sanity check of queue            int i;            for (i = 0; i < cpd->rx_ring_cnt; i++) {                rxd = cpd->rx_ring + i*RHINE_RD_SIZE;                rstat = _SU32(rxd, RHINE_RDES0);                if (!(rstat & RHINE_RDES0_OWN)) {                    int i;                    cyg_uint32 rstat;                    cyg_uint8* rxd;                    diag_printf("####Rx %s Inconsistent RX state - next was %d\n",                                 __FUNCTION__, cpd->rx_ring_next);                    for (i = 0; i < cpd->rx_ring_cnt; i++) {                        rxd = cpd->rx_ring + i*RHINE_RD_SIZE;                        rstat = _SU32(rxd, RHINE_RDES0);                        diag_printf("#### %02d: 0x%08x\n", i, rstat);                    }                }                break;            }#endif            break;        }#if DEBUG & 4        diag_printf("##Rx packet %d RDES %08x stat %08x\n",                     cpd->rxpacket, rxd, rstat);#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 = (rstat & RHINE_RDES0_FLNG_mask) >> RHINE_RDES0_FLNG_shift;#ifdef KEEP_STATISTICS        if ( rstat & RHINE_RDES0_CRC ) INCR_STAT( rx_crc_errors );        if ( rstat & RHINE_RDES0_FAE ) INCR_STAT( rx_align_errors );        if ( rstat & RHINE_RDES0_LONG ) INCR_STAT( rx_too_long_frames );#endif // KEEP_STATISTICS        if (RHINE_RDES0_RXOK & rstat) {            // It's OK            INCR_STAT( rx_good );#if DEBUG & 1            diag_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);            {                    unsigned char *buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;                    int i;                    diag_printf("RDES: %08x %08x %08x %08x\n",                                 _SU32(rxd, RHINE_RDES0), _SU32(rxd, RHINE_RDES1),                                _SU32(rxd, RHINE_RDES2), _SU32(rxd, RHINE_RDES3));                    diag_printf("Packet data at %p\n", buf);                    for (i=0;i<len;i++) diag_printf("%02x ", buf[i]);                    diag_printf("\n");            }#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            diag_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, RHINE_RDES0) = RHINE_RDES0_OWN;    }    // Ack RX int    HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_PRX);    // And reenable the interrupt    HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_IMR, mask);    mask |= RHINE_IMR_PRX;    HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_IMR, mask);}//// 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 voidrhine_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){    struct rhine_priv_data *cpd =         (struct rhine_priv_data *)sc->driver_private;    int i, mlen=0, plen;    cyg_uint8 *data, *rxd, *buf;    DEBUG_FUNCTION();    rxd = cpd->rx_ring + cpd->rxpacket*RHINE_RD_SIZE;    buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;    INCR_STAT( rx_deliver );    plen = (_SU32(rxd, RHINE_RDES0) & RHINE_RDES0_FLNG_mask) >> RHINE_RDES0_FLNG_shift;    for (i = 0;  i < sg_len;  i++) {        data = (cyg_uint8*)sg_list[i].buf;        mlen = sg_list[i].len;#if DEBUG & 1        diag_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);#endif        if (data) {            while (mlen > 0) {                *data++ = *buf++;                mlen--;                plen--;            }        }    }}static voidrhine_poll(struct eth_drv_sc *sc){    struct rhine_priv_data *cpd =         (struct rhine_priv_data *)sc->driver_private;    cyg_uint16 event, mask;    static volatile bool locked = false;//    DEBUG_FUNCTION();    while (1) {        // Get the (unmasked) requests        HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_ISR, event);        HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_IMR, mask);        event &= mask;        if (0 == event)            break;        if (event & RHINE_ISR_PRX) {            rhine_RxEvent(sc);        }        else if (event & RHINE_ISR_PTX) {            rhine_TxEvent(sc, event);        }         else if (event & RHINE_ISR_RU) {#if DEBUG & 1            int i;            cyg_uint32 rstat;            cyg_uint8* rxd;            struct rhine_priv_data *cpd =                 (struct rhine_priv_data *)sc->driver_private;            diag_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*RHINE_RD_SIZE;                                rstat = _SU32(rxd, RHINE_RDES0);                diag_printf(" %02d: 0x%08x\n", i, rstat);            }#endif            HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_RU);        }        else {#if DEBUG & 1            diag_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);#endif            // Clear unhandled interrupts and hope for the best            // This should never happen though, since we only enable            // the sources we handle.            HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, event);        }    }    locked = false;}// EOF if_rhine.c

⌨️ 快捷键说明

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