if_rhine.c
来自「eCos操作系统源码」· 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 voidrhine_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 voidrhine_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 intrhine_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 intrhine_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 + -
显示快捷键?