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

📄 if_ebsa285.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 5 页
字号:
    TxMachine(p_i82559);
    Acknowledge82559Interrupt(p_i82559); // This can eat an Rx interrupt, so
    PacketRxReady(p_i82559);
    UnMask82559Interrupt(p_i82559,ints);

    return ! p_i82559->tx_queue_full;
}

// ------------------------------------------------------------------------
//
//  Function : i82559_send
//
// ------------------------------------------------------------------------

static void 
i82559_send(struct eth_drv_sc *sc,
            struct eth_drv_sg *sg_list, int sg_len, int total_len,
            unsigned long key)
{
    struct i82559 *p_i82559;
    int tx_descriptor_add, ints;
    TxCB *p_txcb;
    cyg_uint32 ioaddr;

    p_i82559 = (struct i82559 *)sc->driver_private;

    IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
        os_printf( "i82559_send: Bad device pointer %x\n", p_i82559 );
#endif
        return;
    }

#ifdef DEBUG_82559
    os_printf("Tx %d %x: %d sg's, %d bytes, KEY %x\n",
              p_i82559->index, (int)p_i82559, sg_len, total_len, key );
#endif

    if ( ! p_i82559->active )
        return;                         // device inactive, no return
#ifdef KEEP_STATISTICS
    statistics[p_i82559->index].tx_count++;
#endif
    ioaddr = p_i82559->io_address;      // get device I/O address

    if ( p_i82559->tx_queue_full ) {
#ifdef KEEP_STATISTICS
        statistics[p_i82559->index].tx_dropped++;
#endif
#ifdef DEBUG_82559
        os_printf( "i82559_send: Queue full, device %x, key %x\n",
                   p_i82559, key );
#endif
    }
    else {
        struct eth_drv_sg *last_sg;
        volatile cyg_uint8 *to_p;

        tx_descriptor_add = p_i82559->tx_descriptor_add;

        p_i82559->tx_keys[tx_descriptor_add] = key;

        p_txcb = p_i82559->tx_ring[tx_descriptor_add];

        CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" );
        CYG_ASSERT( (cyg_uint8 *)p_txcb <  i82559_heap_free, "txcb over" );

        p_txcb->txstatus = 0;
        p_txcb->command = TxCB_CMD_TRANSMIT | TxCB_CMD_S
                                | TxCB_CMD_I | TxCB_CMD_EL;
        p_txcb->link = VIRT_TO_BUS((cyg_uint32)p_txcb);
        p_txcb->tbd_address = 0xFFFFFFFF;
        p_txcb->tbd_number = 0;
        p_txcb->tx_threshold = 16;
        p_txcb->eof = 1;
        p_txcb->count = total_len;

        // Copy from the sglist into the txcb
        to_p = &p_txcb->buffer[0];

        CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
        CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );

        for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
            cyg_uint8 *from_p;
            int l;
            
            from_p = (cyg_uint8 *)(sg_list->buf);
            l = sg_list->len;

            if ( l > total_len )
                l = total_len;

            memcpy( (unsigned char *)to_p, from_p, l );
            to_p += l;
            total_len -= l;

            if ( 0 > total_len ) 
                break; // Should exit via sg_last normally
        }

        CYG_ASSERT( 0 == total_len, "length mismatch in tx" );
        CYG_ASSERT( last_sg == sg_list, "sg count mismatch in tx" );
        CYG_ASSERT( &p_txcb->buffer[0] < to_p, "to_p wild in tx" );
        CYG_ASSERT( &p_txcb->buffer[0] + MAX_TX_PACKET_SIZE >= to_p,
                    "to_p overflow in tx" );
  
        // Next descriptor
        if ( ++tx_descriptor_add >= MAX_TX_DESCRIPTORS)
            tx_descriptor_add = 0;
        p_i82559->tx_descriptor_add = tx_descriptor_add;

        // From this instant, interrupts can advance the world and start,
        // even complete, this tx request...

        if ( p_i82559->tx_descriptor_remove == tx_descriptor_add )
            p_i82559->tx_queue_full = 1;
    }

    // Try advancing the Tx Machine regardless

    // no more interrupts until started
    ints = Mask82559Interrupt(p_i82559);

    // Check that either:
    //     tx is already active, there is other stuff queued,
    // OR  this tx just added is the current active one
    // OR  this tx just added is already complete
    CYG_ASSERT(
        // The machine is busy:
        (p_i82559->tx_in_progress == 1) ||
        // or: The machine is idle and this just added is the next one
        (((p_i82559->tx_descriptor_add-1) == p_i82559->tx_descriptor_active)
         || ((0 == p_i82559->tx_descriptor_add) &&
             ((MAX_TX_DESCRIPTORS-1) == p_i82559->tx_descriptor_active))) ||
        // or: This tx is already complete
        (p_i82559->tx_descriptor_add == p_i82559->tx_descriptor_active),
                "Active/add mismatch" );

    // Advance TxMachine atomically
    TxMachine(p_i82559);
    Acknowledge82559Interrupt(p_i82559); // This can eat an Rx interrupt, so
    PacketRxReady(p_i82559);
    UnMask82559Interrupt(p_i82559, ints);
}

