if_rhine.c

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

C
1,320
字号

                // Reload ESA from EEPROM
                {
                    cyg_uint8 tmp;
                    int i;

#if DEBUG & 8
                    diag_printf("Reload ESA from EEPROM...");
#endif
                    HAL_PCI_IO_WRITE_UINT8(cpd->base+RHINE_EECSR, 0x20);
                    for (i = 0; i < 150; i++) {
                        HAL_PCI_IO_READ_UINT8(cpd->base+RHINE_EECSR, tmp);
                        if (!(tmp & 0x20)) {
                            break;
                        }
                    }
#if DEBUG & 8
                    if (tmp & 0x20)
                        diag_printf("Timed out\n");
                    else
                        diag_printf("Done\n");
#endif
                }

                // This is the indicator for "uses an interrupt"
                if (cpd->interrupt_handle != 0) {
                    cyg_drv_interrupt_acknowledge(cpd->interrupt);
                    cyg_drv_interrupt_unmask(cpd->interrupt);
#if DEBUG & 8
                    diag_printf(" Enabled interrupt %d\n", cpd->interrupt);
#endif
                }
#if DEBUG & 8
                diag_printf(" **** Device enabled for I/O and Memory "
                            "and Bus Master\n");
#endif
            }
            else {
                cpd->found = 0;
                cpd->active = 0;
#if DEBUG & 8
                diag_printf("Failed to configure device %d\n", device_index);
#endif
            }
        }
        else {
            cpd->found = 0;
            cpd->active = 0;
#if DEBUG & 8
            diag_printf("eth%d not found\n", device_index);
#endif
        }
    }

    if (0 == found_devices)
        return 0;

    return 1;
}

