if_i82559.c

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

C
1,724
字号
#endif // ! CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM_WITHOUT_CRC
        {
#ifdef DEBUG_EE
	    os_printf("Valid EEPROM checksum\n");
#endif
	    return 1;
	}
    }
    return 0;
}
#endif // ! CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM

// ------------------------------------------------------------------------
//
//                NETWORK INTERFACE INITIALIZATION
//
//  Function : Init82559
//
//  Description :
//       This routine resets, configures, and initializes the chip.
//       It also clears the ethernet statistics structure, and selects
//       which statistics are supported by this driver.
//
// ------------------------------------------------------------------------
static bool
i82559_init(struct cyg_netdevtab_entry * ndp)
{
    static int initialized = 0; // only probe PCI et al *once*

    struct eth_drv_sc *sc;
    cyg_uint32 selftest;
    volatile cyg_uint32 *p_selftest;
    cyg_uint32 ioaddr;
    int count;
    int ints;
    struct i82559 *p_i82559;
    cyg_uint8 mac_address[ETHER_ADDR_LEN];

#ifdef DEBUG
    //    db_printf("intel_i82559_init\n");
#endif

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

    IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
        os_printf( "Bad device private pointer %x\n", sc->driver_private );
#endif
        return 0;
    }

    CHECK_NDP_SC_LINK();

    if ( 0 == initialized++ ) {
        // then this is the first time ever:
        if ( ! pci_init_find_82559s() ) {
#ifdef DEBUG
            os_printf( "pci_init_find_82559s failed\n" );
#endif
            return 0;
        }
    }

    // If this device is not present, exit
    if (0 == p_i82559->found)
        return 0;

    p_i82559->mac_addr_ok = 0;

    ioaddr = p_i82559->io_address; // get I/O address for 82559

#ifdef DEBUG
    os_printf("Init82559 %d @ %x\n82559 Self Test\n",
              p_i82559->index, (int)ndp);
#endif

    ints = Mask82559Interrupt(p_i82559);

    // Reset device
    i82559_reset(p_i82559);

    // Perform a system self-test. (get enough mem to round address)
    if ( (selftest = (cyg_uint32)pciwindow_mem_alloc(32) ) == 0)
        return (0);
    p_selftest = (cyg_uint32 *) ((selftest + 15) & ~0xf);
    p_selftest[0] = p_selftest[1] = -1;

    OUTL( (VIRT_TO_BUS(p_selftest)) | I82559_SELFTEST, ioaddr + SCBPort);
    count = 0x7FFFF;                // Timeout for self-test.
    do {
        udelay(10);
    } while ( (p_selftest[1] == -1)  &&  (--count >= 0) );

    // Reset device again after selftest
    i82559_reset(p_i82559);

    Acknowledge82559Interrupt(p_i82559);
    UnMask82559Interrupt(p_i82559, ints );
    
    if (count < 0) {
        // Test timed out.
#ifdef DEBUG
        os_printf("Self test failed\n");
#endif
        return (0);
    }
#ifdef DEBUG
    os_printf("  General self-test: %s.\n"
              "  Serial sub-system self-test: %s.\n"
              "  Internal registers self-test: %s.\n"
              "  ROM checksum self-test: %s (%08X).\n",
              HAL_LE32TOC(p_selftest[1]) & 0x1000 ? "failed" : "passed",
              HAL_LE32TOC(p_selftest[1]) & 0x0020 ? "failed" : "passed",
              HAL_LE32TOC(p_selftest[1]) & 0x0008 ? "failed" : "passed",
              HAL_LE32TOC(p_selftest[1]) & 0x0004 ? "failed" : "passed",
              HAL_LE32TOC(p_selftest[0]));
#endif

    // free self-test memory?
    // No, there's no point: this "heap" does not support free.

    if (p_i82559->hardwired_esa) {
        // Hardwire the address without consulting the EEPROM.
        // When this flag is set, the p_i82559 will already contain
        // the ESA. Copy it to a mac_address for call to set_mac_addr
        mac_address[0] = p_i82559->mac_address[0];
        mac_address[1] = p_i82559->mac_address[1];
        mac_address[2] = p_i82559->mac_address[2];
        mac_address[3] = p_i82559->mac_address[3];
        mac_address[4] = p_i82559->mac_address[4];
        mac_address[5] = p_i82559->mac_address[5];

        eth_set_mac_address(p_i82559, mac_address, 0);

    } else {

        // Acquire the ESA either from extenal means (probably RedBoot
        // variables) or from the attached EEPROM - if there is one.

#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_GET_ESA
        int ok = false;
        int wflag = 0;
        CYGHWR_DEVS_ETH_INTEL_I82559_GET_ESA( p_i82559, mac_address, ok );
        if ( ok ) {
#ifndef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM
#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM
	    if ( CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM == p_i82559->index )
#endif // CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM
	    {
		cyg_uint8 tmp_addr[ETHER_ADDR_LEN];

		// write eeprom address unless it is already there
		wflag = 1;
		if (read_eeprom_esa(p_i82559, tmp_addr)) {
		    int i;
		    for (i = 0; i < ETHER_ADDR_LEN; i++)
			if (tmp_addr[i] != mac_address[i])
			    break;
		    if (i >= ETHER_ADDR_LEN)
			wflag = 0;
		}
	    }
#endif // ! CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM
	    eth_set_mac_address(p_i82559, mac_address, wflag);
	}
#else // ! CYGHWR_DEVS_ETH_INTEL_I82559_GET_ESA

#ifndef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM

#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM
        if ( CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM == p_i82559->index ) {
#endif // CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM

	    if (read_eeprom_esa(p_i82559, mac_address)) {
		// record the MAC address in the device structure
		p_i82559->mac_address[0] = mac_address[0];
		p_i82559->mac_address[1] = mac_address[1];
		p_i82559->mac_address[2] = mac_address[2];
		p_i82559->mac_address[3] = mac_address[3];
		p_i82559->mac_address[4] = mac_address[4];
		p_i82559->mac_address[5] = mac_address[5];

                p_i82559->mac_addr_ok = 1;

                eth_set_mac_address(p_i82559, mac_address, 0);
	    }

#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM
        }
        else { // We are now "in" another device
#if 1 < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT
            struct i82559 *other; // The one that *is* set up from EEPROM
            other = i82559_priv_array[CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM];
            if ( other->mac_addr_ok ) {
                mac_address[0] = other->mac_address[0];
                mac_address[1] = other->mac_address[1];
                mac_address[2] = other->mac_address[2];
                mac_address[3] = other->mac_address[3];
                mac_address[4] = other->mac_address[4];
                mac_address[5] = other->mac_address[5];

#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM_MAC_ADJUST
                mac_address[5] += CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM_MAC_ADJUST;
#endif
                eth_set_mac_address(p_i82559, mac_address, 0);
            }
#endif // 1 < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT
        }
#endif // CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM

#endif // ! CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM
#endif // ! CYGHWR_DEVS_ETH_INTEL_I82559_GET_ESA
    }

