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 + -
显示快捷键?