// ------------------------------------------------------------------------
//
//  Function : i82559_reset
//
// ------------------------------------------------------------------------
static void i82559_reset(struct i82559* p_i82559)
{
    cyg_uint32 ioaddr;
    int count;

    ioaddr = p_i82559->io_address;
    // make sure no command operating
    wait_for_cmd_done(ioaddr);   
 
    OUTL(I82559_SELECTIVE_RESET, ioaddr + SCBPort);
  
    for (count = 10 ; count-- ; ) {
        udelay(1000);
    }

    OUTL(I82559_RESET, ioaddr + SCBPort);
    
    for (count = 10 ; count-- ; ) {
      udelay(1000);
    }
}


// ------------------------------------------------------------------------
//
//                       INTERRUPT HANDLERS
//
// ------------------------------------------------------------------------

static cyg_uint32 eth_isr(cyg_vector_t vector, cyg_addrword_t data)
{
    struct i82559* p_i82559 = (struct i82559 *)data;
    cyg_uint16 status;
    cyg_uint32 ioaddr;

    IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
        os_printf( "i82559_isr: Bad device pointer %x\n", p_i82559 );
#endif
        return 0;
    }

    ioaddr = p_i82559->io_address;
    status = INW(ioaddr + SCBStatus);
    // Acknowledge all INT sources that were active
    OUTW( status & SCB_INTACK_MASK, ioaddr + SCBStatus);
    // (see pages 6-10 & 6-90)

#ifdef KEEP_STATISTICS
    statistics[p_i82559->index].interrupts++;

    // receiver left ready state ?
    if ( status & SCB_STATUS_RNR )
        statistics[p_i82559->index].rx_resource++;

    // frame receive interrupt ?
    if ( status & SCB_STATUS_FR )
        statistics[p_i82559->index].rx_count++;

    // transmit interrupt ?
    if ( status & SCB_STATUS_CX )
        statistics[p_i82559->index].tx_complete++;
#endif

    // Advance the Tx Machine regardless
    TxMachine(p_i82559);

    // it should have settled down now...
    Acknowledge82559Interrupt(p_i82559);

    return CYG_ISR_CALL_DSR;        // schedule DSR
}


// ------------------------------------------------------------------------
static int mux_device_index = 0;

static cyg_uint32 eth_mux_isr(cyg_vector_t vector, cyg_addrword_t data)
{
    int device_index = mux_device_index;
    struct i82559* p_i82559;

    mux_device_index ^= 1; // look at the other one first next time.

    do {
        p_i82559 = &i82559[device_index];
        if ( p_i82559->active )
            (void)eth_isr( vector, (cyg_addrword_t)p_i82559 );
        device_index ^= 1;
    } while ( device_index == mux_device_index );

    return CYG_ISR_CALL_DSR;
}

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

