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

📄 if_iq80310.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 5 页
字号:
    CYG_ASSERT( (&i82559[0] == (_p_)) || (&i82559[1] == (_p_)), \
                "Bad pointer-to-i82559" );                      \
    if ( (&i82559[0] != (_p_)) && (&i82559[1] != (_p_)) )

// ------------------------------------------------------------------------
// Instantiate the interfaces that we have:

// number of interfaces
#define MAX_82559 1

I82559 i82559[MAX_82559];               // i82559 device info. structure

// eth0

ETH_DRV_SC(iq80310_sc0,
           &i82559[0],                  // Driver specific data
           "eth0",                      // Name for this interface
           i82559_start,
           i82559_stop,
           i82559_ioctl,
           i82559_can_send,
           i82559_send,
           i82559_recv,
           i82559_deliver,
           i82559_poll,
           i82559_int_vector
    );

NETDEVTAB_ENTRY(iq80310_netdev0, 
                "iq80310-0", 
                iq80310_i82559_init, 
                &iq80310_sc0);

#if (MAX_82559 > 1)

// eth1

ETH_DRV_SC(iq80310_sc1,
           &i82559[1],                  // Driver specific data
           "eth1",                      // Name for this interface
           i82559_start,
           i82559_stop,
           i82559_ioctl,
           i82559_can_send,
           i82559_send,
           i82559_recv,
           i82559_deliver,
           i82559_poll,
           i82559_int_vector
    );

NETDEVTAB_ENTRY(iq80310_netdev1, 
                "iq80310-1", 
                iq80310_i82559_init, 
                &iq80310_sc1);

#else
int iq80310_netdev1 = -1; // for asserts about valid addresses
int iq80310_sc1 = -1;
#endif // eth1 is included

// This is in a macro so that if more devices arrive it can easily be changed
#define CHECK_NDP_SC_LINK() CYG_MACRO_START                                \
    CYG_ASSERT( ((void *)ndp == (void *)&iq80310_netdev0) ||               \
                ((void *)ndp == (void *)&iq80310_netdev1), "Bad ndp" );    \
    CYG_ASSERT( ((void *)sc == (void *)&iq80310_sc0) ||                    \
                ((void *)sc == (void *)&iq80310_sc1), "Bad sc" );          \
    CYG_ASSERT( (void *)p_i82559 == sc->driver_private, "sc pointer bad" );\
CYG_MACRO_END

// ------------------------------------------------------------------------
//
// Managing the memory that is windowed onto the PCI bus
//
// ------------------------------------------------------------------------

static cyg_uint32 i82559_heap_size;
static cyg_uint8 *i82559_heap_base;
static cyg_uint8 *i82559_heap_free;

static void *mem_reserved_ioctl = (void*)0;
// uncacheable memory reserved for ioctl calls

// ------------------------------------------------------------------------
//
//                       FUNCTION PROTOTYPES
//
// ------------------------------------------------------------------------

static int pci_init_find_82559s(void);

static void i82559_reset(struct i82559* p_i82559);

static void InitRxRing(struct i82559* p_i82559);
static void ResetRxRing(struct i82559* p_i82559);
static void InitTxRing(struct i82559* p_i82559);
static void ResetTxRing(struct i82559* p_i82559);

#ifdef CYGPKG_DEVS_ETH_ARM_IQ80310_WRITE_EEPROM
static void program_eeprom(cyg_uint32 , cyg_uint32 , cyg_uint8 * );
#endif
#ifdef CYGPKG_NET
static int eth_set_promiscuous_mode(struct i82559* p_i82559);
#endif

// debugging/logging only:
void dump_txcb(TxCB *p_txcb);
void DisplayStatistics(void);
void update_statistics(struct i82559* p_i82559);
void dump_rfd(RFD *p_rfd, int anyway );
void dump_all_rfds( int intf );
void dump_packet(cyg_uint8 *p_buffer, int length);

// ------------------------------------------------------------------------
// utilities
// ------------------------------------------------------------------------

static // inline
void wait_for_cmd_done(long scb_ioaddr)
{
    register int CSRstatus;
    register int wait = 0x100000;
    do CSRstatus = INB(scb_ioaddr + SCBCmd) ;
    while( CSRstatus && --wait >= 0);
    CYG_ASSERT( wait > 0, "wait_for_cmd_done" );
}

// Short circuit the drv_interrupt_XXX API once we are started:

