5728 lines
165 KiB
C
5728 lines
165 KiB
C
/* motFecEnd.c - END style Motorola FEC Ethernet network interface driver */
|
|
|
|
/*
|
|
* Copyright (c) 1998-2006, 2013 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
02p,04sep13,xms fix CHECKED_RETURN error. (WIND00414265)
|
|
02o,14jun13,fao Fix Coverity Prevent warnings.(WIND00414265)
|
|
02n,05sep06,kch Removed unnecessary coreip header includes.
|
|
02m,11may06,dgp doc: fix list formatting in library
|
|
02l,20apr06,wap Increase TX FIFO threshold to avoid underuns (SPR #120075)
|
|
02k,30mar06,dlk Free TX M_BLK chain only when last TBD corresponding to
|
|
the chain is done (SPR #119743).
|
|
02j,26jan06,wap Return END_ERR_BLOCK from motFecSend() on TX stall, not OK.
|
|
02i,25jan06,wap Correct RX and TX problems so this driver can survive torture
|
|
testing
|
|
02h,11nov05,wap Merge in coldfire FEC support, fix SPR #115124, fix
|
|
multicast support, implement IFF_ALLMULTI mode.
|
|
02g,31aug04,mdo Documentation fixes for apigen
|
|
02f,05dec03,rcs fixed warnings for base6
|
|
02e,05dec03,rcs changed IMPORT vxImmrGet() to vxImmrDevGet()
|
|
02d,30jan03,m_h IPv6 Support
|
|
02c,02may02,pmr SPR 75008: only set txStall flag if motFecTbdClean() fails to
|
|
free any Tx BDs in motFecSend().
|
|
02b,30apr02,rcs SPR 76102: polling mode fix
|
|
02a,28jan02,rcs changed motRevNumGet() to call vxImmrDevGet() SPR# 7120
|
|
01z,06dec01,rcs changed REV_D_4 back to REV_D_3 SPR# 71420
|
|
01y,04dec01,kab Removed decl for vxImmrGet(), get from vxPpcLib.h
|
|
01x,26oct01,crg fixed a possible cause of transmitter underruns by preventing
|
|
generation of TBDs with no data (SPR 29513)
|
|
added support for proper setting of MII management interface
|
|
speed (SPR 33812)
|
|
corrected clearing of receive events in motFecHandleRecvInt()
|
|
(SPR 69440)
|
|
01w,21sep01,dat Removing ANSI errors for diab compiler (needs more work)
|
|
01v,15sep01,dat Removed special definition of CACHE_PIPE_FLUSH
|
|
01u,01feb01,rcs added motRevNumGet() using vxImmrGet()
|
|
01t,01feb01,rcs merged in Motorola's modifications.
|
|
01s,29jan01,rcs in motFecRxCtrlRegValGet initialized *rxCtrlVal (SPR# 63479)
|
|
01r,29jan01,rcs in motFecTxCtrlRegValGet initialized *txCtrlVal (SPR# 63479)
|
|
01q,05dec00,dat merge from sustaining branch to tor2_0_x
|
|
01p,21nov00,rhk changes to initialization of FEC in order to support
|
|
rev. D.4 and newer 860T processors.
|
|
01o,05jul00,stv fixed the coding error in motFecHashTblPopulate (SPR #31622).
|
|
01n,07jul00,stv fixed the coding error in motFecHashTblPopulate (SPR# 31283).
|
|
01m,11jun00,ham removed reference to etherLib.
|
|
01l,22may00,pai Repaired (SPR #30673) by adding Keith Wiles' corrections to
|
|
hash register bit settings and his table driven CRC funtion.
|
|
Updated comments in motFecHashRegValGet(). Corrected the
|
|
coding error in motFecHashTblPopulate() (SPR #31283).
|
|
Released transmit semaphore and incremented MIB-II counter
|
|
in motFecSend() when returning ERROR as a result of being
|
|
called in polled mode.
|
|
01k,29mar00,pai allocated memory for PHY_INFO struct in motFecEndLoad() (SPR
|
|
#30085).
|
|
01j,01feb00,pai set driver control TX stall flag in motFecSend() if clean
|
|
TBD count becomes 0 (SPR #30135).
|
|
01i,27jan00,dat fixed use of NULL
|
|
01h,05jan00,stv removed private/funcBindP.h (SPR# 29875).
|
|
01g,06dec99,stv corrected return error code and freed mBlk chain (SPR #28492).
|
|
01f,11nov99,cn removed unnecessary freeing of pDrvCtrl in motFecUnload
|
|
(SPR# 28772).
|
|
01e,09sep99,rhk added a check to make sure driver is operational before
|
|
shutting down in motFecStop.
|
|
01d,31aug99,rhk disabled the MOT_FEC_DBG switch, pointed to the local
|
|
copy of ppc860Intr.h.
|
|
01c,19feb99,cn corrected a bug in motFecMiiDiag ().
|
|
01b,09feb99,cn changes required by performance improvement (SPR# 24883).
|
|
Also up-dated documentation, added probing of the device
|
|
in the motFecStart () routine.
|
|
01a,09nov98,cn written.
|
|
*/
|
|
|
|
/*
|
|
DESCRIPTION
|
|
This module implements a Motorola Fast Ethernet Controller (FEC) network
|
|
interface driver. The FEC is fully compliant with the IEEE 802.3
|
|
10Base-T and 100Base-T specifications. Hardware support of
|
|
the Media Independent Interface (MII) is built in the chip.
|
|
|
|
The FEC establishes a shared memory communication system with the CPU,
|
|
which is divided into two parts: the Control/Status Registers (CSR),
|
|
and the buffer descriptors (BD).
|
|
|
|
The CSRs reside in the MPC860T Communication Controller's internal RAM.
|
|
They are used for mode control and to extract status information
|
|
of a global nature. For instance, the types of events that should
|
|
generate an interrupt, or features like the promiscuous mode or the
|
|
max receive frame length may be set programming some of the CSRs properly.
|
|
Pointers to both the Transmit Buffer Descriptors ring (TBD) and the
|
|
Receive Buffer Descriptors ring (RBD) are also stored in the CSRs.
|
|
The CSRs are located in on-chip RAM and must be accessed using the
|
|
big-endian mode.
|
|
|
|
The BDs are used to pass data buffers and related buffer information
|
|
between the hardware and the software. They reside in the host main
|
|
memory and basically include local status information and a pointer
|
|
to the actual buffer, again in external memory.
|
|
|
|
This driver must be given several target-specific parameters, and
|
|
some external support routines must be provided. These parameters,
|
|
and the mechanisms used to communicate them to the driver, are
|
|
detailed below.
|
|
|
|
For versions of the MPC860T starting with revision D.4 and beyond
|
|
the functioning of the FEC changes slightly. An additional bit has
|
|
been added to the Ethernet Control Register (ECNTRL), the FEC PIN
|
|
MUX bit. This bit must be set prior to issuing commands involving
|
|
the other two bits in the register (ETHER_EN, RESET). The bit must
|
|
also be set when either of the other two bits are being utilized.
|
|
For versions of the 860T prior to revision D.4, this bit should not
|
|
be set.
|
|
|
|
BOARD LAYOUT
|
|
This device is on-board. No jumpering diagram is necessary.
|
|
|
|
EXTERNAL INTERFACE
|
|
|
|
The driver provides the standard external interface, motFecEndLoad(), which
|
|
takes a string of colon-separated parameters. The parameters should be
|
|
specified in hexadecimal, optionally preceded by "0x" or a minus sign "-".
|
|
|
|
The parameter string is parsed using strtok_r() and each parameter is
|
|
converted from a string representation to binary by a call to
|
|
strtoul(parameter, NULL, 16).
|
|
|
|
The format of the parameter string is:
|
|
|
|
"<motCpmAddr>:<ivec>:<bufBase>:<bufSize>:<fifoTxBase>:<fifoRxBase>
|
|
:<tbdNum>:<rbdNum>:<phyAddr>:<isoPhyAddr>:<phyDefMode>:<userFlags>
|
|
:<clockSpeed>"
|
|
|
|
TARGET-SPECIFIC PARAMETERS
|
|
|
|
\is
|
|
\i <motCpmAddr>
|
|
Indicates the address at which the host processor presents its internal
|
|
memory (also known as the dual ported RAM base address). With this address,
|
|
the driver is able to compute the location of the FEC parameter RAM, and,
|
|
ultimately, to program the FEC for proper operations.
|
|
|
|
\i <ivec>
|
|
This driver configures the host processor to generate hardware interrupts
|
|
for various events within the device. The interrupt-vector offset
|
|
parameter is used to connect the driver's ISR to the interrupt through
|
|
a call to the VxWorks system function intConnect(). It is also used to
|
|
compute the interrupt level (0-7) associated with the FEC interrupt (one
|
|
of the MPC860T SIU internal interrupt sources). The latter is given as
|
|
a parameter to intEnable(), in order to enable this level interrupt to
|
|
the PPC core.
|
|
|
|
\i <bufBase>
|
|
The Motorola Fast Ethernet Controller is a DMA-type device and typically
|
|
shares access to some region of memory with the CPU. This driver is designed
|
|
for systems that directly share memory between the CPU and the FEC.
|
|
|
|
This parameter tells the driver that space for the both the TBDs and the
|
|
RBDs needs not be allocated but should be taken from a cache-coherent
|
|
private memory space provided by the user at the given address. The user
|
|
should be aware that memory used for buffers descriptors must be 8-byte
|
|
aligned and non-cacheable. All the buffer descriptors should fit
|
|
in the given memory space.
|
|
|
|
If this parameter is "NONE", space for buffer descriptors is obtained
|
|
by calling cacheDmaMalloc() in motFecEndLoad().
|
|
|
|
\i <bufSize>
|
|
The memory size parameter specifies the size of the pre-allocated memory
|
|
region. If <bufBase> is specified as NONE (-1), the driver ignores this
|
|
parameter. Otherwise, the driver checks the size of the provided memory
|
|
region is adequate with respect to the given number of Transmit Buffer
|
|
Descriptors and Receive Buffer Descriptors.
|
|
|
|
\i <fifoTxBase>
|
|
Indicate the base location of the transmit FIFO, in internal memory.
|
|
The user does not need to initialize this parameter, as the related
|
|
FEC register defaults to a proper value after reset. The specific
|
|
reset value is microcode dependent. However, if the user wishes to
|
|
reserve some RAM for other purposes, he may set this parameter to a
|
|
different value. This should not be less than the default.
|
|
|
|
If <fifoTxBase> is specified as NONE (-1), the driver ignores it.
|
|
|
|
\i <fifoRxBase>
|
|
Indicate the base location of the receive FIFO, in internal memory.
|
|
The user does not need to initialize this parameter, as the related
|
|
FEC register defaults to a proper value after reset. The specific
|
|
reset value is microcode dependent. However, if the user wishes to
|
|
reserve some RAM for other purposes, he may set this parameter to a
|
|
different value. This should not be less than the default.
|
|
|
|
If <fifoRxBase> is specified as NONE (-1), the driver ignores it.
|
|
|
|
\i <tbdNum>
|
|
This parameter specifies the number of transmit buffer descriptors (TBDs).
|
|
Each buffer descriptor resides in 8 bytes of the processor's external
|
|
RAM space, and each one points to a 1536-byte buffer again in external
|
|
RAM. If this parameter is less than a minimum number specified in the
|
|
macro MOT_FEC_TBD_MIN, or if it is "NULL", a default value of 64 is used.
|
|
This default number is kept deliberately high, since each packet the driver
|
|
sends may consume more than a single TBD. This parameter should always
|
|
equal a even number.
|
|
|
|
\i <rbdNum>
|
|
This parameter specifies the number of receive buffer descriptors (RBDs).
|
|
Each buffer descriptor resides in 8 bytes of the processor's external
|
|
RAM space, and each one points to a 1536-byte buffer again in external
|
|
RAM. If this parameter is less than a minimum number specified in the
|
|
macro MOT_FEC_RBD_MIN, or if it is "NULL", a default value of 48 is used.
|
|
This parameter should always equal a even number.
|
|
|
|
\i <phyAddr>
|
|
This parameter specifies the logical address of a MII-compliant physical
|
|
device (PHY) that is to be used as a physical media on the network.
|
|
Valid addresses are in the range 0-31. There may be more than one device
|
|
under the control of the same management interface. If this parameter is
|
|
"NULL", the default physical layer initialization routine will find out the
|
|
PHY actual address by scanning the whole range. The one with the lowest
|
|
address will be chosen.
|
|
|
|
\i <isoPhyAddr>
|
|
This parameter specifies the logical address of a MII-compliant physical
|
|
device (PHY) that is to be electrically isolated by the management
|
|
interface. Valid addresses are in the range 0-31. If this parameter
|
|
equals 0xff, the default physical layer initialization routine will
|
|
assume there is no need to isolate any device. However, this parameter
|
|
will be ignored unless the MOT_FEC_USR_PHY_ISO bit in the <userFlags>
|
|
is set to one.
|
|
|
|
\i <phyDefMode>
|
|
This parameter specifies the operating mode that will be set up
|
|
by the default physical layer initialization routine in case all
|
|
the attempts made to establish a valid link failed. If that happens,
|
|
the first PHY that matches the specified abilities will be chosen to
|
|
work in that mode, and the physical link will not be tested.
|
|
|
|
\i <userFlags>
|
|
This field enables the user to give some degree of customization to the
|
|
driver, especially as regards the physical layer interface.
|
|
|
|
\i <clockSpeed>
|
|
This field enables the user to define the speed of the clock being used
|
|
to drive the interface. The clock speed is used to derive the MII
|
|
management interface clock, which cannot exceed 2.5 MHz. <clockSpeed>
|
|
is optional in BSPs using clocks that are 50 MHz or less, but it is
|
|
required in faster designs to ensure proper MII interface operation.
|
|
|
|
MOT_FEC_USR_PHY_NO_AN: the default physical layer initialization
|
|
routine will exploit the auto-negotiation mechanism as described in
|
|
the IEEE Std 802.3, to bring a valid link up. According to it, all
|
|
the link partners on the media will take part to the negotiation
|
|
process, and the highest priority common denominator technology ability
|
|
will be chosen. It the user wishes to prevent auto-negotiation from
|
|
occurring, he may set this bit in the user flags.
|
|
|
|
MOT_FEC_USR_PHY_TBL: in the auto-negotiation process, PHYs
|
|
advertise all their technology abilities at the same time,
|
|
and the result is that the maximum common denominator is used. However,
|
|
this behaviour may be changed, and the user may affect the order how
|
|
each subset of PHY's abilities is negotiated. Hence, when the
|
|
MOT_FEC_USR_PHY_TBL bit is set, the default physical layer
|
|
initialization routine will look at the motFecPhyAnOrderTbl[] table and
|
|
auto-negotiate a subset of abilities at a time, as suggested by the
|
|
table itself. It is worth noticing here, however, that if the
|
|
MOT_FEC_USR_PHY_NO_AN bit is on, the above table will be ignored.
|
|
|
|
MOT_FEC_USR_PHY_NO_FD: the PHY may be set to operate in full duplex mode,
|
|
provided it has this ability, as a result of the negotiation with other
|
|
link partners. However, in this operating mode, the FEC will ignore the
|
|
collision detect and carrier sense signals. If the user wishes not to
|
|
negotiate full duplex mode, he should set the MOT_FEC_USR_PHY_NO_FD bit
|
|
in the user flags.
|
|
|
|
MOT_FEC_USR_PHY_NO_HD: the PHY may be set to operate in half duplex mode,
|
|
provided it has this ability, as a result of the negotiation with other link
|
|
partners. If the user wishes not to negotiate half duplex mode, he should
|
|
set the MOT_FEC_USR_PHY_NO_HD bit in the user flags.
|
|
|
|
MOT_FEC_USR_PHY_NO_100: the PHY may be set to operate at 100Mbit/s speed,
|
|
provided it has this ability, as a result of the negotiation with
|
|
other link partners. If the user wishes not to negotiate 100Mbit/s speed,
|
|
he should set the MOT_FEC_USR_PHY_NO_100 bit in the user flags.
|
|
|
|
MOT_FEC_USR_PHY_NO_10: the PHY may be set to operate at 10Mbit/s speed,
|
|
provided it has this ability, as a result of the negotiation with
|
|
other link partners. If the user wishes not to negotiate 10Mbit/s speed,
|
|
he should set the MOT_FEC_USR_PHY_NO_10 bit in the user flags.
|
|
|
|
MOT_FEC_USR_PHY_ISO: some boards may have different PHYs controlled by the
|
|
same management interface. In some cases, there may be the need of
|
|
electrically isolating some of them from the interface itself, in order
|
|
to guarantee a proper behaviour on the medium layer. If the user wishes to
|
|
electrically isolate one PHY from the MII interface, he should set the
|
|
MOT_FEC_USR_PHY_ISO bit and provide its logical address in the <isoPhyAddr>
|
|
field of the load string. The default behaviour is to not isolate any
|
|
PHY on the board.
|
|
|
|
MOT_FEC_USR_SER: the user may set the MOT_FEC_USR_SER bit to enable
|
|
the 7-wire interface instead of the MII which is the default.
|
|
|
|
MOT_FEC_USR_LOOP: when the MOT_FEC_USR_LOOP bit is set, the driver will
|
|
configure the FEC to work in loopback mode, with the TX signal directly
|
|
connected to the RX. This mode should only be used for testing.
|
|
|
|
MOT_FEC_USR_HBC: if the MOT_FEC_USR_HBC bit is set, the driver will
|
|
configure the FEC to perform heartbeat check following end of transmission
|
|
and the HB bit in the status field of the TBD will be set if the collision
|
|
input does not assert within the heartbeat window (also see _func_motFecHbFail,
|
|
below). The user does not normally need to set this bit.
|
|
|
|
\ie
|
|
|
|
EXTERNAL SUPPORT REQUIREMENTS
|
|
This driver requires three external support functions:
|
|
\is
|
|
\i sysFecEnetEnable()
|
|
\cs
|
|
STATUS sysFecEnetEnable (UINT32 motCpmAddr);
|
|
\ce
|
|
This routine is expected to handle any target-specific functions needed
|
|
to enable the FEC. These functions typically include setting the Port D
|
|
on the 860T-based board so that the MII interface may be used, and also
|
|
disabling the IRQ7 signal. This routine is expected to return OK on
|
|
success, or ERROR. The driver calls this routine, once per device, from the
|
|
motFecEndLoad() routine.
|
|
\i sysFecEnetDisable()
|
|
\cs
|
|
STATUS sysFecEnetDisable (UINT32 motCpmAddr);
|
|
\ce
|
|
This routine is expected to perform any target specific functions required
|
|
to disable the MII interface to the FEC. This involves restoring the
|
|
default values for all the Port D signals. This routine is expected to
|
|
return OK on success, or ERROR. The driver calls this routine from the
|
|
motFecEndStop() routine each time a device is disabled.
|
|
\i sysFecEnetAddrGet()
|
|
\cs
|
|
STATUS sysFecEnetAddrGet (UINT32 motCpmAddr, UCHAR * enetAddr);
|
|
\ce
|
|
The driver expects this routine to provide the six-byte Ethernet hardware
|
|
address that is used by this device. This routine must copy the six-byte
|
|
address to the space provided by <enetAddr>. This routine is expected to
|
|
return OK on success, or ERROR. The driver calls this routine, once per
|
|
device, from the motFecEndLoad() routine.
|
|
\i `_func_motFecPhyInit'
|
|
\cs
|
|
FUNCPTR _func_motFecPhyInit
|
|
\ce
|
|
This driver sets the global variable `_func_motFecPhyInit' to the
|
|
MII-compliant media initialization routine motFecPhyInit(). If the user
|
|
wishes to exploit a different way to configure the PHY, he may set
|
|
this variable to his own media initialization routine, typically
|
|
in sysHwInit().
|
|
\i `_func_motFecHbFail'
|
|
\cs
|
|
FUNCPTR _func_motFecPhyInit
|
|
\ce
|
|
The FEC may be configured to perform heartbeat check following end
|
|
of transmission, and to generate an interrupt, when this event occurs.
|
|
If this is the case, and if the global variable `_func_motFecHbFail'
|
|
is not NULL, the routine referenced to by `_func_motFecHbFail' is called,
|
|
with a pointer to the driver control structure as parameter. Hence,
|
|
the user may set this variable to his own heart beat check fail routine,
|
|
where he can take any action he sees appropriate.
|
|
The default value for the global variable `_func_motFecHbFail' is NULL.
|
|
\ie
|
|
|
|
|
|
SYSTEM RESOURCE USAGE
|
|
If the driver allocates the memory to share with the Ethernet device,
|
|
it does so by calling the cacheDmaMalloc() routine. For the default case
|
|
of 64 transmit buffers and 48 receive buffers, the total size requested
|
|
is 912 bytes, and this includes the 16-byte alignment requirement of the
|
|
device. If a non-cacheable memory region is provided by the user, the
|
|
size of this region should be this amount, unless the user has specified
|
|
a different number of transmit or receive BDs.
|
|
|
|
This driver can operate only if this memory region is non-cacheable
|
|
or if the hardware implements bus snooping. The driver cannot maintain
|
|
cache coherency for the device because the BDs are asynchronously
|
|
modified by both the driver and the device, and these fields might share
|
|
the same cache line.
|
|
|
|
Data buffers are instead allocated in the external memory through the
|
|
regular memory allocation routine (memalign), and the related cache lines
|
|
are then flushed or invalidated as appropriate. The user should not allocate
|
|
memory for them.
|
|
|
|
TUNING HINTS
|
|
|
|
The only adjustable parameters are the number of TBDs and RBDs that will be
|
|
created at run-time. These parameters are given to the driver when
|
|
motFecEndLoad() is called. There is one RBD associated with each received
|
|
frame whereas a single transmit packet normally uses more than one TBD. For
|
|
memory-limited applications, decreasing the number of RBDs may be
|
|
desirable. Decreasing the number of TBDs below a certain point will
|
|
provide substantial performance degradation, and is not recommended. An
|
|
adequate number of loaning buffers are also pre-allocated to provide more
|
|
buffering before packets are dropped, but this is not configurable.
|
|
|
|
The relative priority of the netTask and of the other tasks in the system
|
|
may heavily affect performance of this driver. Usually the best performance
|
|
is achieved when the netTask priority equals that of the other
|
|
applications using the driver.
|
|
|
|
SPECIAL CONSIDERATIONS
|
|
|
|
Due to the FEC8 errata in the document: "MPC860 Family Device Errata Reference"
|
|
available at the Motorola web site, the number of receive buffer
|
|
descriptors (RBD) for the FEC (see configNet.h) is kept deliberately high.
|
|
According to Motorola, this problem was fixed in Rev. B3 of the silicon.
|
|
In memory-bound applications, when using the above mentioned revision of
|
|
the MPC860T processor, the user may decrease the number of RBDs
|
|
to fit his needs.
|
|
|
|
DIFFERENCES BETWEEN PPC FEC AND COLDFIRE FEC
|
|
|
|
This driver now supports the FEC as implemented in the Coldfire range
|
|
of processors (MCF5272 and MCF5282). The Coldfire implementation
|
|
differs from the PPC in the following ways:
|
|
|
|
\ms
|
|
\m -
|
|
The register addresses are different, and not in the same order in
|
|
memory.
|
|
|
|
\m -
|
|
Limited throughput full-duplex 100Mbps operation. External bus use
|
|
is the limiting factor.
|
|
|
|
\m -
|
|
Only big-endian mode is supported for buffer descriptors and buffers.
|
|
|
|
\m -
|
|
Separate interrupt vectors for Rx, Tx and non-time-critical interrupts.
|
|
It is assumed that these three interrupts occupy three consecutive vectors
|
|
starting at iVec.
|
|
|
|
\m -
|
|
Interrupt priority is set in the interrupt controller. This is handled
|
|
by the BSP.
|
|
|
|
\m -
|
|
The formula for calculating the MDC frequency.
|
|
On the MCF5282, MDCfreq = SYSfreq/4*div
|
|
(where div = value written to the MII_SPEED field of the MII_SPEED register).
|
|
\me
|
|
|
|
SEE ALSO: ifLib,
|
|
\tb MPC860T Fast Ethernet Controller (Supplement to the MPC860 User's Manual)
|
|
\tb Motorola MPC860 User's Manual ,
|
|
|
|
\INTERNAL
|
|
This driver contains conditional compilation switch MOT_FEC_END_DEBUG.
|
|
If defined, adds debug output routines. Output is further
|
|
selectable at run-time via the motFecEndDbg global variable.
|
|
*/
|
|
|
|
#include "vxWorks.h"
|
|
#include "wdLib.h"
|
|
#include "iv.h"
|
|
#include "vme.h"
|
|
#include "net/mbuf.h"
|
|
#include "semLib.h"
|
|
#include "lstLib.h"
|
|
#include "sys/times.h"
|
|
#include "sys/ioctl.h"
|
|
#include "errno.h"
|
|
#include "memLib.h"
|
|
#include "intLib.h"
|
|
#include "iosLib.h"
|
|
#include "errnoLib.h"
|
|
#include "vxLib.h"
|
|
|
|
#include "cacheLib.h"
|
|
#include "logLib.h"
|
|
#include "netLib.h"
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
#include "sysLib.h"
|
|
#include "taskLib.h"
|
|
|
|
#undef ETHER_MAP_IP_MULTICAST
|
|
#include "etherMultiLib.h"
|
|
#include "end.h"
|
|
|
|
#define END_MACROS
|
|
#include "endLib.h"
|
|
|
|
#ifdef WR_IPV6
|
|
#include "adv_net.h"
|
|
#endif /*WR_IPV6*/
|
|
|
|
#include "drv/intrCtl/ppc860Intr.h"
|
|
#include "drv/end/motFecEnd.h"
|
|
|
|
/* defines */
|
|
|
|
/* initial divisor and final XOR value for reflected CRC */
|
|
|
|
#define INIT_REFLECTED 0xFFFFFFFF
|
|
#define XOROT INIT_REFLECTED
|
|
|
|
/* Driver debug control */
|
|
|
|
#undef MOT_FEC_DBG
|
|
|
|
/* Driver debug control */
|
|
|
|
#ifdef MOT_FEC_DBG
|
|
#define MOT_FEC_DBG_OFF 0x0000
|
|
#define MOT_FEC_DBG_RX 0x0001
|
|
#define MOT_FEC_DBG_TX 0x0002
|
|
#define MOT_FEC_DBG_POLL 0x0004
|
|
#define MOT_FEC_DBG_MII 0x0008
|
|
#define MOT_FEC_DBG_LOAD 0x0010
|
|
#define MOT_FEC_DBG_IOCTL 0x0020
|
|
#define MOT_FEC_DBG_INT 0x0040
|
|
#define MOT_FEC_DBG_START 0x0080
|
|
#define MOT_FEC_DBG_ANY 0xffff
|
|
|
|
UINT32 motFecEndDbg = 0x0;
|
|
UINT32 motFecBabRxErr = 0x0;
|
|
UINT32 motFecBabTxErr = 0x0;
|
|
UINT32 motFecHbFailErr = 0x0;
|
|
UINT32 motFecTxLcErr = 0x0;
|
|
UINT32 motFecTxUrErr = 0x0;
|
|
UINT32 motFecTxCslErr = 0x0;
|
|
UINT32 motFecTxRlErr = 0x0;
|
|
UINT32 motFecRxLgErr = 0x0;
|
|
UINT32 motFecRxNoErr = 0x0;
|
|
UINT32 motFecRxCrcErr = 0x0;
|
|
UINT32 motFecRxOvErr = 0x0;
|
|
UINT32 motFecRxTrErr = 0x0;
|
|
UINT32 motFecRxLsErr = 0x0;
|
|
UINT32 motFecRxMemErr = 0x0;
|
|
|
|
DRV_CTRL * pDrvCtrlDbg = NULL;
|
|
|
|
#define MOT_FEC_BAB_RX_ADD \
|
|
motFecBabRxErr++;
|
|
|
|
#define MOT_FEC_BAB_TX_ADD \
|
|
motFecBabTxErr++;
|
|
|
|
#define MOT_FEC_HB_FAIL_ADD \
|
|
motFecHbFailErr++;
|
|
|
|
#define MOT_FEC_TX_LC_ADD \
|
|
motFecTxLcErr++;
|
|
|
|
#define MOT_FEC_TX_UR_ADD \
|
|
motFecTxUrErr++;
|
|
|
|
#define MOT_FEC_TX_CSL_ADD \
|
|
motFecTxCslErr++;
|
|
|
|
#define MOT_FEC_TX_RL_ADD \
|
|
motFecTxRlErr++;
|
|
|
|
#define MOT_FEC_RX_LG_ADD \
|
|
motFecRxLgErr++;
|
|
|
|
#define MOT_FEC_RX_NO_ADD \
|
|
motFecRxNoErr++;
|
|
|
|
#define MOT_FEC_RX_CRC_ADD \
|
|
motFecRxCrcErr++;
|
|
|
|
#define MOT_FEC_RX_OV_ADD \
|
|
motFecRxOvErr++;
|
|
|
|
#define MOT_FEC_RX_TR_ADD \
|
|
motFecRxTrErr++;
|
|
|
|
#define MOT_FEC_RX_MEM_ADD \
|
|
motFecRxMemErr++;
|
|
|
|
#define MOT_FEC_RX_LS_ADD \
|
|
motFecRxLsErr++;
|
|
|
|
#define MOT_FEC_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
|
|
{ \
|
|
if (motFecEndDbg & FLG) \
|
|
logMsg (X0, X1, X2, X3, X4, X5, X6); \
|
|
}
|
|
|
|
#else /* MOT_FEC_DBG */
|
|
|
|
#define MOT_FEC_BAB_RX_ADD
|
|
#define MOT_FEC_BAB_TX_ADD
|
|
#define MOT_FEC_HB_FAIL_ADD
|
|
#define MOT_FEC_TX_LC_ADD
|
|
#define MOT_FEC_TX_UR_ADD
|
|
#define MOT_FEC_TX_CSL_ADD
|
|
#define MOT_FEC_TX_RL_ADD
|
|
#define MOT_FEC_RX_MEM_ADD
|
|
#define MOT_FEC_RX_LS_ADD
|
|
#define MOT_FEC_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
|
|
|
|
#endif /* MOT_FEC_DBG */
|
|
|
|
/* general macros for reading/writing from/to specified locations */
|
|
|
|
/* Cache and virtual/physical memory related macros */
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
/*
|
|
* The Coldfire currently uses a 1-1 address mapping, so
|
|
* no translation should be needed.
|
|
*/
|
|
#define MOT_FEC_PHYS_TO_VIRT(physAddr) (physAddr)
|
|
#define MOT_FEC_VIRT_TO_PHYS(virtAddr) (virtAddr)
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
#define MOT_FEC_PHYS_TO_VIRT(physAddr) \
|
|
CACHE_DRV_PHYS_TO_VIRT (&pDrvCtrl->bdCacheFuncs, (char *)(physAddr))
|
|
|
|
#define MOT_FEC_VIRT_TO_PHYS(virtAddr) \
|
|
CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->bdCacheFuncs, (char *)(virtAddr))
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
#define MOT_FEC_BD_CACHE_INVAL(address, len) \
|
|
CACHE_DRV_INVALIDATE (&pDrvCtrl->bdCacheFuncs, (address), (len))
|
|
|
|
#define MOT_FEC_CACHE_INVAL(address, len) \
|
|
CACHE_DRV_INVALIDATE (&pDrvCtrl->bufCacheFuncs, (address), (len))
|
|
|
|
#define MOT_FEC_CACHE_FLUSH(address, len) \
|
|
CACHE_DRV_FLUSH (&pDrvCtrl->bufCacheFuncs, (address), (len))
|
|
|
|
/* driver flags */
|
|
|
|
#define MOT_FEC_OWN_MEM 0x01 /* internally provided memory */
|
|
#define MOT_FEC_INV_TBD_NUM 0x02 /* invalid tbdNum provided */
|
|
#define MOT_FEC_INV_RBD_NUM 0x04 /* invalid rbdNum provided */
|
|
#define MOT_FEC_POLLING 0x08 /* polling mode */
|
|
#define MOT_FEC_PROM 0x20 /* promiscuous mode */
|
|
#define MOT_FEC_MCAST 0x40 /* multicast addressing mode */
|
|
#define MOT_FEC_FD 0x80 /* full duplex mode */
|
|
|
|
/* shortcuts */
|
|
|
|
#define MOT_FEC_FLAG_CLEAR(clearBits) \
|
|
(pDrvCtrl->flags &= ~(clearBits))
|
|
|
|
#define MOT_FEC_FLAG_SET(setBits) \
|
|
(pDrvCtrl->flags |= (setBits))
|
|
|
|
#define MOT_FEC_FLAG_GET() \
|
|
(pDrvCtrl->flags)
|
|
|
|
#define MOT_FEC_FLAG_ISSET(setBits) \
|
|
(pDrvCtrl->flags & (setBits))
|
|
|
|
#define MOT_FEC_PHY_FLAGS_SET(setBits) \
|
|
(pDrvCtrl->phyInfo->phyFlags |= (setBits))
|
|
|
|
#define MOT_FEC_PHY_FLAGS_ISSET(setBits) \
|
|
(pDrvCtrl->phyInfo->phyFlags & (setBits))
|
|
|
|
#define MOT_FEC_PHY_FLAGS_GET(setBits) \
|
|
(pDrvCtrl->phyInfo->phyFlags)
|
|
|
|
#define MOT_FEC_PHY_FLAGS_CLEAR(clearBits) \
|
|
(pDrvCtrl->phyInfo->phyFlags &= ~(clearBits))
|
|
|
|
#define MOT_FEC_USR_FLAG_ISSET(setBits) \
|
|
(pDrvCtrl->userFlags & (setBits))
|
|
|
|
#define END_FLAGS_ISSET(setBits) \
|
|
((&pDrvCtrl->endObj)->flags & (setBits))
|
|
|
|
#define MOT_FEC_ADDR_GET(pEnd) \
|
|
((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
|
|
|
|
#define MOT_FEC_ADDR_LEN_GET(pEnd) \
|
|
((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
|
|
|
|
/* some BDs definitions */
|
|
|
|
/*
|
|
* the total is 0x600 and it accounts for the required alignment
|
|
* of receive data buffers, and the cluster overhead.
|
|
*/
|
|
|
|
#define MOT_FEC_MAX_CL_LEN ((MOT_FEC_MAX_PCK_SZ \
|
|
+ (MOT_FEC_BD_ALIGN - 1) \
|
|
+ (CL_OVERHEAD - 1)) \
|
|
& (~ (CL_OVERHEAD - 1)))
|
|
|
|
#define MOT_FEC_MAX_RX_BUF ((MOT_FEC_MAX_PCK_SZ + MOT_FEC_BD_ALIGN - 1) \
|
|
& (~(MOT_FEC_BD_ALIGN - 1)))
|
|
|
|
#define MOT_FEC_BUF_V_LEN (MOT_FEC_MAX_RX_BUF + 16)
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
#define MOT_FEC_RX_BUF_SZ 2048 /* Required by DMA engine */
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
#define MOT_FEC_RX_BUF_SZ (MOT_FEC_MAX_CL_LEN)
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
#define MOT_FEC_TX_BUF_SZ (MOT_FEC_MAX_CL_LEN)
|
|
|
|
#define MOT_FEC_MEM_SZ(pDrvCtrl) \
|
|
((pDrvCtrl)->bufSize)
|
|
|
|
#define MOT_FEC_LOAN_SZ \
|
|
(MOT_FEC_RX_BUF_SZ * MOT_FEC_BD_LOAN_NUM)
|
|
|
|
#define MOT_FEC_RX_MEM(pDrvCtrl) \
|
|
(MOT_FEC_RX_BUF_SZ * ((pDrvCtrl)->rbdNum + MOT_FEC_BD_LOAN_NUM))
|
|
|
|
#define MOT_FEC_TX_MEM(pDrvCtrl) \
|
|
(MOT_FEC_TX_BUF_SZ * (MOT_FEC_TBD_POLL_NUM + MOT_FEC_TX_CL_NUM))
|
|
|
|
#define MOT_FEC_TBD_MEM(pDrvCtrl) \
|
|
(MOT_FEC_TBD_SZ * (pDrvCtrl)->tbdNum)
|
|
|
|
#define MOT_FEC_RBD_MEM(pDrvCtrl) \
|
|
(MOT_FEC_RBD_SZ * (pDrvCtrl)->rbdNum)
|
|
|
|
#define MOT_FEC_BD_MEM(pDrvCtrl) \
|
|
(MOT_FEC_TBD_MEM (pDrvCtrl) + MOT_FEC_RBD_MEM (pDrvCtrl))
|
|
|
|
/* Control/Status Registers (CSR) definitions */
|
|
|
|
#define MOT_FEC_CSR_WR(csrOff, csrVal) \
|
|
{ \
|
|
UINT32 temp = 0; \
|
|
\
|
|
temp = (UINT32) MOT_FEC_VIRT_TO_PHYS ((pDrvCtrl->motCpmAddr) \
|
|
+ (csrOff)); \
|
|
\
|
|
MOT_FEC_LONG_WR ((UINT32 *) (temp), (csrVal)); \
|
|
}
|
|
|
|
#define MOT_FEC_CSR_RD(csrOff, csrVal) \
|
|
{ \
|
|
UINT32 temp = 0; \
|
|
\
|
|
temp = (UINT32) MOT_FEC_VIRT_TO_PHYS ((pDrvCtrl->motCpmAddr) \
|
|
+ (csrOff)); \
|
|
\
|
|
MOT_FEC_LONG_RD ((UINT32 *) (temp), (csrVal)); \
|
|
}
|
|
|
|
/* macros to read/write tx/rx buffer descriptors */
|
|
|
|
#define MOT_FEC_BD_WORD_WR(bdAddr, bdOff, bdVal) \
|
|
{ \
|
|
UINT32 temp = 0; \
|
|
\
|
|
temp = (UINT32) MOT_FEC_VIRT_TO_PHYS ((bdAddr) + (bdOff)); \
|
|
\
|
|
MOT_FEC_WORD_WR ((UINT16 *) (temp), (bdVal)); \
|
|
}
|
|
|
|
/* here we're writing the data pointer, so it's a physical address */
|
|
|
|
#define MOT_FEC_BD_LONG_WR(bdAddr, bdOff, bdVal) \
|
|
{ \
|
|
UINT32 temp1 = 0; \
|
|
UINT32 temp2 = 0; \
|
|
\
|
|
temp1 = (UINT32) MOT_FEC_VIRT_TO_PHYS ((bdAddr) + (bdOff)); \
|
|
temp2 = (UINT32) MOT_FEC_VIRT_TO_PHYS (bdVal); \
|
|
\
|
|
MOT_FEC_LONG_WR ((UINT32 *) (temp1), (temp2)); \
|
|
}
|
|
|
|
#define MOT_FEC_BD_WORD_RD(bdAddr, bdOff, bdVal) \
|
|
{ \
|
|
UINT32 temp = 0; \
|
|
\
|
|
temp = (UINT32) MOT_FEC_VIRT_TO_PHYS ((bdAddr) + (bdOff)); \
|
|
\
|
|
MOT_FEC_WORD_RD ((UINT16 *) (temp), (bdVal)); \
|
|
}
|
|
|
|
#define MOT_FEC_BD_LONG_RD(bdAddr, bdOff, bdVal) \
|
|
{ \
|
|
UINT32 temp1 = 0; \
|
|
UINT32 temp2 = 0; \
|
|
\
|
|
temp1 = (UINT32) MOT_FEC_VIRT_TO_PHYS ((bdAddr) + (bdOff)); \
|
|
\
|
|
MOT_FEC_LONG_RD ((UINT32 *) (temp1), (temp2)); \
|
|
\
|
|
bdVal = (char *) MOT_FEC_PHYS_TO_VIRT (temp2); \
|
|
}
|
|
|
|
#define MOT_FEC_NEXT_TBD(pDrvCtrl, pTbd) \
|
|
(pTbd) = (MOT_FEC_TBD_ID) ((pDrvCtrl)->tbdBase + \
|
|
((pDrvCtrl)->tbdIndex * MOT_FEC_TBD_SZ))
|
|
|
|
#define MOT_FEC_USED_TBD(pDrvCtrl, pTbd) \
|
|
(pTbd) = (MOT_FEC_TBD_ID) ((pDrvCtrl)->tbdBase + \
|
|
((pDrvCtrl)->usedTbdIndex * MOT_FEC_TBD_SZ))
|
|
|
|
#define MOT_FEC_NEXT_RBD(pDrvCtrl, pRbd) \
|
|
(pRbd) = (MOT_FEC_RBD_ID) ((pDrvCtrl)->rbdBase + \
|
|
(((pDrvCtrl)->rbdIndex) * MOT_FEC_RBD_SZ))
|
|
|
|
#define MOT_FEC_ETH_SET \
|
|
MOT_FEC_CSR_WR (MOT_FEC_CTRL_OFF, pinMux);
|
|
|
|
#define MOT_FEC_ETH_ENABLE \
|
|
MOT_FEC_CSR_WR (MOT_FEC_CTRL_OFF, (MOT_FEC_ETH_EN | pinMux));
|
|
|
|
#define MOT_FEC_ETH_DISABLE \
|
|
MOT_FEC_CSR_WR (MOT_FEC_CTRL_OFF, (MOT_FEC_ETH_DIS | pinMux));
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
|
|
#define MOT_FEC_RX_ACTIVATE sysFecEnetRxResume(pDrvCtrl)
|
|
#define MOT_FEC_TX_ACTIVATE sysFecEnetTxResume(pDrvCtrl)
|
|
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
|
|
#define MOT_FEC_RX_ACTIVATE \
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_ACT_OFF, MOT_FEC_RX_ACT);
|
|
|
|
#define MOT_FEC_TX_ACTIVATE \
|
|
MOT_FEC_CSR_WR (MOT_FEC_TX_ACT_OFF, MOT_FEC_TX_ACT);
|
|
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
#define MOT_FEC_INT_DISABLE \
|
|
MOT_FEC_CSR_WR (MOT_FEC_MASK_OFF, 0);
|
|
|
|
#define MOT_FEC_INT_ENABLE \
|
|
MOT_FEC_CSR_WR (MOT_FEC_MASK_OFF, (pDrvCtrl->intMask));
|
|
|
|
#define MOT_FEC_VECTOR(pDrvCtrl) \
|
|
((pDrvCtrl)->ivec)
|
|
|
|
/* more shortcuts */
|
|
|
|
#define MOT_FEC_GRA_SEM_CREATE \
|
|
if ((pDrvCtrl->graSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY)) \
|
|
== NULL) \
|
|
goto errorExit
|
|
|
|
#define MOT_FEC_GRA_SEM_DELETE \
|
|
if ((pDrvCtrl->graSem) != NULL) \
|
|
semDelete (pDrvCtrl->graSem)
|
|
|
|
#define MOT_FEC_GRA_SEM_GIVE \
|
|
(semGive (pDrvCtrl->graSem))
|
|
|
|
#define MOT_FEC_GRA_SEM_TAKE \
|
|
(semTake (pDrvCtrl->graSem, WAIT_FOREVER))
|
|
|
|
#define MOT_FEC_MII_SEM_CREATE \
|
|
if ((pDrvCtrl->miiSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY)) \
|
|
== NULL) \
|
|
goto errorExit
|
|
|
|
#define MOT_FEC_MII_SEM_DELETE \
|
|
if ((pDrvCtrl->miiSem) != NULL) \
|
|
semDelete (pDrvCtrl->miiSem)
|
|
|
|
#define MOT_FEC_MII_SEM_GIVE \
|
|
(semGive (pDrvCtrl->miiSem))
|
|
|
|
#define MOT_FEC_MII_SEM_TAKE \
|
|
(semTake (pDrvCtrl->miiSem, WAIT_FOREVER))
|
|
|
|
#define NET_BUF_ALLOC() \
|
|
netClusterGet (pDrvCtrl->endObj.pNetPool, pDrvCtrl->pClPoolId) \
|
|
|
|
#define NET_TO_MOT_FEC_BUF(netBuf) \
|
|
(((UINT32) (netBuf) + MOT_FEC_BD_ALIGN - 1) \
|
|
& ~(MOT_FEC_BD_ALIGN - 1))
|
|
|
|
#define NET_BUF_FREE(pBuffer) \
|
|
netClFree (pDrvCtrl->endObj.pNetPool, (pBuffer))
|
|
|
|
#define NET_MBLK_ALLOC() \
|
|
netMblkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT, MT_DATA)
|
|
|
|
#define NET_MBLK_FREE(pMblock) \
|
|
netMblkFree (pDrvCtrl->endObj.pNetPool, (M_BLK_ID) (pMblock))
|
|
|
|
#define NET_CL_BLK_ALLOC() \
|
|
netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT)
|
|
|
|
#define NET_CL_BLK_FREE(pClBlock) \
|
|
netClBlkFree (pDrvCtrl->endObj.pNetPool, (CL_BLK_ID) (pClBlock))
|
|
|
|
#define NET_MBLK_BUF_FREE(pMblock) \
|
|
netMblkClFree ((M_BLK_ID) (pMblock))
|
|
|
|
#define NET_MBLK_CL_JOIN(pMblock, pClBlock, ret) \
|
|
ret = netMblkClJoin ((pMblock), (pClBlock))
|
|
|
|
#define NET_CL_BLK_JOIN(pClBlock, pBuffer, length, ret) \
|
|
ret = netClBlkJoin ((pClBlock), (pBuffer), (length), NULL, 0, 0, 0)
|
|
|
|
/* globals */
|
|
|
|
/* external */
|
|
IMPORT UINT32 vxImmrDevGet(void);
|
|
|
|
/* locals */
|
|
|
|
LOCAL int pinMux;
|
|
|
|
/* intermediate remainders for table-driven CRC calculations */
|
|
|
|
LOCAL UINT32 crctable[256] =
|
|
{
|
|
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
|
|
0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
|
|
0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
|
|
0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
|
|
0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
|
|
0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
|
|
0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
|
|
0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
|
|
0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
|
|
0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
|
|
0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
|
|
0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
|
|
0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
|
|
0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
|
|
0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
|
|
0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
|
|
0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
|
|
0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
|
|
0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
|
|
0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
|
|
0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
|
|
0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
|
|
0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
|
|
0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
|
|
0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
|
|
0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
|
|
0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
|
|
0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
|
|
0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
|
|
0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
|
|
0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
|
|
0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
|
|
0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
|
|
0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
|
|
0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
|
|
0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
|
|
0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
|
|
0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
|
|
0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
|
|
0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
|
|
0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
|
|
0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
|
|
0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
|
|
0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
|
|
0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
|
|
0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
|
|
0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
|
|
0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
|
|
0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
|
|
0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
|
|
0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
|
|
0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
|
|
0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
|
|
0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
|
|
0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
|
|
0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
|
|
0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
|
|
0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
|
|
0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
|
|
0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
|
|
0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
|
|
0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
|
|
0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
|
|
0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
|
|
};
|
|
|
|
/* Function declarations not in any header files */
|
|
|
|
/* forward function declarations */
|
|
|
|
LOCAL STATUS motFecInitParse (DRV_CTRL *pDrvCtrl, char *initString);
|
|
LOCAL STATUS motFecInitMem (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecEncap (DRV_CTRL *pDrvCtrl, M_BLK *pMblk);
|
|
LOCAL STATUS motFecSend (DRV_CTRL *pDrvCtrl, M_BLK *pMblk);
|
|
|
|
LOCAL STATUS motFecPhyInit (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecPhyPreInit (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecReset (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecBdFree (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecRbdInit (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecTbdInit (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecRxCtrlRegValGet (DRV_CTRL *pDrvCtrl, UINT32 * rxCtrlVal);
|
|
LOCAL STATUS motFecTxCtrlRegValGet (DRV_CTRL *pDrvCtrl, UINT32 * txCtrlVal);
|
|
LOCAL STATUS motFecAddrRegValGet (DRV_CTRL *pDrvCtrl, UINT32 * csr0Val,
|
|
UINT32 * csr1Val);
|
|
LOCAL UINT32 motFecCrcGet (char * pAddr);
|
|
LOCAL STATUS motFecHashTblPopulate (DRV_CTRL * pDrvCtrl);
|
|
|
|
LOCAL STATUS motFecPrePhyConfig (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecPostPhyConfig (DRV_CTRL *pDrvCtrl);
|
|
LOCAL void motFecTbdClean (DRV_CTRL *pDrvCtrl);
|
|
LOCAL UINT32 motFecTbdCheck (DRV_CTRL *pDrvCtrl, MOT_FEC_TBD_ID pUsedTbd);
|
|
LOCAL MOT_FEC_TBD_ID motFecTbdGet (DRV_CTRL *pDrvCtrl);
|
|
|
|
LOCAL void motFecInt (DRV_CTRL *pDrvCtrl);
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
LOCAL void motFecDmaInt (DRV_CTRL *pDrvCtrl);
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
LOCAL void motFecRxTxHandle (DRV_CTRL *pDrvCtrl);
|
|
|
|
LOCAL void motFecReceive (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecMiiRead (DRV_CTRL *pDrvCtrl, UINT8 phyAddr,
|
|
UINT8 regAddr, UINT16 *retVal);
|
|
LOCAL STATUS motFecMiiWrite (DRV_CTRL *pDrvCtrl, UINT8 phyAddr,
|
|
UINT8 regAddr, UINT16 writeData);
|
|
|
|
LOCAL STATUS motFecMiiDiag (DRV_CTRL *pDrvCtrl, UINT8 phyAddr);
|
|
LOCAL STATUS motFecMiiIsolate (DRV_CTRL *pDrvCtrl, UINT8 isoPhyAddr);
|
|
|
|
LOCAL STATUS motFecMiiAnRun (DRV_CTRL *pDrvCtrl, UINT8 phyAddr);
|
|
LOCAL STATUS motFecMiiAnStart (DRV_CTRL *pDrvCtrl, UINT8 phyAddr);
|
|
LOCAL STATUS motFecMiiModeForce (DRV_CTRL *pDrvCtrl, UINT8 phyAddr);
|
|
LOCAL STATUS motFecMiiDefForce (DRV_CTRL *pDrvCtrl, UINT8 phyAddr);
|
|
LOCAL STATUS motFecMiiAnCheck (DRV_CTRL *pDrvCtrl, UINT8 phyAddr);
|
|
LOCAL STATUS motFecMiiProbe (DRV_CTRL *pDrvCtrl, UINT8 phyAddr);
|
|
LOCAL void motFecRbdClean (DRV_CTRL *pDrvCtrl,
|
|
volatile MOT_FEC_RBD_ID pRBDNew);
|
|
LOCAL int motRevNumGet (void);
|
|
|
|
/* END Specific interfaces. */
|
|
|
|
END_OBJ * motFecEndLoad (char *initString);
|
|
LOCAL STATUS motFecStart (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecUnload (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecStop (DRV_CTRL *pDrvCtrl);
|
|
LOCAL int motFecIoctl (DRV_CTRL *pDrvCtrl, int cmd, caddr_t data);
|
|
LOCAL STATUS motFecSend (DRV_CTRL *pDrvCtrl, M_BLK_ID pMblk);
|
|
LOCAL STATUS motFecMCastAddrAdd (DRV_CTRL *pDrvCtrl, char* pAddress);
|
|
LOCAL STATUS motFecMCastAddrDel (DRV_CTRL *pDrvCtrl, char* pAddress);
|
|
LOCAL STATUS motFecMCastAddrGet (DRV_CTRL *pDrvCtrl,
|
|
MULTI_TABLE *pTable);
|
|
LOCAL STATUS motFecPollSend (DRV_CTRL *pDrvCtrl, M_BLK_ID pMblk);
|
|
LOCAL STATUS motFecPollReceive (DRV_CTRL *pDrvCtrl, M_BLK_ID pMblk);
|
|
LOCAL STATUS motFecPollStart (DRV_CTRL *pDrvCtrl);
|
|
LOCAL STATUS motFecPollStop (DRV_CTRL *pDrvCtrl);
|
|
|
|
/* globals */
|
|
|
|
FUNCPTR _func_motFecPhyInit = (FUNCPTR) motFecPhyInit;
|
|
FUNCPTR _func_motFecHbFail = (FUNCPTR) NULL;
|
|
|
|
#ifdef MOT_FEC_DBG
|
|
void motFecCsrShow (void);
|
|
void motFecRbdShow (int);
|
|
void motFecTbdShow (int);
|
|
void motFecErrorShow (void);
|
|
void motFecDrvShow (void);
|
|
void motFecMiiShow (void);
|
|
void motFecMibShow (void);
|
|
|
|
#endif /* MOT_FEC_DBG */
|
|
|
|
/*
|
|
* Define the device function table. This is static across all driver
|
|
* instances.
|
|
*/
|
|
|
|
LOCAL NET_FUNCS netFuncs =
|
|
{
|
|
(FUNCPTR) motFecStart, /* start func. */
|
|
(FUNCPTR) motFecStop, /* stop func. */
|
|
(FUNCPTR) motFecUnload, /* unload func. */
|
|
(FUNCPTR) motFecIoctl, /* ioctl func. */
|
|
(FUNCPTR) motFecSend, /* send func. */
|
|
(FUNCPTR) motFecMCastAddrAdd, /* multicast add func. */
|
|
(FUNCPTR) motFecMCastAddrDel, /* multicast delete func. */
|
|
(FUNCPTR) motFecMCastAddrGet, /* multicast get fun. */
|
|
(FUNCPTR) motFecPollSend, /* polling send func. */
|
|
(FUNCPTR) motFecPollReceive, /* polling receive func. */
|
|
endEtherAddressForm, /* put address info into a NET_BUFFER */
|
|
(FUNCPTR) endEtherPacketDataGet, /* get pointer to data in NET_BUFFER */
|
|
(FUNCPTR) endEtherPacketAddrGet /* Get packet addresses */
|
|
};
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecEndLoad - initialize the driver and device
|
|
*
|
|
* This routine initializes both driver and device to an operational state
|
|
* using device specific parameters specified by <initString>.
|
|
*
|
|
* The parameter string, <initString>, is an ordered list of parameters each
|
|
* separated by a colon. The format of <initString> is:
|
|
*
|
|
* "<motCpmAddr>:<ivec>:<bufBase>:<bufSize>:<fifoTxBase>:<fifoRxBase>
|
|
* :<tbdNum>:<rbdNum>:<phyAddr>:<isoPhyAddr>:<phyDefMode>:<userFlags>
|
|
* :<clockSpeed>"
|
|
*
|
|
* The FEC shares a region of memory with the driver. The caller of this
|
|
* routine can specify the address of this memory region, or can specify that
|
|
* the driver must obtain this memory region from the system resources.
|
|
*
|
|
* A default number of transmit/receive buffer descriptors of 32 can be
|
|
* selected by passing zero in the parameters <tbdNum> and <rbdNum>.
|
|
* In other cases, the number of buffers selected should be greater than two.
|
|
*
|
|
* The <bufBase> parameter is used to inform the driver about the shared
|
|
* memory region. If this parameter is set to the constant "NONE," then this
|
|
* routine will attempt to allocate the shared memory from the system. Any
|
|
* other value for this parameter is interpreted by this routine as the address
|
|
* of the shared memory region to be used. The <bufSize> parameter is used
|
|
* to check that this region is large enough with respect to the provided
|
|
* values of both transmit/receive buffer descriptors.
|
|
*
|
|
* If the caller provides the shared memory region, then the driver assumes
|
|
* that this region does not require cache coherency operations, nor does it
|
|
* require conversions between virtual and physical addresses.
|
|
*
|
|
* If the caller indicates that this routine must allocate the shared memory
|
|
* region, then this routine will use cacheDmaMalloc() to obtain
|
|
* some cache-safe memory. The attributes of this memory will be checked,
|
|
* and if the memory is not write coherent, this routine will abort and
|
|
* return NULL.
|
|
*
|
|
* RETURNS: an END object pointer, or NULL on error.
|
|
*
|
|
* SEE ALSO: ifLib,
|
|
* \tb MPC860T Fast Ethernet Controller (Supplement to MPC860 User's Manual)
|
|
*/
|
|
|
|
END_OBJ* motFecEndLoad
|
|
(
|
|
char *initString /* parameter string */
|
|
)
|
|
{
|
|
DRV_CTRL * pDrvCtrl = NULL; /* pointer to DRV_CTRL structure */
|
|
UCHAR enetAddr[6]; /* ethernet address */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("Loading end...\n"), 1, 2, 3, 4, 5, 6);
|
|
|
|
if (initString == NULL)
|
|
return (NULL);
|
|
|
|
if (initString[0] == 0)
|
|
{
|
|
bcopy ((char *)MOT_FEC_DEV_NAME, (void *)initString,
|
|
MOT_FEC_DEV_NAME_LEN);
|
|
return (NULL);
|
|
}
|
|
|
|
/* allocate the device structure */
|
|
|
|
pDrvCtrl = (DRV_CTRL *) calloc (sizeof (DRV_CTRL), 1);
|
|
if (pDrvCtrl == NULL)
|
|
return (NULL);
|
|
|
|
pDrvCtrl->phyInfo = (PHY_INFO *) calloc (sizeof (PHY_INFO), 1);
|
|
if (pDrvCtrl->phyInfo == NULL)
|
|
{
|
|
free ((char *)pDrvCtrl);
|
|
return (NULL);
|
|
}
|
|
|
|
#ifdef MOT_FEC_DBG
|
|
pDrvCtrlDbg = pDrvCtrl;
|
|
#endif /* MOT_FEC_DBG */
|
|
|
|
/* Parse InitString */
|
|
|
|
if (motFecInitParse (pDrvCtrl, initString) == ERROR)
|
|
goto errorExit;
|
|
|
|
pDrvCtrl->ilevel = (int) IVEC_TO_ILEVEL (pDrvCtrl->ivec);
|
|
|
|
/* sanity check the unit number */
|
|
|
|
if (pDrvCtrl->unit < 0 )
|
|
goto errorExit;
|
|
|
|
/* memory initialization */
|
|
|
|
if (motFecInitMem (pDrvCtrl) == ERROR)
|
|
goto errorExit;
|
|
|
|
/* get our ethernet hardware address */
|
|
|
|
if (sysFecEnetAddrGet (pDrvCtrl->unit, enetAddr) == ERROR)
|
|
{
|
|
errnoSet (S_iosLib_INVALID_ETHERNET_ADDRESS);
|
|
goto errorExit;
|
|
}
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecEndLoad: enetAddr= \n\
|
|
0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n "),
|
|
enetAddr[0],
|
|
enetAddr[1],
|
|
enetAddr[2],
|
|
enetAddr[3],
|
|
enetAddr[4],
|
|
enetAddr[5]);
|
|
|
|
/* initialize some flags */
|
|
|
|
pDrvCtrl->loaded = TRUE;
|
|
pDrvCtrl->intrConnect = FALSE;
|
|
|
|
/*
|
|
* create the synchronization semaphores for mii intr handling
|
|
* and for graceful transmit command interrupts.
|
|
*/
|
|
|
|
MOT_FEC_MII_SEM_CREATE;
|
|
MOT_FEC_GRA_SEM_CREATE;
|
|
|
|
/* endObj initializations */
|
|
|
|
if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ*) pDrvCtrl,
|
|
MOT_FEC_DEV_NAME, pDrvCtrl->unit, &netFuncs,
|
|
"Motorola FEC Ethernet Enhanced Network Driver")
|
|
== ERROR)
|
|
goto errorExit;
|
|
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
|
|
if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
|
|
(u_char *) &enetAddr[0], MOT_FEC_ADDR_LEN,
|
|
ETHERMTU, pDrvCtrl->phyInfo->phySpeed) == ERROR)
|
|
goto errorExit;
|
|
|
|
/* Mark the device ready */
|
|
|
|
END_OBJ_READY (&pDrvCtrl->endObj,
|
|
IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecEndLoad... Done \n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
|
|
/*
|
|
* determine the revision number of the processor, and set pinMux
|
|
* bit accordingly
|
|
*/
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
pinMux = 0;
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
if (motRevNumGet () >= REV_D_3)
|
|
pinMux = MOT_FEC_ETH_PINMUX;
|
|
else
|
|
pinMux = 0;
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
return (&pDrvCtrl->endObj);
|
|
|
|
errorExit:
|
|
motFecUnload (pDrvCtrl);
|
|
free ((char *) pDrvCtrl);
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecUnload - unload a driver from the system
|
|
*
|
|
* This routine unloads the driver pointed to by <pDrvCtrl> from the system.
|
|
*
|
|
* RETURNS: OK, always.
|
|
*
|
|
* SEE ALSO: motFecLoad()
|
|
*/
|
|
|
|
LOCAL STATUS motFecUnload
|
|
(
|
|
DRV_CTRL *pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
int ix = 0; /* a counter */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("Unloading end..."), 1, 2, 3, 4, 5, 6);
|
|
|
|
if (pDrvCtrl == NULL)
|
|
return (ERROR);
|
|
|
|
pDrvCtrl->loaded = FALSE;
|
|
|
|
/* free lists */
|
|
|
|
for (ix = 0; ix < pDrvCtrl->tbdNum; ix++)
|
|
{
|
|
cfree ((char *) pDrvCtrl->pTbdList [ix]);
|
|
}
|
|
|
|
END_OBJECT_UNLOAD (&pDrvCtrl->endObj);
|
|
|
|
/* free allocated memory if necessary */
|
|
|
|
if ((MOT_FEC_FLAG_ISSET (MOT_FEC_OWN_MEM)) &&
|
|
(pDrvCtrl->pBufBase != NULL))
|
|
cacheDmaFree (pDrvCtrl->pBufBase);
|
|
|
|
/* free allocated memory if necessary */
|
|
|
|
if ((pDrvCtrl->pMBlkArea) != NULL)
|
|
free (pDrvCtrl->pMBlkArea);
|
|
|
|
/* free the semaphores if necessary */
|
|
|
|
MOT_FEC_MII_SEM_DELETE;
|
|
MOT_FEC_GRA_SEM_DELETE;
|
|
|
|
free (pDrvCtrl->phyInfo);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecUnload... Done\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecInitParse - parse parameter values from initString
|
|
*
|
|
* This routine parses parameter values from initString and stores them in
|
|
* the related fields of the driver control structure.
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
*/
|
|
|
|
LOCAL STATUS motFecInitParse
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
char * initString /* parameter string */
|
|
)
|
|
{
|
|
char * tok; /* an initString token */
|
|
char * holder = NULL; /* points to initString fragment beyond tok */
|
|
|
|
tok = strtok_r (initString, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->unit = atoi (tok);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->motCpmAddr = (UINT32) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->ivec = (int) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->pBufBase = (char *) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->bufSize = strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->fifoTxBase = (UINT32) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->fifoRxBase = (UINT32) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->tbdNum = (UINT16) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->rbdNum = (UINT16) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->phyInfo->phyAddr = (UINT8) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->phyInfo->isoPhyAddr = (UINT8) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->phyInfo->phyDefMode = (UINT8) strtoul (tok, NULL, 16);
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok == NULL)
|
|
return ERROR;
|
|
pDrvCtrl->userFlags = strtoul (tok, NULL, 16);
|
|
|
|
/* start of optional parameters */
|
|
|
|
tok = strtok_r (NULL, ":", &holder);
|
|
if (tok != NULL)
|
|
pDrvCtrl->clockSpeed = atoi (tok);
|
|
|
|
if (!pDrvCtrl->tbdNum || pDrvCtrl->tbdNum <= 2)
|
|
{
|
|
MOT_FEC_FLAG_SET (MOT_FEC_INV_TBD_NUM);
|
|
pDrvCtrl->tbdNum = MOT_FEC_TBD_DEF_NUM;
|
|
}
|
|
|
|
if (!pDrvCtrl->rbdNum || pDrvCtrl->rbdNum <= 2)
|
|
{
|
|
MOT_FEC_FLAG_SET (MOT_FEC_INV_RBD_NUM);
|
|
pDrvCtrl->rbdNum = MOT_FEC_RBD_DEF_NUM;
|
|
}
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD,
|
|
("motFecEndParse: unit=%d motCpmAddr=0x%x ivec=0x%x\n\
|
|
bufBase=0x%x bufSize=0x%x \n"),
|
|
pDrvCtrl->unit,
|
|
(int) pDrvCtrl->motCpmAddr,
|
|
(int) pDrvCtrl->ivec,
|
|
(int) pDrvCtrl->pBufBase,
|
|
pDrvCtrl->bufSize,
|
|
0);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD,
|
|
("motFecEndParse: fifoTxBase=0x%x fifoRxBase=0x%x\n\
|
|
tbdNum=%d rbdNum=%d flags=0x%x\n"),
|
|
pDrvCtrl->fifoTxBase,
|
|
pDrvCtrl->fifoRxBase,
|
|
pDrvCtrl->tbdNum,
|
|
pDrvCtrl->rbdNum,
|
|
pDrvCtrl->userFlags,
|
|
0);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD,
|
|
("motFecEndParse: phyAddr=0x%x isoPhyAddr=0x%x\n\
|
|
phyDefMode=0x%x \n"),
|
|
pDrvCtrl->phyInfo->phyAddr,
|
|
pDrvCtrl->phyInfo->isoPhyAddr,
|
|
pDrvCtrl->phyInfo->phyDefMode,
|
|
0, 0, 0);
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecInitMem - initialize memory
|
|
*
|
|
* This routine initializes all the memory needed by the driver whose control
|
|
* structure is passed in <pDrvCtrl>.
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
*/
|
|
|
|
LOCAL STATUS motFecInitMem
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
UINT32 bdSize; /* temporary size holder */
|
|
UINT32 clSize; /* temporary size holder */
|
|
UINT16 clNum; /* a buffer number holder */
|
|
M_CL_CONFIG mclBlkConfig = {0, 0, NULL, 0};
|
|
/* cluster blocks configuration */
|
|
CL_DESC clDescTbl [] = { {MOT_FEC_MAX_CL_LEN, 0, NULL, 0} };
|
|
/* cluster blocks config table */
|
|
int clDescTblNumEnt = (NELEMENTS (clDescTbl));
|
|
/* number of different clusters */
|
|
|
|
/* initialize the netPool */
|
|
|
|
if ((pDrvCtrl->endObj.pNetPool = malloc (sizeof (NET_POOL))) == NULL)
|
|
return (ERROR);
|
|
|
|
/*
|
|
* we include here room for both TBDs and RBDs,
|
|
* and the alignment factor.
|
|
*/
|
|
|
|
bdSize = (MOT_FEC_BD_MEM (pDrvCtrl));
|
|
|
|
/*
|
|
* Establish the memory area that we will share with the device. If
|
|
* the caller has provided an area, then we assume it is non-cacheable
|
|
* and will not require the use of the special cache routines.
|
|
* If the caller did provide an area, then we must obtain it from
|
|
* the system, using the cache savvy allocation routine.
|
|
*/
|
|
|
|
switch ((int) pDrvCtrl->pBufBase)
|
|
{
|
|
case NONE : /* we must obtain it */
|
|
|
|
/* this driver can't handle write incoherent caches */
|
|
|
|
if (!CACHE_DMA_IS_WRITE_COHERENT ())
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecInitMem: shared \n\
|
|
memory not cache coherent\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
|
|
pDrvCtrl->pBufBase = cacheDmaMalloc (bdSize + MOT_FEC_BD_ALIGN);
|
|
|
|
if (pDrvCtrl->pBufBase == NULL) /* no memory available */
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecInitMem: could not \n\
|
|
obtain memory\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
|
|
pDrvCtrl->pBufBase = (char *) (((UINT32) (pDrvCtrl->pBufBase) +
|
|
MOT_FEC_BD_ALIGN - 1) &
|
|
~(MOT_FEC_BD_ALIGN -1));
|
|
|
|
pDrvCtrl->bufSize = bdSize;
|
|
|
|
MOT_FEC_FLAG_SET (MOT_FEC_OWN_MEM);
|
|
|
|
pDrvCtrl->bdCacheFuncs = cacheDmaFuncs;
|
|
|
|
break;
|
|
|
|
default : /* the user provided an area */
|
|
|
|
if (pDrvCtrl->bufSize == 0)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecInitMem: not enough \n\
|
|
memory\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
|
|
/*
|
|
* check the user provided enough memory with reference
|
|
* to the given number of receive/transmit frames, if any.
|
|
*/
|
|
|
|
if (MOT_FEC_FLAG_ISSET (MOT_FEC_INV_TBD_NUM) &&
|
|
MOT_FEC_FLAG_ISSET (MOT_FEC_INV_RBD_NUM))
|
|
{
|
|
pDrvCtrl->tbdNum = (MOT_FEC_MEM_SZ (pDrvCtrl) /
|
|
(MOT_FEC_TBD_SZ + MOT_FEC_RBD_SZ));
|
|
|
|
pDrvCtrl->rbdNum = pDrvCtrl->tbdNum;
|
|
}
|
|
else if (MOT_FEC_FLAG_ISSET (MOT_FEC_INV_TBD_NUM))
|
|
{
|
|
pDrvCtrl->tbdNum = ((MOT_FEC_MEM_SZ (pDrvCtrl)
|
|
- MOT_FEC_RBD_MEM (pDrvCtrl))
|
|
/ MOT_FEC_TBD_SZ);
|
|
}
|
|
else if (MOT_FEC_FLAG_ISSET (MOT_FEC_INV_RBD_NUM))
|
|
{
|
|
pDrvCtrl->rbdNum = ((MOT_FEC_MEM_SZ (pDrvCtrl)
|
|
- MOT_FEC_TBD_MEM (pDrvCtrl))
|
|
/ MOT_FEC_RBD_SZ);
|
|
}
|
|
else
|
|
{
|
|
if (MOT_FEC_MEM_SZ (pDrvCtrl) < bdSize)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecInitMem: not enough \n\
|
|
memory\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
}
|
|
|
|
if ((pDrvCtrl->tbdNum <= MOT_FEC_TBD_MIN)
|
|
|| (pDrvCtrl->rbdNum <= MOT_FEC_RBD_MIN))
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecInitMem: not enough \n\
|
|
memory\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
|
|
MOT_FEC_FLAG_CLEAR (MOT_FEC_OWN_MEM);
|
|
|
|
pDrvCtrl->bdCacheFuncs = cacheNullFuncs;
|
|
|
|
break;
|
|
}
|
|
|
|
/* cache functions descriptor for data buffers */
|
|
|
|
motFecBufCacheFuncs.flushRtn = motFecBufFlushRtn;
|
|
motFecBufCacheFuncs.invalidateRtn = motFecBufInvRtn;
|
|
motFecBufCacheFuncs.virtToPhysRtn = NULL;
|
|
motFecBufCacheFuncs.physToVirtRtn = NULL;
|
|
|
|
pDrvCtrl->bufCacheFuncs = motFecBufCacheFuncs;
|
|
|
|
/* zero the shared memory */
|
|
|
|
memset (pDrvCtrl->pBufBase, 0, (int) pDrvCtrl->bufSize);
|
|
|
|
/*
|
|
* number of clusters, including loaning buffers, a min number
|
|
* of transmit clusters for copy-mode transmit, and one transmit
|
|
* cluster for polling operation.
|
|
*/
|
|
|
|
clNum = pDrvCtrl->rbdNum + MOT_FEC_BD_LOAN_NUM
|
|
+ 1 + MOT_FEC_TX_CL_NUM;
|
|
|
|
clSize = (MOT_FEC_TX_MEM (pDrvCtrl) + MOT_FEC_RX_MEM (pDrvCtrl)
|
|
+ (CL_OVERHEAD * clNum)
|
|
+ MOT_FEC_BD_ALIGN);
|
|
|
|
/* pool of mblks */
|
|
|
|
if (mclBlkConfig.mBlkNum == 0)
|
|
mclBlkConfig.mBlkNum = clNum * 2;
|
|
|
|
/* pool of clusters, including loaning buffers */
|
|
|
|
if (clDescTbl[0].clNum == 0)
|
|
{
|
|
clDescTbl[0].clNum = clNum;
|
|
clDescTbl[0].clSize = MOT_FEC_MAX_CL_LEN;
|
|
}
|
|
|
|
/* there's a cluster overhead and an alignment issue */
|
|
|
|
clDescTbl[0].memSize = (clDescTbl[0].clNum *
|
|
(clDescTbl[0].clSize + CL_OVERHEAD));
|
|
clDescTbl[0].memArea = (char *) (memalign (CL_ALIGNMENT, clSize));
|
|
|
|
if (clDescTbl[0].memArea == NULL)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
/* store the pointer to the clBlock area */
|
|
|
|
pDrvCtrl->pClBlkArea = clDescTbl[0].memArea;
|
|
pDrvCtrl->clBlkSize = clDescTbl[0].memSize;
|
|
|
|
/* pool of cluster blocks */
|
|
|
|
if (mclBlkConfig.clBlkNum == 0)
|
|
mclBlkConfig.clBlkNum = clDescTbl[0].clNum;
|
|
|
|
/* get memory for mblks */
|
|
|
|
if (mclBlkConfig.memArea == NULL)
|
|
{
|
|
/* memory size adjusted to hold the netPool pointer at the head */
|
|
|
|
mclBlkConfig.memSize = ((mclBlkConfig.mBlkNum
|
|
* (M_BLK_SZ + MBLK_ALIGNMENT))
|
|
+ (mclBlkConfig.clBlkNum
|
|
* (CL_BLK_SZ + CL_ALIGNMENT)));
|
|
|
|
mclBlkConfig.memArea = (char *) memalign (MBLK_ALIGNMENT,
|
|
mclBlkConfig.memSize);
|
|
|
|
if (mclBlkConfig.memArea == NULL)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
/* store the pointer to the mBlock area */
|
|
|
|
pDrvCtrl->pMBlkArea = mclBlkConfig.memArea;
|
|
pDrvCtrl->mBlkSize = mclBlkConfig.memSize;
|
|
}
|
|
|
|
/* init the mem pool */
|
|
|
|
if (netPoolInit (pDrvCtrl->endObj.pNetPool, &mclBlkConfig,
|
|
&clDescTbl[0], clDescTblNumEnt, NULL)
|
|
== ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
if ((pDrvCtrl->pClPoolId = netClPoolIdGet (pDrvCtrl->endObj.pNetPool,
|
|
MOT_FEC_MAX_CL_LEN, FALSE))
|
|
== NULL)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecInitMem... Done\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecStart - start the device
|
|
*
|
|
* This routine starts the FEC device and brings it up to an operational
|
|
* state. The driver must have already been loaded with the motFecEndLoad()
|
|
* routine.
|
|
*
|
|
* RETURNS: OK, or ERROR if the device could not be initialized.
|
|
*
|
|
* \INTERNAL
|
|
* The speed field in the phyInfo structure is only set after the call
|
|
* to the physical layer init routine. On the other hand, the mib2
|
|
* interface is initialized in the motFecEndLoad() routine, and the default
|
|
* value of 10Mbit assumed there is not always correct. We need to
|
|
* correct it here.
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS motFecStart
|
|
(
|
|
DRV_CTRL *pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
int retVal; /* convenient holder for return value */
|
|
char bucket[4];
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START, ("Starting end...\n"), 1, 2, 3, 4, 5, 6);
|
|
|
|
/* must have been loaded */
|
|
|
|
if (!pDrvCtrl->loaded)
|
|
return (ERROR);
|
|
|
|
if (vxMemProbe ((char *) (pDrvCtrl->motCpmAddr + MOT_FEC_CSR_OFF),
|
|
VX_READ, 4, &bucket[0]) != OK)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
(": need MMU mapping for address 0x%x\n"),
|
|
(UINT32) pDrvCtrl->motCpmAddr, 2, 3, 4, 5, 6);
|
|
return (ERROR);
|
|
}
|
|
|
|
/* reset the chip */
|
|
|
|
MOT_FEC_ETH_SET;
|
|
|
|
if (motFecReset (pDrvCtrl) != OK)
|
|
return (ERROR);
|
|
|
|
if (motFecTbdInit (pDrvCtrl) == ERROR)
|
|
return (ERROR);
|
|
|
|
if (motFecRbdInit (pDrvCtrl) == ERROR)
|
|
return (ERROR);
|
|
|
|
/* set some flags to default values */
|
|
|
|
pDrvCtrl->txStall = FALSE;
|
|
pDrvCtrl->tbdIndex = 0;
|
|
pDrvCtrl->usedTbdIndex = 0;
|
|
pDrvCtrl->cleanTbdNum = pDrvCtrl->tbdNum;
|
|
pDrvCtrl->rbdIndex = 0;
|
|
|
|
/* connect the interrupt handler */
|
|
|
|
SYS_FEC_INT_CONNECT (pDrvCtrl, motFecInt, (int) pDrvCtrl, retVal);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/* enable system interrupt: set relevant bit in SIMASK */
|
|
|
|
SYS_FEC_INT_ENABLE (pDrvCtrl, retVal);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/* call the BSP to do any other initialization (port D) */
|
|
|
|
SYS_FEC_ENET_ENABLE;
|
|
|
|
/* configure some chip's registers */
|
|
|
|
if (motFecPrePhyConfig (pDrvCtrl) == ERROR)
|
|
return (ERROR);
|
|
|
|
/* initialize some fields in the PHY info structure */
|
|
|
|
if (motFecPhyPreInit (pDrvCtrl) != OK)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("Failed to pre-initialize the PHY\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
/* initialize the Physical medium layer */
|
|
|
|
if (_func_motFecPhyInit == NULL)
|
|
return (ERROR);
|
|
|
|
if (((* _func_motFecPhyInit) (pDrvCtrl)) != OK)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("Failed to initialize the PHY\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
/* configure other chip's registers */
|
|
|
|
if (motFecPostPhyConfig (pDrvCtrl) == ERROR)
|
|
return (ERROR);
|
|
|
|
/* correct the speed for the mib2 stuff */
|
|
|
|
pDrvCtrl->endObj.mib2Tbl.ifSpeed = pDrvCtrl->phyInfo->phySpeed;
|
|
|
|
if (END_FLAGS_ISSET (IFF_MULTICAST))
|
|
MOT_FEC_FLAG_SET (MOT_FEC_MCAST);
|
|
|
|
/* enable the Ethernet Controller */
|
|
|
|
MOT_FEC_ETH_ENABLE;
|
|
|
|
/* mark the interface as up */
|
|
|
|
END_FLAGS_SET (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
/* startup the receiver */
|
|
|
|
MOT_FEC_RX_ACTIVATE;
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
/* Flush the write pipe */
|
|
|
|
CACHE_PIPE_FLUSH ();
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START, ("Starting end... Done\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecStop - stop the 'motfec' interface
|
|
*
|
|
* This routine marks the interface as inactive, disables interrupts and
|
|
* the Ethernet Controller. As a result, reception is stopped immediately,
|
|
* and transmission is stopped after a bad CRC is appended to any frame
|
|
* currently being transmitted. The reception/transmission control logic
|
|
* (FIFO pointers, buffer descriptors, etc.) is reset. To bring the
|
|
* interface back up, motFecStart() must be called.
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecStop
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
int retVal; /* convenient holder for return value */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecStop...\n"), 1, 2, 3, 4, 5, 6);
|
|
|
|
/* make sure driver is operational before stopping it */
|
|
|
|
if (END_FLAGS_GET(&pDrvCtrl->endObj) & (IFF_UP | IFF_RUNNING))
|
|
{
|
|
|
|
/* mark the interface as down */
|
|
|
|
END_FLAGS_CLR (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
|
|
|
|
/* issue a graceful transmit command */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_TX_CTRL_OFF, MOT_FEC_TX_CTRL_GRA);
|
|
|
|
/* wait for the related interrupt */
|
|
|
|
MOT_FEC_GRA_SEM_TAKE;
|
|
|
|
/* mask chip interrupts */
|
|
|
|
MOT_FEC_INT_DISABLE;
|
|
|
|
/* disable the Ethernet Controller */
|
|
|
|
MOT_FEC_ETH_DISABLE;
|
|
|
|
/* disable system interrupt: reset relevant bit in SIMASK */
|
|
|
|
SYS_FEC_INT_DISABLE (pDrvCtrl, retVal);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/* disconnect the interrupt handler */
|
|
|
|
SYS_FEC_INT_DISCONNECT (pDrvCtrl, motFecInt, (int)pDrvCtrl, retVal);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/* call the BSP to disable the Port D */
|
|
|
|
SYS_FEC_ENET_DISABLE;
|
|
|
|
if (motFecBdFree (pDrvCtrl) != OK)
|
|
return (ERROR);
|
|
|
|
motFecTbdClean (pDrvCtrl);
|
|
}
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_LOAD, ("motFecStop... Done \n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecReset - reset the `motFec' interface
|
|
*
|
|
* This routine resets the chip by setting the Reset bit in the Ethernet
|
|
* Control Register. The ETHER_EN bit is cleared, and all the FEC registers
|
|
* take their default values. In addition, any transmission/reception
|
|
* currently in progress is abruptly aborted.
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecReset
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
/* issue a reset command to the FEC chip */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_CTRL_OFF, (MOT_FEC_ETH_RES | pinMux));
|
|
|
|
/* wait at least 16 clock cycles */
|
|
|
|
taskDelay (1);
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
/* enable the FEC PIN MUX bit if necessary */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_CTRL_OFF, pinMux);
|
|
|
|
/* wait at least 16 clock cycles */
|
|
|
|
taskDelay (1);
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
return (OK);
|
|
}
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
/*******************************************************************************
|
|
*
|
|
* motFecDmaInt - entry point for handling interrupts from the DMA controller
|
|
*
|
|
* RX and TX completion events are signalled by the DMA engine, not the
|
|
* FEC.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
LOCAL void motFecDmaInt
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
|
|
if (pDrvCtrl->handlerQueued == FALSE)
|
|
{
|
|
|
|
/* don't need return from function call */
|
|
|
|
(void) netJobAdd ((FUNCPTR) motFecRxTxHandle, (int) pDrvCtrl,
|
|
0, 0, 0, 0);
|
|
pDrvCtrl->handlerQueued = TRUE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecInt - entry point for handling interrupts from the FEC
|
|
*
|
|
* The interrupting events are acknowledged to the device, so that the device
|
|
* will de-assert its interrupt signal. The amount of work done here is kept
|
|
* to a minimum; the bulk of the work is deferred to the netTask.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
LOCAL void motFecInt
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
UINT32 event = 0; /* event intr register */
|
|
UINT32 mask = 0; /* holder for the mask intr register */
|
|
UINT32 status; /* status word */
|
|
|
|
CACHE_PIPE_FLUSH ();
|
|
|
|
/* read and save the interrupt event register */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_EVENT_OFF, event);
|
|
|
|
/* clear all interrupts */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_EVENT_OFF, (event & MOT_FEC_EVENT_MSK));
|
|
|
|
CACHE_PIPE_FLUSH ();
|
|
|
|
/* read the interrupt mask register */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_MASK_OFF, mask);
|
|
|
|
/* read CSR status word again */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_EVENT_OFF, status);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: event 0x%x, status 0x%x\n"),
|
|
(event & MOT_FEC_EVENT_MSK), status,
|
|
0, 0, 0, 0);
|
|
|
|
/* handle bus error interrupts */
|
|
|
|
if ((event & MOT_FEC_EVENT_BERR) == MOT_FEC_EVENT_BERR)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: bus error, restart chip\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* stop and restart the device
|
|
* don't need return from function call
|
|
*/
|
|
|
|
(void) netJobAdd ((FUNCPTR) motFecStop, (int) pDrvCtrl,
|
|
event, 0, 0, 0);
|
|
|
|
/* don't need return from function call */
|
|
|
|
(void) netJobAdd ((FUNCPTR) motFecStart, (int) pDrvCtrl,
|
|
event, 0, 0, 0);
|
|
}
|
|
|
|
/* handle babbling transmit error interrupts */
|
|
|
|
if ((event & MOT_FEC_EVENT_BABT) == MOT_FEC_EVENT_BABT)
|
|
{
|
|
MOT_FEC_BAB_TX_ADD;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: babbling tx error\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/* handle babbling receive error interrupts */
|
|
|
|
if ((event & MOT_FEC_EVENT_BABR) == MOT_FEC_EVENT_BABR)
|
|
{
|
|
MOT_FEC_BAB_RX_ADD;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: babbling rx error\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/*
|
|
* The Coldfire FEC doesn't have RX and TX completion events
|
|
* in its interrupt register. Those are indicated by separate
|
|
* DMA interrupts.
|
|
*/
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
/* handle transmit and receive interrupts */
|
|
|
|
if ((((event & MOT_FEC_EVENT_TXF) == MOT_FEC_EVENT_TXF)
|
|
&& ((mask & MOT_FEC_EVENT_TXF) == MOT_FEC_EVENT_TXF)) ||
|
|
(((event & MOT_FEC_EVENT_RXF) == MOT_FEC_EVENT_RXF)
|
|
&& ((mask & MOT_FEC_EVENT_RXF) == MOT_FEC_EVENT_RXF)))
|
|
{
|
|
/* disable tx/rx interrupts */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_MASK_OFF, (mask & (~(MOT_FEC_EVENT_TXF
|
|
| MOT_FEC_EVENT_RXF))));
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: tx/rx intr\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/* don't need return from function call */
|
|
|
|
(void) netJobAdd ((FUNCPTR) motFecRxTxHandle, (int) pDrvCtrl,
|
|
0, 0, 0, 0);
|
|
}
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
/* handle heartbeat check fail interrupts */
|
|
|
|
if ((event & MOT_FEC_EVENT_HB) == MOT_FEC_EVENT_HB)
|
|
{
|
|
MOT_FEC_HB_FAIL_ADD;
|
|
|
|
if (_func_motFecHbFail != NULL)
|
|
(* _func_motFecHbFail) (pDrvCtrl);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: heartbeat check fail\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/* handle mii frame completion interrupts */
|
|
|
|
if ((event & MOT_FEC_EVENT_MII) == MOT_FEC_EVENT_MII)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: mii transfer\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/* let the PHY configuration task finish off its job */
|
|
|
|
MOT_FEC_MII_SEM_GIVE;
|
|
}
|
|
|
|
/* handle graceful transmit interrupts */
|
|
|
|
if ((event & MOT_FEC_EVENT_GRA) == MOT_FEC_EVENT_GRA)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_INT, ("motFecInt: graceful transmit\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/* let the Stop task finish off its job */
|
|
|
|
MOT_FEC_GRA_SEM_GIVE;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecEncap - Encapsulate a packet in the TX DMA ring
|
|
*
|
|
* This routine packages up an mBlk chain into the TX DMA ring starting
|
|
* at the first available TX descriptor. If it turns out there aren't enough
|
|
* TX descriptors to hold all the packet fragments, we revert all the
|
|
* changes we made and return error.
|
|
*
|
|
* RETURNS: OK, or ERROR, if no resources are available
|
|
*/
|
|
|
|
#define MOT_FEC_MAX_FRAGS 16
|
|
|
|
LOCAL int motFecEncap
|
|
(
|
|
DRV_CTRL * pDrvCtrl,
|
|
M_BLK_ID pMblk
|
|
)
|
|
{
|
|
MOT_FEC_TBD_ID pTbdFirst, pTbd = NULL;
|
|
M_BLK_ID pCurr;
|
|
UINT32 used, first = pDrvCtrl->tbdIndex;
|
|
UINT32 tbdStatus = 0;
|
|
UINT16 len;
|
|
int ix = 0;
|
|
|
|
/* save the first TBD pointer */
|
|
|
|
pTbdFirst = motFecTbdGet (pDrvCtrl);
|
|
|
|
for (pCurr = pMblk, used = 0; pCurr != NULL; pCurr = pCurr->m_next)
|
|
{
|
|
if (pCurr->m_len != 0)
|
|
{
|
|
if (used == MOT_FEC_MAX_FRAGS || pDrvCtrl->cleanTbdNum == 0)
|
|
break;
|
|
|
|
/* get the current pTbd */
|
|
|
|
pTbd = motFecTbdGet (pDrvCtrl);
|
|
if (pTbd == NULL)
|
|
break;
|
|
|
|
/* Set up len, buffer addr, descriptor flags. */
|
|
|
|
len = pCurr->m_len;
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_LEN_OFF, (UINT32)pCurr->m_len);
|
|
MOT_FEC_BD_LONG_WR (pTbd, MOT_FEC_BD_ADDR_OFF, pCurr->m_data);
|
|
tbdStatus = MOT_FEC_TBD_CRC;
|
|
|
|
MOT_FEC_CACHE_FLUSH (pCurr->m_data, pCurr->m_len);
|
|
|
|
/*
|
|
* Set the ready bit everywhere except the first
|
|
* descriptor.
|
|
*/
|
|
|
|
if (used)
|
|
tbdStatus |= MOT_FEC_TBD_RDY;
|
|
|
|
ix = (int) (pDrvCtrl->tbdIndex);
|
|
|
|
/*
|
|
* Set the 'wrap' bit for the last descriptor in
|
|
* the table.
|
|
*/
|
|
if ((++pDrvCtrl->tbdIndex) == pDrvCtrl->tbdNum)
|
|
{
|
|
tbdStatus |= MOT_FEC_TBD_WRAP;
|
|
pDrvCtrl->tbdIndex = 0;
|
|
}
|
|
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
|
|
used++;
|
|
pDrvCtrl->cleanTbdNum--;
|
|
}
|
|
}
|
|
|
|
if (pCurr != NULL)
|
|
goto noDescs;
|
|
|
|
pDrvCtrl->pTbdList[ix]->pBuf = (UCHAR *)pMblk;
|
|
tbdStatus |= MOT_FEC_TBD_INTERRUPT | MOT_FEC_TBD_LAST;
|
|
if (pMblk->m_pkthdr.len < ETHERSMALL)
|
|
{
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_LEN_OFF,
|
|
len + (ETHERSMALL - pMblk->m_pkthdr.len));
|
|
}
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
MOT_FEC_BD_WORD_RD (pTbdFirst, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
tbdStatus |= MOT_FEC_TBD_RDY;
|
|
MOT_FEC_BD_WORD_WR (pTbdFirst, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
|
|
/* up-date statistics */
|
|
|
|
if (pMblk->m_data[0] & 0x01)
|
|
{
|
|
pDrvCtrl->endObj.mib2Tbl.ifOutNUcastPkts += 1;
|
|
}
|
|
else
|
|
{
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
|
|
}
|
|
|
|
return (OK);
|
|
|
|
noDescs:
|
|
|
|
/*
|
|
* Ran out of descriptors: undo all relevant changes
|
|
* and fall back to copying.
|
|
*/
|
|
|
|
pDrvCtrl->tbdIndex = first;
|
|
for (ix = 0; ix < used; ix++)
|
|
{
|
|
pDrvCtrl->cleanTbdNum++;
|
|
MOT_FEC_NEXT_TBD (pDrvCtrl, pTbd);
|
|
MOT_FEC_BD_WORD_RD (pTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
tbdStatus &= MOT_FEC_TBD_WRAP;
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
MOT_FEC_BD_LONG_WR (pTbd, MOT_FEC_BD_ADDR_OFF, 0);
|
|
pDrvCtrl->tbdIndex = (pDrvCtrl->tbdIndex + 1) % pDrvCtrl->tbdNum;
|
|
}
|
|
pDrvCtrl->tbdIndex = first;
|
|
|
|
return (ERROR);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecSend - send an Ethernet packet
|
|
*
|
|
* This routine() takes a M_BLK_ID and sends off the data in the M_BLK_ID.
|
|
* The buffer must already have the addressing information properly installed
|
|
* in it. This is done by a higher layer.
|
|
*
|
|
* muxSend() calls this routine each time it wants to send a packet.
|
|
*
|
|
* RETURNS: OK, or END_ERR_BLOCK, if no resources are available, or ERROR,
|
|
* if the device is currently working in polling mode.
|
|
*/
|
|
|
|
LOCAL STATUS motFecSend
|
|
(
|
|
DRV_CTRL * pDrvCtrl,
|
|
M_BLK_ID pMblk
|
|
)
|
|
{
|
|
int rval;
|
|
int len;
|
|
M_BLK_ID pTmp;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecSend...\n"), 1, 2, 3, 4, 5, 6);
|
|
|
|
END_TX_SEM_TAKE(&pDrvCtrl->endObj, WAIT_FOREVER);
|
|
|
|
if (pDrvCtrl->txStall == TRUE || pDrvCtrl->cleanTbdNum == 0)
|
|
goto send_block;
|
|
|
|
/*
|
|
* First, try to do an in-place transmission, using
|
|
* gather-write DMA.
|
|
*/
|
|
|
|
rval = motFecEncap (pDrvCtrl, pMblk);
|
|
|
|
/*
|
|
* In-place DMA didn't work, coalesce everything
|
|
* into a single buffer and try again.
|
|
*/
|
|
|
|
if (rval == ERROR)
|
|
{
|
|
if ((pTmp = netTupleGet (pDrvCtrl->endObj.pNetPool,
|
|
MOT_FEC_MAX_CL_LEN, M_DONTWAIT,
|
|
MT_DATA, 0)) == NULL)
|
|
goto send_block;
|
|
|
|
len = netMblkToBufCopy (pMblk, mtod(pTmp, char *), NULL);
|
|
pTmp->m_len = pTmp->m_pkthdr.len = len;
|
|
pTmp->m_flags = pMblk->m_flags;
|
|
netMblkClChainFree (pMblk);
|
|
pMblk = pTmp;
|
|
/* Try transmission again, must succeed this time. */
|
|
rval = motFecEncap (pDrvCtrl, pMblk);
|
|
}
|
|
|
|
if (rval == ERROR)
|
|
goto send_block;
|
|
|
|
/* Issue TX command. */
|
|
|
|
MOT_FEC_TX_ACTIVATE;
|
|
|
|
CACHE_PIPE_FLUSH ();
|
|
|
|
END_TX_SEM_GIVE (&pDrvCtrl->endObj);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecSend...Done\n"), 1, 2, 3, 4, 5, 6);
|
|
|
|
return (OK);
|
|
|
|
send_block:
|
|
|
|
pDrvCtrl->txStall = TRUE;
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
|
|
END_TX_SEM_GIVE (&pDrvCtrl->endObj);
|
|
|
|
return (END_ERR_BLOCK);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* motFecTbdGet - get the first available transmit descriptor
|
|
*
|
|
* This routine gets the first available buffer descriptor in the transmit
|
|
* ring. It checks the descriptor is owned by the host and it has been
|
|
* cleaned by the motFecTbdClean() routine.
|
|
*
|
|
* RETURNS: an available transmit descriptor, otherwise NULL.
|
|
*/
|
|
|
|
LOCAL MOT_FEC_TBD_ID motFecTbdGet
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
MOT_FEC_TBD_ID nextTbd = NULL; /* holder for the next TBD */
|
|
UINT16 tbdStatus; /* holder for the TBD status */
|
|
|
|
MOT_FEC_NEXT_TBD (pDrvCtrl, nextTbd);
|
|
|
|
MOT_FEC_BD_WORD_RD ((char *) nextTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
|
|
if ((tbdStatus & MOT_FEC_TBD_RDY) == MOT_FEC_TBD_RDY)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecSend... not our Tbd \n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
return (NULL);
|
|
}
|
|
|
|
return ((MOT_FEC_TBD_ID) nextTbd);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* motFecTbdClean - clean the transmit buffer descriptors ring
|
|
*
|
|
* This routine is run in netTask's context. It cleans the transmit
|
|
* buffer descriptors ring. It also calls motFecTbdCheck() to check
|
|
* for any transmit errors, and possibly up-dates statistics.
|
|
*
|
|
* SEE ALSO: motFecTbdCheck()
|
|
*
|
|
* RETURNS: N/A.
|
|
*/
|
|
|
|
LOCAL void motFecTbdClean
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
MOT_FEC_TBD_ID pUsedTbd; /* first used TBD */
|
|
UINT32 retVal = 0; /* return value */
|
|
M_BLK_ID pMblk;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecTbdClean\n"), 1, 2, 3, 4, 5, 6);
|
|
|
|
END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
|
|
|
|
/* process all the consumed TBDs */
|
|
|
|
while (pDrvCtrl->cleanTbdNum < pDrvCtrl->tbdNum)
|
|
{
|
|
MOT_FEC_USED_TBD (pDrvCtrl, pUsedTbd);
|
|
retVal = motFecTbdCheck (pDrvCtrl, pUsedTbd);
|
|
if (retVal == MOT_FEC_TBD_BUSY)
|
|
break;
|
|
if (retVal == MOT_FEC_TBD_ERROR)
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
|
|
pMblk = (M_BLK_ID)pDrvCtrl->pTbdList[pDrvCtrl->usedTbdIndex]->pBuf;
|
|
if (pMblk != NULL)
|
|
{
|
|
netMblkClChainFree (pMblk);
|
|
pDrvCtrl->pTbdList[pDrvCtrl->usedTbdIndex]->pBuf = NULL;
|
|
}
|
|
|
|
pDrvCtrl->cleanTbdNum++;
|
|
pDrvCtrl->usedTbdIndex = (pDrvCtrl->usedTbdIndex + 1)
|
|
% (pDrvCtrl->tbdNum);
|
|
}
|
|
|
|
if (pDrvCtrl->cleanTbdNum && pDrvCtrl->txStall == TRUE)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("Restart mux \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
(void) netJobAdd ((FUNCPTR) muxTxRestart,
|
|
(int) &pDrvCtrl->endObj, 0, 0, 0, 0);
|
|
|
|
pDrvCtrl->txStall = FALSE;
|
|
}
|
|
|
|
END_TX_SEM_GIVE (&pDrvCtrl->endObj);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecTbdClean...Done\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* motFecTbdCheck - check the transmit buffer descriptor
|
|
*
|
|
* This routine checks for any transmit errors by looking at the
|
|
* descriptor status.
|
|
*
|
|
* SEE ALSO: motFecTbdClean()
|
|
*
|
|
* RETURNS: MOT_FEC_TBD_OK, or MOT_FEC_TBD_BUSY if the specified TBD is
|
|
* not ready, or MOT_FEC_TBD_ERROR in case of errored TBD.
|
|
*/
|
|
|
|
LOCAL UINT32 motFecTbdCheck
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
MOT_FEC_TBD_ID pUsedTbd /* holder for the first used TBD */
|
|
)
|
|
{
|
|
UINT16 tbdStatus; /* holder for the TBD status */
|
|
|
|
MOT_FEC_BD_WORD_RD ((char *) pUsedTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
|
|
/* if it's not ready, don't touch it! */
|
|
|
|
if ((tbdStatus & MOT_FEC_TBD_RDY) == MOT_FEC_TBD_RDY)
|
|
{
|
|
return (MOT_FEC_TBD_BUSY);
|
|
}
|
|
|
|
#ifdef MOT_FEC_DBG
|
|
|
|
if ((tbdStatus & MOT_FEC_TBD_LC) == MOT_FEC_TBD_LC)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecTbdCheck: late collision\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
MOT_FEC_TX_LC_ADD;
|
|
}
|
|
|
|
if ((tbdStatus & MOT_FEC_TBD_RL) == MOT_FEC_TBD_RL)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecTbdCheck: retransmit limit"),
|
|
1, 2, 3, 4, 5, 6);
|
|
MOT_FEC_TX_RL_ADD;
|
|
}
|
|
|
|
if ((tbdStatus & MOT_FEC_TBD_UN) == MOT_FEC_TBD_UN)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecTbdCheck: tx underrun\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
MOT_FEC_TX_UR_ADD;
|
|
}
|
|
|
|
if ((tbdStatus & MOT_FEC_TBD_CSL) == MOT_FEC_TBD_CSL)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_TX, ("motFecTbdCheck: carrier sense \n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
MOT_FEC_TX_CSL_ADD;
|
|
}
|
|
#endif /* MOT_FEC_DBG */
|
|
|
|
/* in case of errors, report it to the calling routine */
|
|
|
|
if (tbdStatus & (MOT_FEC_TBD_LC |
|
|
MOT_FEC_TBD_RL |
|
|
MOT_FEC_TBD_UN |
|
|
MOT_FEC_TBD_CSL))
|
|
{
|
|
return (MOT_FEC_TBD_ERROR);
|
|
}
|
|
|
|
return (MOT_FEC_TBD_OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecTbdInit - initialize the transmit buffer ring
|
|
*
|
|
* This routine initializes the transmit buffer descriptors ring.
|
|
*
|
|
* SEE ALSO: motFecRbdInit()
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecTbdInit
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
UINT16 ix; /* a counter */
|
|
MOT_FEC_TBD_ID pTbd; /* generic TBD pointer */
|
|
|
|
/* carve up the shared-memory region */
|
|
|
|
pDrvCtrl->tbdBase = pTbd = (MOT_FEC_TBD_ID) pDrvCtrl->pBufBase;
|
|
|
|
for (ix = 0; ix < pDrvCtrl->tbdNum; ix++)
|
|
{
|
|
/*
|
|
* put a fragment of each frame in a single buffer and
|
|
* generate the 4-byte CRC at the end of each frame.
|
|
* Do not make it ready for transmission yet.
|
|
*/
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF, MOT_FEC_TBD_INTERRUPT);
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF, 0);
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
pTbd += MOT_FEC_TBD_SZ;
|
|
|
|
/* get memory for the TBD list */
|
|
|
|
pDrvCtrl->pTbdList [ix] = (MOT_FEC_TBD_LIST_ID)
|
|
calloc (sizeof (MOT_FEC_TBD_LIST), 1);
|
|
}
|
|
|
|
/* have the last TBD to close the ring */
|
|
|
|
pTbd -= MOT_FEC_TBD_SZ;
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF,
|
|
(MOT_FEC_TBD_WRAP | MOT_FEC_TBD_INTERRUPT));
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF,
|
|
(MOT_FEC_TBD_WRAP | 0));
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/* get a cluster buffer from the pool */
|
|
|
|
pDrvCtrl->pTxPollBuf = (UINT8 *)NET_BUF_ALLOC();
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* motFecRxTxHandle - service task-level interrupts for rx and tx frames
|
|
*
|
|
* This routine is run in netTask's context. The ISR scheduled
|
|
* this routine so that it could handle receive and transmit packets
|
|
* at task level.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
LOCAL void motFecRxTxHandle
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
int intLevel; /* current intr level */
|
|
UINT32 event = 0; /* event intr register */
|
|
UINT32 mask = 0; /* holder for the mask intr register */
|
|
#endif
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecRxTxHandle: \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/* while tx/rx interrupts to be processed */
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
motFecRxTxProcess:
|
|
#endif
|
|
|
|
motFecReceive (pDrvCtrl);
|
|
|
|
motFecTbdClean (pDrvCtrl);
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
intLevel = intLock();
|
|
|
|
/*
|
|
* This piece of code is to deal with any events that have occurred
|
|
* since the events were masked off in the ISR. These events will
|
|
* have occurred but no interrupt would have been generated.
|
|
*
|
|
* Note that this is only needed on the PPC FEC. On the Coldfire,
|
|
* RX and TX events come from the DMA controller and are handled
|
|
* differently.
|
|
*/
|
|
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_EVENT_OFF, event);
|
|
|
|
/* clear all interrupts */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_EVENT_OFF, (event & MOT_FEC_EVENT_MSK));
|
|
|
|
if (((event & MOT_FEC_EVENT_TXF) == MOT_FEC_EVENT_TXF) ||
|
|
((event & MOT_FEC_EVENT_RXF) == MOT_FEC_EVENT_RXF))
|
|
{
|
|
intUnlock (intLevel);
|
|
goto motFecRxTxProcess;
|
|
}
|
|
else
|
|
{
|
|
/* re-enable receive and transmit interrupts */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_MASK_OFF, mask);
|
|
MOT_FEC_CSR_WR (MOT_FEC_MASK_OFF, (mask | MOT_FEC_EVENT_TXF
|
|
| MOT_FEC_EVENT_RXF));
|
|
/* Flush the write pipe */
|
|
|
|
CACHE_PIPE_FLUSH ();
|
|
|
|
intUnlock (intLevel);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* motFecReceive - pass a received frame to the next layer up
|
|
*
|
|
* This routine hands the packet off to the upper layer after cleaning the
|
|
* RBD that was used for its reception.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
#define MOT_FEC_MAX_RX 16
|
|
|
|
LOCAL void motFecReceive
|
|
(
|
|
DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
MOT_FEC_RBD_ID pRbd;
|
|
UINT16 rbdStatus, rbdLength;
|
|
int loopCounter = MOT_FEC_MAX_RX;
|
|
M_BLK_ID pMblk; /* MBLK to send upstream */
|
|
M_BLK_ID pNewMblk; /* MBLK to replace pMblk */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive rbdIndex=%d\n"),
|
|
pDrvCtrl->rbdIndex, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_NEXT_RBD (pDrvCtrl, pRbd);
|
|
MOT_FEC_BD_WORD_RD (pRbd, MOT_FEC_BD_STAT_OFF, rbdStatus);
|
|
|
|
while (loopCounter && !(rbdStatus & MOT_FEC_RBD_EMPTY))
|
|
{
|
|
|
|
if (rbdStatus & MOT_FEC_RBD_ERR)
|
|
goto skip;
|
|
|
|
/*
|
|
* Try to conjure up a new mBlk tuple to replace the one
|
|
* we're about to loan out. If that fails, leave the
|
|
* old one in place and reset the descriptor to allow
|
|
* a new packet to be received.
|
|
*/
|
|
|
|
pNewMblk = netTupleGet (pDrvCtrl->endObj.pNetPool,
|
|
MOT_FEC_MAX_CL_LEN, M_DONTWAIT, MT_DATA, 0);
|
|
|
|
if (pNewMblk == NULL)
|
|
{
|
|
skip:
|
|
pDrvCtrl->rbdIndex = (pDrvCtrl->rbdIndex + 1) % (pDrvCtrl->rbdNum);
|
|
rbdStatus |= MOT_FEC_RBD_EMPTY | MOT_FEC_RBD_INTERRUPT;
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_LEN_OFF, MOT_FEC_RX_BUF_SZ);
|
|
#else
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_LEN_OFF, 0);
|
|
#endif
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF, rbdStatus);
|
|
goto do_next;
|
|
}
|
|
|
|
pMblk = (M_BLK_ID)pDrvCtrl->rxBuf[pDrvCtrl->rbdIndex];
|
|
pDrvCtrl->rxBuf[pDrvCtrl->rbdIndex] = (UCHAR *)pNewMblk;
|
|
|
|
MOT_FEC_BD_WORD_RD (pRbd, MOT_FEC_BD_LEN_OFF, rbdLength);
|
|
|
|
pMblk->m_len = (rbdLength & ~0xc000) - ETHER_CRC_LEN;
|
|
pMblk->m_pkthdr.len = pMblk->m_len;
|
|
pMblk->m_flags = M_PKTHDR|M_EXT;
|
|
MOT_FEC_CACHE_INVAL (pMblk->m_data, pMblk->m_pkthdr.len);
|
|
|
|
pNewMblk->m_data = (char *)NET_TO_MOT_FEC_BUF (pNewMblk->m_data);
|
|
MOT_FEC_BD_LONG_WR (pRbd, MOT_FEC_BD_ADDR_OFF, pNewMblk->m_data);
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_LEN_OFF, MOT_FEC_RX_BUF_SZ);
|
|
#else
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_LEN_OFF, 0);
|
|
#endif
|
|
|
|
if (pMblk->m_data[0] & (UINT8) 0x01)
|
|
pDrvCtrl->endObj.mib2Tbl.ifInNUcastPkts += 1;
|
|
else
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
|
|
|
|
/* Update rbdIndex before passing the packet up the stack. */
|
|
|
|
pDrvCtrl->rbdIndex = (pDrvCtrl->rbdIndex + 1) % (pDrvCtrl->rbdNum);
|
|
rbdStatus |= MOT_FEC_RBD_EMPTY | MOT_FEC_RBD_INTERRUPT;
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF, rbdStatus);
|
|
|
|
END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk);
|
|
|
|
do_next:
|
|
|
|
loopCounter--;
|
|
MOT_FEC_NEXT_RBD (pDrvCtrl, pRbd);
|
|
MOT_FEC_BD_WORD_RD (pRbd, MOT_FEC_BD_STAT_OFF, rbdStatus);
|
|
}
|
|
|
|
/*
|
|
* If we exceeded our work quota, queue ourselves up for
|
|
* another round of processing. Otherwise, re-enable interrupts
|
|
* and just bail.
|
|
*/
|
|
|
|
if (loopCounter == 0)
|
|
{
|
|
|
|
/* don't need return from function call */
|
|
|
|
(void) netJobAdd ((FUNCPTR) motFecRxTxHandle, (int) pDrvCtrl,
|
|
0, 0, 0, 0);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Note: we must clear the rxJobQued flag _before_ resuming
|
|
* the RX DMA channel to avoid a race condition. If the RX
|
|
* DMA ring has been completely filled, the RX DMA channel will
|
|
* stall. When this happens, we must restart it (after processing
|
|
* all the packets in the ring). But if traffic is still arriving
|
|
* when we restart the channel, an interrupt may occur immediately,
|
|
* and the interrupt handler will fire. If the rxJobQued flag is
|
|
* still set when the handler runs, it won't bother to queue the
|
|
* RX handler back up again. If traffic continues to arrive, the
|
|
* the ring will fill up again and interrupts will stop, and since
|
|
* rxJobQued flag prevented the receive handler from being queued
|
|
* up, receive processing will never occur again.
|
|
*/
|
|
|
|
pDrvCtrl->handlerQueued = FALSE;
|
|
|
|
MOT_FEC_RX_ACTIVATE;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive... Done, \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecRbdClean - clean a receive buffer descriptor
|
|
*
|
|
* This routine cleans a receive buffer descriptor and initializes it
|
|
* with the data pointer <pBuf>.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
*/
|
|
|
|
LOCAL void motFecRbdClean
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
char * pBuf /* pointer to a new data buffer */
|
|
)
|
|
{
|
|
MOT_FEC_RBD_ID pUsedRbd; /* pointer to a RBD */
|
|
|
|
/* get the first used RBD */
|
|
|
|
MOT_FEC_NEXT_RBD (pDrvCtrl, pUsedRbd);
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_LEN_OFF, MOT_FEC_RX_BUF_SZ);
|
|
|
|
/* up-date the status word: treat the last RBD in the ring differently */
|
|
|
|
if ((pDrvCtrl->rbdIndex) == (pDrvCtrl->rbdNum - 1))
|
|
{
|
|
MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_STAT_OFF,
|
|
(MOT_FEC_RBD_WRAP | MOT_FEC_RBD_EMPTY | MOT_FEC_RBD_INTERRUPT));
|
|
}
|
|
else
|
|
{
|
|
MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_STAT_OFF,
|
|
MOT_FEC_RBD_EMPTY | MOT_FEC_RBD_INTERRUPT);
|
|
}
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_LEN_OFF, 0);
|
|
|
|
/* up-date the status word: treat the last RBD in the ring differently */
|
|
|
|
if ((pDrvCtrl->rbdIndex) == (pDrvCtrl->rbdNum - 1))
|
|
{
|
|
MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_STAT_OFF,
|
|
(MOT_FEC_RBD_WRAP | MOT_FEC_RBD_EMPTY));
|
|
}
|
|
else
|
|
{
|
|
MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_STAT_OFF,
|
|
MOT_FEC_RBD_EMPTY);
|
|
}
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/* let's move on to the next used RBD */
|
|
|
|
pDrvCtrl->rbdIndex = (pDrvCtrl->rbdIndex + 1) % (pDrvCtrl->rbdNum);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecRbdClean... Done, \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecRbdInit - initialize the receive buffer ring
|
|
*
|
|
* This routine initializes the receive buffer descriptors ring.
|
|
*
|
|
* SEE ALSO: motFecTbdInit()
|
|
*
|
|
* RETURNS: OK, or ERROR if not enough clusters were available.
|
|
*/
|
|
|
|
LOCAL STATUS motFecRbdInit
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
MOT_FEC_RBD_ID pRbd = NULL; /* generic rbd pointer */
|
|
UINT16 ix; /* a counter */
|
|
M_BLK_ID pMblk;
|
|
|
|
/* the receive ring is located right after the transmit one */
|
|
|
|
pDrvCtrl->rbdBase = pRbd = (MOT_FEC_RBD_ID) (pDrvCtrl->pBufBase
|
|
+ MOT_FEC_TBD_MEM (pDrvCtrl));
|
|
|
|
for (ix = 0; ix < pDrvCtrl->rbdNum; ix++)
|
|
{
|
|
/* get a cluster buffer from the pool */
|
|
|
|
pMblk = netTupleGet (pDrvCtrl->endObj.pNetPool,
|
|
MOT_FEC_MAX_CL_LEN, M_DONTWAIT, MT_DATA, 0);
|
|
|
|
if (pMblk == NULL)
|
|
return (ERROR);
|
|
|
|
/*
|
|
* fill each buffer with an entire frame and make it available
|
|
* for the receiver. Do not activate the receiver yet.
|
|
*/
|
|
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF,
|
|
MOT_FEC_RBD_EMPTY | MOT_FEC_RBD_INTERRUPT);
|
|
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_LEN_OFF, MOT_FEC_RX_BUF_SZ);
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF,
|
|
MOT_FEC_RBD_EMPTY);
|
|
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_LEN_OFF, 0);
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/*
|
|
* what we need to do here is to save the cluster pointer
|
|
* for use by the net pool later. We won't be using that
|
|
* cluster as is, because the FEC requires receive buffers
|
|
* being aligned by 16. So we move that cluster pointer to
|
|
* the next 16-byte aligned boundary, and program the chip
|
|
* with that value. When we receive the packet, we'll have
|
|
* to join the saved cluster pointer to the mBlk.
|
|
*/
|
|
|
|
pDrvCtrl->rxBuf [ix] = (UCHAR *) pMblk;
|
|
|
|
pMblk->m_data = (char *)NET_TO_MOT_FEC_BUF (pMblk->m_data);
|
|
MOT_FEC_BD_LONG_WR (pRbd, MOT_FEC_BD_ADDR_OFF, pMblk->m_data);
|
|
|
|
/* move on to the next RBD */
|
|
|
|
pRbd += MOT_FEC_RBD_SZ;
|
|
}
|
|
|
|
/* have the last RBD to close the ring */
|
|
|
|
pRbd -= MOT_FEC_RBD_SZ;
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF,
|
|
(MOT_FEC_RBD_WRAP | MOT_FEC_RBD_EMPTY| MOT_FEC_RBD_INTERRUPT));
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF,
|
|
(MOT_FEC_RBD_WRAP | MOT_FEC_RBD_EMPTY));
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecBdFree - free the receive buffers
|
|
*
|
|
* This routine frees the netpool clusters associated with the receive
|
|
* buffer descriptors ring. It is called by motFecStop(), in order to
|
|
* properly release the driver's resources when the device is stopped.
|
|
*
|
|
* SEE ALSO: motFecStop()
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecBdFree
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
MOT_FEC_RBD_ID pRbd = NULL; /* generic rbd pointer */
|
|
UINT16 ix; /* a counter */
|
|
|
|
pRbd = (MOT_FEC_RBD_ID) (pDrvCtrl->rbdBase);
|
|
|
|
for (ix = 0; ix < pDrvCtrl->rbdNum; ix++)
|
|
{
|
|
/* return the cluster buffer to the pool */
|
|
|
|
if ((pDrvCtrl->rxBuf [ix]) != NULL)
|
|
netMblkClChainFree ((M_BLK_ID)(pDrvCtrl->rxBuf [ix]));
|
|
|
|
pRbd += MOT_FEC_RBD_SZ;
|
|
}
|
|
|
|
/* free the transmit poll buffer */
|
|
|
|
if ((pDrvCtrl->pTxPollBuf) != NULL)
|
|
NET_BUF_FREE ((UCHAR *) (pDrvCtrl->pTxPollBuf));
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecPrePhyConfig - configure the chip before the PHY is initialized
|
|
*
|
|
* This routine programs all the CSRs that are not concerned with the
|
|
* PHY configuration. It follows closely but not entirely the
|
|
* initialization sequence recommended in the FEC User's Manual.
|
|
*
|
|
* SEE ALSO: motFecPostPhyConfig()
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecPrePhyConfig
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
UINT32 csrVal = 0; /* holder for the CSR value */
|
|
UINT32 csr0Val = 0; /* holder for the CSR0 value */
|
|
UINT32 csr1Val = 0; /* holder for the CSR1 value */
|
|
static BOOL first = TRUE; /* first initialization */
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
UINT32 miiSpeed; /* calculated value for MII_SPEED */
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
/*
|
|
* we enable the following event interrupts:
|
|
* heartbeat check fail, only if the user requested it;
|
|
* tx and rx babbling errors;
|
|
* tx and rx frame completion;
|
|
* graceful transmit command;
|
|
* mii management interface frame completion;
|
|
* U-bus access error.
|
|
*/
|
|
|
|
if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_HBC))
|
|
{
|
|
csrVal |= MOT_FEC_EVENT_HB;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecPrePhyConfig: heartbeat control \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
csrVal &= ~MOT_FEC_EVENT_HB;
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
csrVal |= (MOT_FEC_EVENT_GRA | MOT_FEC_EVENT_MII |
|
|
MOT_FEC_EVENT_BABR | MOT_FEC_EVENT_BABT |
|
|
MOT_FEC_EVENT_BERR);
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
csrVal |= (MOT_FEC_EVENT_GRA | MOT_FEC_EVENT_MII | MOT_FEC_EVENT_TXF |
|
|
MOT_FEC_EVENT_RXF | MOT_FEC_EVENT_BABR | MOT_FEC_EVENT_BABT |
|
|
MOT_FEC_EVENT_BERR);
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_MASK_OFF, csrVal);
|
|
|
|
/* save the interrupt mask register */
|
|
|
|
pDrvCtrl->intMask = csrVal;
|
|
|
|
/* clear all interrupts */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_EVENT_OFF, MOT_FEC_EVENT_MSK);
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
/* set the interrupt level */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_VEC_OFF, (pDrvCtrl->ilevel << MOT_FEC_LVL_SHIFT));
|
|
|
|
if (pDrvCtrl->fifoTxBase != (UINT32)NONE)
|
|
MOT_FEC_CSR_WR (MOT_FEC_TX_FIFO_OFF, pDrvCtrl->fifoTxBase);
|
|
|
|
if (pDrvCtrl->fifoRxBase != (UINT32)NONE)
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_FIFO_OFF, pDrvCtrl->fifoRxBase);
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
/* program the individual enet address */
|
|
|
|
if (motFecAddrRegValGet (pDrvCtrl, &csr0Val, &csr1Val) != OK)
|
|
return (ERROR);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_ADDR_L_OFF, csr0Val);
|
|
MOT_FEC_CSR_WR (MOT_FEC_ADDR_H_OFF, csr1Val);
|
|
|
|
/* reset the hash table */
|
|
/* question: does muxDevStop/Start re-init the multi table? */
|
|
|
|
if (first)
|
|
{
|
|
first = FALSE;
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_L_OFF, 0);
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_H_OFF, 0);
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
MOT_FEC_CSR_WR (MOT_FEC_IAHASH_L_OFF, 0);
|
|
MOT_FEC_CSR_WR (MOT_FEC_IAHASH_H_OFF, 0);
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
}
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
|
|
|
|
/*
|
|
* The MII clock speed is derived from the following formula.
|
|
*
|
|
* MII_SPEED = Fsys / (2 * Femdc) = Fsys / 5 MHz
|
|
*
|
|
* Femdc = 2.5 MHz.
|
|
*/
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_MII_SPEED_OFF,
|
|
((pDrvCtrl->clockSpeed / 5000000) << 1));
|
|
|
|
{
|
|
UINT32 csrOldVal;
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_CTRL_OFF, csrOldVal);
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_CTRL_OFF,
|
|
((csrOldVal & 0x0000ffff) | (1518<<16)));
|
|
}
|
|
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/*
|
|
* if no clock speed is defined, assume a clock speed of 50 MHz.
|
|
* Otherwise, derive the MII clock speed according to the formula
|
|
* MII_SPEED = ceil(pDrvCtrl->clockSpeed / (2 * MII_CLOCK_MAX))
|
|
*/
|
|
|
|
if (pDrvCtrl->clockSpeed == 0)
|
|
miiSpeed = MOT_FEC_MII_SPEED_50;
|
|
else
|
|
miiSpeed = (pDrvCtrl->clockSpeed + (2 * MOT_FEC_MII_CLOCK_MAX) - 1) /
|
|
(2 * MOT_FEC_MII_CLOCK_MAX);
|
|
|
|
/* MII_SPEED is left-shifted in the MII_SPEED register */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_MII_SPEED_OFF, miiSpeed << MOT_FEC_MII_SPEED_SHIFT);
|
|
|
|
/* program the max receive buffer length */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_BUF_OFF, MOT_FEC_MAX_RX_BUF);
|
|
|
|
/* program the receive and transmit rings registers */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_START_OFF, (UINT32) (pDrvCtrl->rbdBase));
|
|
MOT_FEC_CSR_WR (MOT_FEC_TX_START_OFF, (UINT32) (pDrvCtrl->tbdBase));
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_SDMA_OFF, MOT_FEC_SDMA_DATA_BE |
|
|
MOT_FEC_SDMA_BD_BE |
|
|
MOT_FEC_SDMA_FUNC_0);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_FR_OFF, MOT_FEC_BUF_V_LEN);
|
|
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
return (OK);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecPostPhyConfig - configure the chip after the PHY is initialized
|
|
*
|
|
* This routine programs all the CSRs that are concerned with the
|
|
* PHY configuration.
|
|
*
|
|
* SEE ALSO: motFecPrePhyConfig()
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecPostPhyConfig
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
UINT32 rxCtrlVal; /* holder for the rx CSR value */
|
|
UINT32 txCtrlVal; /* holder for the tx CSR value */
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
UINT32 csrOldVal;
|
|
|
|
/*
|
|
* Program Rx Control Register. All other bits besides Max frame length
|
|
* MAX frame length was programmed in PrePhyConfig
|
|
*/
|
|
if (motFecRxCtrlRegValGet (pDrvCtrl, &rxCtrlVal) == ERROR)
|
|
return (ERROR);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_CTRL_OFF, csrOldVal);
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_CTRL_OFF,
|
|
((csrOldVal & 0xffff0000) | rxCtrlVal));
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_CTRL_OFF, csrOldVal);
|
|
|
|
/*
|
|
* Set Rx FIFO granularity
|
|
*/
|
|
rxCtrlVal = MOT_FEC_RFCR_FRMEN | MOT_FEC_RFCR_RXWMSK
|
|
| MOT_FEC_TFCR_GR(7);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_RFCR_OFF, rxCtrlVal);
|
|
MOT_FEC_CSR_RD (MOT_FEC_RFCR_OFF, csrOldVal);
|
|
|
|
|
|
/*Set Rx FIFO Alarm register*/
|
|
MOT_FEC_CSR_WR (MOT_FEC_RFAR_OFF, MOT_FEC_RFAR(768));
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_RFAR_OFF, csrOldVal);
|
|
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/* get the proper value for the rx CSR and program it accordingly */
|
|
|
|
if (motFecRxCtrlRegValGet (pDrvCtrl, &rxCtrlVal) == ERROR)
|
|
return (ERROR);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_CTRL_OFF, rxCtrlVal);
|
|
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/*
|
|
* get the proper value for the tx CSR and program it accordingly.
|
|
* At this point we do not have to check whether the FEC is
|
|
* active, as we already know.
|
|
*/
|
|
|
|
if (motFecTxCtrlRegValGet (pDrvCtrl, &txCtrlVal) == ERROR)
|
|
return (ERROR);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_TX_CTRL_OFF, txCtrlVal);
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
|
|
/* Program the TX FIFO Watermark */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_TFWR_OFF, MOT_FEC_TFWR_X_WMRK_256);
|
|
|
|
/* Program the TX FIFO Alarm */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_TFAR_OFF, MOT_FEC_TFAR(512));
|
|
|
|
txCtrlVal = MOT_FEC_TFCR_FRMEN | MOT_FEC_TFCR_TXWMSK
|
|
| MOT_FEC_TFCR_GR(7);
|
|
|
|
/*
|
|
* Program the TX FIFO Control register
|
|
* Set granularity and frame enable bits
|
|
*/
|
|
MOT_FEC_CSR_WR (MOT_FEC_TFCR_OFF, txCtrlVal);
|
|
|
|
/*
|
|
* Enable the transmitter to append the CRC
|
|
*/
|
|
MOT_FEC_CSR_WR (MOT_FEC_CTCWR_OFF,
|
|
(MOT_FEC_CTCWR_TFCW | MOT_FEC_CTCWR_CRC));
|
|
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
#ifdef notdef
|
|
/*
|
|
* disable the MII management interface, as we do not
|
|
* need to change the MII setting at any time.
|
|
*
|
|
* Wrong. We may need to touch the PHYs later.
|
|
*/
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_MII_SPEED_OFF, MOT_FEC_MII_MAN_DIS);
|
|
#endif
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecRxCtrlRegValGet - get the proper value for the receive CSR
|
|
*
|
|
* This routine finds out the proper value to be programmed in the
|
|
* receive CSR by looking at some of the user/driver flags. It deals
|
|
* with options like promiscuous mode, full duplex, loopback and
|
|
* the physical serial interface.
|
|
*
|
|
* This routine does not program the receive CSR.
|
|
*
|
|
* SEE ALSO: motFecTxCtrlRegValGet(), motFecPostPhyConfig()
|
|
*
|
|
* RETURNS: OK or ERROR if rxCtrlVal is NULL pointer.
|
|
*/
|
|
|
|
LOCAL STATUS motFecRxCtrlRegValGet
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT32 * rxCtrlVal /* holder for the rx CSR value */
|
|
)
|
|
{
|
|
|
|
/* Initialize holder for the rx CSR value */
|
|
|
|
if (rxCtrlVal == NULL)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecRxCtrlRegValGet: rxCtrlVal is NULL \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
else
|
|
*rxCtrlVal = 0;
|
|
|
|
/* deal with promiscuous mode */
|
|
|
|
if (MOT_FEC_FLAG_ISSET (MOT_FEC_PROM))
|
|
{
|
|
*rxCtrlVal |= MOT_FEC_RX_CTRL_PROM;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecRxCtrlRegValGet: promiscuous mode \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
*rxCtrlVal &= ~MOT_FEC_RX_CTRL_PROM;
|
|
|
|
/*
|
|
* enable full duplex mode if the PHY was configured
|
|
* to work in full duplex mode.
|
|
*/
|
|
|
|
if (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD))
|
|
{
|
|
*rxCtrlVal &= ~MOT_FEC_RX_CTRL_DRT;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecRxCtrlRegValGet: full duplex \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
*rxCtrlVal |= MOT_FEC_RX_CTRL_DRT;
|
|
|
|
/*
|
|
* enable the 7-wire serial interface if the
|
|
* related user flag was set.
|
|
*/
|
|
|
|
if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_SER))
|
|
{
|
|
*rxCtrlVal &= ~MOT_FEC_RX_CTRL_MII;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecRxCtrlRegValGet: serial interface \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
*rxCtrlVal |= MOT_FEC_RX_CTRL_MII;
|
|
|
|
/*
|
|
* if the user wishes to go in loopback mode,
|
|
* enable it. Also enable receiver and transmitter
|
|
* to work independently from each other.
|
|
*/
|
|
|
|
if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_LOOP))
|
|
{
|
|
*rxCtrlVal |= MOT_FEC_RX_CTRL_LOOP;
|
|
*rxCtrlVal &= ~MOT_FEC_RX_CTRL_DRT;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecRxCtrlRegValGet: loopback mode \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
*rxCtrlVal &= ~MOT_FEC_RX_CTRL_LOOP;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecTxCtrlRegValGet - get the proper value for the transmit CSR
|
|
*
|
|
* This routine finds out the proper value to be programmed in the
|
|
* transmit CSR by looking at some of the user/driver flags. It deals
|
|
* with options like full duplex mode and the heartbeat control.
|
|
*
|
|
* This routine does not program the transmit CSR.
|
|
*
|
|
* RETURNS: OK or ERROR if txCtrlVal is NULL pointer.
|
|
*
|
|
* SEE ALSO: motFecRxCtrlRegValGet(), motFecPostPhyConfig()
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS motFecTxCtrlRegValGet
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT32 * txCtrlVal /* holder for the tx CSR value */
|
|
)
|
|
{
|
|
|
|
/* Initialize holder for the tx CSR value */
|
|
|
|
if (txCtrlVal == NULL)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecTxCtrlRegValGet: txCtrlVal is NULL \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
else
|
|
*txCtrlVal = 0;
|
|
|
|
/* deal with the heartbeat control */
|
|
|
|
if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_HBC))
|
|
{
|
|
*txCtrlVal |= MOT_FEC_TX_CTRL_HBC;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecTxCtrlRegValGet: heartbeat control \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
*txCtrlVal &= ~MOT_FEC_TX_CTRL_HBC;
|
|
|
|
/*
|
|
* enable full duplex mode if the PHY was configured
|
|
* to work in full duplex mode.
|
|
*/
|
|
|
|
if (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD))
|
|
{
|
|
*txCtrlVal |= MOT_FEC_TX_CTRL_FD;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_START,
|
|
("motFecTxCtrlRegValGet: full duplex \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
*txCtrlVal &= ~MOT_FEC_TX_CTRL_FD;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecAddrRegValGet - get the values to program in CSR0 and CSR1
|
|
*
|
|
* This routine finds out the proper values to be programmed in the
|
|
* two 32-bit perfect match address registers (CSR0 and CSR1).
|
|
*
|
|
* This routine does not program neither CSR0 nor CSR1.
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecAddrRegValGet
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT32 * csr0Val, /* holder for the CSR0 value */
|
|
UINT32 * csr1Val /* holder for the CSR1 value */
|
|
)
|
|
{
|
|
char * enetAddr = NULL; /* holder for the enet address */
|
|
|
|
/*
|
|
* programming the enet address is done by writing
|
|
* its low-order 4 bytes to CSR0 and its high-order
|
|
* 2 bytes to the MSW of CSR1.
|
|
*/
|
|
|
|
enetAddr = (char *) MOT_FEC_ADDR_GET (&pDrvCtrl->endObj);
|
|
|
|
*csr0Val = * (UINT32 *) enetAddr;
|
|
|
|
/*
|
|
* this way we'll zero-out the low-order 16 bits in the
|
|
* CSR, as recommended in the documentation.
|
|
*/
|
|
|
|
*csr1Val = ((UINT32) (* (UINT16 *) (enetAddr + 4)) << 16);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecIoctl - interface ioctl procedure
|
|
*
|
|
* Process an interface ioctl request.
|
|
*
|
|
* RETURNS: OK, or ERROR.
|
|
*/
|
|
|
|
LOCAL int motFecIoctl
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
int cmd, /* command to process */
|
|
caddr_t data /* pointer to data */
|
|
)
|
|
{
|
|
int error = OK;
|
|
INT8 savedFlags;
|
|
long value;
|
|
END_OBJ * pEndObj=&pDrvCtrl->endObj;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL,
|
|
("Ioctl unit=0x%x cmd=%d data=0x%x\n"),
|
|
pDrvCtrl->unit, cmd, (int)data, 0, 0, 0);
|
|
|
|
switch (cmd)
|
|
{
|
|
case EIOCSADDR:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
{
|
|
UINT32 csr0Val; /* holder for the CSR0 value */
|
|
UINT32 csr1Val; /* holder for the CSR1 value */
|
|
|
|
/* Copy and install the new address */
|
|
|
|
bcopy ((char *) data,
|
|
(char *) MOT_FEC_ADDR_GET (&pDrvCtrl->endObj),
|
|
MOT_FEC_ADDR_LEN_GET (&pDrvCtrl->endObj));
|
|
|
|
/* stop the FEC */
|
|
|
|
if (motFecStop (pDrvCtrl) != OK)
|
|
return (ERROR);
|
|
|
|
/* program the individual enet address */
|
|
|
|
if (motFecAddrRegValGet (pDrvCtrl, &csr0Val, &csr1Val) != OK)
|
|
return (ERROR);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_ADDR_L_OFF, csr0Val);
|
|
MOT_FEC_CSR_WR (MOT_FEC_ADDR_H_OFF, csr1Val);
|
|
|
|
/* restart the FEC */
|
|
|
|
if (motFecStart (pDrvCtrl) != OK)
|
|
return (ERROR);
|
|
}
|
|
|
|
break;
|
|
|
|
case EIOCGADDR:
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
bcopy ((char *) MOT_FEC_ADDR_GET (&pDrvCtrl->endObj),
|
|
(char *) data,
|
|
MOT_FEC_ADDR_LEN_GET (&pDrvCtrl->endObj));
|
|
|
|
break;
|
|
|
|
case EIOCSFLAGS:
|
|
|
|
value = (long) data;
|
|
if (value < 0)
|
|
{
|
|
value = -value;
|
|
value--;
|
|
END_FLAGS_CLR (pEndObj, value);
|
|
}
|
|
else
|
|
END_FLAGS_SET (pEndObj, value);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("endFlags=0x%x \n"),
|
|
END_FLAGS_GET(pEndObj),
|
|
0, 0, 0, 0, 0);
|
|
|
|
/* handle IFF_PROMISC */
|
|
|
|
savedFlags = MOT_FEC_FLAG_GET();
|
|
if (END_FLAGS_ISSET (IFF_PROMISC))
|
|
{
|
|
MOT_FEC_FLAG_SET (MOT_FEC_PROM);
|
|
|
|
if ((MOT_FEC_FLAG_GET () != savedFlags) &&
|
|
(END_FLAGS_GET (pEndObj) & IFF_UP))
|
|
{
|
|
UINT32 rxCtrlVal;
|
|
|
|
/* config down */
|
|
|
|
END_FLAGS_CLR (pEndObj, IFF_UP | IFF_RUNNING);
|
|
|
|
/* program the rx CSR to promiscuous mode */
|
|
|
|
if (motFecRxCtrlRegValGet (pDrvCtrl, &rxCtrlVal) == ERROR)
|
|
return (ERROR);
|
|
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
{
|
|
UINT32 csrOldVal;
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_CTRL_OFF, csrOldVal);
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_CTRL_OFF,
|
|
((csrOldVal & 0xffff0000) | rxCtrlVal));
|
|
}
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
MOT_FEC_CSR_WR (MOT_FEC_RX_CTRL_OFF, rxCtrlVal);
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
|
|
/* config up */
|
|
|
|
END_FLAGS_SET (pEndObj, IFF_UP | IFF_RUNNING);
|
|
}
|
|
}
|
|
else
|
|
MOT_FEC_FLAG_CLEAR (MOT_FEC_PROM);
|
|
|
|
/* handle IFF_ALLMULTI */
|
|
|
|
(void) motFecHashTblPopulate (pDrvCtrl);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("EIOCSFLAGS: 0x%x: 0x%x\n"),
|
|
pEndObj->flags, savedFlags,
|
|
0, 0, 0, 0);
|
|
|
|
break;
|
|
|
|
case EIOCGFLAGS:
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("EIOCGFLAGS: 0x%x: 0x%x\n"),
|
|
pEndObj->flags, *(long *)data,
|
|
0, 0, 0, 0);
|
|
|
|
if (data == NULL)
|
|
error = EINVAL;
|
|
else
|
|
*(long *)data = END_FLAGS_GET(pEndObj);
|
|
|
|
break;
|
|
|
|
case EIOCMULTIADD:
|
|
error = motFecMCastAddrAdd (pDrvCtrl, (char *) data);
|
|
break;
|
|
|
|
case EIOCMULTIDEL:
|
|
error = motFecMCastAddrDel (pDrvCtrl, (char *) data);
|
|
break;
|
|
|
|
case EIOCMULTIGET:
|
|
error = motFecMCastAddrGet (pDrvCtrl, (MULTI_TABLE *) data);
|
|
break;
|
|
|
|
case EIOCPOLLSTART:
|
|
MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("IOCTL call motFecPollStart\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
motFecPollStart (pDrvCtrl);
|
|
break;
|
|
|
|
case EIOCPOLLSTOP:
|
|
MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("IOCTL call motFecPollStop\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
motFecPollStop (pDrvCtrl);
|
|
break;
|
|
|
|
case EIOCGMIB2:
|
|
if (data == NULL)
|
|
error=EINVAL;
|
|
else
|
|
bcopy ((char *) &pEndObj->mib2Tbl, (char *) data,
|
|
sizeof (pEndObj->mib2Tbl));
|
|
|
|
break;
|
|
|
|
default:
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("INVALID IO COMMAND!! \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
error = EINVAL;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecPhyInit - initialize and configure the PHY devices
|
|
*
|
|
* This routine scans, initializes and configures PHY devices.
|
|
*
|
|
* This routine is called from the driver's Start routine to
|
|
* perform media invalidation and configuration. To access the PHY
|
|
* device, it uses the routines: motFecPhyRead(), motFecPhyWrite(),
|
|
* which exploit the support to the MII interface built in the
|
|
* FEC.
|
|
*
|
|
* Before it attempts to bring the link up, this routine checks the
|
|
* phyInfo structure in the driver control structure for a device that
|
|
* needs to be electrically isolated by the MII interface; if a valid
|
|
* device is found it is isolated.
|
|
*
|
|
* The routine then scans for all possible PHY addresses in the range 0-31,
|
|
* checking for an MII-compliant PHY, and attempts to establish a
|
|
* valid link for it. If none is found, ERROR is returned.
|
|
* Typically PHYs are scanned from address 0, but if the user specifies
|
|
* an alternative start PHY address via the parameter phyAddr in the
|
|
* driver's load string, all (32) PHYs are scanned in order starting
|
|
* with the specified PHY address.
|
|
*
|
|
* This routine offers two strategies to select a PHY and establish a
|
|
* valid link. The default strategy is to use the standard 802.3 style
|
|
* auto-negotiation, where both link partners negotiate all their
|
|
* technology abilities at the same time, and the highest common
|
|
* denominator ability is chosen. Before the auto-negotiation
|
|
* is started, the next-page exchange mechanism is disabled.
|
|
*
|
|
* The user can prevent the PHY from negotiating certain abilities via
|
|
* userFlags -- <MOT_FEC_USR_PHY_NO_FD>, <MOT_FEC_USR_PHY_NO_100>,
|
|
* <MOT_FEC_USR_PHY_NO_HD>, and <MOT_FEC_USR_PHY_NO_10>. When
|
|
* <MOT_FEC_USR_PHY_NO_FD> is specified, full duplex will not be
|
|
* negotiated; when <MOT_FEC_USR_PHY_NO_HD> is specified half duplex
|
|
* will not be negotiated, when <MOT_FEC_USR_PHY_NO_100> is specified,
|
|
* 100Mbps ability will not negotiated; when <MOT_FEC_USR_PHY_NO_10>
|
|
* 10Mbps ability will not be negotiated.
|
|
*
|
|
* When <MOT_FEC_USR_PHY_TBL> is set in the user flags, the BSP specific
|
|
* table <motFecPhyAnOrderTbl> is used to obtain the list, and the order
|
|
* of technology abilities to be negotiated.
|
|
* The entries in this table are ordered such that entry 0 is the
|
|
* highest priority, entry 1 in next and so on. Entries in this table
|
|
* may be repeated, and multiple technology abilities can
|
|
* be OR'd to create a single entry. If a PHY cannot support a
|
|
* ability in an entry, that entry is ignored. Currently, only one
|
|
* table per driver is supported.
|
|
*
|
|
* If no PHY provides a valid link, the PHYs are scanned again in the
|
|
* same order, and the first PHY that supports the default abilities
|
|
* defined in the <phyDefMode> of the Load string will be selected,
|
|
* regardless of the link status.
|
|
*
|
|
* RETURNS: OK or ERROR if the PHY could not be initialized.
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS motFecPhyInit
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
UINT8 phyAddr; /* address of a PHY */
|
|
UINT8 isoPhyAddr; /* address of a PHY to be isolated */
|
|
UINT8 ix; /* an index */
|
|
int retVal; /* convenient holder for return value */
|
|
BOOL found = FALSE; /* no PHY has been found */
|
|
|
|
/* isolate the PHY in the phyInfo structure */
|
|
|
|
isoPhyAddr = pDrvCtrl->phyInfo->isoPhyAddr;
|
|
|
|
if (isoPhyAddr != MOT_FEC_PHY_NULL)
|
|
{
|
|
/* check the PHY is there */
|
|
|
|
retVal = motFecMiiProbe (pDrvCtrl, isoPhyAddr);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
if (retVal == OK)
|
|
if (motFecMiiIsolate (pDrvCtrl, isoPhyAddr) == ERROR)
|
|
return (ERROR);
|
|
}
|
|
|
|
/*
|
|
* there may be several PHYs, with distinct logical addresses
|
|
* and these can be as high as 31. Start with the one the
|
|
* user suggested and, in case of failure, scan the whole range.
|
|
*/
|
|
|
|
for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
|
|
{
|
|
phyAddr = (ix + pDrvCtrl->phyInfo->phyAddr) % MII_MAX_PHY_NUM;
|
|
|
|
/* check this is not the isolated PHY */
|
|
|
|
if (phyAddr == isoPhyAddr)
|
|
continue;
|
|
|
|
/* check the PHY is there */
|
|
|
|
retVal = motFecMiiProbe (pDrvCtrl, phyAddr);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
if (retVal == MOT_FEC_PHY_NULL)
|
|
continue;
|
|
|
|
found = TRUE;
|
|
|
|
/* run some diagnostics */
|
|
|
|
if (motFecMiiDiag (pDrvCtrl, phyAddr) != OK)
|
|
return (ERROR);
|
|
|
|
/*
|
|
* start the auto-negotiation process,
|
|
* unless the user dictated the contrary.
|
|
*/
|
|
|
|
if (pDrvCtrl->phyInfo->phyFlags & MOT_FEC_PHY_AUTO)
|
|
if (motFecMiiAnRun (pDrvCtrl, phyAddr) == OK)
|
|
return (OK);
|
|
|
|
/*
|
|
* the auto-negotiation process did not succeed
|
|
* in establishing a valid link: try to do it
|
|
* manually, enabling as high priority abilities
|
|
* as you can.
|
|
*/
|
|
|
|
if (motFecMiiModeForce (pDrvCtrl, phyAddr) == OK)
|
|
return (OK);
|
|
|
|
/*
|
|
* Trying to force a specific operating mode was
|
|
* unsuccessful, too. Force default parameters:
|
|
* field phyDefMode in the PHY info structure.
|
|
*/
|
|
|
|
if (motFecMiiDefForce (pDrvCtrl, phyAddr) == OK)
|
|
return (OK);
|
|
}
|
|
|
|
if (!(found))
|
|
return (ERROR);
|
|
|
|
/* if we're here, none of the PHYs could be initialized */
|
|
|
|
logMsg ("motFecPhyInit check cable connection \n",
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/* try to establish a default operating mode, do not check the link! */
|
|
|
|
for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
|
|
{
|
|
phyAddr = (ix + pDrvCtrl->phyInfo->phyAddr) % MII_MAX_PHY_NUM;
|
|
|
|
/* check this is not the isolated PHY */
|
|
|
|
if (phyAddr == isoPhyAddr)
|
|
continue;
|
|
|
|
/* check the PHY is there */
|
|
|
|
retVal = motFecMiiProbe (pDrvCtrl, phyAddr);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
if (retVal == MOT_FEC_PHY_NULL)
|
|
continue;
|
|
|
|
/* return OK even if the link is not up */
|
|
|
|
retVal = motFecMiiDefForce (pDrvCtrl, phyAddr);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/* if the PHY does not have the default abilities... */
|
|
|
|
if (retVal == MOT_FEC_PHY_NO_ABLE)
|
|
continue;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
return (ERROR);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecMiiProbe - probe the PHY device
|
|
*
|
|
* This routine probes the PHY device by reading its control register.
|
|
*
|
|
* RETURNS: OK, ERROR in case of fatal errors, or MOT_FEC_PHY_NULL, if
|
|
* the device was not found.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiProbe
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* the PHY being read */
|
|
)
|
|
{
|
|
UINT8 regAddr; /* the PHY's register being read */
|
|
UINT16 data; /* data to be written to the control reg */
|
|
|
|
regAddr = MII_STAT_REG;
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &data) != OK)
|
|
return (ERROR);
|
|
|
|
if (data == 0xffff)
|
|
return (MOT_FEC_PHY_NULL);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiProbe... ends\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecPhyPreInit - initialize some fields in the phy info structure
|
|
*
|
|
* This routine initializes some fields in the phy info structure,
|
|
* for use of the motFecPhyInit() routine.
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecPhyPreInit
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
/* set some default values */
|
|
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
|
|
pDrvCtrl->phyInfo->phyFlags = 0;
|
|
|
|
/* handle some user-to-physical flags */
|
|
|
|
if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_AN)))
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_AUTO);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_AUTO);
|
|
|
|
if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_TBL))
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_TBL);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_TBL);
|
|
|
|
if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_100)))
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_100);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
|
|
|
|
if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_FD)))
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_FD);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
|
|
|
|
if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_10)))
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_10);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_10);
|
|
|
|
if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_HD)))
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_HD);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_HD);
|
|
|
|
/* mark it as pre-initialized */
|
|
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_PRE_INIT);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecMiiRead - read the MII register
|
|
*
|
|
* This routine reads the register specified by <phyReg> in the PHY device
|
|
* whose address is <phyAddr>. The value read is returned in the location
|
|
* pointed to by <retVal>.
|
|
*
|
|
* SEE ALSO: motFecMiiWrite()
|
|
*
|
|
* RETURNS: OK, always.
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiRead
|
|
(
|
|
DRV_CTRL * _pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr, /* the PHY being read */
|
|
UINT8 regAddr, /* the PHY's register being read */
|
|
UINT16 *retVal /* the value read */
|
|
)
|
|
{
|
|
UINT32 reg; /* convenient holder for the PHY register */
|
|
UINT32 phy; /* convenient holder for the PHY */
|
|
UINT32 miiVal; /* value written/read to/from the FEC's MII register */
|
|
DRV_CTRL *pDrvCtrl;
|
|
|
|
/*
|
|
* In typical Motorola style, even though some boards have two
|
|
* FEC devices, the PHYs for both ports are only accessible
|
|
* via motfec0. To deal with this, we always grovel around
|
|
* for the pDrvCtrl for motfec0 when doing MII reads or
|
|
* writes.
|
|
*/
|
|
|
|
pDrvCtrl = (DRV_CTRL *)endFindByName("motfec", 0);
|
|
if (pDrvCtrl == NULL)
|
|
return(ERROR);
|
|
|
|
/*
|
|
* reading from any PHY's register is done by properly
|
|
* programming the FEC's MII data register.
|
|
*/
|
|
|
|
reg = regAddr << MOT_FEC_MII_RA_SHIFT;
|
|
phy = phyAddr << MOT_FEC_MII_PA_SHIFT;
|
|
|
|
miiVal = (MOT_FEC_MII_ST | MOT_FEC_MII_OP_RD | MOT_FEC_MII_TA |
|
|
phy | reg);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_MII_DATA_OFF, miiVal);
|
|
|
|
/* wait for the related interrupt */
|
|
|
|
MOT_FEC_MII_SEM_TAKE;
|
|
|
|
/* it's now safe to read the PHY's register */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_MII_DATA_OFF, miiVal);
|
|
|
|
*retVal = (UINT16) miiVal;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* motFecMiiWrite - write to the MII register
|
|
*
|
|
* This routine writes the register specified by <phyReg> in the PHY device,
|
|
* whose address is <phyAddr>, with the 16-bit value included in <data>.
|
|
*
|
|
* SEE ALSO: motFecMiiRead()
|
|
*
|
|
* RETURNS: OK, always.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiWrite
|
|
(
|
|
DRV_CTRL * _pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr, /* the PHY being written */
|
|
UINT8 regAddr, /* the PHY's register being written */
|
|
UINT16 data /* the value written to the PHY register */
|
|
)
|
|
{
|
|
UINT32 reg; /* convenient holder for the PHY register */
|
|
UINT32 phy; /* convenient holder for the PHY */
|
|
UINT32 miiVal; /* value written to the mii reg */
|
|
DRV_CTRL *pDrvCtrl;
|
|
|
|
pDrvCtrl = (DRV_CTRL *)endFindByName("motfec", 0);
|
|
if (pDrvCtrl == NULL)
|
|
return(ERROR);
|
|
|
|
reg = regAddr << MOT_FEC_MII_RA_SHIFT;
|
|
phy = phyAddr << MOT_FEC_MII_PA_SHIFT;
|
|
|
|
miiVal = (MOT_FEC_MII_ST | MOT_FEC_MII_OP_WR | MOT_FEC_MII_TA |
|
|
phy | reg | data);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiWrite reg=%d \n\
|
|
PHY=%d data=0x%x\n"),
|
|
regAddr, phyAddr, miiVal, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_MII_DATA_OFF, miiVal);
|
|
|
|
/* wait for the related interrupt */
|
|
|
|
MOT_FEC_MII_SEM_TAKE;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiDiag - run some diagnostics
|
|
*
|
|
* This routine runs some diagnostics on the PHY whose address is
|
|
* specified in the parameter <phyAddr>.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiDiag
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* address of a PHY */
|
|
)
|
|
{
|
|
UINT16 data; /* data to be written to the control reg */
|
|
UINT8 regAddr; /* PHY register */
|
|
UINT16 ix = 0; /* a counter */
|
|
|
|
/* reset the PHY */
|
|
|
|
regAddr = MII_CTRL_REG;
|
|
data = MII_CR_RESET;
|
|
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
|
|
return (ERROR);
|
|
|
|
while (ix++ < MOT_FEC_PHY_MAX_WAIT)
|
|
{
|
|
taskDelay (1);
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &data) != OK)
|
|
return (ERROR);
|
|
|
|
if (!(data & MII_CR_RESET))
|
|
break;
|
|
}
|
|
|
|
if (ix >= MOT_FEC_PHY_MAX_WAIT)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDiag reset fail\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
/* isolate the PHY */
|
|
|
|
if (motFecMiiIsolate (pDrvCtrl, phyAddr) == ERROR)
|
|
return (ERROR);
|
|
|
|
/* re-enable the chip */
|
|
|
|
data = MII_CR_NORM_EN;
|
|
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
|
|
return (ERROR);
|
|
|
|
/* check isolate bit is deasserted */
|
|
|
|
ix = 0;
|
|
while (ix++ < MOT_FEC_PHY_MAX_WAIT)
|
|
{
|
|
taskDelay (1);
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &data) != OK)
|
|
return (ERROR);
|
|
|
|
if (!(data & MII_CR_ISOLATE))
|
|
break;
|
|
}
|
|
|
|
if (ix >= MOT_FEC_PHY_MAX_WAIT)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDiag de-isolate fail\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDiag... ends\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiIsolate - isolate the PHY device
|
|
*
|
|
* This routine isolates the PHY device whose address is specified in
|
|
* the parameter <isoPhyAddr>.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiIsolate
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 isoPhyAddr /* address of a PHY to be isolated */
|
|
)
|
|
{
|
|
UINT8 regAddr; /* PHY register */
|
|
UINT16 ix = 0; /* a counter */
|
|
UINT16 data; /* data to be written to the control reg */
|
|
|
|
if (isoPhyAddr == MOT_FEC_PHY_NULL)
|
|
return (OK);
|
|
|
|
data = MII_CR_ISOLATE;
|
|
regAddr = MII_CTRL_REG;
|
|
|
|
if (motFecMiiWrite (pDrvCtrl, isoPhyAddr, regAddr, data) != OK)
|
|
return (ERROR);
|
|
|
|
/* check isolate bit is asserted */
|
|
|
|
ix = 0;
|
|
while (ix++ < MOT_FEC_PHY_MAX_WAIT)
|
|
{
|
|
taskDelay (1);
|
|
|
|
if (motFecMiiRead (pDrvCtrl, isoPhyAddr, regAddr, &data) != OK)
|
|
return (ERROR);
|
|
|
|
if ((data & MII_CR_ISOLATE))
|
|
break;
|
|
}
|
|
|
|
if (ix >= MOT_FEC_PHY_MAX_WAIT)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiIsolate fail\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiIsolate... ends\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiAnRun - run the auto-negotiation process
|
|
*
|
|
* This routine runs the auto-negotiation process for the PHY whose
|
|
* address is specified in the parameter <phyAddr>, without enabling the
|
|
* next page function. It also calls motFecMiiAnCheck() to ensure
|
|
* a valid link has been established.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiAnRun
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* address of a PHY */
|
|
)
|
|
{
|
|
UINT8 regAddr; /* PHY register */
|
|
UINT16 phyAds; /* holder for the PHY ads register value */
|
|
UINT16 status; /* PHY auto-negotiation status */
|
|
UINT16 ix; /* a counter */
|
|
int retVal; /* holder for return value */
|
|
|
|
regAddr = MII_AN_ADS_REG;
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyAds) != OK)
|
|
return (ERROR);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnRun phyAds=0x%x\n"),
|
|
phyAds, 0, 0, 0, 0, 0);
|
|
|
|
/* disable the next page function */
|
|
|
|
phyAds &= (~MII_NP_NP);
|
|
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, phyAds)
|
|
!= OK)
|
|
return (ERROR);
|
|
|
|
/* Read ANER to clear status from previous operations */
|
|
|
|
regAddr = MII_AN_EXP_REG;
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &status) != OK)
|
|
return (ERROR);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnRun expStat=0x%x\n"),
|
|
status, 0, 0, 0, 0, 0);
|
|
|
|
/* Read ANAR */
|
|
|
|
regAddr = MII_AN_ADS_REG;
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyAds) != OK)
|
|
return (ERROR);
|
|
|
|
/* store the current registers values */
|
|
|
|
pDrvCtrl->phyInfo->miiRegs.phyAds = phyAds;
|
|
|
|
/*
|
|
* start the auto-negotiation process, possibly
|
|
* following the order the user dictated.
|
|
*/
|
|
|
|
for (ix = 0; ; ix++)
|
|
{
|
|
#ifdef DISABLED
|
|
/* This is disabled for now: most BSPs get this horribly wrong. */
|
|
if (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_TBL))
|
|
{
|
|
/* check we're not at the end of the user table */
|
|
|
|
if ((motFecPhyAnOrderTbl [ix]) == -1)
|
|
return (ERROR);
|
|
|
|
/* just negotiate one ability at a time */
|
|
|
|
phyAds &= ~MII_TECH_MASK;
|
|
|
|
/* translate user settings */
|
|
|
|
phyAds |= miiAnLookupTbl [(motFecPhyAnOrderTbl [ix])];
|
|
|
|
/* check the PHY has the desired ability */
|
|
|
|
if (!(phyAds & pDrvCtrl->phyInfo->miiRegs.phyAds))
|
|
continue;
|
|
|
|
/* set the ANAR accordingly */
|
|
|
|
regAddr = MII_AN_ADS_REG;
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, phyAds)
|
|
!= OK)
|
|
return (ERROR);
|
|
}
|
|
else
|
|
{
|
|
/* check the PHY flags and possibly mask some abilities off */
|
|
|
|
if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD)))
|
|
phyAds &= ~(MII_TECH_10BASE_FD | MII_TECH_100BASE_TX_FD
|
|
| MII_TECH_100BASE_T4);
|
|
|
|
if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_HD)))
|
|
phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_100BASE_TX);
|
|
|
|
if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_100)))
|
|
phyAds &= ~(MII_TECH_100BASE_TX | MII_TECH_100BASE_TX_FD
|
|
| MII_TECH_100BASE_T4);
|
|
|
|
if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_10)))
|
|
phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_10BASE_FD);
|
|
|
|
/* Write ANAR */
|
|
|
|
regAddr = MII_AN_ADS_REG;
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, phyAds) != OK)
|
|
return (ERROR);
|
|
|
|
/* store the current registers values */
|
|
|
|
pDrvCtrl->phyInfo->miiRegs.phyAds = phyAds;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnRun phyAds=0x%x\n"),
|
|
phyAds, 0, 0, 0, 0, 0);
|
|
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* start the auto-negotiation process: return
|
|
* only in case of fatal error.
|
|
*/
|
|
|
|
retVal = motFecMiiAnStart (pDrvCtrl, phyAddr);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/*
|
|
* in case of failure, we return only if we're using
|
|
* the standard auto-negotiation process.
|
|
*/
|
|
|
|
if (retVal == MII_AN_FAIL)
|
|
{
|
|
if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_TBL)))
|
|
return (retVal);
|
|
else
|
|
continue;
|
|
}
|
|
|
|
/* check the negotiation was successful */
|
|
|
|
if (motFecMiiAnCheck (pDrvCtrl, phyAddr) == OK)
|
|
return (OK);
|
|
|
|
/*
|
|
* we are here if the negotiation went wrong:
|
|
* if the user did not force any priority order,
|
|
* we return ERROR, as all the PHY abilities
|
|
* were negotiated at once.
|
|
*/
|
|
|
|
if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_TBL)))
|
|
return (ERROR);
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiAnStart - start the auto-negotiation process
|
|
*
|
|
* This routine starts the auto-negotiation process for the PHY whose
|
|
* address is specified in the parameter <phyAddr>.
|
|
*
|
|
* RETURNS: OK, ERROR in case of fatal errors or MII_AN_FAIL, if the
|
|
* auto-negotiation did not complete within a reasonable amount of time.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiAnStart
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* address of a PHY */
|
|
)
|
|
{
|
|
UINT16 data; /* data to be written to the control reg */
|
|
UINT8 regAddr; /* PHY register */
|
|
UINT16 phyStatus; /* holder for the PHY status */
|
|
UINT16 ix = 0; /* a counter */
|
|
|
|
regAddr = MII_STAT_REG;
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
|
|
return (ERROR);
|
|
|
|
/* check the PHY has this ability */
|
|
|
|
if ((phyStatus & MII_SR_AUTO_SEL) != MII_SR_AUTO_SEL)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnStart phy not \n\
|
|
auto neg capable\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return (ERROR);
|
|
}
|
|
|
|
/* restart the auto-negotiation process */
|
|
|
|
regAddr = MII_CTRL_REG;
|
|
data = (MII_CR_RESTART | MII_CR_AUTO_EN);
|
|
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
|
|
return (ERROR);
|
|
|
|
/* save status info */
|
|
|
|
pDrvCtrl->phyInfo->miiRegs.phyCtrl = data;
|
|
|
|
/* let's check the PHY status */
|
|
|
|
regAddr = MII_STAT_REG;
|
|
|
|
/* spin until it is done */
|
|
|
|
do
|
|
{
|
|
taskDelay (1);
|
|
|
|
if (ix++ == MOT_FEC_PHY_MAX_WAIT)
|
|
break;
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus)
|
|
!= OK)
|
|
return (ERROR);
|
|
|
|
} while ((phyStatus & MII_SR_AUTO_NEG) != MII_SR_AUTO_NEG);
|
|
|
|
if (ix >= MOT_FEC_PHY_MAX_WAIT)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII,
|
|
("motFecMiiAnStart auto neg fail\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (MII_AN_FAIL);
|
|
}
|
|
else
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII,
|
|
("motFecMiiAnStart auto neg done phyStat=0x%x\n"),
|
|
phyStatus, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiBasicCheck - run a basic check on the PHY status register
|
|
*
|
|
* This routine runs a basic check on the PHY status register to
|
|
* ensure a valid link has been established and no faults have been
|
|
* detected.
|
|
*
|
|
* RETURNS: OK, MII_STAT_FAIL, if an error was reported in the PHY's
|
|
* status register, or ERROR, in case of unrecoverable errors.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiBasicCheck
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* address of a PHY */
|
|
)
|
|
{
|
|
UINT8 regAddr; /* PHY register */
|
|
UINT16 phyStatus; /* holder for the PHY status */
|
|
|
|
/* let's check the PHY status */
|
|
|
|
regAddr = MII_STAT_REG;
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
|
|
return (ERROR);
|
|
|
|
if ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
|
|
{
|
|
/* wait for a while */
|
|
|
|
taskDelay (10);
|
|
|
|
/* we need to read it twice; this is a latched function */
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
|
|
return (ERROR);
|
|
|
|
if ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiBasicCheck \n\
|
|
phy stat=0x%x\n"),
|
|
phyStatus, 0, 0, 0, 0, 0);
|
|
|
|
return (MII_STAT_FAIL);
|
|
}
|
|
}
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiBasicCheck\n\
|
|
Link up! status=0x%x\n"),
|
|
phyStatus, 0, 0, 0, 0, 0);
|
|
|
|
/* check for remote fault condition */
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
|
|
return (ERROR);
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
|
|
return (ERROR);
|
|
|
|
if ((phyStatus & MII_SR_REMOTE_FAULT) == MII_SR_REMOTE_FAULT)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiBasicCheck remote fault\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (MII_STAT_FAIL);
|
|
}
|
|
|
|
/* store the current registers values */
|
|
|
|
pDrvCtrl->phyInfo->miiRegs.phyStatus = phyStatus;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiAnCheck - check the auto-negotiation process result
|
|
*
|
|
* This routine checks the auto-negotiation process has completed
|
|
* successfully and no faults have been detected by any of the PHYs
|
|
* engaged in the process.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiAnCheck
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* address of a PHY */
|
|
)
|
|
{
|
|
UINT8 regAddr; /* PHY register */
|
|
UINT16 phyAds; /* PHY advertisement register value */
|
|
UINT16 phyPrtn; /* PHY partner ability register value */
|
|
UINT16 phyExp = 0; /* PHY expansion register value */
|
|
UINT16 negAbility; /* abilities after negotiation */
|
|
int retVal; /* convenient holder for return value */
|
|
|
|
/* run a check on the status bits of basic registers only */
|
|
|
|
retVal = motFecMiiBasicCheck (pDrvCtrl, phyAddr);
|
|
if (retVal != OK)
|
|
return (retVal);
|
|
|
|
#ifdef DISABLED
|
|
|
|
/*
|
|
* The MPC866ADS board uses an LSI Logic PHY that doesn't
|
|
* have an autoneg expansion register. Trying to read from
|
|
* it always returns 0xFFFF, which looks to this code like
|
|
* a fault was detected. This breaks the autoneg code on
|
|
* this board. The autoneg code works correctly without
|
|
* checking this register, so disable this test for now.
|
|
*/
|
|
|
|
/* we know the auto-negotiation process has terminated */
|
|
|
|
regAddr = MII_AN_EXP_REG;
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyExp) != OK)
|
|
return (ERROR);
|
|
|
|
/* check for faults detected by the parallel function */
|
|
|
|
if ((phyExp & MII_EXP_FAULT) == MII_EXP_FAULT)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck:\n\
|
|
fault expStat=0x%x\n"),
|
|
phyExp, 0, 0, 0, 0, 0);
|
|
|
|
return (ERROR);
|
|
}
|
|
#endif
|
|
|
|
/* check for remote faults */
|
|
|
|
regAddr = MII_AN_PRTN_REG;
|
|
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyPrtn) != OK)
|
|
return (ERROR);
|
|
|
|
if ((phyPrtn & MII_BP_FAULT) == MII_BP_FAULT)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck partner stat=0x%x\n"),
|
|
phyPrtn, 0, 0, 0, 0, 0);
|
|
|
|
return (ERROR);
|
|
}
|
|
|
|
|
|
regAddr = MII_AN_ADS_REG;
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyAds) != OK)
|
|
return (ERROR);
|
|
|
|
/* store the current registers values */
|
|
|
|
pDrvCtrl->phyInfo->miiRegs.phyAds = phyAds;
|
|
pDrvCtrl->phyInfo->miiRegs.phyPrtn = phyPrtn;
|
|
pDrvCtrl->phyInfo->miiRegs.phyExp = phyExp;
|
|
|
|
/* find out the max common abilities */
|
|
|
|
negAbility = phyPrtn & phyAds & MII_TECH_MASK;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck phyAds=0x%x\n\
|
|
phyPrtn=0x%x common=0x%x phyExp=0x%x\n"),
|
|
phyAds,
|
|
phyPrtn,
|
|
negAbility,
|
|
phyExp, 0, 0);
|
|
|
|
if (negAbility & MII_TECH_100BASE_TX_FD)
|
|
{
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%s\n"),
|
|
pDrvCtrl->phyInfo->phySpeed,
|
|
(int) "full duplex", 0, 0, 0, 0);
|
|
}
|
|
else if ((negAbility & MII_TECH_100BASE_T4) ||
|
|
(negAbility & MII_TECH_100BASE_TX))
|
|
{
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%s\n"),
|
|
pDrvCtrl->phyInfo->phySpeed,
|
|
(int) "half duplex", 0, 0, 0, 0);
|
|
}
|
|
else if (negAbility & MII_TECH_10BASE_FD)
|
|
{
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%s\n"),
|
|
pDrvCtrl->phyInfo->phySpeed,
|
|
(int) "full duplex", 0, 0, 0, 0);
|
|
}
|
|
else if (negAbility & MII_TECH_10BASE_T)
|
|
{
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%s\n"),
|
|
pDrvCtrl->phyInfo->phySpeed,
|
|
(int) "half duplex", 0, 0, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck fail!\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
/* handle some flags */
|
|
|
|
if (pDrvCtrl->phyInfo->phySpeed == MOT_FEC_100MBS)
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_100);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
|
|
|
|
if (pDrvCtrl->phyInfo->phyMode == MOT_FEC_PHY_FD)
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_FD);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck OK\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiModeForce - force an operating mode for the PHY
|
|
*
|
|
* This routine forces an operating mode for the PHY whose address is
|
|
* specified in the parameter <phyAddr>. It also calls motFecMiiBasicCheck()
|
|
* to ensure a valid link has been established.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiModeForce
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* address of a PHY */
|
|
)
|
|
{
|
|
UINT16 data; /* data to be written to the control reg */
|
|
UINT8 regAddr; /* PHY register */
|
|
UINT16 phyStatus; /* holder for the PHY status */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiModeForce \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/* find out what abilities the PHY features */
|
|
|
|
regAddr = MII_STAT_REG;
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
|
|
return (ERROR);
|
|
|
|
/*
|
|
* force as a high priority as possible operating
|
|
* mode, not overlooking what the user dictated.
|
|
*/
|
|
|
|
data = MII_CR_NORM_EN;
|
|
|
|
if ((phyStatus & (MII_SR_TX_FULL_DPX | MII_SR_TX_HALF_DPX))
|
|
&& (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_100)))
|
|
{
|
|
data |= MII_CR_100;
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
|
|
}
|
|
|
|
if ((phyStatus & (MII_SR_TX_FULL_DPX | MII_SR_10T_FULL_DPX | MII_SR_T4))
|
|
&& (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD)))
|
|
{
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
|
|
data |= MII_CR_FDX;
|
|
}
|
|
|
|
pDrvCtrl->phyInfo->miiRegs.phyCtrl = data;
|
|
|
|
regAddr = MII_CTRL_REG;
|
|
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
|
|
return (ERROR);
|
|
|
|
/* run a check on the status bits of basic registers only */
|
|
|
|
if (motFecMiiBasicCheck (pDrvCtrl, phyAddr) != OK)
|
|
return (ERROR);
|
|
|
|
/* handle some flags */
|
|
|
|
if (pDrvCtrl->phyInfo->phySpeed == MOT_FEC_100MBS)
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_100);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
|
|
|
|
if (pDrvCtrl->phyInfo->phyMode == MOT_FEC_PHY_FD)
|
|
MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_FD);
|
|
else
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiModeForce speed=%d mode=%d\n"),
|
|
pDrvCtrl->phyInfo->phySpeed,
|
|
pDrvCtrl->phyInfo->phyMode,
|
|
0, 0, 0, 0);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMiiDefForce - force a default operating mode for the PHY
|
|
*
|
|
* This routine forces a default operating mode for the PHY whose address is
|
|
* specified in the parameter <phyAddr>. It also calls motFecMiiBasicCheck()
|
|
* to ensure a valid link has been established.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMiiDefForce
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
UINT8 phyAddr /* address of a PHY */
|
|
)
|
|
{
|
|
UINT16 data; /* data to be written to the control reg */
|
|
UINT8 regAddr; /* PHY register */
|
|
int retVal; /* convenient holder for return value */
|
|
UINT16 phyStatus; /* holder for the PHY status */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDefForce \n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
/* translate user settings */
|
|
|
|
data = miiCrLookupTbl [(pDrvCtrl->phyInfo->phyDefMode)];
|
|
|
|
/* find out what abilities the PHY features */
|
|
|
|
regAddr = MII_STAT_REG;
|
|
if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
|
|
return (ERROR);
|
|
|
|
if (data & MII_CR_100)
|
|
{
|
|
if (!(phyStatus & (MII_SR_TX_HALF_DPX
|
|
| MII_SR_TX_FULL_DPX
|
|
| MII_SR_T4)))
|
|
return (MOT_FEC_PHY_NO_ABLE);
|
|
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
|
|
}
|
|
else
|
|
{
|
|
if (!(phyStatus & (MII_SR_10T_HALF_DPX
|
|
| MII_SR_10T_FULL_DPX)))
|
|
return (MOT_FEC_PHY_NO_ABLE);
|
|
|
|
/* handle phy flags */
|
|
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
|
|
|
|
pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
|
|
}
|
|
|
|
if (data & MII_CR_FDX)
|
|
{
|
|
if (!(phyStatus & (MII_SR_10T_FULL_DPX
|
|
| MII_SR_TX_FULL_DPX
|
|
| MII_SR_T4)))
|
|
return (MOT_FEC_PHY_NO_ABLE);
|
|
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
|
|
}
|
|
else
|
|
{
|
|
if (!(phyStatus & (MII_SR_10T_HALF_DPX
|
|
| MII_SR_TX_HALF_DPX)))
|
|
return (MOT_FEC_PHY_NO_ABLE);
|
|
|
|
/* handle phy flags */
|
|
|
|
MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
|
|
|
|
pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
|
|
}
|
|
|
|
pDrvCtrl->phyInfo->miiRegs.phyCtrl = data;
|
|
|
|
regAddr = MII_CTRL_REG;
|
|
|
|
if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
|
|
return (ERROR);
|
|
|
|
/* run a check on the status bits of basic registers only */
|
|
|
|
retVal = motFecMiiBasicCheck (pDrvCtrl, phyAddr);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDefForce speed=%d mode=%d\n"),
|
|
pDrvCtrl->phyInfo->phySpeed,
|
|
pDrvCtrl->phyInfo->phyMode,
|
|
0, 0, 0, 0);
|
|
|
|
return (retVal);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMCastAddrAdd - add a multicast address for the device
|
|
*
|
|
* This routine adds a multicast address to whatever the driver
|
|
* is already listening for.
|
|
*
|
|
* SEE ALSO: motFecMCastAddrDel() motFecMCastAddrGet()
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMCastAddrAdd
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
char * pAddr /* address to be added */
|
|
)
|
|
{
|
|
int retVal; /* convenient holder for return value */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecMCastAddrAdd addr = 0x%x 0x%x\n\
|
|
0x%x 0x%x 0x%x 0x%x\n"),
|
|
(int) *(pAddr + 0), (int) *(pAddr + 1),
|
|
(int) *(pAddr + 2), (int) *(pAddr + 3),
|
|
(int) *(pAddr + 4), (int) *(pAddr + 5));
|
|
|
|
retVal = etherMultiAdd (&pDrvCtrl->endObj.multiList, pAddr);
|
|
|
|
if (retVal == ENETRESET)
|
|
{
|
|
pDrvCtrl->endObj.nMulti++;
|
|
|
|
retVal = motFecHashTblPopulate (pDrvCtrl);
|
|
}
|
|
|
|
return ((retVal == OK) ? OK : ERROR);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* motFecMCastAddrDel - delete a multicast address for the device
|
|
*
|
|
* This routine deletes a multicast address from the current list of
|
|
* multicast addresses.
|
|
*
|
|
* SEE ALSO: motFecMCastAddrAdd() motFecMCastAddrGet()
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMCastAddrDel
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
char * pAddr /* address to be deleted */
|
|
)
|
|
{
|
|
int retVal; /* convenient holder for return value */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecMCastAddrDel addr = 0x%x 0x%x\n\
|
|
0x%x 0x%x 0x%x 0x%x\n"),
|
|
(int) *(pAddr + 0), (int) *(pAddr + 1),
|
|
(int) *(pAddr + 2), (int) *(pAddr + 3),
|
|
(int) *(pAddr + 4), (int) *(pAddr + 5));
|
|
|
|
retVal = etherMultiDel (&pDrvCtrl->endObj.multiList, pAddr);
|
|
|
|
if (retVal == ENETRESET)
|
|
{
|
|
pDrvCtrl->endObj.nMulti--;
|
|
|
|
/* populate the hash table */
|
|
|
|
retVal = motFecHashTblPopulate (pDrvCtrl);
|
|
}
|
|
|
|
return ((retVal == OK) ? OK : ERROR);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecMCastAddrGet - get the current multicast address list
|
|
*
|
|
* This routine returns the current multicast address list in <pTable>
|
|
*
|
|
* SEE ALSO: motFecMCastAddrAdd() motFecMCastAddrDel()
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecMCastAddrGet
|
|
(
|
|
DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
MULTI_TABLE *pTable /* table into which to copy addresses */
|
|
)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecMCastAddrGet\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return (etherMultiGet (&pDrvCtrl->endObj.multiList, pTable));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecHashTblPopulate - populate the hash table
|
|
*
|
|
* This routine populates the hash table with the entries found in the
|
|
* multicast table. We have to reset the hash registers first, and
|
|
* populate them again, as more than one address may be mapped to
|
|
* the same bit.
|
|
*
|
|
* RETURNS: OK, or ERROR.
|
|
*/
|
|
|
|
LOCAL STATUS motFecHashTblPopulate
|
|
(
|
|
DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
UINT32 crcVal; /* convenient holder for the CRC value */
|
|
UINT32 hashes[2] = { 0, 0 };
|
|
ETHER_MULTI * mCastNode = NULL;
|
|
|
|
/* reset the hash table registers first */
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_L_OFF, 0);
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_H_OFF, 0);
|
|
|
|
/*
|
|
* If we're in ALLMULTI mode, just set all the bits in the filter.
|
|
* This will insure we receive multicasts from all groups.
|
|
*/
|
|
|
|
if (END_FLAGS_ISSET (IFF_ALLMULTI))
|
|
{
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_L_OFF, 0xFFFFFFFF);
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_H_OFF, 0xFFFFFFFF);
|
|
return(OK);
|
|
}
|
|
|
|
/* scan the multicast address list */
|
|
|
|
for (mCastNode = (ETHER_MULTI *) lstFirst (&pDrvCtrl->endObj.multiList);
|
|
mCastNode != NULL;
|
|
mCastNode = (ETHER_MULTI *) lstNext (&mCastNode->node))
|
|
{
|
|
/* get the CRC for the current address in the list */
|
|
|
|
crcVal = motFecCrcGet ((char *) mCastNode->addr);
|
|
|
|
/* get the value to be written to the proper hash register */
|
|
|
|
crcVal = (~crcVal >> 26) & 0x3F;
|
|
|
|
if (crcVal < 32)
|
|
hashes[0] |= (1 << crcVal);
|
|
else
|
|
hashes[1] |= (1 << (crcVal - 32));
|
|
}
|
|
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_L_OFF, hashes[0]);
|
|
MOT_FEC_CSR_WR (MOT_FEC_HASH_H_OFF, hashes[1]);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecCrcGet - compute the cyclic redundant code
|
|
*
|
|
* This routine computes the 32-bit cyclic redundant code (CRC) for the
|
|
* 6-byte array pointed to by <pAddr>. For details on the polynomial used,
|
|
* see:
|
|
* \tb MPC860T Fast Ethernet Controller (Supplement to MPC860 User's Manual)
|
|
*
|
|
* RETURNS: The 32-bit value representing the CRC.
|
|
*/
|
|
|
|
LOCAL UINT32 motFecCrcGet
|
|
(
|
|
char * pAddr
|
|
)
|
|
{
|
|
UINT32 crc = INIT_REFLECTED;
|
|
UINT32 len = 6;
|
|
|
|
while (len--)
|
|
crc = crctable[(crc ^ *pAddr++) & 0xFFL] ^ (crc >> 8);
|
|
|
|
return crc ^ XOROT;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* motFecPollSend - transmit a packet in polled mode
|
|
*
|
|
* This routine is called by a user to try and send a packet on the
|
|
* device. It sends a packet directly on the network, without having to
|
|
* go through the normal process of queuing a packet on an output queue
|
|
* and then waiting for the device to decide to transmit it.
|
|
*
|
|
* These routine should not call any kernel functions.
|
|
*
|
|
* SEE ALSO: motFecPollReceive()
|
|
*
|
|
* RETURNS: OK or EAGAIN.
|
|
*/
|
|
|
|
LOCAL STATUS motFecPollSend
|
|
(
|
|
DRV_CTRL *pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
M_BLK_ID pMblk /* pointer to the mBlk/cluster pair */
|
|
)
|
|
{
|
|
UINT16 pktType = 0; /* packet type (unicast or multicast) */
|
|
int retVal; /* holder for return value */
|
|
char * pBuf = NULL; /* pointer to data to be sent */
|
|
MOT_FEC_TBD_ID pTbd = NULL; /* pointer to the current ready TBD */
|
|
int ix = 0; /* a counter */
|
|
int len = 0; /* length of data to be sent */
|
|
UINT16 tbdStatus; /* holder for the TBD status */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollSend\n"), 0, 0, 0, 0, 0, 0);
|
|
|
|
if (pMblk == NULL)
|
|
{
|
|
goto motFecPollSendError;
|
|
}
|
|
|
|
/* set the packet type to multicast or unicast */
|
|
|
|
if (pMblk->mBlkHdr.mData[0] & (UINT8) 0x01)
|
|
{
|
|
pktType = PKT_TYPE_MULTI;
|
|
}
|
|
else
|
|
{
|
|
pktType = PKT_TYPE_UNI;
|
|
}
|
|
|
|
/* get the current free TBD */
|
|
|
|
pTbd = motFecTbdGet (pDrvCtrl);
|
|
|
|
/* get our own cluster */
|
|
|
|
pBuf = (char *)pDrvCtrl->pTxPollBuf;
|
|
|
|
if ((pTbd == NULL) || (pBuf == NULL))
|
|
{
|
|
goto motFecPollSendError;
|
|
}
|
|
|
|
/* copy data but do not free the Mblk */
|
|
|
|
len = netMblkToBufCopy (pMblk, pBuf, NULL);
|
|
len = max (ETHERSMALL, len);
|
|
|
|
/* flush the cache, if necessary */
|
|
|
|
MOT_FEC_CACHE_FLUSH (pBuf, len);
|
|
|
|
/* set up the current TBD */
|
|
|
|
MOT_FEC_BD_LONG_WR (pTbd, MOT_FEC_BD_ADDR_OFF, (UINT32) pBuf);
|
|
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_LEN_OFF, (UINT32) len);
|
|
|
|
MOT_FEC_BD_WORD_RD (pTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
|
|
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF,
|
|
(MOT_FEC_TBD_LAST | MOT_FEC_TBD_CRC
|
|
| MOT_FEC_TBD_RDY | tbdStatus));
|
|
|
|
/* kick the transmitter */
|
|
|
|
MOT_FEC_TX_ACTIVATE;
|
|
|
|
/* Flush the write pipe */
|
|
|
|
CACHE_PIPE_FLUSH ();
|
|
|
|
/* up-date statistics */
|
|
|
|
if (pktType == PKT_TYPE_MULTI)
|
|
{
|
|
pDrvCtrl->endObj.mib2Tbl.ifOutNUcastPkts += 1;
|
|
}
|
|
else
|
|
{
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
|
|
}
|
|
|
|
do
|
|
{
|
|
retVal = motFecTbdCheck (pDrvCtrl, pTbd);
|
|
|
|
if (ix++ == MOT_FEC_WAIT_MAX)
|
|
break;
|
|
|
|
} while (retVal == MOT_FEC_TBD_BUSY);
|
|
|
|
/* correct statistics, if necessary */
|
|
|
|
if ((retVal == MOT_FEC_TBD_ERROR) || (ix == MOT_FEC_WAIT_MAX))
|
|
{
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
|
|
|
|
if (pktType == PKT_TYPE_MULTI)
|
|
{
|
|
pDrvCtrl->endObj.mib2Tbl.ifOutNUcastPkts -= 1;
|
|
}
|
|
else
|
|
{
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1);
|
|
}
|
|
}
|
|
|
|
/* clean this buffer descriptor, mirror motFecTbdInit() */
|
|
|
|
if (pDrvCtrl->tbdIndex == (pDrvCtrl->tbdNum - 1))
|
|
{
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF,
|
|
MOT_FEC_TBD_WRAP);
|
|
}
|
|
else
|
|
{
|
|
MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF, 0);
|
|
}
|
|
|
|
/* Flush the write pipe */
|
|
|
|
CACHE_PIPE_FLUSH ();
|
|
|
|
/* update some indices for a correct handling of the TBD ring */
|
|
|
|
pDrvCtrl->tbdIndex = (pDrvCtrl->tbdIndex + 1)
|
|
% (pDrvCtrl->tbdNum);
|
|
|
|
pDrvCtrl->usedTbdIndex = (pDrvCtrl->usedTbdIndex + 1)
|
|
% (pDrvCtrl->tbdNum);
|
|
|
|
if (ix == MOT_FEC_WAIT_MAX)
|
|
return (EAGAIN);
|
|
|
|
return (OK);
|
|
|
|
motFecPollSendError:
|
|
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
|
|
|
|
return (EAGAIN);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecPollReceive - receive a packet in polled mode
|
|
*
|
|
* This routine is called by a user to try and get a packet from the
|
|
* device. It returns EAGAIN if no packet is available. The caller must
|
|
* supply a M_BLK_ID with enough space to contain the received packet. If
|
|
* enough buffer is not available then EAGAIN is returned.
|
|
*
|
|
* These routine should not call any kernel functions.
|
|
*
|
|
* SEE ALSO: motFecPollSend()
|
|
*
|
|
* RETURNS: OK or EAGAIN.
|
|
*/
|
|
|
|
LOCAL STATUS motFecPollReceive
|
|
(
|
|
DRV_CTRL *pDrvCtrl, /* pointer to DRV_CTRL structure */
|
|
M_BLK_ID pMblk /* pointer to the mBlk/cluster pair */
|
|
)
|
|
{
|
|
int retVal = OK; /* holder for return value */
|
|
MOT_FEC_RBD_ID pRbd = NULL; /* generic rbd pointer */
|
|
UINT16 rbdStatus = 0; /* holder for the status of this RBD */
|
|
UINT16 rbdLen = 0; /* number of bytes received */
|
|
char * pData = NULL; /* a rx data pointer */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollReceive\n"), 0, 0, 0, 0, 0, 0);
|
|
|
|
if ((pMblk->mBlkHdr.mFlags & M_EXT) != M_EXT)
|
|
return (EAGAIN);
|
|
|
|
/* get the first available RBD */
|
|
|
|
MOT_FEC_NEXT_RBD (pDrvCtrl, pRbd);
|
|
|
|
/* read the RBD status word */
|
|
|
|
MOT_FEC_BD_WORD_RD (pRbd, MOT_FEC_BD_STAT_OFF,
|
|
rbdStatus);
|
|
|
|
/* if it's not ready, don't touch it! */
|
|
|
|
if ((rbdStatus & MOT_FEC_RBD_EMPTY) == MOT_FEC_RBD_EMPTY)
|
|
{
|
|
return (EAGAIN);
|
|
}
|
|
|
|
/* pass the packet up only if reception was Ok */
|
|
|
|
if (rbdStatus & MOT_FEC_RBD_ERR)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecReceive: bad rbd\n"),
|
|
1, 2, 3, 4, 5, 6);
|
|
goto motFecPollReceiveEnd;
|
|
}
|
|
|
|
/* get the actual amount of received data */
|
|
|
|
MOT_FEC_BD_WORD_RD (pRbd, MOT_FEC_BD_LEN_OFF,
|
|
rbdLen);
|
|
|
|
if (rbdLen < ETHERSMALL)
|
|
{
|
|
MOT_FEC_RX_LS_ADD;
|
|
|
|
goto motFecPollReceiveEnd;
|
|
}
|
|
|
|
/*
|
|
* Upper layer provides the buffer. If buffer is not large enough,
|
|
* we do not copy the received buffer.
|
|
*/
|
|
|
|
if (pMblk->mBlkHdr.mLen < rbdLen)
|
|
{
|
|
goto motFecPollReceiveEnd;
|
|
}
|
|
|
|
MOT_FEC_BD_LONG_RD (pRbd, MOT_FEC_BD_ADDR_OFF, pData);
|
|
|
|
/* up-date statistics */
|
|
|
|
if ((*pData ) & (UINT8) 0x01)
|
|
{
|
|
pDrvCtrl->endObj.mib2Tbl.ifInNUcastPkts += 1;
|
|
}
|
|
else
|
|
{
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
|
|
}
|
|
|
|
/* set up the mBlk properly */
|
|
|
|
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
|
|
pMblk->mBlkHdr.mLen = (rbdLen - ETHER_CRC_LEN) & ~0xc000;
|
|
pMblk->mBlkPktHdr.len = pMblk->mBlkHdr.mLen;
|
|
|
|
/* Make cache consistent with memory */
|
|
|
|
MOT_FEC_CACHE_INVAL ((char *) pData, pMblk->mBlkHdr.mLen);
|
|
|
|
bcopy ((char *) pData, (char *) pMblk->mBlkHdr.mData,
|
|
((rbdLen - ETHER_CRC_LEN) & ~0xc000));
|
|
|
|
/* put the used RBD on the RBD queue */
|
|
|
|
motFecRbdClean (pDrvCtrl, NULL);
|
|
|
|
return (retVal);
|
|
|
|
motFecPollReceiveEnd:
|
|
|
|
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
|
|
|
|
/* put the errored RBD on the RBD queue */
|
|
|
|
motFecRbdClean (pDrvCtrl, NULL);
|
|
|
|
return (EAGAIN);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecPollStart - start polling mode
|
|
*
|
|
* This routine starts polling mode by disabling ethernet interrupts and
|
|
* setting the polling flag in the END_CTRL structure.
|
|
*
|
|
* SEE ALSO: motFecPollStop()
|
|
*
|
|
* RETURNS: OK, or ERROR if polling mode could not be started.
|
|
*/
|
|
|
|
LOCAL STATUS motFecPollStart
|
|
(
|
|
DRV_CTRL *pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
int intLevel; /* current intr level */
|
|
int retVal; /* convenient holder for return value */
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollStart\n"), 0, 0, 0, 0, 0, 0);
|
|
|
|
intLevel = intLock();
|
|
|
|
/* disable system interrupt: reset relevant bit in SIMASK */
|
|
|
|
SYS_FEC_INT_DISABLE (pDrvCtrl, retVal);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/* mask chip interrupts */
|
|
|
|
MOT_FEC_INT_DISABLE;
|
|
|
|
MOT_FEC_FLAG_SET (MOT_FEC_POLLING);
|
|
|
|
intUnlock (intLevel);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motFecPollStop - stop polling mode
|
|
*
|
|
* This routine stops polling mode by enabling ethernet interrupts and
|
|
* resetting the polling flag in the END_CTRL structure.
|
|
*
|
|
* SEE ALSO: motFecPollStart()
|
|
*
|
|
* RETURNS: OK, or ERROR if polling mode could not be stopped.
|
|
*/
|
|
|
|
LOCAL STATUS motFecPollStop
|
|
(
|
|
DRV_CTRL *pDrvCtrl /* pointer to DRV_CTRL structure */
|
|
)
|
|
{
|
|
int intLevel;
|
|
int retVal; /* convenient holder for return value */
|
|
|
|
intLevel = intLock();
|
|
|
|
/* enable system interrupt: set relevant bit in SIMASK */
|
|
|
|
SYS_FEC_INT_ENABLE (pDrvCtrl, retVal);
|
|
if (retVal == ERROR)
|
|
return (ERROR);
|
|
|
|
/* enable chip interrupts */
|
|
|
|
MOT_FEC_INT_ENABLE;
|
|
|
|
/* set flags */
|
|
|
|
MOT_FEC_FLAG_CLEAR (MOT_FEC_POLLING);
|
|
|
|
intUnlock (intLevel);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollStop... end\n"),
|
|
0, 0, 0, 0, 0, 0);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
#ifdef MOT_FEC_DBG
|
|
void motFecCsrShow
|
|
(
|
|
)
|
|
{
|
|
UINT32 csrVal;
|
|
DRV_CTRL * pDrvCtrl = pDrvCtrlDbg;
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_ADDR_L_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Addr low: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_ADDR_H_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Addr high: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_HASH_H_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Hash table high: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_HASH_L_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Hash table low: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_START_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx ring start: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_TX_START_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx ring start: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_BUF_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx max buffer: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_CTRL_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Ethernet Controller: 0x%x\n"),
|
|
(csrVal & MOT_FEC_CTRL_MASK),
|
|
0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_EVENT_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Interrupt event: 0x%x\n"),
|
|
(csrVal & MOT_FEC_EVENT_MSK),
|
|
0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_MASK_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Interrupt mask: 0x%x\n"),
|
|
(csrVal & MOT_FEC_EVENT_MSK),
|
|
0, 0, 0, 0, 0);
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
MOT_FEC_CSR_RD (MOT_FEC_VEC_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Interrupt vector/level: 0x%x\n"),
|
|
(csrVal & MOT_FEC_VEC_MSK),
|
|
0, 0, 0, 0, 0);
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_ACT_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx active: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_TX_ACT_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx active: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_MII_DATA_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("MII data : 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_MII_SPEED_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("MII speed : 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_BOUND_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx FIFO bound: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_FIFO_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx FIFO base: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_TX_FIFO_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx FIFO base: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_SDMA_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("SDMA Function Code: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_CTRL_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx Control Register: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
|
|
#if (CPU_FAMILY != COLDFIRE)
|
|
MOT_FEC_CSR_RD (MOT_FEC_RX_FR_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx Max frame length: 0x%x\n"),
|
|
(csrVal & MOT_FEC_RX_FR_MSK),
|
|
0, 0, 0, 0, 0);
|
|
#endif /* CPU_FAMILY != COLDFIRE */
|
|
|
|
MOT_FEC_CSR_RD (MOT_FEC_TX_CTRL_OFF, csrVal);
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx Control Register: 0x%x\n"),
|
|
csrVal, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
void motFecRbdShow
|
|
(
|
|
int rbdNum
|
|
)
|
|
{
|
|
UINT16 status;
|
|
UINT16 length;
|
|
UINT32 buffer;
|
|
|
|
MOT_FEC_WORD_RD ((UINT32 *)(pDrvCtrlDbg->rbdBase +
|
|
(rbdNum * MOT_FEC_RBD_SZ) +
|
|
MOT_FEC_BD_STAT_OFF), status);
|
|
|
|
MOT_FEC_WORD_RD ((UINT32 *)(pDrvCtrlDbg->rbdBase +
|
|
(rbdNum * MOT_FEC_RBD_SZ) +
|
|
MOT_FEC_BD_LEN_OFF), length);
|
|
|
|
MOT_FEC_LONG_RD ((UINT32 *)(pDrvCtrlDbg->rbdBase +
|
|
(rbdNum * MOT_FEC_RBD_SZ) +
|
|
MOT_FEC_BD_ADDR_OFF), buffer);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("rbdStatus=0x%x rbdLen=0x%x rbdBuf=0x%x\n"),
|
|
status, length, buffer, 0, 0, 0);
|
|
}
|
|
|
|
void motFecErrorShow
|
|
(
|
|
)
|
|
{
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("TxBab=0x%x RxBab=0x%x\n"),
|
|
motFecBabTxErr,
|
|
motFecBabRxErr,
|
|
0, 0, 0, 0);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("TxLc=0x%x TxUr=0x%x TxCsl=0x%x \n\
|
|
TxRl=0x%x\n"),
|
|
motFecTxLcErr,
|
|
motFecTxUrErr,
|
|
motFecTxCslErr,
|
|
motFecTxRlErr,
|
|
0, 0);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("RxLg=0x%x RxNo=0x%x RxCrc=0x%x \n\
|
|
RxOv=0x%x RxTr=0x%x\n"),
|
|
motFecRxLgErr,
|
|
motFecRxNoErr,
|
|
motFecRxCrcErr,
|
|
motFecRxOvErr,
|
|
motFecRxTrErr,
|
|
0);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("RxLs=0x%x RxMem=0x%x\n"),
|
|
motFecRxLsErr,
|
|
motFecRxMemErr,
|
|
0, 0, 0, 0);
|
|
}
|
|
|
|
void motFecDrvShow
|
|
(
|
|
)
|
|
{
|
|
DRV_CTRL * pDrvCtrl = pDrvCtrlDbg;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("pDrvCtrl=0x%x pNetPool=0x%x \n\
|
|
pClPool=0x%x\n"),
|
|
(int) pDrvCtrl,
|
|
(int) pDrvCtrl->endObj.pNetPool,
|
|
(int) pDrvCtrl->pClPoolId, 0, 0, 0);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("bufBase=0x%x bufSize=0x%x pClBlkArea=0x%x\n\
|
|
clBlkSize=0x%x pMBlkArea=0x%x \n\
|
|
mBlkSize=0x%x\n"),
|
|
(int) pDrvCtrl->pBufBase,
|
|
pDrvCtrl->bufSize,
|
|
(int) pDrvCtrl->pClBlkArea,
|
|
pDrvCtrl->clBlkSize,
|
|
(int) pDrvCtrl->pMBlkArea,
|
|
pDrvCtrl->mBlkSize);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("tbdNum=%d tbdBase=0x%xtbdIndex=%d \n\
|
|
usedTbdIndex=%d \n\
|
|
cleanTbdNum=%d txStall=%d \n"),
|
|
pDrvCtrl->tbdNum,
|
|
(int) pDrvCtrl->tbdBase,
|
|
pDrvCtrl->tbdIndex,
|
|
pDrvCtrl->usedTbdIndex,
|
|
pDrvCtrl->cleanTbdNum,
|
|
pDrvCtrl->txStall);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("rbdNum=%d rbdBase=0x%x rbdIndex=%d \n"),
|
|
pDrvCtrl->rbdNum,
|
|
(int) pDrvCtrl->rbdBase,
|
|
pDrvCtrl->rbdIndex,
|
|
0, 0, 0);
|
|
}
|
|
|
|
void motFecMiiShow
|
|
(
|
|
)
|
|
{
|
|
DRV_CTRL * pDrvCtrl = pDrvCtrlDbg;
|
|
UCHAR speed [20];
|
|
UCHAR mode [20];
|
|
|
|
strcpy ((char *) speed, (pDrvCtrl->phyInfo->phySpeed == MOT_FEC_100MBS) ?
|
|
"100Mbit/s" : "10Mbit/s");
|
|
strcpy ((char *) mode, (pDrvCtrl->phyInfo->phyMode == MOT_FEC_PHY_FD) ?
|
|
"full duplex" : "half duplex");
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("phySpeed=%s phyMode=%s phyAddr=0x%x\n\
|
|
isoPhyAddr=0x%x phyFlags=0x%x\n\
|
|
phyDefMode=0x%x\n"),
|
|
(int) &speed[0],
|
|
(int) &mode[0],
|
|
pDrvCtrl->phyInfo->phyAddr,
|
|
pDrvCtrl->phyInfo->isoPhyAddr,
|
|
pDrvCtrl->phyInfo->phyFlags,
|
|
pDrvCtrl->phyInfo->phyDefMode);
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("phyStatus=0x%x phyCtrl=0x%x phyAds=0x%x\n\
|
|
phyPrtn=0x%x phyExp=0x%x phyNext=0x%x\n"),
|
|
pDrvCtrl->phyInfo->miiRegs.phyStatus,
|
|
pDrvCtrl->phyInfo->miiRegs.phyCtrl,
|
|
pDrvCtrl->phyInfo->miiRegs.phyAds,
|
|
pDrvCtrl->phyInfo->miiRegs.phyPrtn,
|
|
pDrvCtrl->phyInfo->miiRegs.phyExp,
|
|
pDrvCtrl->phyInfo->miiRegs.phyNext);
|
|
}
|
|
void motFecMibShow
|
|
(
|
|
)
|
|
{
|
|
DRV_CTRL * pDrvCtrl = pDrvCtrlDbg;
|
|
|
|
MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("ifOutNUcastPkts=%d ifOutUcastPkts=%d\n\
|
|
ifInNUcastPkts=%d\n\
|
|
ifInUcastPkts=%d ifOutErrors=%d\n"),
|
|
pDrvCtrl->endObj.mib2Tbl.ifOutNUcastPkts,
|
|
pDrvCtrl->endObj.mib2Tbl.ifOutUcastPkts,
|
|
pDrvCtrl->endObj.mib2Tbl.ifInNUcastPkts,
|
|
pDrvCtrl->endObj.mib2Tbl.ifInUcastPkts,
|
|
pDrvCtrl->endObj.mib2Tbl.ifOutErrors,
|
|
0);
|
|
|
|
}
|
|
#endif /* MOT_FEC_DBG */
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* motRevNumGet - Get the processor revision number
|
|
*
|
|
* This routine will return the lower 16 bits of the IMMR (SPR #638)
|
|
* which will contain the processor revision number.
|
|
*
|
|
* RETURNS: processor revision number (in r3)
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
LOCAL int motRevNumGet(void)
|
|
{
|
|
#if (CPU_FAMILY == COLDFIRE)
|
|
return(0);
|
|
#else /* CPU_FAMILY == COLDFIRE */
|
|
int rev;
|
|
rev = vxImmrDevGet();
|
|
return(rev);
|
|
#endif /* CPU_FAMILY == COLDFIRE */
|
|
}
|
|
|