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];
};