static inline int Mask82559Interrupt(struct i82559* p_i82559)
{
    int cpu_intr;
    int old;
    int mask = 1 << (CYGNUM_HAL_INTERRUPT_ETHERNET - CYGNUM_HAL_INTERRUPT_TIMER);

    HAL_DISABLE_INTERRUPTS( cpu_intr );

    old = *X3MASK_REG;
    *X3MASK_REG = old | mask;

    HAL_RESTORE_INTERRUPTS( cpu_intr );

    return old & mask;
}


static inline void UnMask82559Interrupt(struct i82559* p_i82559, int old)
{
    int cpu_intr;
    int mask = 1 << (CYGNUM_HAL_INTERRUPT_ETHERNET - CYGNUM_HAL_INTERRUPT_TIMER);

    // We must only unmask (enable) if it was unmasked before,
    // according to the bit in old.
    HAL_DISABLE_INTERRUPTS( cpu_intr );
    *X3MASK_REG = (*X3MASK_REG & ~mask) | old;
    HAL_RESTORE_INTERRUPTS( cpu_intr );
}

#ifdef CYGDBG_USE_ASSERTS // an indication of a debug build
static int acknowledge82559interrupt_compensating = 0;
#endif

static void Acknowledge82559Interrupt(struct i82559* p_i82559)
{
    int sources, mask;
    cyg_uint32 ioaddr;
    cyg_uint16 status;
    int loops = 64;

    // XScale does nothing in interrupt_acknowledge, so we can comment
    // this all out.  So this routine really boils down to
    //   "wait for the device to stop interrupting before we unmask"
    // The acknowledge call is left in place, for documentary purposes.

    cyg_drv_interrupt_acknowledge(p_i82559->vector);

    // It appears that some time can be taken before the interrupt source
    // *really* quietens down... this is ugly, but effective.
    // Without it, we get "Spurious Interrupt!" failures.
    ioaddr = p_i82559->io_address; // get I/O address for 82559

    mask = (1 << (CYGNUM_HAL_INTERRUPT_ETHERNET - CYGNUM_HAL_INTERRUPT_TIMER));
    sources = *X3ISR_REG;

    status = INW(ioaddr + SCBStatus);
    while ( ((0 != (sources & mask)) || (0 != (status & SCB_INTACK_MASK)))
            && --loops >= 0) {
        OUTW( status & SCB_INTACK_MASK, ioaddr + SCBStatus);
        cyg_drv_interrupt_acknowledge(p_i82559->vector);
#ifdef CYGDBG_USE_ASSERTS
        acknowledge82559interrupt_compensating++; // verify this is executed
#endif
	sources = *X3ISR_REG;
        status = INW(ioaddr + SCBStatus);
    }
    CYG_ASSERT( loops >= 0, "Acknowledge82559Interrupt" );
}


static void udelay(int delay)
{
  int i;
  // the loop is going to take 3 ticks.  At 600 MHz, to give uS, multiply
  // by 600/3 = 200. No volatile is needed on i; gcc recognizes delay
  // loops and does NOT elide them.
  for ( i = 200 * delay; i ; i--)
    ;
}

// ------------------------------------------------------------------------
// Memory management
//
// Simply carve off from the front of the PCI mapped window into real memory

static void *pciwindow_mem_alloc(int size)
{
    void *p_memory;
    int _size = size;

    CYG_ASSERT(
        (CYGHWR_HAL_ARM_IQ80310_PCI_MEM_MAP_BASE <= (int)i82559_heap_free)
        &&
        ((CYGHWR_HAL_ARM_IQ80310_PCI_MEM_MAP_BASE + 
          CYGHWR_HAL_ARM_IQ80310_PCI_MEM_MAP_SIZE) > (int)i82559_heap_free)
        &&
        (0 < i82559_heap_size)
        &&
        (CYGHWR_HAL_ARM_IQ80310_PCI_MEM_MAP_SIZE >= i82559_heap_size)
        &&
        (CYGHWR_HAL_ARM_IQ80310_PCI_MEM_MAP_BASE == (int)i82559_heap_base),
        "Heap variables corrupted" );

    p_memory = (void *)0;
    size = (size + 3) & ~3;
    if ( (i82559_heap_free+size) < (i82559_heap_base+i82559_heap_size) ) {
        cyg_uint32 *p;
        p_memory = (void *)i82559_heap_free;
        i82559_heap_free += size;
        for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )
            *p++ = 0;
    }

    return p_memory;
}



// ------------------------------------------------------------------------
//
//                       GET EEPROM SIZE
//
// ------------------------------------------------------------------------
static int get_eeprom_size(long ioaddr)
{
    unsigned short retval = 0;
    int ee_addr = ioaddr + SCBeeprom;
    int i, addrbits;

    // Should already be not-selected, but anyway:
    OUTW(EE_ENB & ~EE_CS, ee_addr);
    eeprom_delay(EEPROM_ENABLE_DELAY);
    OUTW(EE_ENB, ee_addr);
    eeprom_delay(EEPROM_ENABLE_DELAY);
    
    // Shift the read command bits out.
    for (i = 2; i >= 0; i--) {
        short dataval = (6 & (1 << i)) ? EE_DATA_WRITE : 0;
        OUTW(EE_ENB | dataval               , ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        OUTW(EE_ENB | dataval               , ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
    }
    // Now clock out address zero, looking for the dummy 0 data bit
    for ( i = 1; i <= 12; i++ ) {
        OUTW(EE_ENB               , ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        OUTW(EE_ENB | EE_SHIFT_CLK, ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        OUTW(EE_ENB               , ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        retval = INW(ee_addr) & EE_DATA_READ;
        if ( 0 == retval )
            break; // The dummy zero est arrive'
    }

#ifdef DEBUG_EE
    os_printf( "eeprom data bits %d (ioaddr %x)\n", i, ee_addr );
#endif
    if ( 6 != i && 8 != i ) {
#ifdef DEBUG_EE
        os_printf( "*****EEPROM data bits not 6 or 8*****\n" );
#endif
        i = 6;
    }
    addrbits = i;

    // clear the dataval, leave the clock low to read in the data regardless
    OUTW(EE_ENB, ee_addr);
    eeprom_delay(1);
    
    retval = INW(ee_addr);
    if ( (EE_DATA_READ & retval) != 0 ) {
#ifdef DEBUG_EE
        os_printf( "Size EEPROM: Dummy data bit not 0, reg %x\n" , retval );
#endif
    }
    eeprom_delay(1);
    
    for (i = EE_TOP_DATA_BIT; i >= 0; i--) {
        OUTW(EE_ENB | EE_SHIFT_CLK, ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        retval = INW(ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        OUTW(EE_ENB, ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
    }
    
    // Terminate the EEPROM access.
    OUTW(EE_ENB & ~EE_CS, ee_addr);
    eeprom_delay(EEPROM_DONE_DELAY);
    
    return addrbits;
}


// ------------------------------------------------------------------------
//
//                       READ EEPROM
//
// ------------------------------------------------------------------------
static int read_eeprom(long ioaddr, int location, int addr_len)
{
    unsigned short retval = 0;
    int ee_addr = ioaddr + SCBeeprom;
    int read_cmd = location | EE_READ_CMD(addr_len);
    int i, tries = 10;

 try_again:
    // Should already be not-selected, but anyway:
    OUTW(EE_ENB & ~EE_CS, ee_addr);
    eeprom_delay(EEPROM_ENABLE_DELAY);
    OUTW(EE_ENB, ee_addr);
    eeprom_delay(EEPROM_ENABLE_DELAY);
    
    // Shift the read command bits out, changing only one bit per time.
    for (i = EE_TOP_CMD_BIT(addr_len); i >= 0; i--) {
        short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
        OUTW(EE_ENB | dataval               , ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        OUTW(EE_ENB | dataval               , ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
    }

    // clear the dataval, leave the clock low
    OUTW(EE_ENB, ee_addr);
    eeprom_delay(1);
    
    retval = INW(ee_addr);
    // This should show a zero in the data read bit to confirm that the
    // address transfer is compelete.  If not, go to the start and try
    // again!
    if ( (0 != (retval & EE_DATA_READ)) && (tries-- > 0) ) {
    // Terminate the EEPROM access.
        OUTW(EE_ENB & ~EE_CS, ee_addr);
        eeprom_delay(EEPROM_DONE_DELAY);
#ifdef DEBUG_EE
        os_printf( "Warning: Retrying EEPROM read word %d, address %x, try %d\n",
                   location,  ee_addr, tries+1 );
#endif
        goto try_again;
    }

    // This fires with one device on one of the customer boards!
    // (but is OK on all other h/w.  Worrying huh.)
    if ( (EE_DATA_READ & retval) != 0 ) {
#ifdef DEBUG_EE
        os_printf( "Read EEPROM: Dummy data bit not 0, reg %x\n" , retval );
#endif
    }
    eeprom_delay(1);
    retval = 0;

⌨️ 快捷键说明

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