static 
void eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    struct i82559* p_i82559 = (struct i82559 *)data;
    struct cyg_netdevtab_entry *ndp =
        (struct cyg_netdevtab_entry *)(p_i82559->ndp);
    struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);

    // but here, it must be a *sc:
    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
}

// ------------------------------------------------------------------------
// This is called from the function below (used to be uni-DSR)
static inline void
uni_deliver(struct i82559* p_i82559)
{
    // First pass any rx data up the stack
    PacketRxReady(p_i82559);

    // Then scan for completed Txen and inform the stack
    TxDone(p_i82559);
}


// ------------------------------------------------------------------------
void i82559_deliver(struct eth_drv_sc *sc)
{
    struct i82559* p_i82559;
    int device_index = mux_device_index;

    // Since this must mux both devices, the incoming arg is ignored.

    mux_device_index ^= 1; // look at the other one first next time.
    do {
        p_i82559 = &i82559[device_index];
        if ( p_i82559->active )
            uni_deliver( p_i82559 );
        device_index ^= 1;
    } while ( device_index == mux_device_index );
}

// ------------------------------------------------------------------------
// Device table entry to operate the chip in a polled mode.
// Only diddle the interface we were asked to!

void i82559_poll(struct eth_drv_sc *sc)
{
    struct i82559 *p_i82559;
    int ints;
    p_i82559 = (struct i82559 *)sc->driver_private;
    
    IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
        os_printf( "i82559_poll: Bad device pointer %x\n", p_i82559 );
#endif
        return;
    }

    // Do these atomically
    ints = Mask82559Interrupt(p_i82559);

    // As it happens, this driver always requests the DSR to be called:
    (void)eth_isr( CYGNUM_HAL_INTERRUPT_PCI_IRQ, (cyg_addrword_t)p_i82559 );

    // (no harm in calling this ints-off also, when polled)
    uni_deliver( p_i82559 );

    Acknowledge82559Interrupt(p_i82559);
    UnMask82559Interrupt(p_i82559, ints);
}

// ------------------------------------------------------------------------
// Determine interrupt vector used by a device - for attaching GDB stubs
// packet handler.
int
i82559_int_vector(struct eth_drv_sc *sc)
{
    struct i82559 *p_i82559;
    p_i82559 = (struct i82559 *)sc->driver_private;
    return (p_i82559->vector);
}

#if 0
int
i82559_int_op( struct eth_drv_sc *sc, int mask)
{
    struct i82559 *p_i82559;
    p_i82559 = (struct i82559 *)sc->driver_private;

    if ( 1 == mask )
        return Mask82559Interrupt( p_i82559 );

    if ( 0 == mask )
        UnMask82559Interrupt( p_i82559, 0x0fffffff ); // enable all

    return 0;
}
#endif
    

// ------------------------------------------------------------------------
//
//  Function : pci_init_find_82559s
//
// This is called exactly once at the start of time to:
//  o scan the PCI bus for objects
//  o record them in the device table
//  o acquire all the info needed for the driver to access them
//  o instantiate interrupts for them
//  o attach those interrupts appropriately
// ------------------------------------------------------------------------
static cyg_pci_match_func find_82559s_match_func;

// Intel 82559 and 82557 are virtually identical, with different
// dev codes; also 82559ER (cutdown) = 0x1209.
static cyg_bool
find_82559s_match_func( cyg_uint16 v, cyg_uint16 d, cyg_uint32 c, void *p )
{
    return
        (0x8086 == v) &&
        ((0x1030 == d) ||
         (0x1229 == d) ||
         (0x1209 == d));
}

static int
pci_init_find_82559s( void )
{
    cyg_pci_device_id devid;
    cyg_pci_device dev_info;
    cyg_uint16 cmd;
    int device_index;

    // MUX interrupt - special case when 2 cards share one intr.
    static cyg_ha

⌨️ 快捷键说明

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