static bool 
via_rhine_init(struct cyg_netdevtab_entry *tab)
{
    static int initialized = 0; // only probe PCI et al *once*
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
    struct rhine_priv_data *cpd =
        (struct rhine_priv_data *)sc->driver_private;
    cyg_uint8 *d, *p, *p_next;
    int i;
    cyg_addrword_t ba;

    DEBUG_FUNCTION();

    if ( 0 == initialized++ ) {
        // then this is the first time ever:
        if ( ! pci_init_find_rhines() ) {
#if DEBUG & 8
            diag_printf( "pci_init_find_rhines failed" );
#endif
            return false;
        }
    }

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

#if DEBUG & 8
    diag_printf( "Rhine device SC %08x CPD %08x\n", sc, cpd);
#endif

    // Look for physical MII device
    for (i = 0; i < 32; i++) {
        cyg_uint16 mii_status = rhine_read_MII(cpd, i, MII_BMSR);
        if (mii_status != 0x0000 && mii_status != 0xffff) {
            cpd->phys_id = i;
#if DEBUG & 8
            diag_printf("Found MII interface at id %d, status %04x, adv 0x%04x, link 0x%04x\n",
                        cpd->phys_id, mii_status, rhine_read_MII(cpd,i,4), rhine_read_MII(cpd,i,5));
#endif
            break;
        }
    }
#if DEBUG & 8
    if (i == 32)
        diag_printf("No MII interface found!");
#endif

    // Prepare ESA
    if (cpd->hardwired_esa) {
        // Force the NIC to use the specified ESA
        p = cpd->base + RHINE_PAR0;
        for (i = 0; i < 6; i++)
            *p++ = cpd->esa[i];
    } else {
        // Use the address from the serial EEPROM
        p = cpd->base + RHINE_PAR0;
        for (i = 0; i < 6; i++)
            cpd->esa[i] = *p++;
    }
#if DEBUG & 8
    diag_printf("RHINE - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
                (cpd->hardwired_esa) ? "static" : "eeprom",
                cpd->esa[0],
                cpd->esa[1],
                cpd->esa[2],
                cpd->esa[3],
                cpd->esa[4],
                cpd->esa[5] );
#endif

    // Prepare RX and TX rings
    p = cpd->rx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS(pciwindow_mem_alloc((1<<cpd->rx_ring_log_cnt)*RHINE_RD_SIZE));
    d = cpd->rx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS(pciwindow_mem_alloc(_BUF_SIZE*cpd->rx_ring_cnt));
    for (i = 0; i < cpd->rx_ring_cnt; i++) {
        p_next = p + RHINE_RD_SIZE;
        HAL_PCI_CPU_TO_BUS((cyg_uint32)d, ba);
        _SU32(p, RHINE_RDES2) = ba;
        _SU32(p, RHINE_RDES1) = _BUF_SIZE;
        HAL_PCI_CPU_TO_BUS((cyg_uint32)p_next, ba);
        _SU32(p, RHINE_RDES3) = ba;
        _SU32(p, RHINE_RDES0) = RHINE_RDES0_OWN;
#if DEBUG & 8
        diag_printf("Set RDES at 0x%08lx to 0x%08x 0x%08x 0x%08x 0x%08x\n",
                    (unsigned long)p,
                    _SU32(p, RHINE_RDES0), _SU32(p, RHINE_RDES1),
                    _SU32(p, RHINE_RDES2), _SU32(p, RHINE_RDES3));
#endif
        p = p_next;
        d += _BUF_SIZE;
    }
    // last entry wraps to the first
    p -= RHINE_RD_SIZE;
    HAL_PCI_CPU_TO_BUS((cyg_uint32)cpd->rx_ring, ba);
    _SU32(p, RHINE_RDES3) = ba;
#if DEBUG & 8
    diag_printf("Set RDES at 0x%08lx to 0x%08x 0x%08x 0x%08x 0x%08x\n",
                (unsigned long)p,
                _SU32(p, RHINE_RDES0), _SU32(p, RHINE_RDES1),
                _SU32(p, RHINE_RDES2), _SU32(p, RHINE_RDES3));
#endif
    cpd->rx_ring_next = 0;
    // CPU to PCI space translation
    HAL_PCI_CPU_TO_BUS((cyg_uint32)cpd->rx_ring, ba);
    HAL_PCI_IO_WRITE_UINT32(cpd->base + RHINE_CUR_RX, ba);

    p = cpd->tx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS(pciwindow_mem_alloc((1<<cpd->tx_ring_log_cnt)*RHINE_TD_SIZE));
    d = cpd->tx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS(pciwindow_mem_alloc(_BUF_SIZE*cpd->tx_ring_cnt));
    for (i = 0; i < cpd->tx_ring_cnt; i++) {

        _SU32(p, RHINE_TDES0) = 0;
        _SU32(p, RHINE_TDES1) = (RHINE_TDES1_IC|RHINE_TDES1_EDP|RHINE_TDES1_STP|RHINE_TDES1_C);
        HAL_PCI_CPU_TO_BUS((cyg_uint32)d, ba);
        _SU32(p, RHINE_TDES2) = ba;
        HAL_PCI_CPU_TO_BUS((cyg_uint32)(p + RHINE_TD_SIZE), ba);
        _SU32(p, RHINE_TDES3) = ba;
#if DEBUG & 8
        diag_printf("Set TDES at 0x%08lx to 0x%08x 0x%08x 0x%08x 0x%08x\n",
                    (unsigned long)p,
                    _SU32(p, RHINE_TDES0), _SU32(p, RHINE_TDES1),
                    _SU32(p, RHINE_TDES2), _SU32(p, RHINE_TDES3));
#endif
        p += RHINE_TD_SIZE;
        d += _BUF_SIZE;
    }

    // last entry wraps to the first
    p -= RHINE_TD_SIZE;
    HAL_PCI_CPU_TO_BUS((cyg_uint32)cpd->tx_ring, ba);
    _SU32(p, RHINE_TDES3) = ba;
#if DEBUG & 8
    diag_printf("Set TDES at 0x%08lx to 0x%08x 0x%08x 0x%08x 0x%08x\n",
                (unsigned long)p,
                _SU32(p, RHINE_TDES0), _SU32(p, RHINE_TDES1),
                _SU32(p, RHINE_TDES2), _SU32(p, RHINE_TDES3));
#endif
    cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
    HAL_PCI_CPU_TO_BUS((cyg_uint32)cpd->tx_ring, ba);
    HAL_PCI_IO_WRITE_UINT32(cpd->base + RHINE_CUR_TX, ba);

    cpd->txbusy = 0;

#if DEBUG & 9
    {
        cyg_uint8 tmp1, tmp2;
        HAL_PCI_IO_READ_UINT8(cpd->base+RHINE_CR0, tmp1); 
        HAL_PCI_IO_READ_UINT8(cpd->base+RHINE_CR1, tmp2);
        diag_printf("CR0: %02x  CR1: %02x\n", tmp1, tmp2);
    }
#endif

    // and record the net dev pointer
    cpd->ndp = (void *)tab;

    // Initialize upper level driver
    (sc->funs->eth_drv->init)(sc, cpd->esa);

#if DEBUG & 9
    diag_printf("Done\n");
#endif
    return true;
}

