479 lines
15 KiB
C++
479 lines
15 KiB
C++
/* IntelMausiEthernet.h -- IntelMausi driver class definition.
|
|
*
|
|
* Copyright (c) 2014 Laura Müller <laura-mueller@uni-duesseldorf.de>
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* Driver for Intel PCIe gigabit ethernet controllers.
|
|
*
|
|
* This driver is based on Intel's E1000e driver for Linux.
|
|
*/
|
|
|
|
extern "C" {
|
|
#include "e1000.h"
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
#define DebugLog(args...) IOLog(args)
|
|
#else
|
|
#define DebugLog(args...)
|
|
#endif
|
|
|
|
#define RELEASE(x) if(x){(x)->release();(x)=NULL;}
|
|
|
|
#define intelWriteMem8(reg, val8) _OSWriteInt8((baseAddr), (reg), (val8))
|
|
#define intelWriteMem16(reg, val16) OSWriteLittleInt16((baseAddr), (reg), (val16))
|
|
#define intelWriteMem32(reg, val32) OSWriteLittleInt32((baseAddr), (reg), (val32))
|
|
#define intelReadMem8(reg) _OSReadInt8((baseAddr), (reg))
|
|
#define intelReadMem16(reg) OSReadLittleInt16((baseAddr), (reg))
|
|
#define intelReadMem32(reg) OSReadLittleInt32((baseAddr), (reg))
|
|
#define intelFlush() OSReadLittleInt32((baseAddr), (E1000_STATUS))
|
|
|
|
#define super IOEthernetController
|
|
|
|
enum
|
|
{
|
|
MEDIUM_INDEX_AUTO = 0,
|
|
MEDIUM_INDEX_10HD,
|
|
MEDIUM_INDEX_10FD,
|
|
MEDIUM_INDEX_100HD,
|
|
MEDIUM_INDEX_100FD,
|
|
MEDIUM_INDEX_100FDFC,
|
|
MEDIUM_INDEX_1000FD,
|
|
MEDIUM_INDEX_1000FDFC,
|
|
MEDIUM_INDEX_1000FDEEE,
|
|
MEDIUM_INDEX_1000FDFCEEE,
|
|
MEDIUM_INDEX_100FDEEE,
|
|
MEDIUM_INDEX_100FDFCEEE,
|
|
MEDIUM_INDEX_COUNT
|
|
};
|
|
|
|
#define MBit 1000000
|
|
|
|
enum {
|
|
kSpeed1000MBit = 1000*MBit,
|
|
kSpeed100MBit = 100*MBit,
|
|
kSpeed10MBit = 10*MBit,
|
|
};
|
|
|
|
enum {
|
|
kFlowControlTypeNone = 0,
|
|
kFlowControlTypeRx = 1,
|
|
kFlowControlTypeTx = 2,
|
|
kFlowControlTypeRxTx = 3,
|
|
kFlowControlTypeCount
|
|
};
|
|
|
|
enum {
|
|
kEEETypeNo = 0,
|
|
kEEETypeYes = 1,
|
|
kEEETypeCount
|
|
};
|
|
|
|
#define kTransmitQueueCapacity 1000
|
|
|
|
/* With up to 40 segments we should be on the save side. */
|
|
#define kMaxSegs 40
|
|
|
|
#define kTxSpareDescs 16
|
|
|
|
/* The number of descriptors must be a power of 2. */
|
|
#define kNumTxDesc 1024 /* Number of Tx descriptors */
|
|
#define kNumRxDesc 512 /* Number of Rx descriptors */
|
|
#define kTxLastDesc (kNumTxDesc - 1)
|
|
#define kRxLastDesc (kNumRxDesc - 1)
|
|
#define kTxDescMask (kNumTxDesc - 1)
|
|
#define kRxDescMask (kNumRxDesc - 1)
|
|
#define kTxDescSize (kNumTxDesc*sizeof(struct e1000_data_desc))
|
|
#define kRxDescSize (kNumRxDesc*sizeof(union e1000_rx_desc_extended))
|
|
|
|
/* This is the receive buffer size (must be large enough to hold a packet). */
|
|
#define kRxBufferPktSize 2048
|
|
#define kRxNumSpareMbufs 100
|
|
#define kMCFilterLimit 32
|
|
#define kMaxRxQueques 1
|
|
#define kMaxMtu 9000
|
|
#define kMaxPacketSize (kMaxMtu + ETH_HLEN + ETH_FCS_LEN)
|
|
|
|
/* statitics timer period in ms. */
|
|
#define kTimeoutMS 1000
|
|
|
|
/* Treshhold value to wake a stalled queue */
|
|
#define kTxQueueWakeTreshhold (kNumTxDesc / 4)
|
|
|
|
/* transmitter deadlock treshhold in seconds. */
|
|
#define kTxDeadlockTreshhold 2
|
|
|
|
/* Maximum DMA latency in ns. */
|
|
#define kMaxDmaLatency 75000
|
|
|
|
/* IP specific stuff */
|
|
#define kMinL4HdrOffsetV4 34
|
|
#define kMinL4HdrOffsetV6 54
|
|
|
|
#define kIPv4CSumStart ETH_HLEN
|
|
#define kIPv4CSumOffset (offsetof(struct iphdr, check) + kIPv4CSumStart)
|
|
#define kIPv4CSumEnd (sizeof(struct iphdr) + kIPv4CSumStart - 1)
|
|
|
|
#define kUDPv4CSumStart kMinL4HdrOffsetV4
|
|
#define kUDPv4CSumOffset (offsetof(struct udphdr, uh_sum) + kMinL4HdrOffsetV4)
|
|
#define kUDPv4CSumEnd 0
|
|
|
|
#define kTCPv4CSumStart kMinL4HdrOffsetV4
|
|
#define kTCPv4CSumOffset (offsetof(struct tcphdr, th_sum) + kMinL4HdrOffsetV4)
|
|
#define kTCPv4CSumEnd 0
|
|
|
|
#define kIPv6CSumStart ETH_HLEN
|
|
#define kIPv6CSumOffset 0
|
|
#define kIPv6CSumEnd 0
|
|
|
|
#define kTCPv6CSumStart kMinL4HdrOffsetV6
|
|
#define kTCPv6CSumOffset (offsetof(struct tcphdr, th_sum) + kMinL4HdrOffsetV6)
|
|
#define kTCPv6CSumEnd 0
|
|
|
|
#define kUDPv6CSumStart kMinL4HdrOffsetV6
|
|
#define kUDPv6CSumOffset (offsetof(struct udphdr, uh_sum) + kMinL4HdrOffsetV6)
|
|
#define kUDPv6CSumEnd 0
|
|
|
|
#define SPEED_MODE_BIT (1 << 21)
|
|
#define E1000_TARC_QUEUE_EN 0x00000400
|
|
|
|
#define E1000_RXD_STAT_IPPCS 0x40 /* IP xsum calculated */
|
|
|
|
#define E1000_RXDLGC_ERR_CE 0x0100 /* CRC Error */
|
|
#define E1000_RXDLGC_ERR_SE 0x0200 /* Symbol Error */
|
|
#define E1000_RXDLGC_ERR_SEQ 0x0400 /* Sequence Error */
|
|
#define E1000_RXDLGC_ERR_CXE 0x1000 /* Carrier Extension Error */
|
|
#define E1000_RXDLGC_ERR_TCPE 0x2000 /* TCP/UDP Checksum Error */
|
|
#define E1000_RXDLGC_ERR_IPE 0x4000 /* IP Checksum Error */
|
|
#define E1000_RXDLGC_ERR_RXE 0x8000 /* Rx Data Error */
|
|
|
|
#define E1000_RXDEXT_STATERR_TCPE 0x20000000
|
|
#define E1000_RXDEXT_STATERR_IPE 0x40000000
|
|
|
|
/* mask to determine if packets should be dropped due to frame errors */
|
|
#define E1000_RXDLGC_ERR_FRAME_ERR_MASK ( \
|
|
E1000_RXDLGC_ERR_CE | \
|
|
E1000_RXDLGC_ERR_SE | \
|
|
E1000_RXDLGC_ERR_SEQ | \
|
|
E1000_RXDLGC_ERR_CXE | \
|
|
E1000_RXDLGC_ERR_RXE)
|
|
|
|
#define E1000_TX_FLAGS_CSUM 0x00000001
|
|
#define E1000_TX_FLAGS_VLAN 0x00000002
|
|
#define E1000_TX_FLAGS_TSO 0x00000004
|
|
#define E1000_TX_FLAGS_IPV4 0x00000008
|
|
#define E1000_TX_FLAGS_NO_FCS 0x00000010
|
|
#define E1000_TX_FLAGS_HWTSTAMP 0x00000020
|
|
#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
|
|
#define E1000_TX_FLAGS_VLAN_SHIFT 16
|
|
|
|
#define E1000_TXD_OPTS_IXSM 0x00000100
|
|
#define E1000_TXD_OPTS_TXSM 0x00000200
|
|
|
|
#define E1000_RCTL_FLXB_SHIFT 27
|
|
|
|
#define E1000_ICR_TXQE 0x00000002 /* Transmit queue empty */
|
|
#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit queue empty */
|
|
|
|
/* Transmit Interrupt Delay */
|
|
#define DEFAULT_TIDV 8
|
|
|
|
/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds */
|
|
#define DEFAULT_TADV 32
|
|
|
|
/*
|
|
#define E1000_SRPD 0x02C00
|
|
#define E1000_RAID 0x02C08
|
|
#define E1000_IMS_RSPD 0x00010000
|
|
#define E1000_IMS_ACK 0x00020000
|
|
*/
|
|
|
|
/* These definitions should have been in IOPCIDevice.h. */
|
|
enum
|
|
{
|
|
kIOPCIPMCapability = 2,
|
|
kIOPCIPMControl = 4,
|
|
};
|
|
|
|
enum
|
|
{
|
|
kIOPCIEDeviceControl = 8,
|
|
kIOPCIELinkCapability = 12,
|
|
kIOPCIELinkControl = 16,
|
|
};
|
|
|
|
enum
|
|
{
|
|
kIOPCIELinkCtlASPM = 0x0003, /* ASPM Control */
|
|
kIOPCIELinkCtlL0s = 0x0001, /* L0s Enable */
|
|
kIOPCIELinkCtlL1 = 0x0002, /* L1 Enable */
|
|
kIOPCIELinkCtlCcc = 0x0040, /* Common Clock Configuration */
|
|
kIOPCIELinkCtlClkReqEn = 0x100, /* Enable clkreq */
|
|
};
|
|
|
|
enum
|
|
{
|
|
kIOPCIEDevCtlReadQ = 0x7000,
|
|
};
|
|
|
|
enum
|
|
{
|
|
kPowerStateOff = 0,
|
|
kPowerStateOn,
|
|
kPowerStateCount
|
|
};
|
|
|
|
#define kEnableCSO6Name "enableCSO6"
|
|
#define kEnableTSO4Name "enableTSO4"
|
|
#define kEnableTSO6Name "enableTSO6"
|
|
#define kIntrRateName "maxIntrRate"
|
|
#define kDriverVersionName "Driver_Version"
|
|
#define kNameLenght 64
|
|
|
|
struct intelDevice {
|
|
UInt16 pciDevId;
|
|
UInt16 device;
|
|
const char *deviceName;
|
|
const struct e1000_info *deviceInfo;
|
|
};
|
|
|
|
#define kInvalidRingIndex 0xffffffff;
|
|
|
|
struct intelTxBufferInfo {
|
|
mbuf_t mbuf;
|
|
UInt32 numDescs;
|
|
UInt32 pad;
|
|
};
|
|
struct intelRxBufferInfo {
|
|
mbuf_t mbuf;
|
|
IOPhysicalAddress64 phyAddr;
|
|
};
|
|
|
|
struct IntelRxDesc {
|
|
UInt64 bufferAddr;
|
|
UInt64 status;
|
|
};
|
|
|
|
class IntelMausi : public super
|
|
{
|
|
|
|
OSDeclareDefaultStructors(IntelMausi)
|
|
|
|
public:
|
|
/* IOService (or its superclass) methods. */
|
|
virtual bool start(IOService *provider);
|
|
virtual void stop(IOService *provider);
|
|
virtual bool init(OSDictionary *properties);
|
|
virtual void free();
|
|
|
|
/* Power Management Support */
|
|
virtual IOReturn registerWithPolicyMaker(IOService *policyMaker);
|
|
virtual IOReturn setPowerState(unsigned long powerStateOrdinal, IOService *policyMaker );
|
|
virtual void systemWillShutdown(IOOptionBits specifier);
|
|
|
|
/* IONetworkController methods. */
|
|
virtual IOReturn enable(IONetworkInterface *netif);
|
|
virtual IOReturn disable(IONetworkInterface *netif);
|
|
|
|
virtual IOReturn outputStart(IONetworkInterface *interface, IOOptionBits options );
|
|
virtual IOReturn setInputPacketPollingEnable(IONetworkInterface *interface, bool enabled);
|
|
virtual void pollInputPackets(IONetworkInterface *interface, uint32_t maxCount, IOMbufQueue *pollQueue, void *context);
|
|
|
|
virtual void getPacketBufferConstraints(IOPacketBufferConstraints *constraints) const;
|
|
|
|
virtual IOOutputQueue* createOutputQueue();
|
|
|
|
virtual const OSString* newVendorString() const;
|
|
virtual const OSString* newModelString() const;
|
|
|
|
virtual IOReturn selectMedium(const IONetworkMedium *medium);
|
|
virtual bool configureInterface(IONetworkInterface *interface);
|
|
|
|
virtual bool createWorkLoop();
|
|
virtual IOWorkLoop* getWorkLoop() const;
|
|
|
|
/* Methods inherited from IOEthernetController. */
|
|
virtual IOReturn getHardwareAddress(IOEthernetAddress *addr);
|
|
virtual IOReturn setHardwareAddress(const IOEthernetAddress *addr);
|
|
virtual IOReturn setPromiscuousMode(bool active);
|
|
virtual IOReturn setMulticastMode(bool active);
|
|
virtual IOReturn setMulticastList(IOEthernetAddress *addrs, UInt32 count);
|
|
virtual IOReturn getChecksumSupport(UInt32 *checksumMask, UInt32 checksumFamily, bool isOutput);
|
|
virtual IOReturn getMinPacketSize(UInt32 *minSize) const;
|
|
virtual IOReturn setWakeOnMagicPacket(bool active);
|
|
virtual IOReturn getPacketFilters(const OSSymbol *group, UInt32 *filters) const;
|
|
|
|
virtual UInt32 getFeatures() const;
|
|
virtual IOReturn getMaxPacketSize(UInt32 * maxSize) const;
|
|
virtual IOReturn setMaxPacketSize(UInt32 maxSize);
|
|
|
|
private:
|
|
bool initPCIConfigSpace(IOPCIDevice *provider);
|
|
void initPCIPowerManagment(IOPCIDevice *provider, const struct e1000_info *ei);
|
|
inline void intelEnablePCIDevice(IOPCIDevice *provider);
|
|
static IOReturn setPowerStateWakeAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
|
|
static IOReturn setPowerStateSleepAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
|
|
void getParams();
|
|
bool setupMediumDict();
|
|
bool initEventSources(IOService *provider);
|
|
void interruptOccurred(OSObject *client, IOInterruptEventSource *src, int count);
|
|
void txInterrupt();
|
|
|
|
UInt32 rxInterrupt(IONetworkInterface *interface, uint32_t maxCount, IOMbufQueue *pollQueue, void *context);
|
|
|
|
bool setupDMADescriptors();
|
|
void freeDMADescriptors();
|
|
void clearDescriptors();
|
|
void checkLinkStatus();
|
|
void updateStatistics(struct e1000_adapter *adapter);
|
|
void setLinkUp();
|
|
void setLinkDown();
|
|
bool checkForDeadlock();
|
|
|
|
/* Jumbo frame support methods */
|
|
void discardPacketFragment();
|
|
|
|
/* Hardware specific methods */
|
|
bool intelIdentifyChip();
|
|
bool intelStart();
|
|
void intelEEPROMChecks(struct e1000_adapter *adapter);
|
|
void intelInitTxRing();
|
|
void intelInitRxRing();
|
|
void intelEnableIRQ(UInt32 newMask);
|
|
void intelDisableIRQ();
|
|
void intelUpdateTxDescTail(UInt32 index);
|
|
void intelUpdateRxDescTail(UInt32 index);
|
|
|
|
void intelEnable();
|
|
void intelDisable();
|
|
void intelConfigure(struct e1000_adapter *adapter);
|
|
void intelConfigureTx(struct e1000_adapter *adapter);
|
|
void intelSetupRxControl(struct e1000_adapter *adapter);
|
|
void intelConfigureRx(struct e1000_adapter *adapter);
|
|
void intelDown(struct e1000_adapter *adapter, bool reset);
|
|
void intelInitManageabilityPt(struct e1000_adapter *adapter);
|
|
void intelReset(struct e1000_adapter *adapter);
|
|
void intelPowerDownPhy(struct e1000_adapter *adapter);
|
|
bool intelEnableMngPassThru(struct e1000_hw *hw);
|
|
void intelResetAdaptive(struct e1000_hw *hw);
|
|
void intelUpdateAdaptive(struct e1000_hw *hw);
|
|
void intelVlanStripDisable(struct e1000_adapter *adapter);
|
|
void intelVlanStripEnable(struct e1000_adapter *adapter);
|
|
void intelSetupRssHash(struct e1000_adapter *adapter);
|
|
|
|
void intelRestart();
|
|
bool intelCheckLink(struct e1000_adapter *adapter);
|
|
void intelFlushDescriptors();
|
|
void intelFlushTxRing(struct e1000_adapter *adapter);
|
|
void intelFlushRxRing(struct e1000_adapter *adapter);
|
|
void intelFlushDescRings(struct e1000_adapter *adapter);
|
|
void intelPhyReadStatus(struct e1000_adapter *adapter);
|
|
void intelInitPhyWakeup(UInt32 wufc);
|
|
void intelSetupAdvForMedium(const IONetworkMedium *medium);
|
|
void intelFlushLPIC();
|
|
void setMaxLatency(UInt32 linkSpeed);
|
|
|
|
UInt16 intelSupportsEEE(struct e1000_adapter *adapter);
|
|
SInt32 intelEnableEEE(struct e1000_hw *hw, UInt16 mode);
|
|
|
|
inline void intelGetChecksumResult(mbuf_t m, UInt32 status);
|
|
|
|
/* timer action */
|
|
void timerAction(IOTimerEventSource *timer);
|
|
|
|
private:
|
|
IOWorkLoop *workLoop;
|
|
IOCommandGate *commandGate;
|
|
IOPCIDevice *pciDevice;
|
|
OSDictionary *mediumDict;
|
|
IONetworkMedium *mediumTable[MEDIUM_INDEX_COUNT];
|
|
IOBasicOutputQueue *txQueue;
|
|
|
|
IOInterruptEventSource *interruptSource;
|
|
IOTimerEventSource *timerSource;
|
|
IOEthernetInterface *netif;
|
|
IOMemoryMap *baseMap;
|
|
volatile void *baseAddr;
|
|
IOMemoryMap *flashMap;
|
|
volatile void *flashAddr;
|
|
|
|
/* transmitter data */
|
|
IODMACommand *txDescDmaCmd;
|
|
IOBufferMemoryDescriptor *txBufDesc;
|
|
IOPhysicalAddress64 txPhyAddr;
|
|
struct e1000_data_desc *txDescArray;
|
|
IOMbufNaturalMemoryCursor *txMbufCursor;
|
|
UInt64 txDescDoneCount;
|
|
UInt64 txDescDoneLast;
|
|
SInt32 txNumFreeDesc;
|
|
UInt32 mtu;
|
|
UInt32 maxLatency;
|
|
UInt16 txNextDescIndex;
|
|
UInt16 txDirtyIndex;
|
|
UInt16 txCleanBarrierIndex;
|
|
|
|
/* receiver data */
|
|
IODMACommand *rxDescDmaCmd;
|
|
IOBufferMemoryDescriptor *rxBufDesc;
|
|
IOPhysicalAddress64 rxPhyAddr;
|
|
union e1000_rx_desc_extended *rxDescArray;
|
|
IOMbufNaturalMemoryCursor *rxMbufCursor;
|
|
mbuf_t rxPacketHead;
|
|
mbuf_t rxPacketTail;
|
|
UInt32 rxPacketSize;
|
|
IOEthernetAddress *mcAddrList;
|
|
UInt32 mcListCount;
|
|
UInt16 rxNextDescIndex;
|
|
UInt16 rxCleanedCount;
|
|
|
|
/* power management data */
|
|
unsigned long powerState;
|
|
|
|
/* statistics data */
|
|
UInt32 deadlockWarn;
|
|
IONetworkStats *netStats;
|
|
IOEthernetStats *etherStats;
|
|
|
|
UInt32 chip;
|
|
UInt32 chipType;
|
|
UInt32 intrMask;
|
|
UInt32 intrThrValue;
|
|
struct e1000_adapter adapterData;
|
|
struct pci_dev pciDeviceData;
|
|
UInt16 eeeMode;
|
|
UInt8 pcieCapOffset;
|
|
UInt8 pciPMCtrlOffset;
|
|
|
|
UInt32 linkOpts;
|
|
IONetworkPacketPollingParameters pollParams;
|
|
|
|
/* flags */
|
|
bool isEnabled;
|
|
bool promiscusMode;
|
|
bool multicastMode;
|
|
bool linkUp;
|
|
|
|
bool polling;
|
|
|
|
bool forceReset;
|
|
bool wolCapable;
|
|
bool wolActive;
|
|
bool enableTSO4;
|
|
bool enableTSO6;
|
|
bool enableCSO6;
|
|
|
|
/* mbuf_t arrays */
|
|
struct intelTxBufferInfo txBufArray[kNumTxDesc];
|
|
struct intelRxBufferInfo rxBufArray[kNumRxDesc];
|
|
};
|