if_i82559.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,724 行 · 第 1/5 页

C
1,724
字号
         # omit both from any restoration: #/
        old = 0;
    */

    return old;
}

static inline void
UnMask82559Interrupt(struct i82559* p_i82559, int old)
{
#ifdef CYGPRI_DEVS_ETH_INTEL_I82559_UNMASK_INTERRUPTS
    CYGPRI_DEVS_ETH_INTEL_I82559_UNMASK_INTERRUPTS(p_i82559,old);
#else
    // We must only unmask (enable) those which were unmasked before,
    // according to the bits in old.
    if (old & 1)
        cyg_drv_interrupt_unmask(p_i82559->vector);
#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT
    if (old & 2)
        cyg_drv_interrupt_mask(CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT);
#endif
#endif
}


static inline void
Acknowledge82559Interrupt(struct i82559* p_i82559)
{
#ifdef CYGPRI_DEVS_ETH_INTEL_I82559_ACK_INTERRUPTS
    CYGPRI_DEVS_ETH_INTEL_I82559_ACK_INTERRUPTS(p_i82559);
#else
    cyg_drv_interrupt_acknowledge(p_i82559->vector);
#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT
    cyg_drv_interrupt_acknowledge(CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT);
#endif
#endif

#ifdef CYGPRI_DEVS_ETH_INTEL_I82559_INTERRUPT_ACK_LOOP
    CYGPRI_DEVS_ETH_INTEL_I82559_INTERRUPT_ACK_LOOP(p_i82559);
#endif
}


static inline void
Check82559TxLockupTimeout(struct i82559* p_i82559)
{
#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_RESET_TIMEOUT
#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_TIMEOUT_FIRED
    int ints = Mask82559Interrupt(p_i82559);
    if ( p_i82559->tx_in_progress &&
        (p_i82559->tx_descriptor_timeout == p_i82559->tx_descriptor_active) ) {
        if ( CYGHWR_DEVS_ETH_INTEL_I82559_TIMEOUT_FIRED( p_i82559->platform_timeout ) ) {
            // Then reset the device; the TX unit is locked up.
            cyg_uint32 ioaddr = p_i82559->io_address;
            // Wait some time afterwards for chip to settle.
            OUTL(I82559_SELECTIVE_RESET, ioaddr + SCBPort);
#ifdef CYGDBG_USE_ASSERTS
            missed_interrupt.lockup_timeouts++;
#endif
            udelay(20);
        }
    }
    else {
        // All is well:
        CYGHWR_DEVS_ETH_INTEL_I82559_RESET_TIMEOUT( p_i82559->platform_timeout );
        p_i82559->tx_descriptor_timeout = p_i82559->tx_descriptor_active;
    }
    UnMask82559Interrupt(p_i82559,ints);
#endif
#endif
}

// ------------------------------------------------------------------------
// 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_INTEL_I82559_PCI_MEM_MAP_BASE <= (int)i82559_heap_free)
        &&
        ((CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE + 
          CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE) > (int)i82559_heap_free)
        &&
        (0 < i82559_heap_size)
        &&
        (CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE >= i82559_heap_size)
        &&
        (CYGHWR_INTEL_I82559_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;
    }

#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_PCIMEM_DISCONTIGUOUS
    // Then the underlying physical address can have breaks in it.
    // We cannot use such a block, clearly, so we just discard and re-do.
    if ( p_memory ) {
        char *bpm = (char *)VIRT_TO_BUS( p_memory );
        char *bmf = (char *)VIRT_TO_BUS( i82559_heap_free );
        
        if ( bpm + size != bmf ) {
            // then we found a break; retry:
            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;
            }
        }
    }
#endif
    CYG_ASSERT(
        NULL == p_memory ||
        VIRT_TO_BUS( p_memory ) + size == VIRT_TO_BUS( i82559_heap_free ),
        "Discontiguous PCI memory in real addresses" );

    return p_memory;
}


// ------------------------------------------------------------------------
//
//                       GET EEPROM SIZE
//
// ------------------------------------------------------------------------
#ifndef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM
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 && 1 != i) {
#ifdef DEBUG_EE
        os_printf( "*****EEPROM data bits not 6, 8 or 1*****\n" );
#endif
        i = 6; // guess, to complete this routine
        addrbits = 1; // Flag no eeprom here.
    }
    else
        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;

    for (i = EE_TOP_DATA_BIT; i >= 0; i--) {
        OUTW(EE_ENB | EE_SHIFT_CLK, ee_addr);
        eeprom_delay(EEPROM_SK_DELAY);
        retval = (retval << 1) | ((INW(ee_addr) & EE_DATA_READ) ? 1 : 0);
        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 retval;
}

static int
read_eeprom_esa(struct i82559 *p_i82559, cyg_uint8 *addr)
{
    int addr_length, i, count;
    cyg_uint16 checksum;
    cyg_uint32 ioaddr = p_i82559->io_address;

    // read eeprom and get 82559's mac address
    addr_length = get_eeprom_size(ioaddr);
    // (this is the length of the *EEPROM*s address, not MAC address)

    // If length is 1, it _probably_ means there's no EEPROM
    // present.  Couldn't find an explicit mention of this in the
    // docs, but length=1 appears to be the behaviour in that case.
    if (1 == addr_length) {
#ifdef DEBUG_EE
	os_printf("Error: No EEPROM present for device %d\n", 
		  p_i82559->index);
#endif
    } else {
	for (checksum = 0, i = 0, count = 0; count < (1 << addr_length); count++) {
	    cyg_uint16 value;
	    // read word from eeprom
	    value = read_eeprom(ioaddr, count, addr_length);
#ifdef DEBUG_EE
	    os_printf( "%2d: %04x\n", count, value );
#endif
	    checksum += value;
	    if (count < 3) {
		addr[i++] = value & 0xFF;
		addr[i++] = (value >> 8) & 0xFF;
	    }
	}

#ifndef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM_WITHOUT_CRC
	// If the EEPROM checksum is wrong, the MAC address read
	// from the EEPROM is probably wrong as well. In that
	// case, we don't set mac_addr_ok, but continue the
	// initialization. If then somebody calls i82559_start
	// without calling eth_set_mac_address() first, we refuse
	// to bring up the interface, because running with an
	// invalid MAC address is not a very brilliant idea.
        
	if ((checksum & 0xFFFF) != 0xBABA)  {
	    // selftest verified checksum, verify again
#ifdef DEBUG_EE
	    os_printf("Warning: Invalid EEPROM checksum %04X for device %d\n",
		      checksum, p_i82559->index);
#endif
	} else // trailing block

⌨️ 快捷键说明

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