static void
rhine_stop(struct eth_drv_sc *sc)
{
    struct rhine_priv_data *cpd =
        (struct rhine_priv_data *)sc->driver_private;

    DEBUG_FUNCTION();

    // Stop chip
    HAL_PCI_IO_WRITE_UINT8(cpd->base+RHINE_CR0, RHINE_CR0_STOP);
}

//
// This function is called to "start up" the interface.  It may be called
// multiple times, even when the hardware is already running.  It will be
// called whenever something "hardware oriented" changes and should leave
// the hardware ready to send/receive packets.
//
static void
rhine_start(struct eth_drv_sc *sc, unsigned char *esa, int flags)
{
#ifdef CYGPKG_NET
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif
    struct rhine_priv_data *cpd =
        (struct rhine_priv_data *)sc->driver_private;

    DEBUG_FUNCTION();
    // Disable device
    HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, RHINE_CR0_STOP);
    // Ack old interrupts
    HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, 0xffff);
    // Enable interrupts
    HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_IMR, RHINE_IMR_INIT);
    // Enable duplex
    HAL_PCI_IO_WRITE_UINT8(cpd->base+RHINE_CR1, RHINE_CR1_DPOLL /* | RHINE_CR1_FDX*/);
    // Accept broadcast, multicast and small packets
    HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_RCR, RHINE_RCR_AB | RHINE_RCR_AM | RHINE_RCR_AR);
    // Tweak some magic (undocumented) parameters
    HAL_PCI_IO_WRITE_UINT8(cpd->base+RHINE_BCR0, RHINE_BCR0_MAGIC_INIT);
    HAL_PCI_IO_WRITE_UINT8(cpd->base+RHINE_BCR1, RHINE_BCR1_MAGIC_INIT);

#if 1 // FIXME
    HAL_PCI_IO_WRITE_UINT8(cpd->base+RHINE_TCR, 0x20);
#endif

#ifdef CYGPKG_NET
    if (( 0
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
         != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
#endif
        ) || (ifp->if_flags & IFF_PROMISC)
        ) {
        // Then we select promiscuous mode.
        cyg_uint8 rcr;
        HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_RCR, rcr);
        rcr |= RHINE_RCR_PRO;
        HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_RCR, rcr);
    }
#endif
    // Enable device
    HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, RHINE_CR0_STRT | RHINE_CR0_RXON | RHINE_CR0_TXON);
}

//
// This routine is called to perform special "control" opertions
//
static int
rhine_control(struct eth_drv_sc *sc, unsigned long key,
               void *data, int data_length)
{
    cyg_uint8 *esa = (cyg_uint8 *)data;
    int i, res;
    cyg_uint8 reg, old_stat;
    struct rhine_priv_data *cpd =
        (struct rhine_priv_data *)sc->driver_private;

    DEBUG_FUNCTION();

    // Stop the controller while accessing (possibly altering) registers
    HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR0, old_stat);
    reg = old_stat;
    reg |= RHINE_CR0_STOP;
    reg &= ~RHINE_CR0_STRT;
    HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, reg);

    res = 0;                            // expect success
    switch (key) {
    case ETH_DRV_SET_MAC_ADDRESS:
#if DEBUG & 9
        diag_printf("RHINE - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
                esa[0],
                esa[1],
                esa[2],
                esa[3],
                esa[4],
                esa[5] );
#endif // DEBUG

        for ( i = 0; i < sizeof(cpd->esa);  i++ ) {
            cpd->esa[i] = esa[i];
            HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_PAR0 + i, esa[i]);
        }
        break;

