#include <IOKit/network/IOEthernetController.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IOGatedOutputQueue.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/network/IOMbufMemoryCursor.h>
#include <IOKit/IODeviceMemory.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOUserClient.h>
extern "C"
{
#include <sys/param.h>
#include <sys/mbuf.h>
}
typedef volatile UInt32 VU32;
typedef volatile UInt16 VU16;
#define KERNEL_DEBUG( x, a, b, c, d, e )
#include "UniNEnetRegisters.h"
#define USE_ELG 0 // for debugging
#define kEvLogSize (4096*16) // 16 pages = 64K = 4096 events 0x10000
#if USE_ELG
#define ELG(A,B,ASCI,STRING) EvLog( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING )
#define ALRT(A,B,ASCI,STRING) Alrt( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING )
#define UC_ELG(A,B,ASCI,STRING) fProvider->EvLog( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING )
void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str );
UInt32 Alrt( UInt32 a, UInt32 b, UInt32 ascii, char* str );
#warning *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
#warning The USE_ELG debugging facility is enabled. *** *** *** *** *** *** *** *** *** *** ***
#warning *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
#else
#define ELG(A,B,ASCI,S)
#define ALRT(A,B,ASCI,STRING) IOLog( "UniNEnet: %8x %8x " STRING "\n", (unsigned int)(A), (unsigned int)(B) )
#define UC_ELG(A,B,ASCI,STRING)
#endif
typedef struct elg
{
UInt32 evLogFlag; UInt8 *evLogBuf;
UInt8 *evLogBufe;
UInt8 *evLogBufp;
UInt32 startTimeSecs; UInt32 physAddr; UInt32 alertCount; UInt32 wrapCount;
UInt32 lostEvents; UInt32 res1; UInt32 res2; UInt32 res3; };
#if USE_ELG
#define READ_REGISTER( REG ) (UInt32)(fCellClockEnabled ? OSReadLittleInt32( (void*)&fpRegs->REG, 0 ) : Alrt( 0, 0, 'REG-', "regs unavail" ) )
#define WRITE_REGISTER( REG, VAL ) writeRegister( &fpRegs->REG, VAL )
#else
#define READ_REGISTER( REG ) OSReadLittleInt32( (void*)fpRegs, offsetof( GMAC_Registers, REG ) )
#define WRITE_REGISTER( REG, VAL ) OSWriteLittleInt32( (void*)fpRegs, offsetof( GMAC_Registers, REG ), VAL )
#endif // USE_ELG
#define NETWORK_STAT_ADD( x ) (fpNetStats->x++)
#define ETHERNET_STAT_ADD( x ) (fpEtherStats->x++)
typedef void *IOPPCAddress;
enum LinkStatus
{
kLinkStatusUnknown,
kLinkStatusDown,
kLinkStatusUp,
};
struct MediumTable
{
UInt32 type;
UInt32 speed;
};
#define kNumOfPowerStates 2
#define kUniNsettle_time 500 // guess 500 microseconds for settling
#define kTxQueueSize "TxPacketQueueSize"
#define kTxRingElements "TxRingElements: 32,64,128,256,512,1024,2048,4096,8192"
#define kRxRingElements "RxRingElements: 32,64,128,256,512,1024,2048,4096,8192"
#define DBG_UniN_ENET 0x0900
#define DBG_UniN_RXIRQ DRVDBG_CODE( DBG_DRVNETWORK, (DBG_UniN_ENET+1) )
#define DBG_UniN_TXIRQ DRVDBG_CODE( DBG_DRVNETWORK, (DBG_UniN_ENET+2) )
#define DBG_UniN_TXQUEUE DRVDBG_CODE( DBG_DRVNETWORK, (DBG_UniN_ENET+3) )
#define DBG_UniN_TXCOMPLETE DRVDBG_CODE( DBG_DRVNETWORK, (DBG_UniN_ENET+4) )
#define DBG_UniN_RXCOMPLETE DRVDBG_CODE( DBG_DRVNETWORK, (DBG_UniN_ENET+5) )
enum
{
kGMACUserCmd_GetLog = 0x30, kGMACUserCmd_GetRegs = 0x31, kGMACUserCmd_GetPHY = 0x32, kGMACUserCmd_GetTxRing = 0x33, kGMACUserCmd_GetRxRing = 0x34,
kGMACUserCmd_ReadAllMII = 0x50, kGMACUserCmd_ReadMII = 0x51, kGMACUserCmd_WriteMII = 0x52 };
struct UCRequest
{
UInt32 reqID;
UInt8* pLogBuffer;
UInt32 bufSize;
};
class UniNEnet;
class UniNEnetUserClient : public IOUserClient
{
OSDeclareDefaultStructors( UniNEnetUserClient ) ;
private:
UniNEnet *fProvider;
IOExternalMethod fMethods[1]; task_t fTask;
IOMemoryMap *fmap;
public:
static UniNEnetUserClient* withTask( task_t owningTask );
virtual IOReturn clientClose();
virtual IOReturn clientDied();
virtual IOReturn registerNotificationPort( mach_port_t port, UInt32 type ); virtual IOReturn connectClient( IOUserClient *client );
virtual IOExternalMethod* getExternalMethodForIndex( UInt32 index );
virtual bool start( IOService *provider );
IOReturn doRequest( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
IOReturn getGMACLog( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
IOReturn getGMACRegs( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
IOReturn getGMACTxRing( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
IOReturn getGMACRxRing( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
IOReturn readAllMII( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
IOReturn readMII( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
IOReturn writeMII( void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize );
};
class UniNEnet: public IOEthernetController
{
OSDeclareDefaultStructors( UniNEnet )
public:
elg *fpELG; IOMemoryDescriptor *fpELGMemDesc; volatile GMAC_Registers *fpRegs; IOPCIDevice *nub;
IOMemoryMap *ioMapEnet;
volatile IOPPCAddress ioBaseEnet;
IOEthernetInterface *networkInterface;
IOBasicOutputQueue *transmitQueue;
IOPacketQueue *debugQueue;
IOKernelDebugger *debugger;
IOWorkLoop *workLoop;
IOInterruptEventSource *interruptSource;
IOTimerEventSource *timerSource;
IONetworkStats *fpNetStats;
IOEthernetStats *fpEtherStats;
OSDictionary *fMediumDict;
MediumTable *fpgMediumTable;
UInt32 fMediumTableCount;
IOMediumType fMediumType;
IOEthernetAddress myAddress;
bool fBuiltin; bool fK2;
bool fReady;
bool fWOL; bool fCellClockEnabled;
bool netifEnabled;
bool debugEnabled;
bool debugTxPoll;
bool fIsPromiscuous;
bool multicastEnabled;
bool isFullDuplex;
bool txDebuggerPktInUse; bool fLoopback;
UInt32 phyType; UInt8 phyId;
UInt32 fLinkStatus;
UInt16 fPHYStatus;
UInt16 fPHYControl; UInt32 fPHYType;
UInt32 fTxQueueSize; UInt32 fTxRingElements; UInt32 fRxRingElements;
mbuf **fTxMbuf; mbuf **fRxMbuf; mbuf *txDebuggerPkt;
void *debuggerPkt;
UInt32 debuggerPktSize;
UInt32 txCommandHead; UInt32 txCommandTail;
UInt32 rxCommandHead;
IOMbufBigMemoryCursor *fTxMbufCursor;
struct IOPhysicalSegment fTxSegment[ MAX_SEGS_PER_TX_MBUF ];
UInt32 fTxElementsAvail;
TxDescriptor *fTxDescriptorRing; UInt32 fTxDescriptorRingPhys;
UInt32 fTxRingLengthFactor;
RxDescriptor *fRxDescriptorRing; UInt32 fRxDescriptorRingPhys;
UInt32 fRxRingLengthFactor;
IOMemoryDescriptor *fTxRingMemDesc;
IOMemoryDescriptor *fRxRingMemDesc;
UInt32 txIntCnt;
UInt32 txRingIndexLast;
UInt32 txWDCount;
UInt32 rxWDCount;
UInt16 hashTableUseCount[ 256 ];
UInt16 hashTableMask[ 16 ];
UInt32 currentPowerState;
UInt32 fConfiguration;
UInt32 fXIFConfiguration;
UInt32 fRxMACConfiguration;
UInt32 fMACControlConfiguration;
UInt32 fRxMACStatus;
UInt32 fIntStatusForTO;
private: bool allocateMemory();
bool initTxRing();
bool initRxRing();
void flushRings( bool, bool ); bool initChip();
void setDuplexMode( bool duplexMode );
void startChip();
void stopChip();
bool genRxDescriptor( UInt32 index );
void monitorLinkStatus( bool firstPoll = false );
bool transmitPacket( struct mbuf *packet );
bool transmitInterruptOccurred();
void debugTransmitInterruptOccurred();
void debugTransmitCleanup();
bool receivePackets( bool fDebugger );
void packetToDebugger( struct mbuf *packet, u_int size );
void restartReceiver();
void putToSleep( bool pangeaClockOnly );
bool wakeUp( bool pangeaClockOnly );
void resetHashTableMask();
void addToHashTableMask( UInt8 *addr );
void removeFromHashTableMask( UInt8 *addr );
void updateHashTableMask();
void sendPacket( void *pkt, UInt32 pkt_len );
void receivePacket( void *pkt, UInt32 *pkt_len, UInt32 timeout );
void miiWrite( UInt32 miiData, UInt32 dataSize );
bool miiResetPHY();
bool miiWaitForAutoNegotiation();
bool miiFindPHY();
bool miiInitializePHY();
UInt32 outputPacket( struct mbuf *m, void *param );
void interruptOccurred( IOInterruptEventSource *src, int count );
void timeoutOccurred( IOTimerEventSource *timer );
bool createMediumTables();
void writeRegister( volatile UInt32 *pReg, UInt32 data );
void getPhyType();
void stopPHY();
void startPHY();
bool hardwareResetPHY();
const OSSymbol *keyLargo_resetUniNEthernetPhy;
IOService *keyLargo;
public:
#ifdef USE_ELG
void AllocateEventLog( UInt32 size );
void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str );
UInt32 Alrt( UInt32 a, UInt32 b, UInt32 ascii, char* str );
#endif // USE_ELG
virtual bool init( OSDictionary *properties = 0 );
virtual bool start(IOService *provider);
virtual void free();
virtual bool createWorkLoop();
virtual IOWorkLoop* getWorkLoop() const;
virtual IOReturn enable( IONetworkInterface *netif );
virtual IOReturn disable( IONetworkInterface *netif );
virtual IOReturn setWakeOnMagicPacket( bool active );
virtual IOReturn getPacketFilters( const OSSymbol *group,
UInt32 *filters ) const;
virtual IOReturn getHardwareAddress( IOEthernetAddress *addr );
virtual IOReturn setHardwareAddress( const IOEthernetAddress *addr );
virtual IOReturn setMulticastMode( IOEnetMulticastMode mode );
virtual IOReturn setMulticastList( IOEthernetAddress *addrs, UInt32 count );
virtual IOReturn setPromiscuousMode( IOEnetPromiscuousMode mode );
virtual IOOutputQueue* createOutputQueue();
virtual const OSString* newVendorString() const;
virtual const OSString* newModelString() const;
virtual const OSString* newRevisionString() const;
virtual IOReturn enable( IOKernelDebugger *debugger );
virtual IOReturn disable( IOKernelDebugger *debugger );
virtual bool configureInterface( IONetworkInterface *netif );
virtual IOReturn getChecksumSupport( UInt32 *checksumMask,
UInt32 checksumFamily,
bool isOutput );
virtual IOReturn selectMedium( const IONetworkMedium *medium );
IOReturn negotiateSpeedDuplex();
IOReturn forceSpeedDuplex();
virtual IOReturn registerWithPolicyMaker( IOService *policyMaker );
virtual UInt32 maxCapabilityForDomainState( IOPMPowerFlags state);
virtual UInt32 initialPowerStateForDomainState( IOPMPowerFlags state );
virtual UInt32 powerStateForDomainState( IOPMPowerFlags state );
virtual IOReturn setPowerState( UInt32 powerStateOrdinal,
IOService *whatDevice );
virtual IOReturn newUserClient( task_t, void*, UInt32, IOUserClient** );
bool miiReadWord( UInt16 *dataPtr, UInt16 reg );
bool miiWriteWord( UInt16 data, UInt16 reg );
};