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

📄 eth_drv.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
                START_CONSOLE();
                diag_printf("too many mbufs to tx, %d > %d, need %d\n", 
                            sg_len, MAX_ETH_DRV_SG, needed );
                END_CONSOLE();
#endif
                sg_len = 0;
                break; // drop it on the floor
            }
        }

#ifdef _LOCK_WITH_ROM_MONITOR
        // Firm lock on this portion of the driver.  Since we are about to
        // start messing with the actual hardware, it is imperative that the
        // current thread not loose control of the CPU at this time.  Otherwise,
        // the hardware could be left in an unusable state.  This caution is
        // only warranted if there is a possibility of some other thread trying
        // to use the hardware simultaneously.  The network stack would prevent
        // this implicitly since all accesses are controlled by the "splX()"
        // locks, but if there is a ROM monitor, such as RedBoot, also using
        // the hardware, all bets are off.

        // Note: these operations can be avoided if it were well known that
        // RedBoot was not using the network hardware for diagnostic I/O.  This
        // can be inferred by checking which I/O channel RedBoot is currently
        // hooked to.
        debug_chan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
        if (debug_chan == RedBoot_TCP_CHANNEL) {
            need_lock = true;
#ifdef _LOCK_USING_INTERRUPTS
            HAL_DISABLE_INTERRUPTS(ints);
#endif
            cyg_drv_dsr_lock();
        }
#endif // _LOCK_WITH_ROM_MONITOR

        // Tell hardware to send this packet
        if ( sg_len )
            (sc->funs->send)(sc, sg_list, sg_len, total_len, (unsigned long)m0);

#ifdef _LOCK_WITH_ROM_MONITOR
        // Unlock the driver & hardware.  It can once again be safely shared.
        if (need_lock) {
            cyg_drv_dsr_unlock();
#ifdef _LOCK_USING_INTERRUPTS
            HAL_RESTORE_INTERRUPTS(ints);
#endif
        }
#endif // _LOCK_WITH_ROM_MONITOR
#undef _LOCK_WITH_ROM_MONITOR
    }
}

//
// This function is called from the hardware driver when an output operation
// has completed - i.e. the packet has been sent.
//
static struct mbuf *mbuf_key;

static void
eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRESS key, int status)
{
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
    struct mbuf *m0 = (struct mbuf *)key;
    CYGARC_HAL_SAVE_GP();

    // Check for errors here (via 'status')
    ifp->if_opackets++;
    // Done with packet

    // Guard against a NULL return - can be caused by race conditions in
    // the driver, this is the neatest fixup:
    if (m0) { 
        mbuf_key = m0;
        m_freem(m0);
    }
    // Start another if possible
    eth_drv_send(ifp);
    CYGARC_HAL_RESTORE_GP();
}

//
// This function is called from a hardware driver to indicate that an input
// packet has arrived.  The routine will set up appropriate network resources
// (mbuf's) to hold the data and call back into the driver to retrieve the data.
//
static void
eth_drv_recv(struct eth_drv_sc *sc, int total_len)
{
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
    struct ether_header _eh, *eh=&_eh;
    struct mbuf *top, **mp, *m;
    int mlen;
    caddr_t data;
#if MAX_ETH_DRV_SG > 64
    static  // Avoid large stack requirements
#endif
    struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
    int sg_len;

    if ((ifp->if_flags & IFF_RUNNING) != IFF_RUNNING) {
        return;  // Interface not up, ignore this request
    }

    CYG_ASSERT( 0 != total_len, "total_len is zero!" );
    CYG_ASSERT( 0 <= total_len, "total_len is negative!" );
    CYG_ASSERT( sizeof( struct ether_header ) <= total_len,
                "No ether header here!" );

    if ( total_len < sizeof( struct ether_header ) )
        // Our arithmetic below would go wrong
        return;

    CYGARC_HAL_SAVE_GP();  // This is down here to make matching restore neat

    /* Pull packet off interface. */
    MGETHDR(m, M_DONTWAIT, MT_DATA);
    if (m == 0) {
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
        START_CONSOLE();
        diag_printf("warning: eth_recv out of MBUFs\n");
#ifdef CYGDBG_NET_SHOW_MBUFS        
        cyg_net_show_mbufs();
#endif
        END_CONSOLE();
#endif
    }

    // Set up buffers
    // Unload ethernet header separately so IP/UDP/TCP headers are aligned
    sg_list[0].buf = (CYG_ADDRESS)eh;
    sg_list[0].len = sizeof(*eh);
    sg_len = 1;

    // Compute total length (minus ethernet header)
    total_len -= sizeof(*eh);

    top = 0;
    mlen = MHLEN;
    mp = &top;

    if (m) {
        m->m_pkthdr.rcvif = ifp;
        m->m_pkthdr.len = total_len;
    } else {
        sg_list[sg_len].buf = (CYG_ADDRESS)0;
        sg_list[sg_len].len = total_len;
        sg_len++;
        total_len = 0;
    }

    while (total_len > 0) {
        if (top) {
            MGET(m, M_DONTWAIT, MT_DATA);
            if (m == 0) {
                m_freem(top);
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
                START_CONSOLE();
                diag_printf("out of MBUFs [2]");
#ifdef CYGDBG_NET_SHOW_MBUFS                
                cyg_net_show_mbufs();
#endif
                END_CONSOLE();
#endif
                sg_list[sg_len].buf = (CYG_ADDRESS)0;
                sg_list[sg_len].len = total_len;
                sg_len++;
                top = 0;
                break;
            }
            mlen = MLEN;
        }
        if (total_len >= MINCLSIZE) {
            MCLGET(m, M_DONTWAIT);
            if ((m->m_flags & M_EXT) == 0) {
                m_freem(top);
                m_free(m);
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
                START_CONSOLE();
                diag_printf("warning: eth_recv out of MBUFs\n");
#ifdef CYGDBG_NET_SHOW_MBUFS                
                cyg_net_show_mbufs();
#endif
                END_CONSOLE();
#endif
                sg_list[sg_len].buf = (CYG_ADDRESS)0;
                sg_list[sg_len].len = total_len;
                sg_len++;
                top = 0;
                break;
            }
            mlen = MCLBYTES;
        }
        m->m_len = mlen = min(total_len, mlen);
        total_len -= mlen;
        data = mtod(m, caddr_t);
        sg_list[sg_len].buf = (CYG_ADDRESS)data;
        sg_list[sg_len].len = mlen;
        sg_len++;
        *mp = m;
        mp = &m->m_next;
    } // endwhile

    // Ask hardware to unload buffers
    (sc->funs->recv)(sc, sg_list, sg_len);

#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
    if ( simulate_fail( sc, SIMULATE_FAIL_RECV ) ) {
        // toss the packet - note that some hardware gets
        // fussy if the packet isn't "unloaded", thus we
        // have to wait until now to throw it away
        if (top) {
	    m_free(top);
        }
        ifp->if_ierrors++;
        return;
    }

    if ( simulate_fail( sc, SIMULATE_FAIL_CORRUPT ) ) {
        // Corrupt the data
        simulate_fail_corrupt_sglist( sg_list, sg_len );
    }
#endif

#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
    if (cyg_io_eth_net_debug) {
        int i;
        START_CONSOLE();
        for (i = 0;  i < sg_len;  i++) {
            if (sg_list[i].buf) {
                diag_printf("rx %d bytes at %x sg[%d]\n", sg_list[i].len, sg_list[i].buf, i);
                if ( cyg_io_eth_net_debug > 1 )
                    diag_dump_buf((void *)sg_list[i].buf, sg_list[i].len);
            }
        }
        END_CONSOLE();
    }
#endif
    m = top;
    if (m == 0) {
        ifp->if_ierrors++;
    }
    else {
        ifp->if_ipackets++;

#if NBPFILTER > 0
#error FIXME - Need mbuf with ethernet header attached
        /*
         * Check if there's a BPF listener on this interface.
         * If so, hand off the raw packet to bpf.
         */
        if (ifp->if_bpf)
            bpf_mtap(ifp->if_bpf, m);
#endif

        // Push data into protocol stacks
        ether_input(ifp, eh, m);
    }
    CYGARC_HAL_RESTORE_GP();
}


