/*
|
/*
|
* RTEMS/TCPIP driver for MPC860 SCC1 Ethernet
|
* RTEMS/TCPIP driver for MPC860 SCC1 Ethernet
|
*
|
*
|
* Modified for MPC860 by Jay Monkman (jmonkman@frasca.com)
|
* Modified for MPC860 by Jay Monkman (jmonkman@frasca.com)
|
*
|
*
|
* This supports ethernet on either SCC1 or the FEC of the MPC860T.
|
* This supports ethernet on either SCC1 or the FEC of the MPC860T.
|
* Right now, we only do 10 Mbps, even with the FEC. The function
|
* Right now, we only do 10 Mbps, even with the FEC. The function
|
* rtems_m860_enet_driver_attach determines which one to use. Currently,
|
* rtems_m860_enet_driver_attach determines which one to use. Currently,
|
* only one may be used at a time.
|
* only one may be used at a time.
|
*
|
*
|
* W. Eric Norum
|
* W. Eric Norum
|
* Saskatchewan Accelerator Laboratory
|
* Saskatchewan Accelerator Laboratory
|
* University of Saskatchewan
|
* University of Saskatchewan
|
* Saskatoon, Saskatchewan, CANADA
|
* Saskatoon, Saskatchewan, CANADA
|
* eric@skatter.usask.ca
|
* eric@skatter.usask.ca
|
*
|
*
|
* $Id: network.c,v 1.2 2001-09-27 12:00:35 chris Exp $
|
* $Id: network.c,v 1.2 2001-09-27 12:00:35 chris Exp $
|
*/
|
*/
|
#include <bsp.h>
|
#include <bsp.h>
|
#include <mpc860.h>
|
#include <mpc860.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <rtems/error.h>
|
#include <rtems/error.h>
|
#include <rtems/rtems_bsdnet.h>
|
#include <rtems/rtems_bsdnet.h>
|
|
|
#include <sys/param.h>
|
#include <sys/param.h>
|
#include <sys/mbuf.h>
|
#include <sys/mbuf.h>
|
#include <sys/socket.h>
|
#include <sys/socket.h>
|
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
|
|
#include <net/if.h>
|
#include <net/if.h>
|
|
|
#include <netinet/in.h>
|
#include <netinet/in.h>
|
#include <netinet/if_ether.h>
|
#include <netinet/if_ether.h>
|
|
|
/*
|
/*
|
* Number of interfaces supported by this driver
|
* Number of interfaces supported by this driver
|
*/
|
*/
|
#define NIFACES 1
|
#define NIFACES 1
|
|
|
/*
|
/*
|
* Default number of buffer descriptors set aside for this driver.
|
* Default number of buffer descriptors set aside for this driver.
|
* The number of transmit buffer descriptors has to be quite large
|
* The number of transmit buffer descriptors has to be quite large
|
* since a single frame often uses four or more buffer descriptors.
|
* since a single frame often uses four or more buffer descriptors.
|
*/
|
*/
|
#define RX_BUF_COUNT 32
|
#define RX_BUF_COUNT 32
|
#define TX_BUF_COUNT 8
|
#define TX_BUF_COUNT 8
|
#define TX_BD_PER_BUF 4
|
#define TX_BD_PER_BUF 4
|
|
|
/*
|
/*
|
* RTEMS event used by interrupt handler to signal daemons.
|
* RTEMS event used by interrupt handler to signal daemons.
|
* This must *not* be the same event used by the TCP/IP task synchronization.
|
* This must *not* be the same event used by the TCP/IP task synchronization.
|
*/
|
*/
|
#define INTERRUPT_EVENT RTEMS_EVENT_1
|
#define INTERRUPT_EVENT RTEMS_EVENT_1
|
|
|
/*
|
/*
|
* RTEMS event used to start transmit daemon.
|
* RTEMS event used to start transmit daemon.
|
* This must not be the same as INTERRUPT_EVENT.
|
* This must not be the same as INTERRUPT_EVENT.
|
*/
|
*/
|
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
|
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
|
|
|
/*
|
/*
|
* Receive buffer size -- Allow for a full ethernet packet plus a pointer
|
* Receive buffer size -- Allow for a full ethernet packet plus a pointer
|
*/
|
*/
|
#define RBUF_SIZE 1520
|
#define RBUF_SIZE 1520
|
|
|
#if (MCLBYTES < RBUF_SIZE)
|
#if (MCLBYTES < RBUF_SIZE)
|
# error "Driver must have MCLBYTES > RBUF_SIZE"
|
# error "Driver must have MCLBYTES > RBUF_SIZE"
|
#endif
|
#endif
|
|
|
/*
|
/*
|
* Per-device data
|
* Per-device data
|
*/
|
*/
|
struct m860_enet_struct {
|
struct m860_enet_struct {
|
struct arpcom arpcom;
|
struct arpcom arpcom;
|
struct mbuf **rxMbuf;
|
struct mbuf **rxMbuf;
|
struct mbuf **txMbuf;
|
struct mbuf **txMbuf;
|
int acceptBroadcast;
|
int acceptBroadcast;
|
int rxBdCount;
|
int rxBdCount;
|
int txBdCount;
|
int txBdCount;
|
int txBdHead;
|
int txBdHead;
|
int txBdTail;
|
int txBdTail;
|
int txBdActiveCount;
|
int txBdActiveCount;
|
m860BufferDescriptor_t *rxBdBase;
|
m860BufferDescriptor_t *rxBdBase;
|
m860BufferDescriptor_t *txBdBase;
|
m860BufferDescriptor_t *txBdBase;
|
rtems_id rxDaemonTid;
|
rtems_id rxDaemonTid;
|
rtems_id txDaemonTid;
|
rtems_id txDaemonTid;
|
|
|
/*
|
/*
|
* Statistics
|
* Statistics
|
*/
|
*/
|
unsigned long rxInterrupts;
|
unsigned long rxInterrupts;
|
unsigned long rxNotFirst;
|
unsigned long rxNotFirst;
|
unsigned long rxNotLast;
|
unsigned long rxNotLast;
|
unsigned long rxGiant;
|
unsigned long rxGiant;
|
unsigned long rxNonOctet;
|
unsigned long rxNonOctet;
|
unsigned long rxRunt;
|
unsigned long rxRunt;
|
unsigned long rxBadCRC;
|
unsigned long rxBadCRC;
|
unsigned long rxOverrun;
|
unsigned long rxOverrun;
|
unsigned long rxCollision;
|
unsigned long rxCollision;
|
|
|
unsigned long txInterrupts;
|
unsigned long txInterrupts;
|
unsigned long txDeferred;
|
unsigned long txDeferred;
|
unsigned long txHeartbeat;
|
unsigned long txHeartbeat;
|
unsigned long txLateCollision;
|
unsigned long txLateCollision;
|
unsigned long txRetryLimit;
|
unsigned long txRetryLimit;
|
unsigned long txUnderrun;
|
unsigned long txUnderrun;
|
unsigned long txLostCarrier;
|
unsigned long txLostCarrier;
|
unsigned long txRawWait;
|
unsigned long txRawWait;
|
};
|
};
|
static struct m860_enet_struct enet_driver[NIFACES];
|
static struct m860_enet_struct enet_driver[NIFACES];
|
|
|
/*
|
/*
|
* SCC1 interrupt handler
|
* SCC1 interrupt handler
|
*/
|
*/
|
static rtems_isr
|
static rtems_isr
|
m860_scc1_interrupt_handler (rtems_vector_number v)
|
m860_scc1_interrupt_handler (rtems_vector_number v)
|
{
|
{
|
/*
|
/*
|
* Frame received?
|
* Frame received?
|
*/
|
*/
|
if ((m860.scc1.sccm & 0x8) && (m860.scc1.scce & 0x8)) {
|
if ((m860.scc1.sccm & 0x8) && (m860.scc1.scce & 0x8)) {
|
m860.scc1.scce = 0x8;
|
m860.scc1.scce = 0x8;
|
/* I don't think the next line is needed. It was in
|
/* I don't think the next line is needed. It was in
|
* the 68360 stuff, though.
|
* the 68360 stuff, though.
|
* m860.scc1.sccm &= ~0x8;
|
* m860.scc1.sccm &= ~0x8;
|
*/
|
*/
|
enet_driver[0].rxInterrupts++;
|
enet_driver[0].rxInterrupts++;
|
rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
|
rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
|
}
|
}
|
|
|
/*
|
/*
|
* Buffer transmitted or transmitter error?
|
* Buffer transmitted or transmitter error?
|
*/
|
*/
|
if ((m860.scc1.sccm & 0x12) && (m860.scc1.scce & 0x12)) {
|
if ((m860.scc1.sccm & 0x12) && (m860.scc1.scce & 0x12)) {
|
m860.scc1.scce = 0x12;
|
m860.scc1.scce = 0x12;
|
/* I don't think the next line is needed. It was in
|
/* I don't think the next line is needed. It was in
|
* the 68360 stuff, though.
|
* the 68360 stuff, though.
|
* m860.scc1.sccm &= ~0x12;
|
* m860.scc1.sccm &= ~0x12;
|
*/
|
*/
|
enet_driver[0].txInterrupts++;
|
enet_driver[0].txInterrupts++;
|
rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
|
rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
|
}
|
}
|
m860.cisr = 1UL << 30; /* Clear SCC1 interrupt-in-service bit */
|
m860.cisr = 1UL << 30; /* Clear SCC1 interrupt-in-service bit */
|
}
|
}
|
|
|
/*
|
/*
|
* FEC interrupt handler
|
* FEC interrupt handler
|
*/
|
*/
|
static rtems_isr
|
static rtems_isr
|
m860_fec_interrupt_handler (rtems_vector_number v)
|
m860_fec_interrupt_handler (rtems_vector_number v)
|
{
|
{
|
/*
|
/*
|
* Frame received?
|
* Frame received?
|
*/
|
*/
|
if (m860.fec.ievent & M860_FEC_IEVENT_RFINT) {
|
if (m860.fec.ievent & M860_FEC_IEVENT_RFINT) {
|
m860.fec.ievent = M860_FEC_IEVENT_RFINT;
|
m860.fec.ievent = M860_FEC_IEVENT_RFINT;
|
enet_driver[0].rxInterrupts++;
|
enet_driver[0].rxInterrupts++;
|
rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
|
rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
|
}
|
}
|
|
|
/*
|
/*
|
* Buffer transmitted or transmitter error?
|
* Buffer transmitted or transmitter error?
|
*/
|
*/
|
if (m860.fec.ievent & M860_FEC_IEVENT_TFINT) {
|
if (m860.fec.ievent & M860_FEC_IEVENT_TFINT) {
|
m860.fec.ievent = M860_FEC_IEVENT_TFINT;
|
m860.fec.ievent = M860_FEC_IEVENT_TFINT;
|
enet_driver[0].txInterrupts++;
|
enet_driver[0].txInterrupts++;
|
rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
|
rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Initialize the ethernet hardware
|
* Initialize the ethernet hardware
|
*/
|
*/
|
static void
|
static void
|
m860_scc_initialize_hardware (struct m860_enet_struct *sc)
|
m860_scc_initialize_hardware (struct m860_enet_struct *sc)
|
{
|
{
|
int i;
|
int i;
|
unsigned char *hwaddr;
|
unsigned char *hwaddr;
|
rtems_status_code status;
|
rtems_status_code status;
|
rtems_isr_entry old_handler;
|
rtems_isr_entry old_handler;
|
|
|
/*
|
/*
|
* Configure port A CLK1, CLK2, TXD1 and RXD1 pins
|
* Configure port A CLK1, CLK2, TXD1 and RXD1 pins
|
*/
|
*/
|
m860.papar |= 0x303;
|
m860.papar |= 0x303;
|
m860.padir &= ~0x303;
|
m860.padir &= ~0x303;
|
m860.paodr &= ~0x303;
|
m860.paodr &= ~0x303;
|
|
|
/*
|
/*
|
* Configure port C CTS1* and CD1* pins, and PC4-PC7
|
* Configure port C CTS1* and CD1* pins, and PC4-PC7
|
*
|
*
|
*/
|
*/
|
m860.pcpar &= ~0x30;
|
m860.pcpar &= ~0x30;
|
m860.pcdir |= 0x0f00;
|
m860.pcdir |= 0x0f00;
|
m860.pcdir &= ~0x30;
|
m860.pcdir &= ~0x30;
|
m860.pcso |= 0x30;
|
m860.pcso |= 0x30;
|
m860.pcdat &= ~0x0f00; /* Clear LOOP */
|
m860.pcdat &= ~0x0f00; /* Clear LOOP */
|
m860.pcdat |= 0x0700; /* Set FULDL, TPSQEL, TPAPCE */
|
m860.pcdat |= 0x0700; /* Set FULDL, TPSQEL, TPAPCE */
|
|
|
/*
|
/*
|
* Connect CLK1 and CLK2 to SCC1
|
* Connect CLK1 and CLK2 to SCC1
|
*/
|
*/
|
m860.sicr &= ~0xFF;
|
m860.sicr &= ~0xFF;
|
m860.sicr |= (5 << 3) | 4;
|
m860.sicr |= (5 << 3) | 4;
|
|
|
/*
|
/*
|
* Initialize SDMA configuration register
|
* Initialize SDMA configuration register
|
*/
|
*/
|
m860.sdcr = 1;
|
m860.sdcr = 1;
|
|
|
/*
|
/*
|
* Allocate mbuf pointers
|
* Allocate mbuf pointers
|
*/
|
*/
|
sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
|
sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
|
M_MBUF, M_NOWAIT);
|
M_MBUF, M_NOWAIT);
|
sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
|
sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
|
M_MBUF, M_NOWAIT);
|
M_MBUF, M_NOWAIT);
|
if (!sc->rxMbuf || !sc->txMbuf)
|
if (!sc->rxMbuf || !sc->txMbuf)
|
rtems_panic ("No memory for mbuf pointers");
|
rtems_panic ("No memory for mbuf pointers");
|
|
|
/*
|
/*
|
* Set receiver and transmitter buffer descriptor bases
|
* Set receiver and transmitter buffer descriptor bases
|
*/
|
*/
|
sc->rxBdBase = M860AllocateBufferDescriptors(sc->rxBdCount);
|
sc->rxBdBase = M860AllocateBufferDescriptors(sc->rxBdCount);
|
sc->txBdBase = M860AllocateBufferDescriptors(sc->txBdCount);
|
sc->txBdBase = M860AllocateBufferDescriptors(sc->txBdCount);
|
m860.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m860;
|
m860.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m860;
|
m860.scc1p.tbase = (char *)sc->txBdBase - (char *)&m860;
|
m860.scc1p.tbase = (char *)sc->txBdBase - (char *)&m860;
|
|
|
/*
|
/*
|
* Send "Init parameters" command
|
* Send "Init parameters" command
|
*/
|
*/
|
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC1);
|
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC1);
|
|
|
/*
|
/*
|
* Set receive and transmit function codes
|
* Set receive and transmit function codes
|
*/
|
*/
|
m860.scc1p.rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0);
|
m860.scc1p.rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0);
|
m860.scc1p.tfcr = M860_TFCR_MOT | M860_TFCR_DMA_SPACE(0);
|
m860.scc1p.tfcr = M860_TFCR_MOT | M860_TFCR_DMA_SPACE(0);
|
|
|
/*
|
/*
|
* Set maximum receive buffer length
|
* Set maximum receive buffer length
|
*/
|
*/
|
m860.scc1p.mrblr = RBUF_SIZE;
|
m860.scc1p.mrblr = RBUF_SIZE;
|
|
|
/*
|
/*
|
* Set CRC parameters
|
* Set CRC parameters
|
*/
|
*/
|
m860.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
|
m860.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
|
m860.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
|
m860.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
|
|
|
/*
|
/*
|
* Clear diagnostic counters
|
* Clear diagnostic counters
|
*/
|
*/
|
m860.scc1p.un.ethernet.crcec = 0;
|
m860.scc1p.un.ethernet.crcec = 0;
|
m860.scc1p.un.ethernet.alec = 0;
|
m860.scc1p.un.ethernet.alec = 0;
|
m860.scc1p.un.ethernet.disfc = 0;
|
m860.scc1p.un.ethernet.disfc = 0;
|
|
|
/*
|
/*
|
* Set pad value
|
* Set pad value
|
*/
|
*/
|
m860.scc1p.un.ethernet.pads = 0x8888;
|
m860.scc1p.un.ethernet.pads = 0x8888;
|
|
|
/*
|
/*
|
* Set retry limit
|
* Set retry limit
|
*/
|
*/
|
m860.scc1p.un.ethernet.ret_lim = 15;
|
m860.scc1p.un.ethernet.ret_lim = 15;
|
|
|
/*
|
/*
|
* Set maximum and minimum frame length
|
* Set maximum and minimum frame length
|
*/
|
*/
|
m860.scc1p.un.ethernet.mflr = 1518;
|
m860.scc1p.un.ethernet.mflr = 1518;
|
m860.scc1p.un.ethernet.minflr = 64;
|
m860.scc1p.un.ethernet.minflr = 64;
|
m860.scc1p.un.ethernet.maxd1 = RBUF_SIZE;
|
m860.scc1p.un.ethernet.maxd1 = RBUF_SIZE;
|
m860.scc1p.un.ethernet.maxd2 = RBUF_SIZE;
|
m860.scc1p.un.ethernet.maxd2 = RBUF_SIZE;
|
|
|
/*
|
/*
|
* Clear group address hash table
|
* Clear group address hash table
|
*/
|
*/
|
m860.scc1p.un.ethernet.gaddr1 = 0;
|
m860.scc1p.un.ethernet.gaddr1 = 0;
|
m860.scc1p.un.ethernet.gaddr2 = 0;
|
m860.scc1p.un.ethernet.gaddr2 = 0;
|
m860.scc1p.un.ethernet.gaddr3 = 0;
|
m860.scc1p.un.ethernet.gaddr3 = 0;
|
m860.scc1p.un.ethernet.gaddr4 = 0;
|
m860.scc1p.un.ethernet.gaddr4 = 0;
|
|
|
/*
|
/*
|
* Set our physical address
|
* Set our physical address
|
*/
|
*/
|
hwaddr = sc->arpcom.ac_enaddr;
|
hwaddr = sc->arpcom.ac_enaddr;
|
|
|
m860.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
|
m860.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
|
m860.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
|
m860.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
|
m860.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
|
m860.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
|
|
|
/*
|
/*
|
* Aggressive retry
|
* Aggressive retry
|
*/
|
*/
|
m860.scc1p.un.ethernet.p_per = 0;
|
m860.scc1p.un.ethernet.p_per = 0;
|
|
|
/*
|
/*
|
* Clear individual address hash table
|
* Clear individual address hash table
|
*/
|
*/
|
m860.scc1p.un.ethernet.iaddr1 = 0;
|
m860.scc1p.un.ethernet.iaddr1 = 0;
|
m860.scc1p.un.ethernet.iaddr2 = 0;
|
m860.scc1p.un.ethernet.iaddr2 = 0;
|
m860.scc1p.un.ethernet.iaddr3 = 0;
|
m860.scc1p.un.ethernet.iaddr3 = 0;
|
m860.scc1p.un.ethernet.iaddr4 = 0;
|
m860.scc1p.un.ethernet.iaddr4 = 0;
|
|
|
/*
|
/*
|
* Clear temp address
|
* Clear temp address
|
*/
|
*/
|
m860.scc1p.un.ethernet.taddr_l = 0;
|
m860.scc1p.un.ethernet.taddr_l = 0;
|
m860.scc1p.un.ethernet.taddr_m = 0;
|
m860.scc1p.un.ethernet.taddr_m = 0;
|
m860.scc1p.un.ethernet.taddr_h = 0;
|
m860.scc1p.un.ethernet.taddr_h = 0;
|
|
|
/*
|
/*
|
* Set up receive buffer descriptors
|
* Set up receive buffer descriptors
|
*/
|
*/
|
for (i = 0 ; i < sc->rxBdCount ; i++) {
|
for (i = 0 ; i < sc->rxBdCount ; i++) {
|
(sc->rxBdBase + i)->status = 0;
|
(sc->rxBdBase + i)->status = 0;
|
}
|
}
|
|
|
/*
|
/*
|
* Set up transmit buffer descriptors
|
* Set up transmit buffer descriptors
|
*/
|
*/
|
for (i = 0 ; i < sc->txBdCount ; i++) {
|
for (i = 0 ; i < sc->txBdCount ; i++) {
|
(sc->txBdBase + i)->status = 0;
|
(sc->txBdBase + i)->status = 0;
|
sc->txMbuf[i] = NULL;
|
sc->txMbuf[i] = NULL;
|
}
|
}
|
sc->txBdHead = sc->txBdTail = 0;
|
sc->txBdHead = sc->txBdTail = 0;
|
sc->txBdActiveCount = 0;
|
sc->txBdActiveCount = 0;
|
|
|
/*
|
/*
|
* Clear any outstanding events
|
* Clear any outstanding events
|
*/
|
*/
|
m860.scc1.scce = 0xFFFF;
|
m860.scc1.scce = 0xFFFF;
|
|
|
/*
|
/*
|
* Set up interrupts
|
* Set up interrupts
|
*/
|
*/
|
status = rtems_interrupt_catch (m860_scc1_interrupt_handler,
|
status = rtems_interrupt_catch (m860_scc1_interrupt_handler,
|
PPC_IRQ_CPM_SCC1,
|
PPC_IRQ_CPM_SCC1,
|
&old_handler);
|
&old_handler);
|
if (status != RTEMS_SUCCESSFUL) {
|
if (status != RTEMS_SUCCESSFUL) {
|
rtems_panic ("Can't attach M860 SCC1 interrupt handler: %s\n",
|
rtems_panic ("Can't attach M860 SCC1 interrupt handler: %s\n",
|
rtems_status_text (status));
|
rtems_status_text (status));
|
}
|
}
|
m860.scc1.sccm = 0; /* No interrupts unmasked till necessary */
|
m860.scc1.sccm = 0; /* No interrupts unmasked till necessary */
|
m860.cimr |= (1UL << 30); /* Enable SCC1 interrupt */
|
m860.cimr |= (1UL << 30); /* Enable SCC1 interrupt */
|
|
|
/*
|
/*
|
* Set up General SCC Mode Register
|
* Set up General SCC Mode Register
|
* Ethernet configuration
|
* Ethernet configuration
|
*/
|
*/
|
m860.scc1.gsmr_h = 0x0;
|
m860.scc1.gsmr_h = 0x0;
|
m860.scc1.gsmr_l = 0x1088000c;
|
m860.scc1.gsmr_l = 0x1088000c;
|
|
|
/*
|
/*
|
* Set up data synchronization register
|
* Set up data synchronization register
|
* Ethernet synchronization pattern
|
* Ethernet synchronization pattern
|
*/
|
*/
|
m860.scc1.dsr = 0xd555;
|
m860.scc1.dsr = 0xd555;
|
|
|
/*
|
/*
|
* Set up protocol-specific mode register
|
* Set up protocol-specific mode register
|
* No Heartbeat check
|
* No Heartbeat check
|
* No force collision
|
* No force collision
|
* Discard short frames
|
* Discard short frames
|
* Individual address mode
|
* Individual address mode
|
* Ethernet CRC
|
* Ethernet CRC
|
* Not promisuous
|
* Not promisuous
|
* Ignore/accept broadcast packets as specified
|
* Ignore/accept broadcast packets as specified
|
* Normal backoff timer
|
* Normal backoff timer
|
* No loopback
|
* No loopback
|
* No input sample at end of frame
|
* No input sample at end of frame
|
* 64-byte limit for late collision
|
* 64-byte limit for late collision
|
* Wait 22 bits before looking for start of frame delimiter
|
* Wait 22 bits before looking for start of frame delimiter
|
* Disable full-duplex operation
|
* Disable full-duplex operation
|
*/
|
*/
|
m860.scc1.psmr = 0x080A | (sc->acceptBroadcast ? 0 : 0x100);
|
m860.scc1.psmr = 0x080A | (sc->acceptBroadcast ? 0 : 0x100);
|
|
|
/*
|
/*
|
* Enable the TENA (RTS1*) pin
|
* Enable the TENA (RTS1*) pin
|
*/
|
*/
|
m860.pcpar |= 0x1;
|
m860.pcpar |= 0x1;
|
m860.pcdir &= ~0x1;
|
m860.pcdir &= ~0x1;
|
|
|
|
|
/*
|
/*
|
* Set up interrupts
|
* Set up interrupts
|
* FIXME: DANGER: WARNING:
|
* FIXME: DANGER: WARNING:
|
* CICR and SIMASK must be set in any module that uses
|
* CICR and SIMASK must be set in any module that uses
|
* the CPM. Currently those are console-generic.c and
|
* the CPM. Currently those are console-generic.c and
|
* network.c. If the registers are not set the same
|
* network.c. If the registers are not set the same
|
* in both places, strange things may happen.
|
* in both places, strange things may happen.
|
* If they are only set in one place, then an application
|
* If they are only set in one place, then an application
|
* that used the other module won't work correctly.
|
* that used the other module won't work correctly.
|
* Put this comment in each module that sets these 2 registers
|
* Put this comment in each module that sets these 2 registers
|
*/
|
*/
|
m860.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
|
m860.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
|
SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */
|
SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */
|
m860.simask |= M860_SIMASK_LVM1;
|
m860.simask |= M860_SIMASK_LVM1;
|
|
|
/*
|
/*
|
* Enable receiver and transmitter
|
* Enable receiver and transmitter
|
*/
|
*/
|
m860.scc1.gsmr_l = 0x1088003c;
|
m860.scc1.gsmr_l = 0x1088003c;
|
}
|
}
|
|
|
static void
|
static void
|
m860_fec_initialize_hardware (struct m860_enet_struct *sc)
|
m860_fec_initialize_hardware (struct m860_enet_struct *sc)
|
{
|
{
|
int i;
|
int i;
|
unsigned char *hwaddr;
|
unsigned char *hwaddr;
|
rtems_status_code status;
|
rtems_status_code status;
|
rtems_isr_entry old_handler;
|
rtems_isr_entry old_handler;
|
|
|
/*
|
/*
|
* Issue reset to FEC
|
* Issue reset to FEC
|
*/
|
*/
|
m860.fec.ecntrl=0x1;
|
m860.fec.ecntrl=0x1;
|
|
|
/*
|
/*
|
* Put ethernet transciever in reset
|
* Put ethernet transciever in reset
|
*/
|
*/
|
m860.pgcra |= 0x80;
|
m860.pgcra |= 0x80;
|
|
|
/*
|
/*
|
* Configure I/O ports
|
* Configure I/O ports
|
*/
|
*/
|
m860.pdpar = 0x1fff;
|
m860.pdpar = 0x1fff;
|
m860.pddir = 0x1c58;
|
m860.pddir = 0x1c58;
|
|
|
/*
|
/*
|
* Take ethernet transciever out of reset
|
* Take ethernet transciever out of reset
|
*/
|
*/
|
m860.pgcra &= ~0x80;
|
m860.pgcra &= ~0x80;
|
|
|
|
|
/*
|
/*
|
* Set SIU interrupt level to LVL2
|
* Set SIU interrupt level to LVL2
|
*
|
*
|
*/
|
*/
|
m860.fec.ivec = 0x02 << 29;
|
m860.fec.ivec = 0x02 << 29;
|
|
|
/*
|
/*
|
* Set the TX and RX fifo sizes. For now, we'll split it evenly
|
* Set the TX and RX fifo sizes. For now, we'll split it evenly
|
*/
|
*/
|
/* If you uncomment these, the FEC will not work right.
|
/* If you uncomment these, the FEC will not work right.
|
m860.fec.r_fstart = ((m860.fec.r_bound & 0x3ff) >> 2) & 0x3ff;
|
m860.fec.r_fstart = ((m860.fec.r_bound & 0x3ff) >> 2) & 0x3ff;
|
m860.fec.x_fstart = 0;
|
m860.fec.x_fstart = 0;
|
*/
|
*/
|
|
|
/*
|
/*
|
* Set our physical address
|
* Set our physical address
|
*/
|
*/
|
hwaddr = sc->arpcom.ac_enaddr;
|
hwaddr = sc->arpcom.ac_enaddr;
|
|
|
m860.fec.addr_low = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
|
m860.fec.addr_low = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
|
(hwaddr[2] << 8) | (hwaddr[3] << 0);
|
(hwaddr[2] << 8) | (hwaddr[3] << 0);
|
m860.fec.addr_high = (hwaddr[4] << 24) | (hwaddr[5] << 16);
|
m860.fec.addr_high = (hwaddr[4] << 24) | (hwaddr[5] << 16);
|
|
|
/*
|
/*
|
* Clear the hash table
|
* Clear the hash table
|
*/
|
*/
|
m860.fec.hash_table_high = 0;
|
m860.fec.hash_table_high = 0;
|
m860.fec.hash_table_low = 0;
|
m860.fec.hash_table_low = 0;
|
|
|
/*
|
/*
|
* Set up receive buffer size
|
* Set up receive buffer size
|
*/
|
*/
|
m860.fec.r_buf_size = 0x5f0; /* set to 1520 */
|
m860.fec.r_buf_size = 0x5f0; /* set to 1520 */
|
|
|
/*
|
/*
|
* Allocate mbuf pointers
|
* Allocate mbuf pointers
|
*/
|
*/
|
sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
|
sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
|
M_MBUF, M_NOWAIT);
|
M_MBUF, M_NOWAIT);
|
sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
|
sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
|
M_MBUF, M_NOWAIT);
|
M_MBUF, M_NOWAIT);
|
if (!sc->rxMbuf || !sc->txMbuf)
|
if (!sc->rxMbuf || !sc->txMbuf)
|
rtems_panic ("No memory for mbuf pointers");
|
rtems_panic ("No memory for mbuf pointers");
|
|
|
/*
|
/*
|
* Set receiver and transmitter buffer descriptor bases
|
* Set receiver and transmitter buffer descriptor bases
|
*/
|
*/
|
sc->rxBdBase = M860AllocateBufferDescriptors(sc->rxBdCount);
|
sc->rxBdBase = M860AllocateBufferDescriptors(sc->rxBdCount);
|
sc->txBdBase = M860AllocateBufferDescriptors(sc->txBdCount);
|
sc->txBdBase = M860AllocateBufferDescriptors(sc->txBdCount);
|
m860.fec.r_des_start = (int)sc->rxBdBase;
|
m860.fec.r_des_start = (int)sc->rxBdBase;
|
m860.fec.x_des_start = (int)sc->txBdBase;
|
m860.fec.x_des_start = (int)sc->txBdBase;
|
|
|
/*
|
/*
|
* Set up Receive Control Register:
|
* Set up Receive Control Register:
|
* Not promiscuous mode
|
* Not promiscuous mode
|
* MII mode
|
* MII mode
|
* Half duplex
|
* Half duplex
|
* No loopback
|
* No loopback
|
*/
|
*/
|
m860.fec.r_cntrl = 0x00000006;
|
m860.fec.r_cntrl = 0x00000006;
|
|
|
/*
|
/*
|
* Set up Transmit Control Register:
|
* Set up Transmit Control Register:
|
* Half duplex
|
* Half duplex
|
* No heartbeat
|
* No heartbeat
|
*/
|
*/
|
m860.fec.x_cntrl = 0x00000000;
|
m860.fec.x_cntrl = 0x00000000;
|
|
|
/*
|
/*
|
* Set up DMA function code:
|
* Set up DMA function code:
|
* Big-endian
|
* Big-endian
|
* DMA functino code = 0
|
* DMA functino code = 0
|
*/
|
*/
|
m860.fec.fun_code = 0x78000000;
|
m860.fec.fun_code = 0x78000000;
|
|
|
/*
|
/*
|
* Initialize SDMA configuration register
|
* Initialize SDMA configuration register
|
* SDMA ignores FRZ
|
* SDMA ignores FRZ
|
* FEC not aggressive
|
* FEC not aggressive
|
* FEC arbitration ID = 0 => U-bus arbitration = 6
|
* FEC arbitration ID = 0 => U-bus arbitration = 6
|
* RISC arbitration ID = 1 => U-bus arbitration = 5
|
* RISC arbitration ID = 1 => U-bus arbitration = 5
|
*/
|
*/
|
m860.sdcr = 1;
|
m860.sdcr = 1;
|
|
|
/*
|
/*
|
* Set MII speed to 2.5 MHz for 25 Mhz system clock
|
* Set MII speed to 2.5 MHz for 25 Mhz system clock
|
*/
|
*/
|
m860.fec.mii_speed = 0x0a;
|
m860.fec.mii_speed = 0x0a;
|
m860.fec.mii_data = 0x58021000;
|
m860.fec.mii_data = 0x58021000;
|
|
|
/*
|
/*
|
* Set up receive buffer descriptors
|
* Set up receive buffer descriptors
|
*/
|
*/
|
for (i = 0 ; i < sc->rxBdCount ; i++)
|
for (i = 0 ; i < sc->rxBdCount ; i++)
|
(sc->rxBdBase + i)->status = 0;
|
(sc->rxBdBase + i)->status = 0;
|
|
|
/*
|
/*
|
* Set up transmit buffer descriptors
|
* Set up transmit buffer descriptors
|
*/
|
*/
|
for (i = 0 ; i < sc->txBdCount ; i++) {
|
for (i = 0 ; i < sc->txBdCount ; i++) {
|
(sc->txBdBase + i)->status = 0;
|
(sc->txBdBase + i)->status = 0;
|
sc->txMbuf[i] = NULL;
|
sc->txMbuf[i] = NULL;
|
}
|
}
|
sc->txBdHead = sc->txBdTail = 0;
|
sc->txBdHead = sc->txBdTail = 0;
|
sc->txBdActiveCount = 0;
|
sc->txBdActiveCount = 0;
|
|
|
|
|
|
|
/*
|
/*
|
* Mask all FEC interrupts and clear events
|
* Mask all FEC interrupts and clear events
|
*/
|
*/
|
m860.fec.imask = M860_FEC_IEVENT_TFINT |
|
m860.fec.imask = M860_FEC_IEVENT_TFINT |
|
M860_FEC_IEVENT_RFINT;
|
M860_FEC_IEVENT_RFINT;
|
m860.fec.ievent = ~0;
|
m860.fec.ievent = ~0;
|
|
|
/*
|
/*
|
* Set up interrupts
|
* Set up interrupts
|
*/
|
*/
|
status = rtems_interrupt_catch (m860_fec_interrupt_handler,
|
status = rtems_interrupt_catch (m860_fec_interrupt_handler,
|
PPC_IRQ_LVL2,
|
PPC_IRQ_LVL2,
|
&old_handler);
|
&old_handler);
|
if (status != RTEMS_SUCCESSFUL)
|
if (status != RTEMS_SUCCESSFUL)
|
rtems_panic ("Can't attach M860 FEC interrupt handler: %s\n",
|
rtems_panic ("Can't attach M860 FEC interrupt handler: %s\n",
|
rtems_status_text (status));
|
rtems_status_text (status));
|
|
|
m860.simask |= M860_SIMASK_LVM2;
|
m860.simask |= M860_SIMASK_LVM2;
|
|
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Soak up buffer descriptors that have been sent
|
* Soak up buffer descriptors that have been sent
|
* Note that a buffer descriptor can't be retired as soon as it becomes
|
* Note that a buffer descriptor can't be retired as soon as it becomes
|
* ready. The MC68360 Errata (May 96) says that, "If an Ethernet frame is
|
* ready. The MC68360 Errata (May 96) says that, "If an Ethernet frame is
|
* made up of multiple buffers, the user should not reuse the first buffer
|
* made up of multiple buffers, the user should not reuse the first buffer
|
* descriptor until the last buffer descriptor of the frame has had its
|
* descriptor until the last buffer descriptor of the frame has had its
|
* ready bit cleared by the CPM".
|
* ready bit cleared by the CPM".
|
*/
|
*/
|
static void
|
static void
|
m860Enet_retire_tx_bd (struct m860_enet_struct *sc)
|
m860Enet_retire_tx_bd (struct m860_enet_struct *sc)
|
{
|
{
|
rtems_unsigned16 status;
|
rtems_unsigned16 status;
|
int i;
|
int i;
|
int nRetired;
|
int nRetired;
|
struct mbuf *m, *n;
|
struct mbuf *m, *n;
|
|
|
i = sc->txBdTail;
|
i = sc->txBdTail;
|
nRetired = 0;
|
nRetired = 0;
|
while ((sc->txBdActiveCount != 0)
|
while ((sc->txBdActiveCount != 0)
|
&& (((status = (sc->txBdBase + i)->status) & M860_BD_READY) == 0)) {
|
&& (((status = (sc->txBdBase + i)->status) & M860_BD_READY) == 0)) {
|
/*
|
/*
|
* See if anything went wrong
|
* See if anything went wrong
|
*/
|
*/
|
if (status & (M860_BD_DEFER |
|
if (status & (M860_BD_DEFER |
|
M860_BD_HEARTBEAT |
|
M860_BD_HEARTBEAT |
|
M860_BD_LATE_COLLISION |
|
M860_BD_LATE_COLLISION |
|
M860_BD_RETRY_LIMIT |
|
M860_BD_RETRY_LIMIT |
|
M860_BD_UNDERRUN |
|
M860_BD_UNDERRUN |
|
M860_BD_CARRIER_LOST)) {
|
M860_BD_CARRIER_LOST)) {
|
/*
|
/*
|
* Check for errors which stop the transmitter.
|
* Check for errors which stop the transmitter.
|
*/
|
*/
|
if (status & (M860_BD_LATE_COLLISION |
|
if (status & (M860_BD_LATE_COLLISION |
|
M860_BD_RETRY_LIMIT |
|
M860_BD_RETRY_LIMIT |
|
M860_BD_UNDERRUN)) {
|
M860_BD_UNDERRUN)) {
|
if (status & M860_BD_LATE_COLLISION)
|
if (status & M860_BD_LATE_COLLISION)
|
enet_driver[0].txLateCollision++;
|
enet_driver[0].txLateCollision++;
|
if (status & M860_BD_RETRY_LIMIT)
|
if (status & M860_BD_RETRY_LIMIT)
|
enet_driver[0].txRetryLimit++;
|
enet_driver[0].txRetryLimit++;
|
if (status & M860_BD_UNDERRUN)
|
if (status & M860_BD_UNDERRUN)
|
enet_driver[0].txUnderrun++;
|
enet_driver[0].txUnderrun++;
|
|
|
/*
|
/*
|
* Restart the transmitter
|
* Restart the transmitter
|
*/
|
*/
|
/* FIXME: this should get executed only if using the SCC */
|
/* FIXME: this should get executed only if using the SCC */
|
M860ExecuteRISC (M860_CR_OP_RESTART_TX | M860_CR_CHAN_SCC1);
|
M860ExecuteRISC (M860_CR_OP_RESTART_TX | M860_CR_CHAN_SCC1);
|
}
|
}
|
if (status & M860_BD_DEFER)
|
if (status & M860_BD_DEFER)
|
enet_driver[0].txDeferred++;
|
enet_driver[0].txDeferred++;
|
if (status & M860_BD_HEARTBEAT)
|
if (status & M860_BD_HEARTBEAT)
|
enet_driver[0].txHeartbeat++;
|
enet_driver[0].txHeartbeat++;
|
if (status & M860_BD_CARRIER_LOST)
|
if (status & M860_BD_CARRIER_LOST)
|
enet_driver[0].txLostCarrier++;
|
enet_driver[0].txLostCarrier++;
|
}
|
}
|
nRetired++;
|
nRetired++;
|
if (status & M860_BD_LAST) {
|
if (status & M860_BD_LAST) {
|
/*
|
/*
|
* A full frame has been transmitted.
|
* A full frame has been transmitted.
|
* Free all the associated buffer descriptors.
|
* Free all the associated buffer descriptors.
|
*/
|
*/
|
sc->txBdActiveCount -= nRetired;
|
sc->txBdActiveCount -= nRetired;
|
while (nRetired) {
|
while (nRetired) {
|
nRetired--;
|
nRetired--;
|
m = sc->txMbuf[sc->txBdTail];
|
m = sc->txMbuf[sc->txBdTail];
|
MFREE (m, n);
|
MFREE (m, n);
|
if (++sc->txBdTail == sc->txBdCount)
|
if (++sc->txBdTail == sc->txBdCount)
|
sc->txBdTail = 0;
|
sc->txBdTail = 0;
|
}
|
}
|
}
|
}
|
if (++i == sc->txBdCount)
|
if (++i == sc->txBdCount)
|
i = 0;
|
i = 0;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* reader task
|
* reader task
|
*/
|
*/
|
static void
|
static void
|
scc_rxDaemon (void *arg)
|
scc_rxDaemon (void *arg)
|
{
|
{
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct mbuf *m;
|
struct mbuf *m;
|
rtems_unsigned16 status;
|
rtems_unsigned16 status;
|
m860BufferDescriptor_t *rxBd;
|
m860BufferDescriptor_t *rxBd;
|
int rxBdIndex;
|
int rxBdIndex;
|
|
|
/*
|
/*
|
* Allocate space for incoming packets and start reception
|
* Allocate space for incoming packets and start reception
|
*/
|
*/
|
for (rxBdIndex = 0 ; ;) {
|
for (rxBdIndex = 0 ; ;) {
|
rxBd = sc->rxBdBase + rxBdIndex;
|
rxBd = sc->rxBdBase + rxBdIndex;
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MCLGET (m, M_WAIT);
|
MCLGET (m, M_WAIT);
|
m->m_pkthdr.rcvif = ifp;
|
m->m_pkthdr.rcvif = ifp;
|
sc->rxMbuf[rxBdIndex] = m;
|
sc->rxMbuf[rxBdIndex] = m;
|
rxBd->buffer = mtod (m, void *);
|
rxBd->buffer = mtod (m, void *);
|
rxBd->status = M860_BD_EMPTY | M860_BD_INTERRUPT;
|
rxBd->status = M860_BD_EMPTY | M860_BD_INTERRUPT;
|
if (++rxBdIndex == sc->rxBdCount) {
|
if (++rxBdIndex == sc->rxBdCount) {
|
rxBd->status |= M860_BD_WRAP;
|
rxBd->status |= M860_BD_WRAP;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Input packet handling loop
|
* Input packet handling loop
|
*/
|
*/
|
rxBdIndex = 0;
|
rxBdIndex = 0;
|
for (;;) {
|
for (;;) {
|
rxBd = sc->rxBdBase + rxBdIndex;
|
rxBd = sc->rxBdBase + rxBdIndex;
|
|
|
/*
|
/*
|
* Wait for packet if there's not one ready
|
* Wait for packet if there's not one ready
|
*/
|
*/
|
if ((status = rxBd->status) & M860_BD_EMPTY) {
|
if ((status = rxBd->status) & M860_BD_EMPTY) {
|
/*
|
/*
|
* Clear old events
|
* Clear old events
|
*/
|
*/
|
m860.scc1.scce = 0x8;
|
m860.scc1.scce = 0x8;
|
|
|
/*
|
/*
|
* Wait for packet
|
* Wait for packet
|
* Note that the buffer descriptor is checked
|
* Note that the buffer descriptor is checked
|
* *before* the event wait -- this catches the
|
* *before* the event wait -- this catches the
|
* possibility that a packet arrived between the
|
* possibility that a packet arrived between the
|
* `if' above, and the clearing of the event register.
|
* `if' above, and the clearing of the event register.
|
*/
|
*/
|
while ((status = rxBd->status) & M860_BD_EMPTY) {
|
while ((status = rxBd->status) & M860_BD_EMPTY) {
|
rtems_event_set events;
|
rtems_event_set events;
|
|
|
/*
|
/*
|
* Unmask RXF (Full frame received) event
|
* Unmask RXF (Full frame received) event
|
*/
|
*/
|
m860.scc1.sccm |= 0x8;
|
m860.scc1.sccm |= 0x8;
|
|
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_NO_TIMEOUT,
|
RTEMS_NO_TIMEOUT,
|
&events);
|
&events);
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Check that packet is valid
|
* Check that packet is valid
|
*/
|
*/
|
if ((status & (M860_BD_LAST |
|
if ((status & (M860_BD_LAST |
|
M860_BD_FIRST_IN_FRAME |
|
M860_BD_FIRST_IN_FRAME |
|
M860_BD_LONG |
|
M860_BD_LONG |
|
M860_BD_NONALIGNED |
|
M860_BD_NONALIGNED |
|
M860_BD_SHORT |
|
M860_BD_SHORT |
|
M860_BD_CRC_ERROR |
|
M860_BD_CRC_ERROR |
|
M860_BD_OVERRUN |
|
M860_BD_OVERRUN |
|
M860_BD_COLLISION)) ==
|
M860_BD_COLLISION)) ==
|
(M860_BD_LAST |
|
(M860_BD_LAST |
|
M860_BD_FIRST_IN_FRAME)) {
|
M860_BD_FIRST_IN_FRAME)) {
|
/*
|
/*
|
* Pass the packet up the chain.
|
* Pass the packet up the chain.
|
* FIXME: Packet filtering hook could be done here.
|
* FIXME: Packet filtering hook could be done here.
|
*/
|
*/
|
struct ether_header *eh;
|
struct ether_header *eh;
|
|
|
m = sc->rxMbuf[rxBdIndex];
|
m = sc->rxMbuf[rxBdIndex];
|
m->m_len = m->m_pkthdr.len = rxBd->length -
|
m->m_len = m->m_pkthdr.len = rxBd->length -
|
sizeof(rtems_unsigned32) -
|
sizeof(rtems_unsigned32) -
|
sizeof(struct ether_header);
|
sizeof(struct ether_header);
|
eh = mtod (m, struct ether_header *);
|
eh = mtod (m, struct ether_header *);
|
m->m_data += sizeof(struct ether_header);
|
m->m_data += sizeof(struct ether_header);
|
ether_input (ifp, eh, m);
|
ether_input (ifp, eh, m);
|
|
|
/*
|
/*
|
* Allocate a new mbuf
|
* Allocate a new mbuf
|
*/
|
*/
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MCLGET (m, M_WAIT);
|
MCLGET (m, M_WAIT);
|
m->m_pkthdr.rcvif = ifp;
|
m->m_pkthdr.rcvif = ifp;
|
sc->rxMbuf[rxBdIndex] = m;
|
sc->rxMbuf[rxBdIndex] = m;
|
rxBd->buffer = mtod (m, void *);
|
rxBd->buffer = mtod (m, void *);
|
}
|
}
|
else {
|
else {
|
/*
|
/*
|
* Something went wrong with the reception
|
* Something went wrong with the reception
|
*/
|
*/
|
if (!(status & M860_BD_LAST))
|
if (!(status & M860_BD_LAST))
|
sc->rxNotLast++;
|
sc->rxNotLast++;
|
if (!(status & M860_BD_FIRST_IN_FRAME))
|
if (!(status & M860_BD_FIRST_IN_FRAME))
|
sc->rxNotFirst++;
|
sc->rxNotFirst++;
|
if (status & M860_BD_LONG)
|
if (status & M860_BD_LONG)
|
sc->rxGiant++;
|
sc->rxGiant++;
|
if (status & M860_BD_NONALIGNED)
|
if (status & M860_BD_NONALIGNED)
|
sc->rxNonOctet++;
|
sc->rxNonOctet++;
|
if (status & M860_BD_SHORT)
|
if (status & M860_BD_SHORT)
|
sc->rxRunt++;
|
sc->rxRunt++;
|
if (status & M860_BD_CRC_ERROR)
|
if (status & M860_BD_CRC_ERROR)
|
sc->rxBadCRC++;
|
sc->rxBadCRC++;
|
if (status & M860_BD_OVERRUN)
|
if (status & M860_BD_OVERRUN)
|
sc->rxOverrun++;
|
sc->rxOverrun++;
|
if (status & M860_BD_COLLISION)
|
if (status & M860_BD_COLLISION)
|
sc->rxCollision++;
|
sc->rxCollision++;
|
}
|
}
|
|
|
/*
|
/*
|
* Reenable the buffer descriptor
|
* Reenable the buffer descriptor
|
*/
|
*/
|
rxBd->status = (status & (M860_BD_WRAP | M860_BD_INTERRUPT)) |
|
rxBd->status = (status & (M860_BD_WRAP | M860_BD_INTERRUPT)) |
|
M860_BD_EMPTY;
|
M860_BD_EMPTY;
|
|
|
/*
|
/*
|
* Move to next buffer descriptor
|
* Move to next buffer descriptor
|
*/
|
*/
|
if (++rxBdIndex == sc->rxBdCount)
|
if (++rxBdIndex == sc->rxBdCount)
|
rxBdIndex = 0;
|
rxBdIndex = 0;
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
fec_rxDaemon (void *arg)
|
fec_rxDaemon (void *arg)
|
{
|
{
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct mbuf *m;
|
struct mbuf *m;
|
rtems_unsigned16 status;
|
rtems_unsigned16 status;
|
m860BufferDescriptor_t *rxBd;
|
m860BufferDescriptor_t *rxBd;
|
int rxBdIndex;
|
int rxBdIndex;
|
|
|
/*
|
/*
|
* Allocate space for incoming packets and start reception
|
* Allocate space for incoming packets and start reception
|
*/
|
*/
|
for (rxBdIndex = 0 ; ;) {
|
for (rxBdIndex = 0 ; ;) {
|
rxBd = sc->rxBdBase + rxBdIndex;
|
rxBd = sc->rxBdBase + rxBdIndex;
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MCLGET (m, M_WAIT);
|
MCLGET (m, M_WAIT);
|
m->m_pkthdr.rcvif = ifp;
|
m->m_pkthdr.rcvif = ifp;
|
sc->rxMbuf[rxBdIndex] = m;
|
sc->rxMbuf[rxBdIndex] = m;
|
rxBd->buffer = mtod (m, void *);
|
rxBd->buffer = mtod (m, void *);
|
rxBd->status = M860_BD_EMPTY;
|
rxBd->status = M860_BD_EMPTY;
|
m860.fec.r_des_active = 0x1000000;
|
m860.fec.r_des_active = 0x1000000;
|
if (++rxBdIndex == sc->rxBdCount) {
|
if (++rxBdIndex == sc->rxBdCount) {
|
rxBd->status |= M860_BD_WRAP;
|
rxBd->status |= M860_BD_WRAP;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Input packet handling loop
|
* Input packet handling loop
|
*/
|
*/
|
rxBdIndex = 0;
|
rxBdIndex = 0;
|
for (;;) {
|
for (;;) {
|
rxBd = sc->rxBdBase + rxBdIndex;
|
rxBd = sc->rxBdBase + rxBdIndex;
|
|
|
/*
|
/*
|
* Wait for packet if there's not one ready
|
* Wait for packet if there's not one ready
|
*/
|
*/
|
if ((status = rxBd->status) & M860_BD_EMPTY) {
|
if ((status = rxBd->status) & M860_BD_EMPTY) {
|
/*
|
/*
|
* Clear old events
|
* Clear old events
|
*/
|
*/
|
m860.fec.ievent = M860_FEC_IEVENT_RFINT;
|
m860.fec.ievent = M860_FEC_IEVENT_RFINT;
|
|
|
/*
|
/*
|
* Wait for packet
|
* Wait for packet
|
* Note that the buffer descriptor is checked
|
* Note that the buffer descriptor is checked
|
* *before* the event wait -- this catches the
|
* *before* the event wait -- this catches the
|
* possibility that a packet arrived between the
|
* possibility that a packet arrived between the
|
* `if' above, and the clearing of the event register.
|
* `if' above, and the clearing of the event register.
|
*/
|
*/
|
while ((status = rxBd->status) & M860_BD_EMPTY) {
|
while ((status = rxBd->status) & M860_BD_EMPTY) {
|
rtems_event_set events;
|
rtems_event_set events;
|
|
|
/*
|
/*
|
* Unmask RXF (Full frame received) event
|
* Unmask RXF (Full frame received) event
|
*/
|
*/
|
m860.fec.ievent |= M860_FEC_IEVENT_RFINT;
|
m860.fec.ievent |= M860_FEC_IEVENT_RFINT;
|
|
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_NO_TIMEOUT,
|
RTEMS_NO_TIMEOUT,
|
&events);
|
&events);
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Check that packet is valid
|
* Check that packet is valid
|
*/
|
*/
|
if (status & M860_BD_LAST) {
|
if (status & M860_BD_LAST) {
|
/*
|
/*
|
* Pass the packet up the chain.
|
* Pass the packet up the chain.
|
* FIXME: Packet filtering hook could be done here.
|
* FIXME: Packet filtering hook could be done here.
|
*/
|
*/
|
struct ether_header *eh;
|
struct ether_header *eh;
|
|
|
m = sc->rxMbuf[rxBdIndex];
|
m = sc->rxMbuf[rxBdIndex];
|
m->m_len = m->m_pkthdr.len = rxBd->length -
|
m->m_len = m->m_pkthdr.len = rxBd->length -
|
sizeof(rtems_unsigned32) -
|
sizeof(rtems_unsigned32) -
|
sizeof(struct ether_header);
|
sizeof(struct ether_header);
|
eh = mtod (m, struct ether_header *);
|
eh = mtod (m, struct ether_header *);
|
m->m_data += sizeof(struct ether_header);
|
m->m_data += sizeof(struct ether_header);
|
ether_input (ifp, eh, m);
|
ether_input (ifp, eh, m);
|
|
|
/*
|
/*
|
* Allocate a new mbuf
|
* Allocate a new mbuf
|
*/
|
*/
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MGETHDR (m, M_WAIT, MT_DATA);
|
MCLGET (m, M_WAIT);
|
MCLGET (m, M_WAIT);
|
m->m_pkthdr.rcvif = ifp;
|
m->m_pkthdr.rcvif = ifp;
|
sc->rxMbuf[rxBdIndex] = m;
|
sc->rxMbuf[rxBdIndex] = m;
|
rxBd->buffer = mtod (m, void *);
|
rxBd->buffer = mtod (m, void *);
|
}
|
}
|
else {
|
else {
|
/*
|
/*
|
* Something went wrong with the reception
|
* Something went wrong with the reception
|
*/
|
*/
|
if (!(status & M860_BD_LAST))
|
if (!(status & M860_BD_LAST))
|
sc->rxNotLast++;
|
sc->rxNotLast++;
|
if (status & M860_BD_LONG)
|
if (status & M860_BD_LONG)
|
sc->rxGiant++;
|
sc->rxGiant++;
|
if (status & M860_BD_NONALIGNED)
|
if (status & M860_BD_NONALIGNED)
|
sc->rxNonOctet++;
|
sc->rxNonOctet++;
|
if (status & M860_BD_SHORT)
|
if (status & M860_BD_SHORT)
|
sc->rxRunt++;
|
sc->rxRunt++;
|
if (status & M860_BD_CRC_ERROR)
|
if (status & M860_BD_CRC_ERROR)
|
sc->rxBadCRC++;
|
sc->rxBadCRC++;
|
if (status & M860_BD_OVERRUN)
|
if (status & M860_BD_OVERRUN)
|
sc->rxOverrun++;
|
sc->rxOverrun++;
|
if (status & M860_BD_COLLISION)
|
if (status & M860_BD_COLLISION)
|
sc->rxCollision++;
|
sc->rxCollision++;
|
}
|
}
|
/*
|
/*
|
* Reenable the buffer descriptor
|
* Reenable the buffer descriptor
|
*/
|
*/
|
rxBd->status = (status & M860_BD_WRAP) |
|
rxBd->status = (status & M860_BD_WRAP) |
|
M860_BD_EMPTY;
|
M860_BD_EMPTY;
|
m860.fec.r_des_active = 0x1000000;
|
m860.fec.r_des_active = 0x1000000;
|
/*
|
/*
|
* Move to next buffer descriptor
|
* Move to next buffer descriptor
|
*/
|
*/
|
if (++rxBdIndex == sc->rxBdCount)
|
if (++rxBdIndex == sc->rxBdCount)
|
rxBdIndex = 0;
|
rxBdIndex = 0;
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
scc_sendpacket (struct ifnet *ifp, struct mbuf *m)
|
scc_sendpacket (struct ifnet *ifp, struct mbuf *m)
|
{
|
{
|
struct m860_enet_struct *sc = ifp->if_softc;
|
struct m860_enet_struct *sc = ifp->if_softc;
|
volatile m860BufferDescriptor_t *firstTxBd, *txBd;
|
volatile m860BufferDescriptor_t *firstTxBd, *txBd;
|
struct mbuf *l = NULL;
|
struct mbuf *l = NULL;
|
rtems_unsigned16 status;
|
rtems_unsigned16 status;
|
int nAdded;
|
int nAdded;
|
|
|
/*
|
/*
|
* Free up buffer descriptors
|
* Free up buffer descriptors
|
*/
|
*/
|
m860Enet_retire_tx_bd (sc);
|
m860Enet_retire_tx_bd (sc);
|
|
|
/*
|
/*
|
* Set up the transmit buffer descriptors.
|
* Set up the transmit buffer descriptors.
|
* No need to pad out short packets since the
|
* No need to pad out short packets since the
|
* hardware takes care of that automatically.
|
* hardware takes care of that automatically.
|
* No need to copy the packet to a contiguous buffer
|
* No need to copy the packet to a contiguous buffer
|
* since the hardware is capable of scatter/gather DMA.
|
* since the hardware is capable of scatter/gather DMA.
|
*/
|
*/
|
nAdded = 0;
|
nAdded = 0;
|
txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
|
txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
|
for (;;) {
|
for (;;) {
|
/*
|
/*
|
* Wait for buffer descriptor to become available.
|
* Wait for buffer descriptor to become available.
|
*/
|
*/
|
if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
/*
|
/*
|
* Clear old events
|
* Clear old events
|
*/
|
*/
|
m860.scc1.scce = 0x12;
|
m860.scc1.scce = 0x12;
|
|
|
/*
|
/*
|
* Wait for buffer descriptor to become available.
|
* Wait for buffer descriptor to become available.
|
* Note that the buffer descriptors are checked
|
* Note that the buffer descriptors are checked
|
* *before* * entering the wait loop -- this catches
|
* *before* * entering the wait loop -- this catches
|
* the possibility that a buffer descriptor became
|
* the possibility that a buffer descriptor became
|
* available between the `if' above, and the clearing
|
* available between the `if' above, and the clearing
|
* of the event register.
|
* of the event register.
|
* This is to catch the case where the transmitter
|
* This is to catch the case where the transmitter
|
* stops in the middle of a frame -- and only the
|
* stops in the middle of a frame -- and only the
|
* last buffer descriptor in a frame can generate
|
* last buffer descriptor in a frame can generate
|
* an interrupt.
|
* an interrupt.
|
*/
|
*/
|
m860Enet_retire_tx_bd (sc);
|
m860Enet_retire_tx_bd (sc);
|
while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
rtems_event_set events;
|
rtems_event_set events;
|
|
|
/*
|
/*
|
* Unmask TXB (buffer transmitted) and
|
* Unmask TXB (buffer transmitted) and
|
* TXE (transmitter error) events.
|
* TXE (transmitter error) events.
|
*/
|
*/
|
m860.scc1.sccm |= 0x12;
|
m860.scc1.sccm |= 0x12;
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_NO_TIMEOUT,
|
RTEMS_NO_TIMEOUT,
|
&events);
|
&events);
|
m860Enet_retire_tx_bd (sc);
|
m860Enet_retire_tx_bd (sc);
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Don't set the READY flag till the
|
* Don't set the READY flag till the
|
* whole packet has been readied.
|
* whole packet has been readied.
|
*/
|
*/
|
status = nAdded ? M860_BD_READY : 0;
|
status = nAdded ? M860_BD_READY : 0;
|
|
|
/*
|
/*
|
* FIXME: Why not deal with empty mbufs at at higher level?
|
* FIXME: Why not deal with empty mbufs at at higher level?
|
* The IP fragmentation routine in ip_output
|
* The IP fragmentation routine in ip_output
|
* can produce packet fragments with zero length.
|
* can produce packet fragments with zero length.
|
* I think that ip_output should be changed to get
|
* I think that ip_output should be changed to get
|
* rid of these zero-length mbufs, but for now,
|
* rid of these zero-length mbufs, but for now,
|
* I'll deal with them here.
|
* I'll deal with them here.
|
*/
|
*/
|
if (m->m_len) {
|
if (m->m_len) {
|
/*
|
/*
|
* Fill in the buffer descriptor
|
* Fill in the buffer descriptor
|
*/
|
*/
|
txBd->buffer = mtod (m, void *);
|
txBd->buffer = mtod (m, void *);
|
txBd->length = m->m_len;
|
txBd->length = m->m_len;
|
sc->txMbuf[sc->txBdHead] = m;
|
sc->txMbuf[sc->txBdHead] = m;
|
nAdded++;
|
nAdded++;
|
if (++sc->txBdHead == sc->txBdCount) {
|
if (++sc->txBdHead == sc->txBdCount) {
|
status |= M860_BD_WRAP;
|
status |= M860_BD_WRAP;
|
sc->txBdHead = 0;
|
sc->txBdHead = 0;
|
}
|
}
|
l = m;
|
l = m;
|
m = m->m_next;
|
m = m->m_next;
|
}
|
}
|
else {
|
else {
|
/*
|
/*
|
* Just toss empty mbufs
|
* Just toss empty mbufs
|
*/
|
*/
|
struct mbuf *n;
|
struct mbuf *n;
|
MFREE (m, n);
|
MFREE (m, n);
|
m = n;
|
m = n;
|
if (l != NULL)
|
if (l != NULL)
|
l->m_next = m;
|
l->m_next = m;
|
}
|
}
|
|
|
/*
|
/*
|
* Set the transmit buffer status.
|
* Set the transmit buffer status.
|
* Break out of the loop if this mbuf is the last in the frame.
|
* Break out of the loop if this mbuf is the last in the frame.
|
*/
|
*/
|
if (m == NULL) {
|
if (m == NULL) {
|
if (nAdded) {
|
if (nAdded) {
|
status |= M860_BD_PAD | M860_BD_LAST | M860_BD_TX_CRC | M860_BD_INTERRUPT;
|
status |= M860_BD_PAD | M860_BD_LAST | M860_BD_TX_CRC | M860_BD_INTERRUPT;
|
txBd->status = status;
|
txBd->status = status;
|
firstTxBd->status |= M860_BD_READY;
|
firstTxBd->status |= M860_BD_READY;
|
sc->txBdActiveCount += nAdded;
|
sc->txBdActiveCount += nAdded;
|
}
|
}
|
break;
|
break;
|
}
|
}
|
txBd->status = status;
|
txBd->status = status;
|
txBd = sc->txBdBase + sc->txBdHead;
|
txBd = sc->txBdBase + sc->txBdHead;
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
fec_sendpacket (struct ifnet *ifp, struct mbuf *m)
|
fec_sendpacket (struct ifnet *ifp, struct mbuf *m)
|
{
|
{
|
struct m860_enet_struct *sc = ifp->if_softc;
|
struct m860_enet_struct *sc = ifp->if_softc;
|
volatile m860BufferDescriptor_t *firstTxBd, *txBd;
|
volatile m860BufferDescriptor_t *firstTxBd, *txBd;
|
/* struct mbuf *l = NULL; */
|
/* struct mbuf *l = NULL; */
|
rtems_unsigned16 status;
|
rtems_unsigned16 status;
|
int nAdded;
|
int nAdded;
|
|
|
/*
|
/*
|
* Free up buffer descriptors
|
* Free up buffer descriptors
|
*/
|
*/
|
m860Enet_retire_tx_bd (sc);
|
m860Enet_retire_tx_bd (sc);
|
|
|
/*
|
/*
|
* Set up the transmit buffer descriptors.
|
* Set up the transmit buffer descriptors.
|
* No need to pad out short packets since the
|
* No need to pad out short packets since the
|
* hardware takes care of that automatically.
|
* hardware takes care of that automatically.
|
* No need to copy the packet to a contiguous buffer
|
* No need to copy the packet to a contiguous buffer
|
* since the hardware is capable of scatter/gather DMA.
|
* since the hardware is capable of scatter/gather DMA.
|
*/
|
*/
|
nAdded = 0;
|
nAdded = 0;
|
txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
|
txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
|
for (;;) {
|
for (;;) {
|
/*
|
/*
|
* Wait for buffer descriptor to become available.
|
* Wait for buffer descriptor to become available.
|
*/
|
*/
|
if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
/*
|
/*
|
* Clear old events
|
* Clear old events
|
*/
|
*/
|
m860.fec.ievent = M860_FEC_IEVENT_TFINT;
|
m860.fec.ievent = M860_FEC_IEVENT_TFINT;
|
|
|
/*
|
/*
|
* Wait for buffer descriptor to become available.
|
* Wait for buffer descriptor to become available.
|
* Note that the buffer descriptors are checked
|
* Note that the buffer descriptors are checked
|
* *before* * entering the wait loop -- this catches
|
* *before* * entering the wait loop -- this catches
|
* the possibility that a buffer descriptor became
|
* the possibility that a buffer descriptor became
|
* available between the `if' above, and the clearing
|
* available between the `if' above, and the clearing
|
* of the event register.
|
* of the event register.
|
* This is to catch the case where the transmitter
|
* This is to catch the case where the transmitter
|
* stops in the middle of a frame -- and only the
|
* stops in the middle of a frame -- and only the
|
* last buffer descriptor in a frame can generate
|
* last buffer descriptor in a frame can generate
|
* an interrupt.
|
* an interrupt.
|
*/
|
*/
|
m860Enet_retire_tx_bd (sc);
|
m860Enet_retire_tx_bd (sc);
|
while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
|
rtems_event_set events;
|
rtems_event_set events;
|
|
|
/*
|
/*
|
* Unmask TXB (buffer transmitted) and
|
* Unmask TXB (buffer transmitted) and
|
* TXE (transmitter error) events.
|
* TXE (transmitter error) events.
|
*/
|
*/
|
m860.fec.ievent |= M860_FEC_IEVENT_TFINT;
|
m860.fec.ievent |= M860_FEC_IEVENT_TFINT;
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_WAIT|RTEMS_EVENT_ANY,
|
RTEMS_NO_TIMEOUT,
|
RTEMS_NO_TIMEOUT,
|
&events);
|
&events);
|
m860Enet_retire_tx_bd (sc);
|
m860Enet_retire_tx_bd (sc);
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Don't set the READY flag till the
|
* Don't set the READY flag till the
|
* whole packet has been readied.
|
* whole packet has been readied.
|
*/
|
*/
|
status = nAdded ? M860_BD_READY : 0;
|
status = nAdded ? M860_BD_READY : 0;
|
|
|
/*
|
/*
|
* FIXME: Why not deal with empty mbufs at at higher level?
|
* FIXME: Why not deal with empty mbufs at at higher level?
|
* The IP fragmentation routine in ip_output
|
* The IP fragmentation routine in ip_output
|
* can produce packet fragments with zero length.
|
* can produce packet fragments with zero length.
|
* I think that ip_output should be changed to get
|
* I think that ip_output should be changed to get
|
* rid of these zero-length mbufs, but for now,
|
* rid of these zero-length mbufs, but for now,
|
* I'll deal with them here.
|
* I'll deal with them here.
|
*/
|
*/
|
if (m->m_len) {
|
if (m->m_len) {
|
/*
|
/*
|
* Fill in the buffer descriptor
|
* Fill in the buffer descriptor
|
*/
|
*/
|
txBd->buffer = mtod (m, void *);
|
txBd->buffer = mtod (m, void *);
|
txBd->length = m->m_len;
|
txBd->length = m->m_len;
|
sc->txMbuf[sc->txBdHead] = m;
|
sc->txMbuf[sc->txBdHead] = m;
|
nAdded++;
|
nAdded++;
|
if (++sc->txBdHead == sc->txBdCount) {
|
if (++sc->txBdHead == sc->txBdCount) {
|
status |= M860_BD_WRAP;
|
status |= M860_BD_WRAP;
|
sc->txBdHead = 0;
|
sc->txBdHead = 0;
|
}
|
}
|
/* l = m;*/
|
/* l = m;*/
|
m = m->m_next;
|
m = m->m_next;
|
}
|
}
|
else {
|
else {
|
/*
|
/*
|
* Just toss empty mbufs
|
* Just toss empty mbufs
|
*/
|
*/
|
struct mbuf *n;
|
struct mbuf *n;
|
MFREE (m, n);
|
MFREE (m, n);
|
m = n;
|
m = n;
|
/*
|
/*
|
if (l != NULL)
|
if (l != NULL)
|
l->m_next = m;
|
l->m_next = m;
|
*/
|
*/
|
}
|
}
|
|
|
/*
|
/*
|
* Set the transmit buffer status.
|
* Set the transmit buffer status.
|
* Break out of the loop if this mbuf is the last in the frame.
|
* Break out of the loop if this mbuf is the last in the frame.
|
*/
|
*/
|
if (m == NULL) {
|
if (m == NULL) {
|
if (nAdded) {
|
if (nAdded) {
|
status |= M860_BD_LAST | M860_BD_TX_CRC;
|
status |= M860_BD_LAST | M860_BD_TX_CRC;
|
txBd->status = status;
|
txBd->status = status;
|
firstTxBd->status |= M860_BD_READY;
|
firstTxBd->status |= M860_BD_READY;
|
m860.fec.x_des_active = 0x1000000;
|
m860.fec.x_des_active = 0x1000000;
|
sc->txBdActiveCount += nAdded;
|
sc->txBdActiveCount += nAdded;
|
}
|
}
|
break;
|
break;
|
}
|
}
|
txBd->status = status;
|
txBd->status = status;
|
txBd = sc->txBdBase + sc->txBdHead;
|
txBd = sc->txBdBase + sc->txBdHead;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Driver transmit daemon
|
* Driver transmit daemon
|
*/
|
*/
|
void
|
void
|
scc_txDaemon (void *arg)
|
scc_txDaemon (void *arg)
|
{
|
{
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct mbuf *m;
|
struct mbuf *m;
|
rtems_event_set events;
|
rtems_event_set events;
|
|
|
for (;;) {
|
for (;;) {
|
/*
|
/*
|
* Wait for packet
|
* Wait for packet
|
*/
|
*/
|
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
|
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
|
|
|
/*
|
/*
|
* Send packets till queue is empty
|
* Send packets till queue is empty
|
*/
|
*/
|
for (;;) {
|
for (;;) {
|
/*
|
/*
|
* Get the next mbuf chain to transmit.
|
* Get the next mbuf chain to transmit.
|
*/
|
*/
|
IF_DEQUEUE(&ifp->if_snd, m);
|
IF_DEQUEUE(&ifp->if_snd, m);
|
if (!m)
|
if (!m)
|
break;
|
break;
|
scc_sendpacket (ifp, m);
|
scc_sendpacket (ifp, m);
|
}
|
}
|
ifp->if_flags &= ~IFF_OACTIVE;
|
ifp->if_flags &= ~IFF_OACTIVE;
|
}
|
}
|
}
|
}
|
|
|
void
|
void
|
fec_txDaemon (void *arg)
|
fec_txDaemon (void *arg)
|
{
|
{
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct m860_enet_struct *sc = (struct m860_enet_struct *)arg;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct mbuf *m;
|
struct mbuf *m;
|
rtems_event_set events;
|
rtems_event_set events;
|
|
|
for (;;) {
|
for (;;) {
|
/*
|
/*
|
* Wait for packet
|
* Wait for packet
|
*/
|
*/
|
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
|
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
|
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
RTEMS_NO_TIMEOUT,
|
RTEMS_NO_TIMEOUT,
|
&events);
|
&events);
|
|
|
/*
|
/*
|
* Send packets till queue is empty
|
* Send packets till queue is empty
|
*/
|
*/
|
for (;;) {
|
for (;;) {
|
/*
|
/*
|
* Get the next mbuf chain to transmit.
|
* Get the next mbuf chain to transmit.
|
*/
|
*/
|
IF_DEQUEUE(&ifp->if_snd, m);
|
IF_DEQUEUE(&ifp->if_snd, m);
|
if (!m)
|
if (!m)
|
break;
|
break;
|
fec_sendpacket (ifp, m);
|
fec_sendpacket (ifp, m);
|
}
|
}
|
ifp->if_flags &= ~IFF_OACTIVE;
|
ifp->if_flags &= ~IFF_OACTIVE;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Send packet (caller provides header).
|
* Send packet (caller provides header).
|
*/
|
*/
|
static void
|
static void
|
m860_enet_start (struct ifnet *ifp)
|
m860_enet_start (struct ifnet *ifp)
|
{
|
{
|
struct m860_enet_struct *sc = ifp->if_softc;
|
struct m860_enet_struct *sc = ifp->if_softc;
|
|
|
rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
|
rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
|
ifp->if_flags |= IFF_OACTIVE;
|
ifp->if_flags |= IFF_OACTIVE;
|
}
|
}
|
|
|
/*
|
/*
|
* Initialize and start the device
|
* Initialize and start the device
|
*/
|
*/
|
static void
|
static void
|
scc_init (void *arg)
|
scc_init (void *arg)
|
{
|
{
|
struct m860_enet_struct *sc = arg;
|
struct m860_enet_struct *sc = arg;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
|
|
if (sc->txDaemonTid == 0) {
|
if (sc->txDaemonTid == 0) {
|
|
|
/*
|
/*
|
* Set up SCC hardware
|
* Set up SCC hardware
|
*/
|
*/
|
m860_scc_initialize_hardware (sc);
|
m860_scc_initialize_hardware (sc);
|
|
|
/*
|
/*
|
* Start driver tasks
|
* Start driver tasks
|
*/
|
*/
|
sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
|
sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
|
sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
|
sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
|
|
|
}
|
}
|
|
|
/*
|
/*
|
* Set flags appropriately
|
* Set flags appropriately
|
*/
|
*/
|
if (ifp->if_flags & IFF_PROMISC)
|
if (ifp->if_flags & IFF_PROMISC)
|
m860.scc1.psmr |= 0x200;
|
m860.scc1.psmr |= 0x200;
|
else
|
else
|
m860.scc1.psmr &= ~0x200;
|
m860.scc1.psmr &= ~0x200;
|
|
|
/*
|
/*
|
* Tell the world that we're running.
|
* Tell the world that we're running.
|
*/
|
*/
|
ifp->if_flags |= IFF_RUNNING;
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
/*
|
/*
|
* Enable receiver and transmitter
|
* Enable receiver and transmitter
|
*/
|
*/
|
m860.scc1.gsmr_l |= 0x30;
|
m860.scc1.gsmr_l |= 0x30;
|
}
|
}
|
|
|
static void
|
static void
|
fec_init (void *arg)
|
fec_init (void *arg)
|
{
|
{
|
struct m860_enet_struct *sc = arg;
|
struct m860_enet_struct *sc = arg;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
|
|
if (sc->txDaemonTid == 0) {
|
if (sc->txDaemonTid == 0) {
|
|
|
/*
|
/*
|
* Set up SCC hardware
|
* Set up SCC hardware
|
*/
|
*/
|
m860_fec_initialize_hardware (sc);
|
m860_fec_initialize_hardware (sc);
|
|
|
/*
|
/*
|
* Start driver tasks
|
* Start driver tasks
|
*/
|
*/
|
sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, fec_txDaemon, sc);
|
sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, fec_txDaemon, sc);
|
sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, fec_rxDaemon, sc);
|
sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, fec_rxDaemon, sc);
|
|
|
}
|
}
|
|
|
/*
|
/*
|
* Set flags appropriately
|
* Set flags appropriately
|
*/
|
*/
|
if (ifp->if_flags & IFF_PROMISC)
|
if (ifp->if_flags & IFF_PROMISC)
|
m860.fec.r_cntrl |= 0x8;
|
m860.fec.r_cntrl |= 0x8;
|
else
|
else
|
m860.fec.r_cntrl &= ~0x8;
|
m860.fec.r_cntrl &= ~0x8;
|
|
|
|
|
/*
|
/*
|
* Tell the world that we're running.
|
* Tell the world that we're running.
|
*/
|
*/
|
ifp->if_flags |= IFF_RUNNING;
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
/*
|
/*
|
* Enable receiver and transmitter
|
* Enable receiver and transmitter
|
*/
|
*/
|
m860.fec.ecntrl = 0x2;
|
m860.fec.ecntrl = 0x2;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Stop the device
|
* Stop the device
|
*/
|
*/
|
static void
|
static void
|
scc_stop (struct m860_enet_struct *sc)
|
scc_stop (struct m860_enet_struct *sc)
|
{
|
{
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
|
|
ifp->if_flags &= ~IFF_RUNNING;
|
ifp->if_flags &= ~IFF_RUNNING;
|
|
|
/*
|
/*
|
* Shut down receiver and transmitter
|
* Shut down receiver and transmitter
|
*/
|
*/
|
m860.scc1.gsmr_l &= ~0x30;
|
m860.scc1.gsmr_l &= ~0x30;
|
}
|
}
|
|
|
static void
|
static void
|
fec_stop (struct m860_enet_struct *sc)
|
fec_stop (struct m860_enet_struct *sc)
|
{
|
{
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
|
|
ifp->if_flags &= ~IFF_RUNNING;
|
ifp->if_flags &= ~IFF_RUNNING;
|
|
|
/*
|
/*
|
* Shut down receiver and transmitter
|
* Shut down receiver and transmitter
|
*/
|
*/
|
m860.fec.ecntrl = 0x0;
|
m860.fec.ecntrl = 0x0;
|
}
|
}
|
|
|
/*
|
/*
|
* Show interface statistics
|
* Show interface statistics
|
*/
|
*/
|
static void
|
static void
|
enet_stats (struct m860_enet_struct *sc)
|
enet_stats (struct m860_enet_struct *sc)
|
{
|
{
|
printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
|
printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
|
printf (" Not First:%-8lu", sc->rxNotFirst);
|
printf (" Not First:%-8lu", sc->rxNotFirst);
|
printf (" Not Last:%-8lu\n", sc->rxNotLast);
|
printf (" Not Last:%-8lu\n", sc->rxNotLast);
|
printf (" Giant:%-8lu", sc->rxGiant);
|
printf (" Giant:%-8lu", sc->rxGiant);
|
printf (" Runt:%-8lu", sc->rxRunt);
|
printf (" Runt:%-8lu", sc->rxRunt);
|
printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
|
printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
|
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
|
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
|
printf (" Overrun:%-8lu", sc->rxOverrun);
|
printf (" Overrun:%-8lu", sc->rxOverrun);
|
printf (" Collision:%-8lu\n", sc->rxCollision);
|
printf (" Collision:%-8lu\n", sc->rxCollision);
|
printf (" Discarded:%-8lu\n", (unsigned long)m860.scc1p.un.ethernet.disfc);
|
printf (" Discarded:%-8lu\n", (unsigned long)m860.scc1p.un.ethernet.disfc);
|
|
|
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
|
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
|
printf (" Deferred:%-8lu", sc->txDeferred);
|
printf (" Deferred:%-8lu", sc->txDeferred);
|
printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
|
printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
|
printf (" No Carrier:%-8lu", sc->txLostCarrier);
|
printf (" No Carrier:%-8lu", sc->txLostCarrier);
|
printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
|
printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
|
printf (" Late Collision:%-8lu\n", sc->txLateCollision);
|
printf (" Late Collision:%-8lu\n", sc->txLateCollision);
|
printf (" Underrun:%-8lu", sc->txUnderrun);
|
printf (" Underrun:%-8lu", sc->txUnderrun);
|
printf (" Raw output wait:%-8lu\n", sc->txRawWait);
|
printf (" Raw output wait:%-8lu\n", sc->txRawWait);
|
}
|
}
|
|
|
/*
|
/*
|
* Driver ioctl handler
|
* Driver ioctl handler
|
*/
|
*/
|
static int
|
static int
|
scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
|
scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
|
{
|
{
|
struct m860_enet_struct *sc = ifp->if_softc;
|
struct m860_enet_struct *sc = ifp->if_softc;
|
int error = 0;
|
int error = 0;
|
|
|
switch (command) {
|
switch (command) {
|
case SIOCGIFADDR:
|
case SIOCGIFADDR:
|
case SIOCSIFADDR:
|
case SIOCSIFADDR:
|
ether_ioctl (ifp, command, data);
|
ether_ioctl (ifp, command, data);
|
break;
|
break;
|
|
|
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
|
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
|
case IFF_RUNNING:
|
case IFF_RUNNING:
|
scc_stop (sc);
|
scc_stop (sc);
|
break;
|
break;
|
|
|
case IFF_UP:
|
case IFF_UP:
|
scc_init (sc);
|
scc_init (sc);
|
break;
|
break;
|
|
|
case IFF_UP | IFF_RUNNING:
|
case IFF_UP | IFF_RUNNING:
|
scc_stop (sc);
|
scc_stop (sc);
|
scc_init (sc);
|
scc_init (sc);
|
break;
|
break;
|
|
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case SIO_RTEMS_SHOW_STATS:
|
case SIO_RTEMS_SHOW_STATS:
|
enet_stats (sc);
|
enet_stats (sc);
|
break;
|
break;
|
|
|
/*
|
/*
|
* FIXME: All sorts of multicast commands need to be added here!
|
* FIXME: All sorts of multicast commands need to be added here!
|
*/
|
*/
|
default:
|
default:
|
error = EINVAL;
|
error = EINVAL;
|
break;
|
break;
|
}
|
}
|
return error;
|
return error;
|
}
|
}
|
|
|
static int
|
static int
|
fec_ioctl (struct ifnet *ifp, int command, caddr_t data)
|
fec_ioctl (struct ifnet *ifp, int command, caddr_t data)
|
{
|
{
|
struct m860_enet_struct *sc = ifp->if_softc;
|
struct m860_enet_struct *sc = ifp->if_softc;
|
int error = 0;
|
int error = 0;
|
|
|
switch (command) {
|
switch (command) {
|
case SIOCGIFADDR:
|
case SIOCGIFADDR:
|
case SIOCSIFADDR:
|
case SIOCSIFADDR:
|
ether_ioctl (ifp, command, data);
|
ether_ioctl (ifp, command, data);
|
break;
|
break;
|
|
|
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
|
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
|
case IFF_RUNNING:
|
case IFF_RUNNING:
|
fec_stop (sc);
|
fec_stop (sc);
|
break;
|
break;
|
|
|
case IFF_UP:
|
case IFF_UP:
|
fec_init (sc);
|
fec_init (sc);
|
break;
|
break;
|
|
|
case IFF_UP | IFF_RUNNING:
|
case IFF_UP | IFF_RUNNING:
|
fec_stop (sc);
|
fec_stop (sc);
|
fec_init (sc);
|
fec_init (sc);
|
break;
|
break;
|
|
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case SIO_RTEMS_SHOW_STATS:
|
case SIO_RTEMS_SHOW_STATS:
|
enet_stats (sc);
|
enet_stats (sc);
|
break;
|
break;
|
|
|
/*
|
/*
|
* FIXME: All sorts of multicast commands need to be added here!
|
* FIXME: All sorts of multicast commands need to be added here!
|
*/
|
*/
|
default:
|
default:
|
error = EINVAL;
|
error = EINVAL;
|
break;
|
break;
|
}
|
}
|
return error;
|
return error;
|
}
|
}
|
|
|
/*
|
/*
|
* Attach an SCC driver to the system
|
* Attach an SCC driver to the system
|
*/
|
*/
|
int
|
int
|
rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config)
|
rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config)
|
{
|
{
|
struct m860_enet_struct *sc;
|
struct m860_enet_struct *sc;
|
struct ifnet *ifp;
|
struct ifnet *ifp;
|
int mtu;
|
int mtu;
|
int i;
|
int i;
|
|
|
/*
|
/*
|
* Find a free driver
|
* Find a free driver
|
*/
|
*/
|
for (i = 0 ; i < NIFACES ; i++) {
|
for (i = 0 ; i < NIFACES ; i++) {
|
sc = &enet_driver[i];
|
sc = &enet_driver[i];
|
ifp = &sc->arpcom.ac_if;
|
ifp = &sc->arpcom.ac_if;
|
if (ifp->if_softc == NULL)
|
if (ifp->if_softc == NULL)
|
break;
|
break;
|
}
|
}
|
if (i >= NIFACES) {
|
if (i >= NIFACES) {
|
printf ("Too many SCC drivers.\n");
|
printf ("Too many SCC drivers.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/*
|
/*
|
* Process options
|
* Process options
|
*/
|
*/
|
if (config->hardware_address) {
|
if (config->hardware_address) {
|
memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
|
memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
|
}
|
}
|
else {
|
else {
|
sc->arpcom.ac_enaddr[0] = 0x44;
|
sc->arpcom.ac_enaddr[0] = 0x44;
|
sc->arpcom.ac_enaddr[1] = 0x22;
|
sc->arpcom.ac_enaddr[1] = 0x22;
|
sc->arpcom.ac_enaddr[2] = 0x33;
|
sc->arpcom.ac_enaddr[2] = 0x33;
|
sc->arpcom.ac_enaddr[3] = 0x33;
|
sc->arpcom.ac_enaddr[3] = 0x33;
|
sc->arpcom.ac_enaddr[4] = 0x22;
|
sc->arpcom.ac_enaddr[4] = 0x22;
|
sc->arpcom.ac_enaddr[5] = 0x44;
|
sc->arpcom.ac_enaddr[5] = 0x44;
|
}
|
}
|
if (config->mtu)
|
if (config->mtu)
|
mtu = config->mtu;
|
mtu = config->mtu;
|
else
|
else
|
mtu = ETHERMTU;
|
mtu = ETHERMTU;
|
if (config->rbuf_count)
|
if (config->rbuf_count)
|
sc->rxBdCount = config->rbuf_count;
|
sc->rxBdCount = config->rbuf_count;
|
else
|
else
|
sc->rxBdCount = RX_BUF_COUNT;
|
sc->rxBdCount = RX_BUF_COUNT;
|
if (config->xbuf_count)
|
if (config->xbuf_count)
|
sc->txBdCount = config->xbuf_count;
|
sc->txBdCount = config->xbuf_count;
|
else
|
else
|
sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
|
sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
|
sc->acceptBroadcast = !config->ignore_broadcast;
|
sc->acceptBroadcast = !config->ignore_broadcast;
|
|
|
/*
|
/*
|
* Set up network interface values
|
* Set up network interface values
|
*/
|
*/
|
ifp->if_softc = sc;
|
ifp->if_softc = sc;
|
ifp->if_unit = i + 1;
|
ifp->if_unit = i + 1;
|
ifp->if_name = "eth";
|
ifp->if_name = "eth";
|
ifp->if_mtu = mtu;
|
ifp->if_mtu = mtu;
|
ifp->if_init = scc_init;
|
ifp->if_init = scc_init;
|
ifp->if_ioctl = scc_ioctl;
|
ifp->if_ioctl = scc_ioctl;
|
ifp->if_start = m860_enet_start;
|
ifp->if_start = m860_enet_start;
|
ifp->if_output = ether_output;
|
ifp->if_output = ether_output;
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
|
if (ifp->if_snd.ifq_maxlen == 0)
|
if (ifp->if_snd.ifq_maxlen == 0)
|
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
|
|
/*
|
/*
|
* Attach the interface
|
* Attach the interface
|
*/
|
*/
|
if_attach (ifp);
|
if_attach (ifp);
|
ether_ifattach (ifp);
|
ether_ifattach (ifp);
|
return 1;
|
return 1;
|
};
|
};
|
|
|
int
|
int
|
rtems_fec_driver_attach (struct rtems_bsdnet_ifconfig *config)
|
rtems_fec_driver_attach (struct rtems_bsdnet_ifconfig *config)
|
{
|
{
|
struct m860_enet_struct *sc;
|
struct m860_enet_struct *sc;
|
struct ifnet *ifp;
|
struct ifnet *ifp;
|
int mtu;
|
int mtu;
|
|
|
/*
|
/*
|
* Find a free driver
|
* Find a free driver
|
*/
|
*/
|
sc = &enet_driver[0];
|
sc = &enet_driver[0];
|
ifp = &sc->arpcom.ac_if;
|
ifp = &sc->arpcom.ac_if;
|
if (ifp->if_softc != NULL)
|
if (ifp->if_softc != NULL)
|
return 0;
|
return 0;
|
|
|
|
|
/*
|
/*
|
* Process options
|
* Process options
|
*/
|
*/
|
if (config->hardware_address) {
|
if (config->hardware_address) {
|
memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
|
memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
|
}
|
}
|
else {
|
else {
|
sc->arpcom.ac_enaddr[0] = 0x44;
|
sc->arpcom.ac_enaddr[0] = 0x44;
|
sc->arpcom.ac_enaddr[1] = 0x22;
|
sc->arpcom.ac_enaddr[1] = 0x22;
|
sc->arpcom.ac_enaddr[2] = 0x33;
|
sc->arpcom.ac_enaddr[2] = 0x33;
|
sc->arpcom.ac_enaddr[3] = 0x33;
|
sc->arpcom.ac_enaddr[3] = 0x33;
|
sc->arpcom.ac_enaddr[4] = 0x22;
|
sc->arpcom.ac_enaddr[4] = 0x22;
|
sc->arpcom.ac_enaddr[5] = 0x44;
|
sc->arpcom.ac_enaddr[5] = 0x44;
|
}
|
}
|
if (config->mtu)
|
if (config->mtu)
|
mtu = config->mtu;
|
mtu = config->mtu;
|
else
|
else
|
mtu = ETHERMTU;
|
mtu = ETHERMTU;
|
if (config->rbuf_count)
|
if (config->rbuf_count)
|
sc->rxBdCount = config->rbuf_count;
|
sc->rxBdCount = config->rbuf_count;
|
else
|
else
|
sc->rxBdCount = RX_BUF_COUNT;
|
sc->rxBdCount = RX_BUF_COUNT;
|
if (config->xbuf_count)
|
if (config->xbuf_count)
|
sc->txBdCount = config->xbuf_count;
|
sc->txBdCount = config->xbuf_count;
|
else
|
else
|
sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
|
sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
|
sc->acceptBroadcast = !config->ignore_broadcast;
|
sc->acceptBroadcast = !config->ignore_broadcast;
|
|
|
/*
|
/*
|
* Set up network interface values
|
* Set up network interface values
|
*/
|
*/
|
ifp->if_softc = sc;
|
ifp->if_softc = sc;
|
ifp->if_unit = 1;
|
ifp->if_unit = 1;
|
ifp->if_name = "eth";
|
ifp->if_name = "eth";
|
ifp->if_mtu = mtu;
|
ifp->if_mtu = mtu;
|
ifp->if_init = fec_init;
|
ifp->if_init = fec_init;
|
ifp->if_ioctl = fec_ioctl;
|
ifp->if_ioctl = fec_ioctl;
|
ifp->if_start = m860_enet_start;
|
ifp->if_start = m860_enet_start;
|
ifp->if_output = ether_output;
|
ifp->if_output = ether_output;
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
|
if (ifp->if_snd.ifq_maxlen == 0)
|
if (ifp->if_snd.ifq_maxlen == 0)
|
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
|
|
/*
|
/*
|
* Attach the interface
|
* Attach the interface
|
*/
|
*/
|
if_attach (ifp);
|
if_attach (ifp);
|
ether_ifattach (ifp);
|
ether_ifattach (ifp);
|
return 1;
|
return 1;
|
};
|
};
|
|
|
int
|
int
|
rtems_enet_driver_attach (struct rtems_bsdnet_ifconfig *config)
|
rtems_enet_driver_attach (struct rtems_bsdnet_ifconfig *config)
|
{
|
{
|
int i;
|
int i;
|
|
|
if ((m860.fec.mii_data & 0xffff) == 0x2000) {
|
if ((m860.fec.mii_data & 0xffff) == 0x2000) {
|
/* rtems_scc1_driver_attach(config);*/
|
/* rtems_scc1_driver_attach(config);*/
|
return rtems_fec_driver_attach(config);
|
return rtems_fec_driver_attach(config);
|
}
|
}
|
else {
|
else {
|
return rtems_scc1_driver_attach(config);
|
return rtems_scc1_driver_attach(config);
|
}
|
}
|
}
|
}
|
|
|