if_lancepci.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,324 行 · 第 1/4 页
C
1,324 行
DEBUG_FUNCTION();
if (!cpd->active)
return;
if (cpd->txbusyh) {
#if DEBUG & 9
db_printf("Lancepci-stop:waiting for tx empty\n");
#endif
b=100;
while (cpd->txbusyh && b) {
CYGACC_CALL_IF_DELAY_US(200);
b--;
}
}
put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
cpd->active = 0;
#if DEBUG & 9
db_printf("Lancepci-stop:done\n");
#endif
}
//
// 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
lancepci_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
{
cyg_uint16 reg;
cyg_uint32 b;
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
#ifdef CYGPKG_NET
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif
DEBUG_FUNCTION();
// If device is already active, stop it
#if DEBUG & 9
db_printf("Lancepci-start:entered\n");
#endif
if (cpd->active)
{
if (cpd->txbusyh) {
#if DEBUG & 9
db_printf("Lancepci-start:waiting for tx empty\n");
#endif
b=100;
while (cpd->txbusyh && b) {
CYGACC_CALL_IF_DELAY_US(200);
b--;
}
}
put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
cpd->active = 0;
#if DEBUG & 9
db_printf("Lancepci-start:stopped\n");
#endif
}
CYGACC_CALL_IF_DELAY_US(200);
#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.
_SU16(cpd->init_table, LANCE_IB_MODE) = 0x0000|LANCE_CSR_MODE_PROM;
#if DEBUG & 9
db_printf("Promisc MODE!");
#endif
}
else _SU16(cpd->init_table, LANCE_IB_MODE) = 0x0000;
#endif
cpd->rx_ring_next = 0;
cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
// Init the chip again
HAL_PCI_CPU_TO_BUS(cpd->init_table, (cyg_uint8 *)b);
put_reg(sc, LANCE_CSR_IBA0, (b >> 0) & 0xffff);
put_reg(sc, LANCE_CSR_IBA1, (b >> 16) & 0xffff);
// Disable automatic TX polling (_send will force a poll), pad
// XT frames to legal length, mask status interrupts.
put_reg(sc, LANCE_CSR_TFC, (LANCE_CSR_TFC_TXDPOLL | LANCE_CSR_TFC_APAD_XMT
| LANCE_CSR_TFC_MFCOM | LANCE_CSR_TFC_RCVCCOM
| LANCE_CSR_TFC_TXSTRTM));
// Recover after TX FIFO underflow
put_reg(sc, LANCE_CSR_IM, LANCE_CSR_IM_DXSUFLO);
// Initialize controller - load up init_table
put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_INIT);
while (0 == (get_reg(sc, LANCE_CSR_CSCR) & LANCE_CSR_CSCR_IDON));
reg=get_reg(sc,LANCE_CSR_CSCR);
put_reg(sc, LANCE_CSR_CSCR, (reg|(LANCE_CSR_CSCR_IENA | LANCE_CSR_CSCR_STRT))&~LANCE_CSR_CSCR_INIT);
#if DEBUG & 9
reg=get_reg(sc,LANCE_CSR_CSCR);
db_printf("CSR after start = %4x\n",reg);
#endif
cpd->active = 1; cpd->txbusy=0; cpd->txbusyh=0;
// delay is necessary for Vmware to get a tick !!!
CYGACC_CALL_IF_DELAY_US(50000);
}
//
// This routine is called to perform special "control" opertions
//
static int
lancepci_control(struct eth_drv_sc *sc, unsigned long key,
void *data, int data_length)
{
cyg_uint8 *esa = (cyg_uint8 *)data;
int i, res;
cyg_uint16 reg;
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
DEBUG_FUNCTION();
#if DEBUG & 9
db_printf("Lancepci-control:entered\n");
#endif
res = 0; // expect success
switch (key) {
case ETH_DRV_SET_MAC_ADDRESS:
#if 9 & DEBUG
db_printf("PCNET - 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];
for (i = 0; i < sizeof(cpd->esa); i += 2) {
reg = cpd->esa[i] | (cpd->esa[i+1] << 8);
put_reg(sc, LANCE_CSR_PAR0+i/2, reg );
}
for (i = 0; i < 6; i++) // in case of later restart
_SU8(cpd->init_table, LANCE_IB_PADR0+i) = cpd->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 += 2) {
cyg_uint16 z = get_reg(sc, LANCE_CSR_PAR0+i/2 );
esa[i] = (cyg_uint8)(0xff & z);
esa[i+1] = (cyg_uint8)(0xff & (z >> 8));
}
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)
{
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, "AMD LancePCI" );
// CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
p->operational = 3; // LINK UP
p->duplex = 2; // 2 = SIMPLEX
p->speed = 10 * 1000000;
#if FIXME
#ifdef KEEP_STATISTICS
{
struct amd_lancepci_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
#endif // FIXME
p->tx_queue_len = 1;
break;
}
#endif
default:
res = 1;
break;
}
#if DEBUG & 9
db_printf("Lancepci-control:done\n");
#endif
CYGACC_CALL_IF_DELAY_US(50000); // let VMware get a tick
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
lancepci_can_send(struct eth_drv_sc *sc)
{
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
DEBUG_FUNCTION();
return (0 == cpd->txbusy);
}
//
// This routine is called to send data to the hardware.
static void
lancepci_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
int total_len, unsigned long key)
{
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
int i, len, plen, ring_entry;
cyg_uint8* sdata = NULL;
cyg_uint8 *d, *buf, *txd;
cyg_uint16 ints;
cyg_uint32 b;
DEBUG_FUNCTION();
INCR_STAT( tx_count );
cpd->txbusy = 1; cpd->txbusyh=1;
cpd->txkey = key;
// Find packet length
plen = 0;
for (i = 0; i < sg_len; i++)
plen += sg_list[i].len;
CYG_ASSERT( plen == total_len, "sg data length mismatch" );
// Get next TX descriptor
ring_entry = cpd->tx_ring_free;
do {
if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {
// Is this a dead end? Probably is.
#if DEBUG & 1
db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );
#endif
continue;
}
cpd->tx_ring_free++;
cpd->tx_ring_owned++;
if (cpd->tx_ring_free == cpd->tx_ring_cnt)
cpd->tx_ring_free = 0;
} while (0);
txd = cpd->tx_ring + ring_entry*LANCE_TD_SIZE;
buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;
CYG_ASSERT(0 == (_SU32(txd, LANCE_TD_PTR) & LANCE_TD_PTR_OWN),
"TX descriptor not free");
#if DEBUG & 4
db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",
txd, buf);
#endif
// Put data into buffer
d = buf;
for (i = 0; i < sg_len; i++) {
sdata = (cyg_uint8 *)sg_list[i].buf;
len = sg_list[i].len;
CYG_ASSERT( sdata, "No sg data pointer here" );
while(len--)
*d++ = *sdata++;
}
CYG_ASSERT( sdata, "No sg data pointer outside" );
#if DEBUG & 1
db_printf("CSCR %04x\n", get_reg(sc, LANCE_CSR_CSCR));
#endif
_SU16(txd, LANCE_TD_LEN) = (-plen);
_SU16(txd, LANCE_TD_MISC) = 0;
HAL_PCI_CPU_TO_BUS(buf, (cyg_uint8 *)b);
_SU32(txd, LANCE_TD_PTR) = ((b & LANCE_TD_PTR_MASK)
| LANCE_TD_PTR_OWN | LANCE_TD_PTR_STP | LANCE_TD_PTR_ENP);
#if DEBUG & 1
db_printf("Last TX: LEN %04x MISC %04x PTR %08x\n",
_SU16(txd, LANCE_TD_LEN),
_SU16(txd, LANCE_TD_MISC),
_SU32(txd, LANCE_TD_PTR));
#endif
// This delay seems to be necessary on some platforms
// (Malta 5kc for example).
// Why it is needed is not clear, but removing it or
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?