// ------------------------------------------------------------------------
// DSR to schedule network delivery thread

extern void ecos_synch_eth_drv_dsr(void); // from ecos/timeout.c in net stack

void
eth_drv_dsr(cyg_vector_t vector,
            cyg_ucount32 count,
            cyg_addrword_t data)
{
    struct eth_drv_sc *sc = (struct eth_drv_sc *)data;

#ifdef CYGDBG_USE_ASSERTS
    // then check that this really is a "sc"
    {
        cyg_netdevtab_entry_t *t;
        for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++)
            if ( ((struct eth_drv_sc *)t->device_instance) == sc )
                break; // found it
        CYG_ASSERT( t != &__NETDEVTAB_END__, "eth_drv_dsr: Failed to find sc in NETDEVTAB" );
    }
#endif // Checking code

    sc->state |= ETH_DRV_NEEDS_DELIVERY;

    ecos_synch_eth_drv_dsr(); // [request] run delivery function for this dev
}

// This is called from the delivery thread, to do just that:
void eth_drv_run_deliveries( void )
{
    cyg_netdevtab_entry_t *t;
    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
        struct eth_drv_sc *sc = (struct eth_drv_sc *)t->device_instance;
        if ( ETH_DRV_NEEDS_DELIVERY & sc->state ) {
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
            cyg_bool was_ctrlc_int;
#endif
            sc->state &=~ETH_DRV_NEEDS_DELIVERY;
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
            was_ctrlc_int = HAL_CTRLC_CHECK((*sc->funs->int_vector)(sc), (int)sc);
            if (!was_ctrlc_int) // Fall through and run normal code
#endif
            (*sc->funs->deliver)(sc);
        }
    }
}

// This is called from the delivery thread, to unstick devices if there is
// no network activity.
#ifdef CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
void eth_drv_tickle_devices( void )
{
    cyg_netdevtab_entry_t *t;
    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
        struct eth_drv_sc *sc = (struct eth_drv_sc *)t->device_instance;
        if ( ETH_DRV_STATE_ACTIVE & sc->state ) {
            struct ifnet *ifp = &sc->sc_arpcom.ac_if;
            // Try to dequeue a packet for this interface, if we can.  This
            // will call can_send() for active interfaces.  It is calls to
            // this function from tx_done() which normally provide
            // continuous transmissions; otherwise we do not get control.
            // This call fixes that.
            if (!IF_IS_EMPTY(&ifp->if_snd)) {
                eth_drv_send(ifp);
            }
        }
    }
}
#endif // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS

// ------------------------------------------------------------------------

#ifdef CYGPKG_IO_PCMCIA
// Lookup a 'netdev' entry, assuming that it is an ethernet device.
cyg_netdevtab_entry_t * 
eth_drv_netdev(char *name)
{
    cyg_netdevtab_entry_t *t;
    struct eth_drv_sc *sc;
    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
        sc = (struct eth_drv_sc *)t->device_instance;
        if (strcmp(sc->dev_name, name) == 0) {
            return t;
        }
    }
    return (cyg_netdevtab_entry_t *)NULL;
}
#endif // CYGPKG_IO_PCMCIA

// EOF src/net/eth_drv.c

⌨️ 快捷键说明

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