#ifdef DEBUG
    os_printf("i82559_init: MAC Address = %02X %02X %02X %02X %02X %02X\n",
              p_i82559->mac_address[0], p_i82559->mac_address[1],
              p_i82559->mac_address[2], p_i82559->mac_address[3],
              p_i82559->mac_address[4], p_i82559->mac_address[5]);
#endif
    
    // and record the net dev pointer
    p_i82559->ndp = (void *)ndp;
    
    p_i82559->within_send = 0; // init recursion level

    p_i82559->promisc = 0;  // None of these initially
    p_i82559->multicast_all = 0;
    p_i82559->oversized = 1;    // Enable this for VLAN mode by default

    InitRxRing(p_i82559);
    InitTxRing(p_i82559);

    CheckRxRing(p_i82559,__FUNCTION__,__LINE__);

    // Initialize upper level driver
    if ( p_i82559->mac_addr_ok )
        (sc->funs->eth_drv->init)(sc, &(p_i82559->mac_address[0]) );
    else
        (sc->funs->eth_drv->init)(sc, NULL );

    CheckRxRing(p_i82559,__FUNCTION__,__LINE__);

    return (1);
}

// ------------------------------------------------------------------------
//
//  Function : i82559_start
//
// ------------------------------------------------------------------------
static void 
i82559_start( struct eth_drv_sc *sc, unsigned char *enaddr, int flags )
{
    struct i82559 *p_i82559;
    cyg_uint32 ioaddr;
#ifdef KEEP_STATISTICS
    void *p_statistics;
#endif
#ifdef CYGPKG_NET
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif

    p_i82559 = (struct i82559 *)sc->driver_private;
    ioaddr = p_i82559->io_address; // get 82559's I/O address
    
    IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
        os_printf( "i82559_start: Bad device pointer %x\n", p_i82559 );
#endif
        return;
    }

    if ( ! p_i82559->mac_addr_ok ) {
#ifdef DEBUG
        os_printf("i82559_start %d: invalid MAC address, "
                  "can't bring up interface\n",
                  p_i82559->index );
#endif
        return;
    }

    if ( p_i82559->active )
        i82559_stop( sc );

#ifdef KEEP_STATISTICS
#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_STATISTICS
    p_statistics = p_i82559->p_statistics;
    memset(p_statistics, 0xFFFFFFFF, sizeof(I82559_COUNTERS));
    // set statistics dump address
    wait_for_cmd_done(ioaddr, WAIT_CU);
    OUTL(VIRT_TO_BUS(p_statistics), ioaddr + SCBPointer);
    OUTW(SCB_M | CU_STATSADDR, ioaddr + SCBCmd);
    // Start dump command
    wait_for_cmd_done(ioaddr, WAIT_CU);
    OUTW(SCB_M | CU_DUMPSTATS, ioaddr + SCBCmd); // start register dump
    // ...and wait for it to complete operation

    // The code to wait was bogus; it was looking at the structure in the
    // wrong way.  In any case, there is no need to wait, the
    // wait_for_cmd_done() in any following activity is good enough.

#endif
#endif

    // Enable device
    p_i82559->active = 1;

    /* Enable promiscuous mode if requested, reception of oversized frames always.
     * The latter is needed for VLAN support and shouldn't hurt even if we're not
     * using VLANs.  Reset multicastALL reception choice.
     */

    p_i82559->promisc = 0
#ifdef CYGPKG_NET
                     || !!(ifp->if_flags & IFF_PROMISC)
#endif
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
                     || !!(flags & ETH_DRV_FLAGS_PROMISC_MODE)
#endif
            ;

    p_i82559->multicast_all = 0;

    i82559_configure(p_i82559,
                     p_i82559->promisc,
                     p_i82559->oversized,
                     p_i82559->multicast_all );

#ifdef DEBUG
    {
        int status = i82559_status( sc );
        os_printf("i82559_start %d flg %x Link = %s, %s Mbps, %s Duplex\n",
                  p_i82559->index,
                  *(int *)p_i82559,
                  status & GEN_STATUS_LINK ? "Up" : "Down",
                  status & GEN_STATUS_100MBPS ?  "100" : "10",
                  status & GEN_STATUS_FDX ? "Full" : "Half");
    }
#endif

    i82559_restart(p_i82559);
    

⌨️ 快捷键说明

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