#ifdef ETH_DRV_GET_MAC_ADDRESS
    case ETH_DRV_GET_MAC_ADDRESS:
        // Extract the MAC address that is in the chip, and tell the
        // system about it.
        for (i = 0;  i < sizeof(cpd->esa);  i++) {
            HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_PAR0 + i, esa[i]);
        }
        break;
#endif

#ifdef ETH_DRV_GET_IF_STATS_UD
    case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
#endif
        // drop through
#ifdef ETH_DRV_GET_IF_STATS
    case ETH_DRV_GET_IF_STATS:
#endif

#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
    {
        cyg_uint8 reg;
        struct ether_drv_stats *p = (struct ether_drv_stats *)data;
        // Chipset entry is no longer supported; RFC1573.
        for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
            p->snmp_chipset[i] = 0;

        // This perhaps should be a config opt, so you can make up your own
        // description, or supply it from the instantiation.
        strcpy( p->description, "VIA Rhine" );
        // CYG_ASSERT( 48 > strlen(p->description), "Description too long" );

        HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_MIISR, reg);
        if (reg & RHINE_MIISR_LNKFL) {
            p->operational = 2;         // LINK DOWN
            p->duplex = 1;              // UNKNOWN
            p->speed = 0;
        }
        else {
            p->operational = 3;         // LINK UP
            p->speed = (reg & RHINE_MIISR_SPEED) ? 10 * 1000000 : 100 * 1000000;
            HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR1, reg);
            if (reg & RHINE_CR1_FDX)
                p->duplex = 3;              // 3 = DUPLEX
            else
                p->duplex = 2;              // 2 = SIMPLEX
        }

#ifdef KEEP_STATISTICS
        {
            struct via_rhine_stats *ps = &(cpd->stats);

            // Admit to it...
            p->supports_dot3        = true;

            p->tx_good              = ps->tx_good             ;
            p->tx_max_collisions    = ps->tx_max_collisions   ;
            p->tx_late_collisions   = ps->tx_late_collisions  ;
            p->tx_underrun          = ps->tx_underrun         ;
            p->tx_carrier_loss      = ps->tx_carrier_loss     ;
            p->tx_deferred          = ps->tx_deferred         ;
            p->tx_sqetesterrors     = ps->tx_sqetesterrors    ;
            p->tx_single_collisions = ps->tx_single_collisions;
            p->tx_mult_collisions   = ps->tx_mult_collisions  ;
            p->tx_total_collisions  = ps->tx_total_collisions ;
            p->rx_good              = ps->rx_good             ;
            p->rx_crc_errors        = ps->rx_crc_errors       ;
            p->rx_align_errors      = ps->rx_align_errors     ;
            p->rx_resource_errors   = ps->rx_resource_errors  ;
            p->rx_overrun_errors    = ps->rx_overrun_errors   ;
            p->rx_collisions        = ps->rx_collisions       ;
            p->rx_short_frames      = ps->rx_short_frames     ;
            p->rx_too_long_frames   = ps->rx_too_long_frames  ;
            p->rx_symbol_errors     = ps->rx_symbol_errors    ;
        
            p->interrupts           = ps->interrupts          ;
            p->rx_count             = ps->rx_count            ;
            p->rx_deliver           = ps->rx_deliver          ;
            p->rx_resource          = ps->rx_resource         ;
            p->rx_restart           = ps->rx_restart          ;
            p->tx_count             = ps->tx_count            ;
            p->tx_complete          = ps->tx_complete         ;
            p->tx_dropped           = ps->tx_dropped          ;
        }
#endif // KEEP_STATISTICS

        p->tx_queue_len = 1;
        break;
    }
#endif
    default:
        res = 1;
        break;
    }

    // Restore controller state
    HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, old_stat);

    return res;
}

//
// This routine is called to see if it is possible to send another packet.
// It will return non-zero if a transmit is possible, zero otherwise.
//
static int
rhine_can_send(struct eth_drv_sc *sc)
{
    cyg_uint8 stat;
    struct rhine_priv_data *cpd =
        (struct rhine_priv_data *)sc->driver_private;

    DEBUG_FUNCTION();

⌨️ 快捷键说明

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