📄 eth860.c
字号:
}
/* ******************************************************************** */
/* Transmitter Packet. */
/* */
/* This routine is called by when a packet needs sending. The packet contains */
/* a full ethernet frame to be transmitted. The length of the packet is */
/* provided. */
int eth860_xmit(PIFACE pi, DCU msg) /*__fn__*/
{
int i;
int length;
length = DCUTOPACKET(msg)->length;
if (length < 64) length = 64;
eth860_wait_ticks = (word) (ks_ticks_p_sec()/5);
if (!eth860_wait_ticks)
eth860_wait_ticks = ks_ticks_p_sec();
eth860_retry = 0;
pi->xmit_done_timer = eth860_wait_ticks;
/* GSMR_L1 &= ~(GSMR_L_ENT); */
/* (re) Initialize transmitter */
/* CR = CR_INITTX | CR_SCC1 | CR_FLG; */
/* while (CR & CR_FLG) {}; */
/* Re Enable the transmitter and receiver */
/* GSMR_L1 |= GSMR_L_ENT; */
/* start the xmit */
sendbd->buffer = DCUTODATA(msg);
sendbd->length = length;
sendbd->flags &= ~(BD_SCC_ETH_TX_COLLISION |
BD_SCC_ETH_TX_HEARTBEAT |
BD_SCC_ETH_TX_LATE |
BD_SCC_ETH_TX_LIMIT |
BD_SCC_ETH_TX_RETRY_MASK |
BD_SCC_ETH_TX_UNDERRUN |
BD_SCC_ETH_TX_CARRIER);
sendbd->flags |= (BD_SCC_ETH_TX_READY | BD_SCC_ETH_TX_INTERRUPT);
/* sendbd->flags |= BD_SCC_ETH_TX_READY; */
/* wait while current transmit completes */
/* while (sendbd->flags & BD_SCC_ETH_TX_READY) {}; */
/* ks_invoke_output(pi); tell eth860_xmit() it's sent */
return 0;
}
/* this routine is called from the interrupt routine to handle recv packets */
static void eth860_receiver(PIFACE pi)
{
DCU msg;
volatile BUFFER_DESCRIPTOR *rcvbd;
int toss;
# if (DEBUG_ETH)
aa_n_rcv_ints++;
# endif
int start_rx;
start_rx = CurrentRx;
for (;;)
{
if (BUFFER_DESCRIPTORS[SCC1_RX_BD+CurrentRx].flags & BD_SCC_ETH_RX_EMPTY)
{ /* the controller still has this DCU */
if (BUFFER_DESCRIPTORS[SCC1_RX_BD+CurrentRx].flags & BD_SCC_ETH_RX_WRAP)
CurrentRx = 0;
else
CurrentRx += 1;
}
else
{
toss = 0;
/* here's an incoming packet from the packet driver */
rcvbd = BUFFER_DESCRIPTORS+SCC1_RX_BD+CurrentRx;
if (rcvbd->flags & (BD_SCC_ETH_RX_MISS | BD_SCC_ETH_RX_VIOLATION | BD_SCC_ETH_RX_NONALIGNED |
BD_SCC_ETH_RX_LITTLE | BD_SCC_ETH_RX_CRC | BD_SCC_ETH_RX_OVERRUN | BD_SCC_ETH_RX_COLLISION))
{
# if (DEBUG_ETH)
DEBUG_UWORD(rcvbd->flags);
aa_n_bad_rcv_ints++;
if ( rcvbd->flags & BD_SCC_ETH_RX_MISS) aa_n_bad_rcv_miss++;
if ( rcvbd->flags & BD_SCC_ETH_RX_VIOLATION) aa_n_bad_rcv_vi++;
if ( rcvbd->flags & BD_SCC_ETH_RX_NONALIGNED) aa_n_bad_rcv_non++;
if ( rcvbd->flags & BD_SCC_ETH_RX_LITTLE) aa_n_bad_rcv_little++;
if ( rcvbd->flags & BD_SCC_ETH_RX_CRC) aa_n_bad_rcv_crc++;
if ( rcvbd->flags & BD_SCC_ETH_RX_OVERRUN) aa_n_bad_rcv_ov++;
if ( rcvbd->flags & BD_SCC_ETH_RX_COLLISION) aa_n_bad_rcv_coll++;
# endif
toss = 1;
# ifdef RECEIVE_ALL_FRAMES
if ( rcvbd->flags & BD_SCC_ETH_RX_MISS) toss = 0;
# endif
rcvbd->flags &=
~(BD_SCC_ETH_RX_MISS|BD_SCC_ETH_RX_VIOLATION|BD_SCC_ETH_RX_NONALIGNED|
BD_SCC_ETH_RX_LITTLE|BD_SCC_ETH_RX_CRC|BD_SCC_ETH_RX_OVERRUN|BD_SCC_ETH_RX_COLLISION);
mcstats.errors_in += 1;
}
else
toss = 0;
if (toss)
msg = 0;
else
/* allocate a DCU for the incoming packet */
msg = os_alloc_packet_input(CFG_ETHERSIZE, ETH860_ALLOC);
/* If the alloc worked, pass the rcved packet up */
/* If the alloc failed re-use input packet to not starve the controller */
if (msg)
{
RxDCU[CurrentRx]->length = BUFFER_DESCRIPTORS[SCC1_RX_BD+CurrentRx].length-4;
/*DEBUG_ETHERNET_PACKET((rcvbd->buffer)); */
/* invoke an LSR to remove the packet from the */
/* receive list and and place it in the interface's IP queue */
/* and signal the signal the IP task by calling os_sndx_ip_exchg */
#if (RTIP_VERSION > 24)
ks_invoke_input(pi, RxDCU[CurrentRx]);
#else
os_sndx_input_list(pi, RxDCU[CurrentRx]);
ks_invoke_input(pi);
#endif
mcstats.packets_in += 1;
mcstats.bytes_in += RxDCU[CurrentRx]->length;
RxDCU[CurrentRx] = msg;
}
BUFFER_DESCRIPTORS[SCC1_RX_BD+CurrentRx].length = 0;
BUFFER_DESCRIPTORS[SCC1_RX_BD+CurrentRx].buffer = RxDCU[CurrentRx]->data;
BUFFER_DESCRIPTORS[SCC1_RX_BD+CurrentRx].flags |= BD_SCC_ETH_RX_EMPTY;
if (BUFFER_DESCRIPTORS[SCC1_RX_BD+CurrentRx].flags & BD_SCC_ETH_RX_WRAP)
CurrentRx = 0;
else
CurrentRx += 1;
}
if (start_rx == CurrentRx)
break;
}
}
/* ******************************************************************** */
/* Statistic. return statistics about the device interface */
/* */
/* This routine is called by user code that wishes to inspect driver statistics. */
/* We call this routine in the demo program. It is not absolutely necessary */
/* to implement such a function (Leave it empty.), but it is a handy debugging */
/* tool. */
/* */
/* The address of this function must be placed into the "devices" table in */
/* tcdevtbl.c either at compile time or before a device open is called. */
/* */
/* */
/* Non packet drivers should behave the same way. */
/* */
BOOLEAN eth860_statistics(PIFACE pi) /*__fn__*/
{
UPDATE_SET_INFO(pi, interface_packets_in, mcstats.packets_in)
UPDATE_SET_INFO(pi, interface_packets_out, mcstats.packets_out)
UPDATE_SET_INFO(pi, interface_bytes_in, mcstats.bytes_in)
UPDATE_SET_INFO(pi, interface_bytes_out, mcstats.bytes_out)
UPDATE_SET_INFO(pi, interface_errors_in, mcstats.errors_in)
UPDATE_SET_INFO(pi, interface_errors_out, mcstats.errors_out)
UPDATE_SET_INFO(pi, interface_packets_lost, mcstats.packets_lost)
return(TRUE);
}
/*--------------------------------------------------------------------------
*
* FUNCTION NAME: EthernetIntHandler
*
* DESCRIPTION:
*
* Process External Interrupt (assumes only interrupts from SCC1)
* Comes here when '860 interrupts us with a received packet.
*
* Main Processing Steps:
*
* (1) Save off SCCE for SCC1 (SCC1 Event Register)
*
* (2) Clear SCC1 Event Register
*
* (3) Test SCC1 Event
*
* (4) Clear SCC1 bit CPM Interrupt In-Service Register
*
*
* NOTE: This ISR will only handle ONE RX event.
*
* EXTERNAL EFFECTS: interrupt related registers
*
* PARAMETERS:
*
* vector - interrupt vector (address)
*
* RETURNS: NONE
*
*-------------------------------------------------------------------------*/
void EthernetIntHandler(int vector)
{
dword my_scce1;
/*-------------------------------------- */
/* Grab the SCC event register (16-333) */
/*-------------------------------------- */
my_scce1 = IMMR->scc_regs[SCC1_REG].scc_scce;
/* Clear all events that will be serviced */
IMMR->scc_regs[SCC1_REG].scc_scce = my_scce1;
n_interrupts += 1;
if (!(my_scce1 & (SCCE_ETH_RXF | SCCE_ETH_TXB | SCCE_ETH_TXE)))
{
n_bogus_interrupts += 1;
}
if (my_scce1 & SCCE_ETH_RXF) /* Frame received - signal interrupt task */
eth860_receiver(myIface);
if (my_scce1 & SCCE_ETH_TXB) /* Buffer transmitted */
{
while (!(sentbd->flags & BD_SCC_ETH_TX_READY) && sentbd->buffer)
{ /* transmit packet has been sent */
/*if(sentbd->flags & 0x3ff) DEBUG_UWORD(sentbd->flags); */
sentbd->flags &= ~(BD_SCC_ETH_TX_COLLISION |
BD_SCC_ETH_TX_HEARTBEAT |
BD_SCC_ETH_TX_LATE |
BD_SCC_ETH_TX_LIMIT |
BD_SCC_ETH_TX_RETRY_MASK |
BD_SCC_ETH_TX_UNDERRUN |
BD_SCC_ETH_TX_CARRIER);
sentbd->buffer = 0;
ks_invoke_output(myIface); /* tell eth860_xmit() it's sent */
if (sentbd->flags & BD_SCC_ETH_TX_WRAP)
sentbd = (BUFFER_DESCRIPTORS+SCC1_TX_BD);
else
sentbd++;
}
}
if (my_scce1 & SCCE_ETH_TXE) /* transmit error */
{
ks_invoke_output(myIface); /* signal eth860_xmit() he'll reset */
}
IMMR->cpmi_cisr = CIMR_SCC1; /* Clear any existing in-service interrupt */
}
/*-------------------------------------------------------------------------
* FUNCTION NAME: ether_enable_ads
* DESCRIPTION:
*
* Enable/Disable Ethernet on 821/860 ADS board.
*
* PARAMETERS:
* setting - 0 in lsb Disable Ethernet and turns off LED
* 1 in lsb Enable Ethernet and turns on LED.
*-------------------------------------------------------------------------*/
void ether_enable_ads(word setting)
{
BCSR *csr;
#if(ADS860)
csr = (BCSR *)(IMMR->memc_br1 & 0xFFFF8000);
if (setting & 0x01)
csr->bcsr1 &= ~ETHEN; /* Enable Ethernet (turn on LED) */
else
csr->bcsr1 |= ETHEN; /* Disable Ethernet (turn off LED) */
#elif(MPC860)
csr = (BCSR *)((IMMR->memc_br4 & 0xffff8000) | 0x00100000);
if (setting & 0x01)
csr->bcsr1 |= 0x9C; /* Enable Ethernet10baset */
else
csr->bcsr1 &= ~0x80; /* Disable Ethernet*/
#else
#error
#endif
} /* end ether_enable_ads */
#if(!RTKD860)
/*-------------------------------------------------------------------------
* FUNCTION NAME: rs232_1_enable_ads
* DESCRIPTION:
*
* Enable/Disable RS232 port1 on 821/860 ADS and MBX boards.
*
* PARAMETERS:
* setting - 0 in lsb Disable port and (turns off LED on ADS)
* 1 in lsb Enable port and turns on LED.
*-------------------------------------------------------------------------*/
void rs232_1_enable_ads(word setting)
{
BCSR *csr;
#if (ADS860)
csr = (BCSR *)(IMMR->memc_br1 & 0xFFFF8000);
if (setting & 0x01)
csr->bcsr1 &= ~RS232EN1; /* Enable RS232 port1 (turn on LED) */
else
csr->bcsr1 |= RS232EN1; /* Disable RS232 port1 (turn off LED) */
#elif(MPC860)
csr = (BCSR *)((IMMR->memc_br4 & 0xffff8000) | 0x00100000);
if (setting & 0x01)
csr->bcsr1 &= ~0x03; /* Enable RS232 port1 */
else
csr->bcsr1 |= 0x01; /* Disable RS232 port1 */
#else
#error
#endif
} /* end rs232_1_enable_ads */
/*-------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -