2015-01-27 23:52:50 +01:00
|
|
|
/* IntelMausiHardware.cpp -- IntelMausi hardware specific routines.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "IntelMausiEthernet.h"
|
|
|
|
|
|
|
|
#pragma mark --- hardware initialization methods ---
|
|
|
|
|
|
|
|
bool IntelMausi::initPCIConfigSpace(IOPCIDevice *provider)
|
|
|
|
{
|
2016-08-27 00:59:27 +02:00
|
|
|
UInt32 lat1, lat2;
|
2015-01-27 23:52:50 +01:00
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
/* Get vendor and device info. */
|
2016-04-19 00:14:50 +02:00
|
|
|
pciDeviceData.vendor = provider->extendedConfigRead16(kIOPCIConfigVendorID);
|
|
|
|
pciDeviceData.device = provider->extendedConfigRead16(kIOPCIConfigDeviceID);
|
|
|
|
pciDeviceData.subsystem_vendor = provider->extendedConfigRead16(kIOPCIConfigSubSystemVendorID);
|
|
|
|
pciDeviceData.subsystem_device = provider->extendedConfigRead16(kIOPCIConfigSubSystemID);
|
|
|
|
pciDeviceData.revision = provider->extendedConfigRead8(kIOPCIConfigRevisionID);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
/* Identify the chipset. */
|
|
|
|
if (!intelIdentifyChip())
|
|
|
|
goto done;
|
|
|
|
|
2018-02-15 21:34:46 +01:00
|
|
|
if (chipType >= board_pch_lpt) {
|
2016-04-19 00:14:50 +02:00
|
|
|
pciDeviceData.maxSnoop = provider->extendedConfigRead16(E1000_PCI_LTR_CAP_LPT);
|
|
|
|
pciDeviceData.maxNoSnoop = provider->extendedConfigRead16(E1000_PCI_LTR_CAP_LPT + 2);
|
2016-08-27 00:59:27 +02:00
|
|
|
|
|
|
|
lat1 = (pciDeviceData.maxSnoop & 0x3ff) << (((pciDeviceData.maxSnoop >> 10) & 0x7) * 5);
|
|
|
|
lat2 = (pciDeviceData.maxNoSnoop & 0x3ff) << (((pciDeviceData.maxNoSnoop >> 10) & 0x7) * 5);
|
|
|
|
maxLatency = (lat1 > lat2) ? lat1 : lat2;
|
|
|
|
|
|
|
|
if (maxLatency > kMaxDmaLatency)
|
|
|
|
maxLatency = kMaxDmaLatency;
|
|
|
|
|
|
|
|
DebugLog("Ethernet [IntelMausi]: maxSnoop: 0x%04x (%uns), maxNoSnoop: 0x%04x (%uns).\n", pciDeviceData.maxSnoop, lat1, pciDeviceData.maxNoSnoop, lat2);
|
2015-10-30 14:06:33 +01:00
|
|
|
}
|
2015-01-27 23:52:50 +01:00
|
|
|
/* Get the bus information. */
|
|
|
|
adapterData.hw.bus.func = pciDevice->getFunctionNumber();
|
|
|
|
adapterData.hw.bus.width = e1000_bus_width_pcie_x1;
|
|
|
|
|
|
|
|
/* Enable the device. */
|
|
|
|
intelEnablePCIDevice(provider);
|
|
|
|
|
2015-08-12 22:44:04 +02:00
|
|
|
baseMap = provider->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0, kIOMapInhibitCache);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
if (!baseMap) {
|
|
|
|
IOLog("Ethernet [IntelMausi]: region #0 not an MMIO resource, aborting.\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
baseAddr = reinterpret_cast<volatile void *>(baseMap->getVirtualAddress());
|
|
|
|
adapterData.hw.hw_addr = (u8 __iomem *)baseAddr;
|
2016-01-18 01:57:14 +01:00
|
|
|
adapterData.hw.flash_address = NULL;
|
2015-01-27 23:52:50 +01:00
|
|
|
|
2016-01-18 01:57:14 +01:00
|
|
|
if ((adapterData.flags & FLAG_HAS_FLASH) && (adapterData.hw.mac.type < e1000_pch_spt)) {
|
2015-08-12 22:44:04 +02:00
|
|
|
flashMap = provider->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress1, kIOMapInhibitCache);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
if (!flashMap) {
|
|
|
|
IOLog("Ethernet [IntelMausi]: region #1 not an MMIO resource, aborting.\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
flashAddr = reinterpret_cast<volatile void *>(flashMap->getVirtualAddress());
|
|
|
|
adapterData.hw.flash_address = (u8 __iomem *)flashAddr;
|
|
|
|
}
|
|
|
|
result = true;
|
|
|
|
|
|
|
|
done:
|
|
|
|
return result;
|
|
|
|
|
|
|
|
error:
|
|
|
|
RELEASE(baseMap);
|
|
|
|
baseMap = NULL;
|
|
|
|
adapterData.hw.hw_addr = NULL;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::initPCIPowerManagment(IOPCIDevice *provider, const struct e1000_info *ei)
|
|
|
|
{
|
|
|
|
UInt32 pcieLinkCap;
|
|
|
|
UInt16 pcieLinkCtl;
|
|
|
|
UInt16 aspmDisable;
|
|
|
|
UInt16 pmCap;
|
|
|
|
UInt8 pmCapOffset;
|
|
|
|
|
|
|
|
/* Setup power management. */
|
|
|
|
if (provider->findPCICapability(kIOPCIPowerManagementCapability, &pmCapOffset)) {
|
2016-04-19 00:14:50 +02:00
|
|
|
pmCap = provider->extendedConfigRead16(pmCapOffset + kIOPCIPMCapability);
|
2015-01-27 23:52:50 +01:00
|
|
|
DebugLog("Ethernet [IntelMausi]: PCI power management capabilities: 0x%x.\n", pmCap);
|
|
|
|
|
|
|
|
if (pmCap & (kPCIPMCPMESupportFromD3Cold | kPCIPMCPMESupportFromD3Hot)) {
|
|
|
|
wolCapable = true;
|
|
|
|
DebugLog("Ethernet [IntelMausi]: PME# from D3 (cold/hot) supported.\n");
|
|
|
|
}
|
|
|
|
pciPMCtrlOffset = pmCapOffset + kIOPCIPMControl;
|
|
|
|
} else {
|
|
|
|
IOLog("Ethernet [IntelMausi]: PCI power management unsupported.\n");
|
|
|
|
}
|
|
|
|
provider->enablePCIPowerManagement();
|
|
|
|
|
|
|
|
/* Get PCIe link information. */
|
|
|
|
if (provider->findPCICapability(kIOPCIPCIExpressCapability, &pcieCapOffset)) {
|
2016-04-19 00:14:50 +02:00
|
|
|
pcieLinkCap = provider->extendedConfigRead32(pcieCapOffset + kIOPCIELinkCapability);
|
|
|
|
pcieLinkCtl = provider->extendedConfigRead16(pcieCapOffset + kIOPCIELinkControl);
|
2015-01-27 23:52:50 +01:00
|
|
|
DebugLog("Ethernet [IntelMausi]: PCIe link capabilities: 0x%08x, link control: 0x%04x.\n", pcieLinkCap, pcieLinkCtl);
|
|
|
|
aspmDisable = 0;
|
|
|
|
|
|
|
|
if (ei->flags2 & FLAG2_DISABLE_ASPM_L0S)
|
|
|
|
aspmDisable |= kIOPCIELinkCtlL0s;
|
|
|
|
|
|
|
|
if (ei->flags2 & FLAG2_DISABLE_ASPM_L1)
|
|
|
|
aspmDisable |= kIOPCIELinkCtlL1;
|
|
|
|
|
|
|
|
if (aspmDisable)
|
2016-04-19 00:14:50 +02:00
|
|
|
provider->extendedConfigWrite16(pcieCapOffset + kIOPCIELinkControl, (pcieLinkCtl & ~aspmDisable));
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2016-04-19 00:14:50 +02:00
|
|
|
pcieLinkCtl = provider->extendedConfigRead16(pcieCapOffset + kIOPCIELinkControl);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
if (pcieLinkCtl & (kIOPCIELinkCtlASPM | kIOPCIELinkCtlClkReqEn))
|
|
|
|
IOLog("Ethernet [IntelMausi]: PCIe ASPM enabled. link control: 0x%04x.\n", pcieLinkCtl);
|
|
|
|
else
|
|
|
|
IOLog("Ethernet [IntelMausi]: PCIe ASPM disabled. link control: 0x%04x.\n", pcieLinkCtl);
|
|
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IOReturn IntelMausi::setPowerStateWakeAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
|
|
|
|
{
|
|
|
|
IntelMausi *ethCtlr = OSDynamicCast(IntelMausi, owner);
|
|
|
|
IOPCIDevice *dev;
|
|
|
|
UInt16 val16;
|
|
|
|
UInt8 offset;
|
|
|
|
|
|
|
|
if (ethCtlr) {
|
|
|
|
dev = ethCtlr->pciDevice;
|
|
|
|
offset = ethCtlr->pciPMCtrlOffset;
|
|
|
|
|
2016-04-19 00:14:50 +02:00
|
|
|
val16 = dev->extendedConfigRead16(offset);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
val16 &= ~(kPCIPMCSPowerStateMask | kPCIPMCSPMEStatus | kPCIPMCSPMEEnable);
|
|
|
|
val16 |= kPCIPMCSPowerStateD0;
|
|
|
|
|
2016-04-19 00:14:50 +02:00
|
|
|
dev->extendedConfigWrite16(offset, val16);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
/* Restore the PCI Command register. */
|
|
|
|
ethCtlr->intelEnablePCIDevice(dev);
|
|
|
|
}
|
|
|
|
return kIOReturnSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
IOReturn IntelMausi::setPowerStateSleepAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
|
|
|
|
{
|
|
|
|
IntelMausi *ethCtlr = OSDynamicCast(IntelMausi, owner);
|
|
|
|
IOPCIDevice *dev;
|
|
|
|
UInt16 val16;
|
|
|
|
UInt8 offset;
|
|
|
|
|
|
|
|
if (ethCtlr) {
|
|
|
|
dev = ethCtlr->pciDevice;
|
|
|
|
offset = ethCtlr->pciPMCtrlOffset;
|
|
|
|
|
2016-04-19 00:14:50 +02:00
|
|
|
val16 = dev->extendedConfigRead16(offset);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
val16 &= ~(kPCIPMCSPowerStateMask | kPCIPMCSPMEStatus | kPCIPMCSPMEEnable);
|
|
|
|
|
2015-03-05 00:11:40 +01:00
|
|
|
if (ethCtlr->wolActive)
|
2015-01-27 23:52:50 +01:00
|
|
|
val16 |= (kPCIPMCSPMEStatus | kPCIPMCSPMEEnable | kPCIPMCSPowerStateD3);
|
|
|
|
else
|
|
|
|
val16 |= kPCIPMCSPowerStateD3;
|
|
|
|
|
2016-04-19 00:14:50 +02:00
|
|
|
dev->extendedConfigWrite16(offset, val16);
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
|
|
|
return kIOReturnSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelEEPROMChecks(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
int ret_val;
|
|
|
|
u16 buf = 0;
|
|
|
|
|
|
|
|
if (hw->mac.type != e1000_82573)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf);
|
|
|
|
le16_to_cpus(&buf);
|
|
|
|
|
|
|
|
if (!ret_val && (!(buf & (1 << 0)))) {
|
|
|
|
/* Deep Smart Power Down (DSPD) */
|
|
|
|
IOLog("Ethernet [IntelMausi]: Warning: detected DSPD enabled in EEPROM.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelEnableIRQ(UInt32 newMask)
|
|
|
|
{
|
2016-09-14 23:55:24 +02:00
|
|
|
intelWriteMem32(E1000_IMC, ~newMask);
|
2015-01-27 23:52:50 +01:00
|
|
|
intelWriteMem32(E1000_IMS, newMask);
|
|
|
|
intelFlush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelDisableIRQ()
|
|
|
|
{
|
|
|
|
intelWriteMem32(E1000_IMC, 0xFFFFFFFF);
|
|
|
|
intelFlush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelEnable()
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
2016-04-19 00:14:50 +02:00
|
|
|
const IONetworkMedium *selectedMedium;
|
|
|
|
|
|
|
|
selectedMedium = getSelectedMedium();
|
|
|
|
|
|
|
|
if (!selectedMedium) {
|
|
|
|
DebugLog("Ethernet [IntelMausi]: No medium selected. Falling back to autonegotiation.\n");
|
|
|
|
selectedMedium = mediumTable[MEDIUM_INDEX_AUTO];
|
|
|
|
setCurrentMedium(selectedMedium);
|
|
|
|
}
|
2015-01-27 23:52:50 +01:00
|
|
|
|
2016-04-19 00:14:50 +02:00
|
|
|
/* Check if we re waking up from sleep with WoL enabled and still have a valid link. */
|
|
|
|
if (!linkOpts || !intelCheckLink(&adapterData)) {
|
|
|
|
linkOpts = 0;
|
|
|
|
setLinkStatus(kIONetworkLinkValid);
|
|
|
|
}
|
2016-08-27 00:59:27 +02:00
|
|
|
polling = false;
|
2016-04-19 00:14:50 +02:00
|
|
|
|
|
|
|
intelSetupAdvForMedium(selectedMedium);
|
|
|
|
|
2015-01-27 23:52:50 +01:00
|
|
|
e1000_phy_hw_reset(hw);
|
|
|
|
|
|
|
|
if (hw->mac.type >= e1000_pch2lan)
|
|
|
|
e1000_resume_workarounds_pchlan(hw);
|
|
|
|
|
|
|
|
e1000e_power_up_phy(&adapterData);
|
|
|
|
|
|
|
|
/* If AMT is enabled, let the firmware know that the network
|
|
|
|
* interface is now open and reset the part to a known state.
|
|
|
|
*/
|
|
|
|
if (adapterData.flags & FLAG_HAS_AMT) {
|
|
|
|
e1000e_get_hw_control(&adapterData);
|
|
|
|
}
|
|
|
|
intelReset(&adapterData);
|
|
|
|
|
|
|
|
#if DISABLED_CODE
|
|
|
|
|
|
|
|
/* DMA latency requirement to workaround jumbo issue */
|
|
|
|
pm_qos_add_request(&adapter->netdev->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
|
|
|
|
PM_QOS_DEFAULT_VALUE);
|
|
|
|
|
|
|
|
#endif /* DISABLED_CODE */
|
|
|
|
|
|
|
|
intelConfigure(&adapterData);
|
|
|
|
|
|
|
|
/* From here on the code is the same as e1000e_up() */
|
|
|
|
clear_bit(__E1000_DOWN, &adapterData.state);
|
|
|
|
|
2016-09-14 23:55:24 +02:00
|
|
|
intelEnableIRQ(intrMask);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
hw->mac.get_link_status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelDisable()
|
|
|
|
{
|
2015-03-05 00:11:40 +01:00
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
2016-04-19 00:14:50 +02:00
|
|
|
UInt32 linkStatus = kIONetworkLinkValid;
|
2015-03-05 00:11:40 +01:00
|
|
|
UInt32 wufc = adapterData.wol;
|
|
|
|
UInt32 ctrl, ctrlExt, rctl, status;
|
2016-01-18 01:57:14 +01:00
|
|
|
int retval;
|
2015-03-05 00:11:40 +01:00
|
|
|
|
2016-08-27 00:59:27 +02:00
|
|
|
polling = false;
|
2016-04-19 00:14:50 +02:00
|
|
|
linkOpts = 0;
|
|
|
|
|
2015-03-05 00:11:40 +01:00
|
|
|
/* Flush LPIC. */
|
|
|
|
intelFlushLPIC();
|
|
|
|
|
|
|
|
status = intelReadMem32(E1000_STATUS);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
2015-03-05 00:11:40 +01:00
|
|
|
if (status & E1000_STATUS_LU)
|
|
|
|
wufc &= ~E1000_WUFC_LNKC;
|
|
|
|
|
|
|
|
if (wolActive && wufc) {
|
|
|
|
intelDown(&adapterData, false);
|
|
|
|
intelSetupRxControl(&adapterData);
|
|
|
|
|
|
|
|
rctl = intelReadMem32(E1000_RCTL);
|
|
|
|
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
|
|
|
|
|
|
|
|
/* turn on all-multi mode if wake on multicast is enabled */
|
|
|
|
if (wufc & E1000_WUFC_MC)
|
|
|
|
rctl |= E1000_RCTL_MPE;
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_RCTL, rctl);
|
|
|
|
|
|
|
|
ctrl = intelReadMem32(E1000_CTRL);
|
|
|
|
ctrl |= E1000_CTRL_ADVD3WUC;
|
|
|
|
|
|
|
|
if (!(adapterData.flags2 & FLAG2_HAS_PHY_WAKEUP))
|
|
|
|
ctrl |= E1000_CTRL_EN_PHY_PWR_MGMT;
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_CTRL, ctrl);
|
|
|
|
|
|
|
|
if (adapterData.hw.phy.media_type == e1000_media_type_fiber ||
|
|
|
|
adapterData.hw.phy.media_type == e1000_media_type_internal_serdes) {
|
|
|
|
/* keep the laser running in D3 */
|
|
|
|
ctrlExt = intelReadMem32(E1000_CTRL_EXT);
|
|
|
|
ctrlExt |= E1000_CTRL_EXT_SDP3_DATA;
|
|
|
|
intelWriteMem32(E1000_CTRL_EXT, ctrlExt);
|
|
|
|
}
|
|
|
|
if (adapterData.flags & FLAG_IS_ICH)
|
|
|
|
e1000_suspend_workarounds_ich8lan(hw);
|
|
|
|
|
|
|
|
if (adapterData.flags2 & FLAG2_HAS_PHY_WAKEUP) {
|
|
|
|
/* enable wakeup by the PHY */
|
|
|
|
intelInitPhyWakeup(wufc);
|
|
|
|
} else {
|
|
|
|
/* enable wakeup by the MAC */
|
|
|
|
intelWriteMem32(E1000_WUFC, wufc);
|
|
|
|
intelWriteMem32(E1000_WUC, E1000_WUC_PME_EN);
|
|
|
|
}
|
2015-03-15 00:36:06 +01:00
|
|
|
DebugLog("Ethernet [IntelMausi]: WUFC=0x%08x.\n", wufc);
|
2016-04-19 00:14:50 +02:00
|
|
|
|
|
|
|
linkOpts = kIONetworkLinkNoNetworkChange;
|
|
|
|
linkStatus |= linkOpts;
|
2015-03-05 00:11:40 +01:00
|
|
|
} else {
|
|
|
|
intelDown(&adapterData, true);
|
|
|
|
intelWriteMem32(E1000_WUC, 0);
|
|
|
|
intelWriteMem32(E1000_WUFC, 0);
|
|
|
|
intelPowerDownPhy(&adapterData);
|
2016-04-19 00:14:50 +02:00
|
|
|
|
|
|
|
/* ULP seems to cause trouble on I218LM3 and I218V3. Enable it only for I219V/LM. */
|
2018-02-15 21:34:46 +01:00
|
|
|
if (hw->mac.type >= e1000_pch_spt) {
|
2016-04-19 00:14:50 +02:00
|
|
|
if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)))
|
|
|
|
/* ULP does not support wake from unicast, multicast
|
|
|
|
* or broadcast.
|
|
|
|
*/
|
|
|
|
e1000_enable_ulp_lpt_lp(hw, false);
|
|
|
|
}
|
2016-01-18 01:57:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure that the appropriate bits are set in LPI_CTRL
|
|
|
|
* for EEE in Sx
|
|
|
|
*/
|
|
|
|
if ((hw->phy.type >= e1000_phy_i217) && adapterData.eee_advert && hw->dev_spec.ich8lan.eee_lp_ability) {
|
|
|
|
UInt16 lpi_ctrl = 0;
|
|
|
|
|
|
|
|
retval = hw->phy.ops.acquire(hw);
|
|
|
|
if (!retval) {
|
|
|
|
retval = e1e_rphy_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
|
|
|
|
if (!retval) {
|
|
|
|
if (adapterData.eee_advert &
|
|
|
|
hw->dev_spec.ich8lan.eee_lp_ability &
|
|
|
|
I82579_EEE_100_SUPPORTED)
|
|
|
|
lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
|
|
|
|
if (adapterData.eee_advert &
|
|
|
|
hw->dev_spec.ich8lan.eee_lp_ability &
|
|
|
|
I82579_EEE_1000_SUPPORTED)
|
|
|
|
lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
|
|
|
|
|
|
|
|
retval = e1e_wphy_locked(hw, I82579_LPI_CTRL,
|
|
|
|
lpi_ctrl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hw->phy.ops.release(hw);
|
|
|
|
}
|
|
|
|
|
2015-01-27 23:52:50 +01:00
|
|
|
/* If AMT is enabled, let the firmware know that the network
|
|
|
|
* interface is now closed
|
|
|
|
*/
|
|
|
|
if (adapterData.flags & FLAG_HAS_AMT)
|
|
|
|
e1000e_release_hw_control(&adapterData);
|
2016-04-19 00:14:50 +02:00
|
|
|
|
|
|
|
if (linkUp) {
|
|
|
|
linkUp = false;
|
|
|
|
setLinkStatus(linkStatus);
|
|
|
|
IOLog("Ethernet [IntelMausi]: Link down on en%u\n", netif->getUnitNumber());
|
|
|
|
}
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelConfigure - configure the hardware for Rx and Tx
|
|
|
|
* @adapter: private board structure
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelConfigure(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
setMulticastMode(true);
|
|
|
|
intelInitManageabilityPt(adapter);
|
|
|
|
|
|
|
|
intelSetupRssHash(adapter);
|
|
|
|
intelVlanStripEnable(adapter);
|
|
|
|
intelConfigureTx(adapter);
|
|
|
|
intelSetupRxControl(adapter);
|
|
|
|
intelConfigureRx(adapter);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelConfigureTx - Configure Transmit Unit after Reset
|
|
|
|
* @adapter: board private structure
|
|
|
|
*
|
|
|
|
* Configure the Tx unit of the MAC after a reset.
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelConfigureTx(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
UInt32 tctl, tarc;
|
|
|
|
UInt32 txdctl;
|
|
|
|
|
|
|
|
/* Setup the HW Tx Head and Tail descriptor pointers */
|
|
|
|
intelInitTxRing();
|
|
|
|
|
|
|
|
/* Set the Tx Interrupt Delay register */
|
|
|
|
intelWriteMem32(E1000_TIDV, adapter->tx_int_delay);
|
|
|
|
/* Tx irq moderation */
|
|
|
|
intelWriteMem32(E1000_TADV, adapter->tx_abs_int_delay);
|
|
|
|
|
|
|
|
txdctl = intelReadMem32(E1000_TXDCTL(0));
|
|
|
|
|
2016-09-14 23:55:24 +02:00
|
|
|
/* Fix TXDCTL to disable descriptor prefetch for 82579, I217, I218 and I219. */
|
2018-02-15 21:34:46 +01:00
|
|
|
if (chipType >= board_pch2lan) {
|
2016-09-14 23:55:24 +02:00
|
|
|
txdctl = 0x01410000;
|
2015-04-22 21:09:03 +02:00
|
|
|
intelWriteMem32(E1000_TXDCTL(0), txdctl);
|
|
|
|
}
|
2015-01-27 23:52:50 +01:00
|
|
|
/* erratum work around: set txdctl the same for both queues */
|
|
|
|
intelWriteMem32(E1000_TXDCTL(1), txdctl);
|
|
|
|
|
|
|
|
/* Program the Transmit Control Register */
|
|
|
|
tctl = intelReadMem32(E1000_TCTL);
|
2016-09-14 23:55:24 +02:00
|
|
|
tctl &= ~E1000_TCTL_CT;
|
|
|
|
tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
/* errata: program both queues to unweighted RR */
|
|
|
|
if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
|
|
|
|
tarc = intelReadMem32(E1000_TARC(0));
|
|
|
|
tarc |= 1;
|
|
|
|
intelWriteMem32(E1000_TARC(0), tarc);
|
|
|
|
tarc = intelReadMem32(E1000_TARC(1));
|
|
|
|
tarc |= 1;
|
|
|
|
intelWriteMem32(E1000_TARC(1), tarc);
|
|
|
|
}
|
|
|
|
intelWriteMem32(E1000_TCTL, tctl);
|
|
|
|
|
|
|
|
hw->mac.ops.config_collision_dist(hw);
|
2016-01-18 01:57:14 +01:00
|
|
|
|
|
|
|
/* SPT Si errata workaround to avoid data corruption */
|
|
|
|
if (hw->mac.type == e1000_pch_spt) {
|
|
|
|
UInt32 val;
|
|
|
|
|
|
|
|
val = intelReadMem32(E1000_IOSFPC);
|
|
|
|
val |= E1000_RCTL_RDMTS_HEX;
|
|
|
|
intelWriteMem32(E1000_IOSFPC, val);
|
|
|
|
|
2018-02-15 21:34:46 +01:00
|
|
|
/*
|
|
|
|
* SPT and KBL Si errata workaround to avoid Tx hang.
|
|
|
|
* Dropping the number of outstanding requests from
|
|
|
|
* 3 to 2 in order to avoid a buffer overrun.
|
|
|
|
*/
|
2016-01-18 01:57:14 +01:00
|
|
|
val = intelReadMem32(E1000_TARC(0));
|
2016-04-19 00:14:50 +02:00
|
|
|
val &= ~E1000_TARC0_CB_MULTIQ_3_REQ;
|
2018-02-15 21:34:46 +01:00
|
|
|
val |= E1000_TARC0_CB_MULTIQ_2_REQ;
|
2016-01-18 01:57:14 +01:00
|
|
|
intelWriteMem32(E1000_TARC(0), val);
|
|
|
|
}
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelSetupRxControl - configure the receive control registers
|
|
|
|
* @adapter: Board private structure
|
|
|
|
**/
|
|
|
|
|
|
|
|
void IntelMausi::intelSetupRxControl(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
u32 rctl, rfctl;
|
|
|
|
|
|
|
|
/* Workaround Si errata on PCHx - configure jumbo frame flow.
|
|
|
|
* If jumbo frames not set, program related MAC/PHY registers
|
|
|
|
* to h/w defaults
|
|
|
|
*/
|
|
|
|
if (hw->mac.type >= e1000_pch2lan) {
|
|
|
|
s32 ret_val;
|
|
|
|
|
|
|
|
if (mtu > ETH_DATA_LEN)
|
|
|
|
ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
|
|
|
|
else
|
|
|
|
ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
|
|
|
|
|
|
|
|
if (ret_val)
|
|
|
|
DebugLog("Ethernet [IntelMausi]: failed to enable/disable jumbo frame workaround mode.\n");
|
|
|
|
}
|
|
|
|
/* Program MC offset vector base */
|
|
|
|
rctl = intelReadMem32(E1000_RCTL);
|
|
|
|
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
|
|
|
|
rctl |= E1000_RCTL_BAM | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
|
|
|
|
|
|
|
|
/* Do not Store bad packets */
|
|
|
|
rctl &= ~E1000_RCTL_SBP;
|
|
|
|
|
|
|
|
/* Enable Long Packet receive */
|
|
|
|
if (mtu <= ETH_DATA_LEN)
|
|
|
|
rctl &= ~E1000_RCTL_LPE;
|
|
|
|
else
|
|
|
|
rctl |= E1000_RCTL_LPE;
|
|
|
|
|
|
|
|
/* Some systems expect that the CRC is included in SMBUS traffic. The
|
|
|
|
* hardware strips the CRC before sending to both SMBUS (BMC) and to
|
|
|
|
* host memory when this is enabled
|
2017-04-14 20:52:44 +02:00
|
|
|
*
|
|
|
|
* We setup hardware to always strip CRC as we want jumbo frame support
|
|
|
|
* anyway even if it breaks management SMBUS traffic on some machines.
|
2015-01-27 23:52:50 +01:00
|
|
|
*/
|
2017-04-14 20:52:44 +02:00
|
|
|
rctl |= E1000_RCTL_SECRC;
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
/* Workaround Si errata on 82577 PHY - configure IPG for jumbos */
|
|
|
|
if ((hw->phy.type == e1000_phy_82577) && (rctl & E1000_RCTL_LPE)) {
|
|
|
|
u16 phy_data;
|
|
|
|
|
|
|
|
e1e_rphy(hw, PHY_REG(770, 26), &phy_data);
|
|
|
|
phy_data &= 0xfff8;
|
|
|
|
phy_data |= (1 << 2);
|
|
|
|
e1e_wphy(hw, PHY_REG(770, 26), phy_data);
|
|
|
|
|
|
|
|
e1e_rphy(hw, 22, &phy_data);
|
|
|
|
phy_data &= 0x0fff;
|
|
|
|
phy_data |= (1 << 14);
|
|
|
|
e1e_wphy(hw, 0x10, 0x2823);
|
|
|
|
e1e_wphy(hw, 0x11, 0x0003);
|
|
|
|
e1e_wphy(hw, 22, phy_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set buffer sizes to 2048 */
|
|
|
|
//rctl |= (0x2 << E1000_RCTL_FLXB_SHIFT);
|
|
|
|
rctl &= ~(E1000_RCTL_SZ_256 | E1000_RCTL_BSEX);
|
|
|
|
|
|
|
|
/* Enable Extended Status in all Receive Descriptors */
|
|
|
|
rfctl = intelReadMem32(E1000_RFCTL);
|
|
|
|
rfctl |= (E1000_RFCTL_NEW_IPV6_EXT_DIS | E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_EXTEN | E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
|
|
|
|
intelWriteMem32(E1000_RFCTL, rfctl);
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_RCTL, rctl);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelConfigureRx - Configure Receive Unit after Reset
|
|
|
|
* @adapter: board private structure
|
|
|
|
*
|
|
|
|
* Configure the Rx unit of the MAC after a reset.
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelConfigureRx(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
u32 rctl, rxcsum, ctrl_ext;
|
|
|
|
|
|
|
|
/* disable receives while setting up the descriptors */
|
|
|
|
rctl = intelReadMem32(E1000_RCTL);
|
|
|
|
|
|
|
|
intelFlush();
|
|
|
|
usleep_range(10000, 20000);
|
|
|
|
|
|
|
|
/* set the Receive Delay Timer Register */
|
|
|
|
intelWriteMem32(E1000_RDTR, adapter->rx_int_delay);
|
|
|
|
|
|
|
|
/* irq moderation */
|
|
|
|
intelWriteMem32(E1000_RADV, adapter->rx_abs_int_delay);
|
|
|
|
|
|
|
|
/* Set interrupt throttle value. */
|
|
|
|
intelWriteMem32(E1000_ITR, intrThrValue);
|
|
|
|
|
|
|
|
/* Auto-Mask interrupts upon ICR access. */
|
|
|
|
ctrl_ext = intelReadMem32(E1000_CTRL_EXT);
|
|
|
|
ctrl_ext |= E1000_CTRL_EXT_IAME;
|
|
|
|
intelWriteMem32(E1000_IAM, 0xffffffff);
|
|
|
|
intelWriteMem32(E1000_CTRL_EXT, ctrl_ext);
|
|
|
|
e1e_flush();
|
|
|
|
|
|
|
|
/* Setup the HW Rx Head and Tail Descriptor Pointers and
|
|
|
|
* the Base and Length of the Rx Descriptor Ring
|
|
|
|
*/
|
|
|
|
intelInitRxRing();
|
|
|
|
|
|
|
|
/* Enable Receive Checksum Offload for TCP and UDP */
|
|
|
|
rxcsum = intelReadMem32(E1000_RXCSUM);
|
|
|
|
rxcsum |= E1000_RXCSUM_TUOFL;
|
|
|
|
intelWriteMem32(E1000_RXCSUM, rxcsum);
|
|
|
|
|
|
|
|
/* With jumbo frames, excessive C-state transition latencies result
|
2017-04-14 20:52:44 +02:00
|
|
|
* in dropped transactions. Latency requirements will be adjusted
|
|
|
|
* when the link has been established and speed is known.
|
2015-01-27 23:52:50 +01:00
|
|
|
*/
|
2017-04-14 20:52:44 +02:00
|
|
|
if ((mtu > ETH_DATA_LEN) && (adapter->flags & FLAG_IS_ICH)) {
|
|
|
|
u32 rxdctl = intelReadMem32(E1000_RXDCTL(0));
|
2015-01-27 23:52:50 +01:00
|
|
|
|
2017-04-14 20:52:44 +02:00
|
|
|
intelWriteMem32(E1000_RXDCTL(0), rxdctl | 0x3);
|
|
|
|
}
|
2015-01-27 23:52:50 +01:00
|
|
|
intelWriteMem32(E1000_RCTL, rctl);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelDown - quiesce the device and optionally reset the hardware
|
|
|
|
* @adapter: board private structure
|
|
|
|
* @reset: boolean flag to reset the hardware or not
|
|
|
|
*/
|
|
|
|
void IntelMausi::intelDown(struct e1000_adapter *adapter, bool reset)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
UInt32 tctl, rctl;
|
|
|
|
|
|
|
|
/* signal that we're down so the interrupt handler does not
|
|
|
|
* reschedule our watchdog timer
|
|
|
|
*/
|
|
|
|
set_bit(__E1000_DOWN, &adapter->state);
|
|
|
|
|
|
|
|
/* disable receives in the hardware */
|
|
|
|
rctl = intelReadMem32(E1000_RCTL);
|
|
|
|
rctl &= ~E1000_RCTL_EN;
|
|
|
|
intelWriteMem32(E1000_RCTL, rctl);
|
|
|
|
|
|
|
|
/* disable transmits in the hardware */
|
|
|
|
tctl = intelReadMem32(E1000_TCTL);
|
|
|
|
tctl &= ~E1000_TCTL_EN;
|
|
|
|
intelWriteMem32(E1000_TCTL, tctl);
|
|
|
|
|
|
|
|
/* flush both disables and wait for them to finish */
|
|
|
|
intelFlush();
|
|
|
|
usleep_range(10000, 20000);
|
|
|
|
|
|
|
|
intelDisableIRQ();
|
|
|
|
updateStatistics(adapter);
|
|
|
|
|
|
|
|
adapter->link_speed = 0;
|
|
|
|
adapter->link_duplex = 0;
|
|
|
|
|
|
|
|
/* Disable Si errata workaround on PCHx for jumbo frame flow */
|
|
|
|
if ((hw->mac.type >= e1000_pch2lan) && (mtu > ETH_DATA_LEN) && e1000_lv_jumbo_workaround_ich8lan(hw, false))
|
|
|
|
DebugLog("Ethernet [IntelMausi]: failed to disable jumbo frame workaround mode\n");
|
|
|
|
|
|
|
|
if (reset)
|
|
|
|
intelReset(adapter);
|
2018-02-15 21:34:46 +01:00
|
|
|
else if (hw->mac.type >= e1000_pch_spt)
|
2016-01-18 01:57:14 +01:00
|
|
|
intelFlushDescRings(adapter);
|
|
|
|
|
|
|
|
clearDescriptors();
|
2016-08-27 00:59:27 +02:00
|
|
|
|
2018-02-15 21:34:46 +01:00
|
|
|
if (chipType >= board_pch_lpt)
|
2016-08-27 00:59:27 +02:00
|
|
|
requireMaxBusStall(0);
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelInitManageabilityPt(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
u32 manc, manc2h, mdef, i, j;
|
|
|
|
|
|
|
|
if (!(adapter->flags & FLAG_MNG_PT_ENABLED))
|
|
|
|
return;
|
|
|
|
|
|
|
|
manc = intelReadMem32(E1000_MANC);
|
|
|
|
|
|
|
|
/* enable receiving management packets to the host. this will probably
|
|
|
|
* generate destination unreachable messages from the host OS, but
|
|
|
|
* the packets will be handled on SMBUS
|
|
|
|
*/
|
|
|
|
manc |= E1000_MANC_EN_MNG2HOST;
|
|
|
|
manc2h = intelReadMem32(E1000_MANC2H);
|
|
|
|
|
|
|
|
switch (hw->mac.type) {
|
|
|
|
default:
|
|
|
|
manc2h |= (E1000_MANC2H_PORT_623 | E1000_MANC2H_PORT_664);
|
|
|
|
break;
|
2015-03-05 00:11:40 +01:00
|
|
|
|
2015-01-27 23:52:50 +01:00
|
|
|
case e1000_82574:
|
|
|
|
case e1000_82583:
|
|
|
|
/* Check if IPMI pass-through decision filter already exists;
|
|
|
|
* if so, enable it.
|
|
|
|
*/
|
|
|
|
for (i = 0, j = 0; i < 8; i++) {
|
|
|
|
mdef = intelReadMem32(E1000_MDEF(i));
|
|
|
|
|
|
|
|
/* Ignore filters with anything other than IPMI ports */
|
|
|
|
if (mdef & ~(E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Enable this decision filter in MANC2H */
|
|
|
|
if (mdef)
|
|
|
|
manc2h |= (1 << i);
|
|
|
|
|
|
|
|
j |= mdef;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == (E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Create new decision filter in an empty filter */
|
|
|
|
for (i = 0, j = 0; i < 8; i++)
|
|
|
|
if (intelReadMem32(E1000_MDEF(i)) == 0) {
|
|
|
|
intelWriteMem32(E1000_MDEF(i), (E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664));
|
|
|
|
manc2h |= (1 << 1);
|
|
|
|
j++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!j)
|
|
|
|
IOLog("Ethernet [IntelMausi]: Unable to create IPMI pass-through filter.\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
intelWriteMem32(E1000_MANC2H, manc2h);
|
|
|
|
intelWriteMem32(E1000_MANC, manc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelReset - bring the hardware into a known good state
|
|
|
|
*
|
|
|
|
* This function boots the hardware and enables some settings that
|
|
|
|
* require a configuration cycle of the hardware - those cannot be
|
|
|
|
* set/changed during runtime. After reset the device needs to be
|
|
|
|
* properly configured for Rx, Tx etc.
|
|
|
|
*/
|
|
|
|
void IntelMausi::intelReset(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_mac_info *mac = &adapter->hw.mac;
|
|
|
|
struct e1000_fc_info *fc = &adapter->hw.fc;
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
u32 tx_space, min_tx_space, min_rx_space;
|
|
|
|
u32 pba = adapter->pba;
|
|
|
|
u16 hwm;
|
|
|
|
|
|
|
|
/* reset Packet Buffer Allocation to default */
|
|
|
|
intelWriteMem32(E1000_PBA, pba);
|
|
|
|
|
|
|
|
if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) {
|
|
|
|
/* To maintain wire speed transmits, the Tx FIFO should be
|
|
|
|
* large enough to accommodate two full transmit packets,
|
|
|
|
* rounded up to the next 1KB and expressed in KB. Likewise,
|
|
|
|
* the Rx FIFO should be large enough to accommodate at least
|
|
|
|
* one full receive packet and is similarly rounded up and
|
|
|
|
* expressed in KB.
|
|
|
|
*/
|
|
|
|
pba = intelReadMem32(E1000_PBA);
|
|
|
|
/* upper 16 bits has Tx packet buffer allocation size in KB */
|
|
|
|
tx_space = pba >> 16;
|
|
|
|
/* lower 16 bits has Rx packet buffer allocation size in KB */
|
|
|
|
pba &= 0xffff;
|
|
|
|
/* the Tx fifo also stores 16 bytes of information about the Tx
|
|
|
|
* but don't include ethernet FCS because hardware appends it
|
|
|
|
*/
|
|
|
|
min_tx_space = (adapter->max_frame_size +
|
|
|
|
sizeof(struct e1000_tx_desc) - ETH_FCS_LEN) * 2;
|
|
|
|
min_tx_space = ALIGN(min_tx_space, 1024);
|
|
|
|
min_tx_space >>= 10;
|
|
|
|
/* software strips receive CRC, so leave room for it */
|
|
|
|
min_rx_space = adapter->max_frame_size;
|
|
|
|
min_rx_space = ALIGN(min_rx_space, 1024);
|
|
|
|
min_rx_space >>= 10;
|
|
|
|
|
|
|
|
/* If current Tx allocation is less than the min Tx FIFO size,
|
|
|
|
* and the min Tx FIFO size is less than the current Rx FIFO
|
|
|
|
* allocation, take space away from current Rx allocation
|
|
|
|
*/
|
|
|
|
if ((tx_space < min_tx_space) &&
|
|
|
|
((min_tx_space - tx_space) < pba)) {
|
|
|
|
pba -= min_tx_space - tx_space;
|
|
|
|
|
|
|
|
/* if short on Rx space, Rx wins and must trump Tx
|
|
|
|
* adjustment
|
|
|
|
*/
|
|
|
|
if (pba < min_rx_space)
|
|
|
|
pba = min_rx_space;
|
|
|
|
}
|
|
|
|
intelWriteMem32(E1000_PBA, pba);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flow control settings
|
|
|
|
*
|
|
|
|
* The high water mark must be low enough to fit one full frame
|
|
|
|
* (or the size used for early receive) above it in the Rx FIFO.
|
|
|
|
* Set it to the lower of:
|
|
|
|
* - 90% of the Rx FIFO size, and
|
|
|
|
* - the full Rx FIFO size minus one full frame
|
|
|
|
*/
|
|
|
|
if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
|
|
|
|
fc->pause_time = 0xFFFF;
|
|
|
|
else
|
|
|
|
fc->pause_time = E1000_FC_PAUSE_TIME;
|
|
|
|
fc->send_xon = true;
|
|
|
|
fc->current_mode = fc->requested_mode;
|
|
|
|
|
|
|
|
switch (hw->mac.type) {
|
|
|
|
case e1000_ich9lan:
|
|
|
|
case e1000_ich10lan:
|
|
|
|
if (mtu > ETH_DATA_LEN) {
|
|
|
|
pba = 14;
|
|
|
|
intelWriteMem32(E1000_PBA, pba);
|
|
|
|
fc->high_water = 0x2800;
|
|
|
|
fc->low_water = fc->high_water - 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall-through */
|
|
|
|
default:
|
|
|
|
hwm = min(((pba << 10) * 9 / 10),
|
|
|
|
((pba << 10) - adapter->max_frame_size));
|
|
|
|
|
|
|
|
fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
|
|
|
|
fc->low_water = fc->high_water - 8;
|
|
|
|
break;
|
|
|
|
case e1000_pchlan:
|
|
|
|
/* Workaround PCH LOM adapter hangs with certain network
|
|
|
|
* loads. If hangs persist, try disabling Tx flow control.
|
|
|
|
*/
|
|
|
|
if (mtu > ETH_DATA_LEN) {
|
|
|
|
fc->high_water = 0x3500;
|
|
|
|
fc->low_water = 0x1500;
|
|
|
|
} else {
|
|
|
|
fc->high_water = 0x5000;
|
|
|
|
fc->low_water = 0x3000;
|
|
|
|
}
|
|
|
|
fc->refresh_time = 0x1000;
|
|
|
|
break;
|
|
|
|
case e1000_pch2lan:
|
|
|
|
case e1000_pch_lpt:
|
2016-01-18 01:57:14 +01:00
|
|
|
case e1000_pch_spt:
|
2018-02-15 21:34:46 +01:00
|
|
|
case e1000_pch_cnp:
|
2015-01-27 23:52:50 +01:00
|
|
|
fc->refresh_time = 0x0400;
|
|
|
|
|
|
|
|
if (mtu <= ETH_DATA_LEN) {
|
|
|
|
fc->high_water = 0x05C20;
|
|
|
|
fc->low_water = 0x05048;
|
|
|
|
fc->pause_time = 0x0650;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pba = 14;
|
|
|
|
intelWriteMem32(E1000_PBA, pba);
|
|
|
|
fc->high_water = ((pba << 10) * 9 / 10) & E1000_FCRTH_RTH;
|
|
|
|
fc->low_water = ((pba << 10) * 8 / 10) & E1000_FCRTL_RTL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Alignment of Tx data is on an arbitrary byte boundary with the
|
|
|
|
* maximum size per Tx descriptor limited only to the transmit
|
|
|
|
* allocation of the packet buffer minus 96 bytes with an upper
|
|
|
|
* limit of 24KB due to receive synchronization limitations.
|
|
|
|
*/
|
|
|
|
adapter->tx_fifo_limit = min_t(u32, ((intelReadMem32(E1000_PBA) >> 16) << 10) - 96,
|
|
|
|
24 << 10);
|
|
|
|
|
|
|
|
/* Set interrupt throttle value. */
|
|
|
|
intelWriteMem32(E1000_ITR, intrThrValue);
|
|
|
|
|
2018-02-15 21:34:46 +01:00
|
|
|
if (hw->mac.type >= e1000_pch_spt)
|
2016-01-18 01:57:14 +01:00
|
|
|
intelFlushDescRings(adapter);
|
|
|
|
|
2015-01-27 23:52:50 +01:00
|
|
|
/* Allow time for pending master requests to run */
|
|
|
|
mac->ops.reset_hw(hw);
|
|
|
|
|
|
|
|
/* For parts with AMT enabled, let the firmware know
|
|
|
|
* that the network interface is in control
|
|
|
|
*/
|
|
|
|
if (adapter->flags & FLAG_HAS_AMT)
|
|
|
|
e1000e_get_hw_control(adapter);
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_WUC, 0);
|
|
|
|
|
|
|
|
if (mac->ops.init_hw(hw))
|
|
|
|
IOLog("Ethernet [IntelMausi]: Hardware Error.\n");
|
|
|
|
|
|
|
|
//e1000_update_mng_vlan(adapter);
|
|
|
|
|
|
|
|
/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
|
|
|
|
intelWriteMem32(E1000_VET, ETH_P_8021Q);
|
|
|
|
|
|
|
|
intelResetAdaptive(hw);
|
|
|
|
|
|
|
|
/* initialize systim and reset the ns time counter */
|
|
|
|
//e1000e_config_hwtstamp(adapter, &adapter->hwtstamp_config);
|
|
|
|
|
|
|
|
/* Set EEE advertisement as appropriate */
|
|
|
|
if (adapter->flags2 & FLAG2_HAS_EEE) {
|
|
|
|
s32 ret_val;
|
|
|
|
u16 adv_addr;
|
|
|
|
|
|
|
|
switch (hw->phy.type) {
|
|
|
|
case e1000_phy_82579:
|
|
|
|
adv_addr = I82579_EEE_ADVERTISEMENT;
|
|
|
|
break;
|
|
|
|
case e1000_phy_i217:
|
|
|
|
adv_addr = I217_EEE_ADVERTISEMENT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
IOLog("Ethernet [IntelMausi]: Invalid PHY type setting EEE advertisement.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret_val = hw->phy.ops.acquire(hw);
|
|
|
|
|
|
|
|
if (ret_val) {
|
|
|
|
IOLog("Ethernet [IntelMausi]: EEE advertisement - unable to acquire PHY.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
e1000_write_emi_reg_locked(hw, adv_addr, hw->dev_spec.ich8lan.eee_disable ? 0 : adapter->eee_advert);
|
|
|
|
hw->phy.ops.release(hw);
|
|
|
|
}
|
|
|
|
e1000_get_phy_info(hw);
|
|
|
|
|
|
|
|
if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && !(adapter->flags & FLAG_SMART_POWER_DOWN)) {
|
|
|
|
u16 phy_data = 0;
|
|
|
|
/* speed up time to link by disabling smart power down, ignore
|
|
|
|
* the return value of this function because there is nothing
|
|
|
|
* different we would do if it failed
|
|
|
|
*/
|
|
|
|
e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
|
|
|
|
phy_data &= ~IGP02E1000_PM_SPD;
|
|
|
|
e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelPowerDownPhy - Power down the PHY
|
|
|
|
*
|
|
|
|
* Power down the PHY so no link is implied when interface is down.
|
|
|
|
* The PHY cannot be powered down if management or WoL is active.
|
|
|
|
*/
|
|
|
|
void IntelMausi::intelPowerDownPhy(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
if (adapter->hw.phy.ops.power_down)
|
|
|
|
adapter->hw.phy.ops.power_down(&adapter->hw);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelEnableMngPassThru - Check if management passthrough is needed
|
|
|
|
* @hw: pointer to the HW structure
|
|
|
|
*
|
|
|
|
* Verifies the hardware needs to leave interface enabled so that frames can
|
|
|
|
* be directed to and from the management interface.
|
|
|
|
**/
|
|
|
|
bool IntelMausi::intelEnableMngPassThru(struct e1000_hw *hw)
|
|
|
|
{
|
|
|
|
u32 manc;
|
|
|
|
u32 fwsm, factps;
|
|
|
|
|
|
|
|
manc = intelReadMem32(E1000_MANC);
|
|
|
|
|
|
|
|
if (!(manc & E1000_MANC_RCV_TCO_EN))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (hw->mac.has_fwsm) {
|
|
|
|
fwsm = intelReadMem32(E1000_FWSM);
|
|
|
|
factps = intelReadMem32(E1000_FACTPS);
|
|
|
|
|
|
|
|
if (!(factps & E1000_FACTPS_MNGCG) &&
|
|
|
|
((fwsm & E1000_FWSM_MODE_MASK) ==
|
|
|
|
(e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)))
|
|
|
|
return true;
|
|
|
|
} else if ((manc & E1000_MANC_SMBUS_EN) &&
|
|
|
|
!(manc & E1000_MANC_ASF_EN)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelResetAdaptive - Reset Adaptive Interframe Spacing
|
|
|
|
* @hw: pointer to the HW structure
|
|
|
|
*
|
|
|
|
* Reset the Adaptive Interframe Spacing throttle to default values.
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelResetAdaptive(struct e1000_hw *hw)
|
|
|
|
{
|
|
|
|
struct e1000_mac_info *mac = &hw->mac;
|
|
|
|
|
|
|
|
if (!mac->adaptive_ifs) {
|
|
|
|
DebugLog("Ethernet [IntelMausi]: Not in Adaptive IFS mode!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mac->current_ifs_val = 0;
|
|
|
|
mac->ifs_min_val = IFS_MIN;
|
|
|
|
mac->ifs_max_val = IFS_MAX;
|
|
|
|
mac->ifs_step_size = IFS_STEP;
|
|
|
|
mac->ifs_ratio = IFS_RATIO;
|
|
|
|
|
|
|
|
mac->in_ifs_mode = false;
|
|
|
|
intelWriteMem32(E1000_AIT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelUpdateAdaptive - Update Adaptive Interframe Spacing
|
|
|
|
* @hw: pointer to the HW structure
|
|
|
|
*
|
|
|
|
* Update the Adaptive Interframe Spacing Throttle value based on the
|
|
|
|
* time between transmitted packets and time between collisions.
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelUpdateAdaptive(struct e1000_hw *hw)
|
|
|
|
{
|
|
|
|
struct e1000_mac_info *mac = &hw->mac;
|
|
|
|
|
|
|
|
if (!mac->adaptive_ifs) {
|
|
|
|
DebugLog("Ethernet [IntelMausi]: Not in Adaptive IFS mode!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
|
|
|
|
if (mac->tx_packet_delta > MIN_NUM_XMITS) {
|
|
|
|
mac->in_ifs_mode = true;
|
|
|
|
if (mac->current_ifs_val < mac->ifs_max_val) {
|
|
|
|
if (!mac->current_ifs_val)
|
|
|
|
mac->current_ifs_val = mac->ifs_min_val;
|
|
|
|
else
|
|
|
|
mac->current_ifs_val += mac->ifs_step_size;
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_AIT, mac->current_ifs_val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mac->in_ifs_mode && (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
|
|
|
|
mac->current_ifs_val = 0;
|
|
|
|
mac->in_ifs_mode = false;
|
|
|
|
intelWriteMem32(E1000_AIT, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelVlanStripDisable - helper to disable HW VLAN stripping
|
|
|
|
* @adapter: board private structure to initialize
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelVlanStripDisable(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
UInt32 ctrl;
|
|
|
|
|
|
|
|
/* disable VLAN tag insert/strip */
|
|
|
|
ctrl = intelReadMem32(E1000_CTRL);
|
|
|
|
ctrl &= ~E1000_CTRL_VME;
|
|
|
|
intelWriteMem32(E1000_CTRL, ctrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelVlanStripEnable - helper to enable HW VLAN stripping
|
|
|
|
* @adapter: board private structure to initialize
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelVlanStripEnable(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
UInt32 ctrl;
|
|
|
|
|
|
|
|
/* enable VLAN tag insert/strip */
|
|
|
|
ctrl = intelReadMem32(E1000_CTRL);
|
|
|
|
ctrl |= E1000_CTRL_VME;
|
|
|
|
intelWriteMem32(E1000_CTRL, ctrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const u32 rsskey[10] = {
|
|
|
|
0xda565a6d, 0xc20e5b25, 0x3d256741, 0xb08fa343, 0xcb2bcad0,
|
|
|
|
0xb4307bae, 0xa32dcb77, 0x0cf23080, 0x3bb7426a, 0xfa01acbe
|
|
|
|
};
|
|
|
|
|
|
|
|
void IntelMausi::intelSetupRssHash(struct e1000_adapter *adapter)
|
|
|
|
{
|
2015-03-05 00:11:40 +01:00
|
|
|
UInt32 mrqc, rxcsum;
|
2015-01-27 23:52:50 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 10; i++)
|
2015-03-05 00:11:40 +01:00
|
|
|
intelWriteMem32(E1000_RSSRK(i), rsskey[i]);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
/* Direct all traffic to queue 0 */
|
|
|
|
for (i = 0; i < 32; i++)
|
2015-03-05 00:11:40 +01:00
|
|
|
intelWriteMem32(E1000_RETA(i), 0);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
/* Disable raw packet checksumming so that RSS hash is placed in
|
|
|
|
* descriptor on writeback.
|
|
|
|
*/
|
2015-03-05 00:11:40 +01:00
|
|
|
rxcsum = intelReadMem32(E1000_RXCSUM);
|
2015-01-27 23:52:50 +01:00
|
|
|
rxcsum |= E1000_RXCSUM_PCSD;
|
|
|
|
|
2015-03-05 00:11:40 +01:00
|
|
|
intelWriteMem32(E1000_RXCSUM, rxcsum);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
mrqc = (E1000_MRQC_RSS_FIELD_IPV4 |
|
|
|
|
E1000_MRQC_RSS_FIELD_IPV4_TCP |
|
|
|
|
E1000_MRQC_RSS_FIELD_IPV6 |
|
|
|
|
E1000_MRQC_RSS_FIELD_IPV6_TCP |
|
|
|
|
E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
|
|
|
|
|
|
|
|
mrqc |= 0x01;
|
2015-03-05 00:11:40 +01:00
|
|
|
intelWriteMem32(E1000_MRQC, mrqc);
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Reset the NIC in case a tx deadlock or a pci error occurred. timerSource and txQueue
|
|
|
|
* are stopped immediately but will be restarted by checkLinkStatus() when the link has
|
|
|
|
* been reestablished.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void IntelMausi::intelRestart()
|
|
|
|
{
|
2015-03-15 00:36:06 +01:00
|
|
|
|
|
|
|
/* Stop output thread and flush txQueue */
|
|
|
|
netif->stopOutputThread();
|
|
|
|
netif->flushOutputQueue();
|
|
|
|
|
|
|
|
/* Also set the link status to down. */
|
2015-02-11 12:25:43 +01:00
|
|
|
if (linkUp)
|
|
|
|
IOLog("Ethernet [IntelMausi]: Link down on en%u\n", netif->getUnitNumber());
|
|
|
|
|
|
|
|
setLinkStatus(kIONetworkLinkValid);
|
|
|
|
linkUp = false;
|
|
|
|
|
2015-01-27 23:52:50 +01:00
|
|
|
/* Reset NIC and cleanup both descriptor rings. */
|
|
|
|
intelDisableIRQ();
|
|
|
|
intelReset(&adapterData);
|
|
|
|
|
|
|
|
clearDescriptors();
|
|
|
|
rxCleanedCount = rxNextDescIndex = 0;
|
|
|
|
deadlockWarn = 0;
|
|
|
|
forceReset = false;
|
2015-02-11 12:25:43 +01:00
|
|
|
eeeMode = 0;
|
2015-01-27 23:52:50 +01:00
|
|
|
|
|
|
|
/* Reinitialize NIC. */
|
|
|
|
intelConfigure(&adapterData);
|
|
|
|
|
|
|
|
/* From here on the code is the same as e1000e_up() */
|
|
|
|
clear_bit(__E1000_DOWN, &adapterData.state);
|
|
|
|
|
2016-09-14 23:55:24 +02:00
|
|
|
intelEnableIRQ(intrMask);
|
2015-08-24 11:40:32 +02:00
|
|
|
|
2015-01-27 23:52:50 +01:00
|
|
|
adapterData.hw.mac.get_link_status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelInitTxRing()
|
|
|
|
{
|
|
|
|
intelWriteMem32(E1000_TDBAL(0), (txPhyAddr & 0xffffffff));
|
|
|
|
intelWriteMem32(E1000_TDBAH(0), (txPhyAddr >> 32));
|
|
|
|
intelWriteMem32(E1000_TDLEN(0), kTxDescSize);
|
|
|
|
intelWriteMem32(E1000_TDH(0), 0);
|
|
|
|
intelWriteMem32(E1000_TDT(0), 0);
|
|
|
|
txNextDescIndex = txDirtyIndex = txCleanBarrierIndex = 0;
|
|
|
|
txNumFreeDesc = kNumTxDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelInitRxRing()
|
|
|
|
{
|
|
|
|
intelWriteMem32(E1000_RDBAL(0), (rxPhyAddr & 0xffffffff));
|
|
|
|
intelWriteMem32(E1000_RDBAH(0), (rxPhyAddr >> 32));
|
|
|
|
intelWriteMem32(E1000_RDLEN(0), kRxDescSize);
|
|
|
|
intelWriteMem32(E1000_RDH(0), 0);
|
|
|
|
|
|
|
|
if (adapterData.flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
|
|
|
|
intelUpdateRxDescTail(kRxLastDesc);
|
|
|
|
else
|
|
|
|
intelWriteMem32(E1000_RDT(0), kRxLastDesc);
|
|
|
|
|
|
|
|
rxCleanedCount = rxNextDescIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelUpdateTxDescTail(UInt32 index)
|
|
|
|
{
|
2015-03-15 00:36:06 +01:00
|
|
|
if (adapterData.flags2 & FLAG2_PCIM2PCI_ARBITER_WA) {
|
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
|
|
|
s32 ret = __ew32_prepare(hw);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
2015-03-15 00:36:06 +01:00
|
|
|
intelWriteMem32(E1000_TDT(0),index);
|
2015-01-27 23:52:50 +01:00
|
|
|
|
2015-03-15 00:36:06 +01:00
|
|
|
if (!ret && (index != intelReadMem32(E1000_TDT(0)))) {
|
|
|
|
UInt32 tctl = intelReadMem32(E1000_TCTL);
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_TCTL, tctl & ~E1000_TCTL_EN);
|
|
|
|
forceReset = true;
|
|
|
|
|
|
|
|
IOLog("Ethernet [IntelMausi]: ME firmware caused invalid TDT - resetting.\n");
|
|
|
|
}
|
|
|
|
} else {
|
2016-09-14 23:55:24 +02:00
|
|
|
intelWriteMem32(E1000_TDT(0), index);
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
2016-09-14 23:55:24 +02:00
|
|
|
txCleanBarrierIndex = txNextDescIndex;
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void IntelMausi::intelUpdateRxDescTail(UInt32 index)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
|
|
|
SInt32 ret = __ew32_prepare(hw);
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_RDT(0),index);
|
|
|
|
|
|
|
|
if (!ret && (index != intelReadMem32(E1000_RDT(0)))) {
|
|
|
|
UInt32 rctl = intelReadMem32(E1000_RCTL);
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
|
|
|
|
forceReset = true;
|
|
|
|
|
|
|
|
IOLog("Ethernet [IntelMausi]: ME firmware caused invalid RDT - resetting.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void IntelMausi::intelEnablePCIDevice(IOPCIDevice *provider)
|
|
|
|
{
|
|
|
|
UInt16 cmdReg;
|
|
|
|
|
2016-04-19 00:14:50 +02:00
|
|
|
cmdReg = provider->extendedConfigRead16(kIOPCIConfigCommand);
|
2016-01-18 01:57:14 +01:00
|
|
|
cmdReg |= (kIOPCICommandBusMaster | kIOPCICommandMemorySpace);
|
2015-01-27 23:52:50 +01:00
|
|
|
cmdReg &= ~kIOPCICommandIOSpace;
|
2016-04-19 00:14:50 +02:00
|
|
|
provider->extendedConfigWrite16(kIOPCIConfigCommand, cmdReg);
|
2015-01-27 23:52:50 +01:00
|
|
|
}
|
|
|
|
|
2015-08-24 11:40:32 +02:00
|
|
|
void IntelMausi::intelFlushDescriptors()
|
|
|
|
{
|
|
|
|
/* flush pending descriptor writebacks to memory */
|
|
|
|
intelWriteMem32(E1000_TIDV, adapterData.tx_int_delay | E1000_TIDV_FPD);
|
|
|
|
//intelWriteMem32(E1000_RDTR, adapterData.rx_int_delay | E1000_RDTR_FPD);
|
|
|
|
|
|
|
|
/* execute the writes immediately */
|
|
|
|
intelFlush();
|
|
|
|
|
|
|
|
/* due to rare timing issues, write to TIDV/RDTR again to ensure the
|
|
|
|
* write is successful
|
|
|
|
*/
|
|
|
|
intelWriteMem32(E1000_TIDV, adapterData.tx_int_delay | E1000_TIDV_FPD);
|
|
|
|
//intelWriteMem32(E1000_RDTR, adapterData.rx_int_delay | E1000_RDTR_FPD);
|
|
|
|
|
|
|
|
/* execute the writes immediately */
|
|
|
|
intelFlush();
|
|
|
|
}
|
|
|
|
|
2016-01-18 01:57:14 +01:00
|
|
|
/**
|
|
|
|
* intelFlushTxRing - remove all descriptors from the tx_ring
|
|
|
|
*
|
|
|
|
* We want to clear all pending descriptors from the TX ring.
|
|
|
|
* zeroing happens when the HW reads the regs. We assign the ring itself as
|
|
|
|
* the data of the next descriptor. We don't care about the data we are about
|
|
|
|
* to reset the HW.
|
|
|
|
*/
|
|
|
|
void IntelMausi::intelFlushTxRing(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_data_desc *desc = NULL;
|
|
|
|
UInt32 tdt, tctl, txdLower = E1000_TXD_CMD_IFCS;
|
|
|
|
UInt16 size = 512;
|
|
|
|
|
|
|
|
tctl = intelReadMem32(E1000_TCTL);
|
|
|
|
intelWriteMem32(E1000_TCTL, tctl | E1000_TCTL_EN);
|
|
|
|
tdt = intelReadMem32(E1000_TDT(0));
|
|
|
|
|
|
|
|
if (tdt != txNextDescIndex) {
|
|
|
|
IOLog("Ethernet [IntelMausi]: Failed to flush tx descriptor ring.\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
DebugLog("Ethernet [IntelMausi]: Flushing tx descriptor ring.\n");
|
|
|
|
|
|
|
|
OSAddAtomic(-1, &txNumFreeDesc);
|
|
|
|
desc = &txDescArray[txNextDescIndex++];
|
|
|
|
txNextDescIndex &= kTxDescMask;
|
|
|
|
|
|
|
|
desc->buffer_addr = OSSwapHostToLittleInt64(txPhyAddr);
|
|
|
|
desc->lower.data = OSSwapHostToLittleInt32(txdLower | size);
|
|
|
|
desc->upper.data = 0;
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_TDT(0), txNextDescIndex);
|
|
|
|
intelFlush();
|
|
|
|
usleep_range(200, 250);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelFlushRxRing - remove all descriptors from the rx_ring
|
|
|
|
*
|
|
|
|
* Mark all descriptors in the RX ring as consumed and disable the rx ring
|
|
|
|
*/
|
|
|
|
void IntelMausi::intelFlushRxRing(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
UInt32 rctl, rxdctl;
|
|
|
|
|
|
|
|
DebugLog("Ethernet [IntelMausi]: Flushing rx descriptor ring.\n");
|
|
|
|
|
|
|
|
rctl = intelReadMem32(E1000_RCTL);
|
|
|
|
intelWriteMem32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
|
|
|
|
intelFlush();
|
|
|
|
usleep_range(100, 150);
|
|
|
|
|
|
|
|
rxdctl = intelReadMem32(E1000_RXDCTL(0));
|
|
|
|
/* zero the lower 14 bits (prefetch and host thresholds) */
|
|
|
|
rxdctl &= 0xffffc000;
|
|
|
|
|
|
|
|
/* update thresholds: prefetch threshold to 31, host threshold to 1
|
|
|
|
* and make sure the granularity is "descriptors" and not "cache lines"
|
|
|
|
*/
|
|
|
|
rxdctl |= (0x1F | (1 << 8) | E1000_RXDCTL_THRESH_UNIT_DESC);
|
|
|
|
|
|
|
|
intelWriteMem32(E1000_RXDCTL(0), rxdctl);
|
|
|
|
/* momentarily enable the RX ring for the changes to take effect */
|
|
|
|
intelWriteMem32(E1000_RCTL, rctl | E1000_RCTL_EN);
|
|
|
|
intelFlush();
|
|
|
|
usleep_range(100, 150);
|
|
|
|
intelWriteMem32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelFlushDescRings - remove all descriptors from the descriptor rings
|
|
|
|
*
|
|
|
|
* In i219, the descriptor rings must be emptied before resetting the HW
|
|
|
|
* or before changing the device state to D3 during runtime (runtime PM).
|
|
|
|
*
|
|
|
|
* Failure to do this will cause the HW to enter a unit hang state which can
|
|
|
|
* only be released by PCI reset on the device
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
void IntelMausi::intelFlushDescRings(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
UInt16 hangState;
|
|
|
|
u32 fext_nvm11, tdlen;
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
|
|
|
|
/* First, disable MULR fix in FEXTNVM11 */
|
2016-08-27 00:59:27 +02:00
|
|
|
fext_nvm11 = intelReadMem32(E1000_FEXTNVM11);
|
2016-01-18 01:57:14 +01:00
|
|
|
fext_nvm11 |= E1000_FEXTNVM11_DISABLE_MULR_FIX;
|
|
|
|
ew32(FEXTNVM11, fext_nvm11);
|
|
|
|
/* do nothing if we're not in faulty state, or if the queue is empty */
|
|
|
|
tdlen = er32(TDLEN(0));
|
2016-04-19 00:14:50 +02:00
|
|
|
hangState = pciDevice->extendedConfigRead16(PCICFG_DESC_RING_STATUS);
|
2016-01-18 01:57:14 +01:00
|
|
|
|
|
|
|
if (!(hangState & FLUSH_DESC_REQUIRED) || !tdlen)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
intelFlushTxRing(adapter);
|
|
|
|
/* recheck, maybe the fault is caused by the rx ring */
|
2016-04-19 00:14:50 +02:00
|
|
|
hangState = pciDevice->extendedConfigRead16(PCICFG_DESC_RING_STATUS);
|
2016-01-18 01:57:14 +01:00
|
|
|
|
|
|
|
if (hangState & FLUSH_DESC_REQUIRED)
|
|
|
|
intelFlushRxRing(adapter);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-27 23:52:50 +01:00
|
|
|
bool IntelMausi::intelCheckLink(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
bool link_active = false;
|
|
|
|
s32 ret_val = 0;
|
|
|
|
|
|
|
|
/* get_link_status is set on LSC (link status) interrupt or
|
|
|
|
* Rx sequence error interrupt. get_link_status will stay
|
|
|
|
* false until the check_for_link establishes link
|
|
|
|
* for copper adapters ONLY
|
|
|
|
*/
|
|
|
|
switch (hw->phy.media_type) {
|
|
|
|
case e1000_media_type_copper:
|
|
|
|
if (hw->mac.get_link_status) {
|
|
|
|
ret_val = hw->mac.ops.check_for_link(hw);
|
|
|
|
link_active = !hw->mac.get_link_status;
|
|
|
|
} else {
|
|
|
|
link_active = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case e1000_media_type_fiber:
|
|
|
|
ret_val = hw->mac.ops.check_for_link(hw);
|
|
|
|
link_active = !!(intelReadMem32(E1000_STATUS) & E1000_STATUS_LU);
|
|
|
|
break;
|
|
|
|
case e1000_media_type_internal_serdes:
|
|
|
|
ret_val = hw->mac.ops.check_for_link(hw);
|
|
|
|
link_active = adapter->hw.mac.serdes_has_link;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case e1000_media_type_unknown:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) &&
|
|
|
|
(intelReadMem32(E1000_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
|
|
|
|
/* See e1000_kmrn_lock_loss_workaround_ich8lan() */
|
|
|
|
IOLog("Ethernet [IntelMausi]: Gigabit has been disabled, downgrading speed.\n");
|
|
|
|
}
|
|
|
|
return link_active;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intelPhyReadStatus - Update the PHY register status snapshot
|
|
|
|
* @adapter: board private structure
|
|
|
|
**/
|
|
|
|
void IntelMausi::intelPhyReadStatus(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
struct e1000_phy_regs *phy = &adapter->phy_regs;
|
|
|
|
|
|
|
|
if ((intelReadMem32(E1000_STATUS) & E1000_STATUS_LU) &&
|
|
|
|
(adapter->hw.phy.media_type == e1000_media_type_copper)) {
|
|
|
|
int ret_val;
|
|
|
|
|
|
|
|
ret_val = e1e_rphy(hw, MII_BMCR, &phy->bmcr);
|
|
|
|
ret_val |= e1e_rphy(hw, MII_BMSR, &phy->bmsr);
|
|
|
|
ret_val |= e1e_rphy(hw, MII_ADVERTISE, &phy->advertise);
|
|
|
|
ret_val |= e1e_rphy(hw, MII_LPA, &phy->lpa);
|
|
|
|
ret_val |= e1e_rphy(hw, MII_EXPANSION, &phy->expansion);
|
|
|
|
ret_val |= e1e_rphy(hw, MII_CTRL1000, &phy->ctrl1000);
|
|
|
|
ret_val |= e1e_rphy(hw, MII_STAT1000, &phy->stat1000);
|
|
|
|
ret_val |= e1e_rphy(hw, MII_ESTATUS, &phy->estatus);
|
|
|
|
|
|
|
|
if (ret_val)
|
2015-02-11 12:25:43 +01:00
|
|
|
IOLog("Ethernet [IntelMausi]: Error reading PHY register.\n");
|
2015-01-27 23:52:50 +01:00
|
|
|
} else {
|
|
|
|
/* Do not read PHY registers if link is not up
|
|
|
|
* Set values to typical power-on defaults
|
|
|
|
*/
|
|
|
|
phy->bmcr = (BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_FULLDPLX);
|
|
|
|
phy->bmsr = (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL |
|
|
|
|
BMSR_10HALF | BMSR_ESTATEN | BMSR_ANEGCAPABLE |
|
|
|
|
BMSR_ERCAP);
|
|
|
|
phy->advertise = (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP |
|
|
|
|
ADVERTISE_ALL | ADVERTISE_CSMA);
|
|
|
|
phy->lpa = 0;
|
|
|
|
phy->expansion = EXPANSION_ENABLENPAGE;
|
|
|
|
phy->ctrl1000 = ADVERTISE_1000FULL;
|
|
|
|
phy->stat1000 = 0;
|
|
|
|
phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF);
|
|
|
|
}
|
|
|
|
}
|
2015-02-11 12:25:43 +01:00
|
|
|
|
2015-03-05 00:11:40 +01:00
|
|
|
void IntelMausi::intelInitPhyWakeup(UInt32 wufc)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
|
|
|
u32 i, mac_reg, wuc;
|
|
|
|
u16 phy_reg, wuc_enable;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
/* copy MAC RARs to PHY RARs */
|
|
|
|
e1000_copy_rx_addrs_to_phy_ich8lan(hw);
|
|
|
|
|
|
|
|
error = hw->phy.ops.acquire(hw);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
DebugLog("Ethernet [IntelMausi]: Failed to acquire PHY.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Enable access to wakeup registers on and set page to BM_WUC_PAGE */
|
|
|
|
error = e1000_enable_phy_wakeup_reg_access_bm(hw, &wuc_enable);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
DebugLog("Ethernet [IntelMausi]: Failed to access PHY wakeup registers.\n");
|
|
|
|
goto release;
|
|
|
|
}
|
|
|
|
/* copy MAC MTA to PHY MTA - only needed for pchlan */
|
|
|
|
for (i = 0; i < hw->mac.mta_reg_count; i++) {
|
|
|
|
mac_reg = E1000_READ_REG_ARRAY(hw, E1000_MTA, i);
|
|
|
|
hw->phy.ops.write_reg_page(hw, BM_MTA(i),
|
|
|
|
(u16)(mac_reg & 0xFFFF));
|
|
|
|
hw->phy.ops.write_reg_page(hw, BM_MTA(i) + 1,
|
|
|
|
(u16)((mac_reg >> 16) & 0xFFFF));
|
|
|
|
}
|
|
|
|
/* configure PHY Rx Control register */
|
|
|
|
hw->phy.ops.read_reg_page(hw, BM_RCTL, &phy_reg);
|
|
|
|
mac_reg = er32(RCTL);
|
|
|
|
|
|
|
|
if (mac_reg & E1000_RCTL_UPE)
|
|
|
|
phy_reg |= BM_RCTL_UPE;
|
|
|
|
|
|
|
|
if (mac_reg & E1000_RCTL_MPE)
|
|
|
|
phy_reg |= BM_RCTL_MPE;
|
|
|
|
|
|
|
|
phy_reg &= ~(BM_RCTL_MO_MASK);
|
|
|
|
|
|
|
|
if (mac_reg & E1000_RCTL_MO_3)
|
|
|
|
phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT) << BM_RCTL_MO_SHIFT);
|
|
|
|
|
|
|
|
if (mac_reg & E1000_RCTL_BAM)
|
|
|
|
phy_reg |= BM_RCTL_BAM;
|
|
|
|
|
|
|
|
if (mac_reg & E1000_RCTL_PMCF)
|
|
|
|
phy_reg |= BM_RCTL_PMCF;
|
|
|
|
|
|
|
|
mac_reg = er32(CTRL);
|
|
|
|
|
|
|
|
if (mac_reg & E1000_CTRL_RFCE)
|
|
|
|
phy_reg |= BM_RCTL_RFCE;
|
|
|
|
|
|
|
|
hw->phy.ops.write_reg_page(hw, BM_RCTL, phy_reg);
|
|
|
|
|
|
|
|
wuc = E1000_WUC_PME_EN;
|
|
|
|
|
|
|
|
if (wufc & (E1000_WUFC_MAG | E1000_WUFC_LNKC))
|
|
|
|
wuc |= E1000_WUC_APME;
|
|
|
|
|
|
|
|
/* enable PHY wakeup in MAC register */
|
|
|
|
ew32(WUFC, wufc);
|
|
|
|
ew32(WUC, (E1000_WUC_PHY_WAKE | E1000_WUC_APMPME | E1000_WUC_PME_STATUS | wuc));
|
|
|
|
|
|
|
|
/* configure and enable PHY wakeup in PHY registers */
|
|
|
|
hw->phy.ops.write_reg_page(hw, BM_WUFC, wufc);
|
|
|
|
hw->phy.ops.write_reg_page(hw, BM_WUC, wuc);
|
|
|
|
|
|
|
|
/* activate PHY wakeup */
|
|
|
|
wuc_enable |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT;
|
|
|
|
error = e1000_disable_phy_wakeup_reg_access_bm(hw, &wuc_enable);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
DebugLog("Ethernet [IntelMausi]: Failed to set PHY Host Wakeup bit.\n");
|
|
|
|
|
|
|
|
release:
|
|
|
|
hw->phy.ops.release(hw);
|
|
|
|
}
|
|
|
|
|
2016-04-19 00:14:50 +02:00
|
|
|
void IntelMausi::intelSetupAdvForMedium(const IONetworkMedium *medium)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
|
|
|
struct e1000_mac_info *mac = &hw->mac;
|
|
|
|
|
|
|
|
if (adapterData.flags2 & FLAG2_HAS_EEE)
|
|
|
|
hw->dev_spec.ich8lan.eee_disable = true;
|
|
|
|
|
|
|
|
switch (medium->getIndex()) {
|
|
|
|
case MEDIUM_INDEX_10HD:
|
|
|
|
mac->forced_speed_duplex = ADVERTISE_10_HALF;
|
|
|
|
hw->mac.autoneg = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_10FD:
|
|
|
|
mac->forced_speed_duplex = ADVERTISE_10_FULL;
|
|
|
|
hw->mac.autoneg = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_100HD:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_100baseT_Half;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_none;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_100FD:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_100baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_none;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_100FDFC:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_100baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_full;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_1000FD:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_none;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_1000FDFC:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_full;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_1000FDEEE:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_none;
|
|
|
|
hw->dev_spec.ich8lan.eee_disable = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_1000FDFCEEE:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_full;
|
|
|
|
hw->dev_spec.ich8lan.eee_disable = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_100FDEEE:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_100baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_none;
|
|
|
|
hw->dev_spec.ich8lan.eee_disable = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEDIUM_INDEX_100FDFCEEE:
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_100baseT_Full;
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
hw->fc.requested_mode = e1000_fc_full;
|
|
|
|
hw->dev_spec.ich8lan.eee_disable = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (hw->phy.media_type == e1000_media_type_fiber) {
|
|
|
|
hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg;
|
|
|
|
} else {
|
|
|
|
hw->phy.autoneg_advertised = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
|
|
|
|
ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half |
|
|
|
|
ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
|
|
|
|
ADVERTISED_TP | ADVERTISED_MII);
|
|
|
|
|
|
|
|
if (adapterData.fc_autoneg)
|
|
|
|
hw->fc.requested_mode = e1000_fc_default;
|
|
|
|
|
|
|
|
if (adapterData.flags2 & FLAG2_HAS_EEE)
|
|
|
|
hw->dev_spec.ich8lan.eee_disable = false;
|
|
|
|
}
|
|
|
|
hw->mac.autoneg = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* clear MDI, MDI(-X) override is only allowed when autoneg enabled */
|
|
|
|
hw->phy.mdix = AUTO_ALL_MODES;
|
|
|
|
}
|
|
|
|
|
2015-03-05 00:11:40 +01:00
|
|
|
void IntelMausi::intelFlushLPIC()
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
|
|
|
UInt32 error, lpic;
|
|
|
|
|
|
|
|
/* Flush LPIC. */
|
|
|
|
error = hw->phy.ops.acquire(hw);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lpic = intelReadMem32(E1000_LPIC);
|
2015-03-15 00:36:06 +01:00
|
|
|
DebugLog("Ethernet [IntelMausi]: LPIC=0x%08x.\n", lpic);
|
2015-03-05 00:11:40 +01:00
|
|
|
|
|
|
|
hw->phy.ops.release(hw);
|
|
|
|
}
|
|
|
|
|
2016-08-27 00:59:27 +02:00
|
|
|
void IntelMausi::setMaxLatency(UInt32 linkSpeed)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapterData.hw;
|
|
|
|
UInt32 rxa = intelReadMem32(E1000_PBA) & E1000_PBA_RXA_MASK;
|
|
|
|
UInt32 latency;
|
|
|
|
|
|
|
|
rxa = rxa << 9;
|
|
|
|
latency = (rxa > hw->adapter->max_frame_size) ? (rxa - hw->adapter->max_frame_size) * (16000 / linkSpeed) : 0;
|
|
|
|
|
|
|
|
if (maxLatency && (latency > maxLatency))
|
|
|
|
latency = maxLatency;
|
|
|
|
|
|
|
|
requireMaxBusStall(latency);
|
|
|
|
|
|
|
|
DebugLog("Ethernet [IntelMausi]: requireMaxBusStall(%uns).\n", latency);
|
|
|
|
}
|
|
|
|
|
2015-02-11 12:25:43 +01:00
|
|
|
UInt16 IntelMausi::intelSupportsEEE(struct e1000_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct e1000_hw *hw = &adapter->hw;
|
|
|
|
struct e1000_dev_spec_ich8lan *dev_spec;
|
|
|
|
SInt32 error;
|
|
|
|
UInt16 result = 0;
|
|
|
|
UInt16 lpa, adv, advAddr;
|
|
|
|
|
|
|
|
if (!(adapter->flags2 & FLAG2_HAS_EEE))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
dev_spec = &hw->dev_spec.ich8lan;
|
|
|
|
|
|
|
|
if (hw->dev_spec.ich8lan.eee_disable)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
switch (hw->phy.type) {
|
|
|
|
case e1000_phy_82579:
|
|
|
|
lpa = I82579_EEE_LP_ABILITY;
|
|
|
|
advAddr = I82579_EEE_ADVERTISEMENT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case e1000_phy_i217:
|
|
|
|
lpa = I217_EEE_LP_ABILITY;
|
|
|
|
advAddr = I217_EEE_ADVERTISEMENT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
error = hw->phy.ops.acquire(hw);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Save off link partner's EEE ability */
|
|
|
|
error = e1000_read_emi_reg_locked(hw, lpa, &dev_spec->eee_lp_ability);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto release;
|
|
|
|
|
|
|
|
/* Read EEE advertisement */
|
|
|
|
error = e1000_read_emi_reg_locked(hw, advAddr, &adv);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto release;
|
|
|
|
|
|
|
|
/* Enable EEE only for speeds in which the link partner is
|
|
|
|
* EEE capable and for which we advertise EEE.
|
|
|
|
*/
|
|
|
|
if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
|
|
|
|
result |= I82579_LPI_CTRL_1000_ENABLE;
|
|
|
|
|
|
|
|
if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED)
|
|
|
|
result |= I82579_LPI_CTRL_100_ENABLE;
|
|
|
|
|
|
|
|
DebugLog("Ethernet [IntelMausi]: EEE mode = 0x%04x, adv=0x%04x, lpa=0x%04x\n", result, adv, dev_spec->eee_lp_ability);
|
|
|
|
|
|
|
|
release:
|
|
|
|
hw->phy.ops.release(hw);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
SInt32 IntelMausi::intelEnableEEE(struct e1000_hw *hw, UInt16 mode)
|
|
|
|
{
|
|
|
|
SInt32 error = 0;
|
2015-03-05 00:11:40 +01:00
|
|
|
UInt16 pcsStatus, lpiCtrl, data;
|
2015-02-11 12:25:43 +01:00
|
|
|
|
|
|
|
switch (hw->phy.type) {
|
|
|
|
case e1000_phy_82579:
|
|
|
|
pcsStatus = I82579_EEE_PCS_STATUS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case e1000_phy_i217:
|
|
|
|
pcsStatus = I217_EEE_PCS_STATUS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
error = hw->phy.ops.acquire(hw);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
error = e1e_rphy_locked(hw, I82579_LPI_CTRL, &lpiCtrl);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto release;
|
|
|
|
|
|
|
|
/* Clear bits that enable EEE in various speeds */
|
|
|
|
lpiCtrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
|
|
|
|
|
|
|
|
/* Set the new EEE mode. */
|
|
|
|
lpiCtrl |= mode;
|
|
|
|
|
|
|
|
if (hw->phy.type == e1000_phy_82579) {
|
|
|
|
error = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, &data);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto release;
|
|
|
|
|
|
|
|
data &= ~I82579_LPI_100_PLL_SHUT;
|
2015-03-15 00:36:06 +01:00
|
|
|
e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, data);
|
2015-02-11 12:25:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
|
|
|
|
error = e1000_read_emi_reg_locked(hw, pcsStatus, &data);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto release;
|
|
|
|
|
|
|
|
error = e1e_wphy_locked(hw, I82579_LPI_CTRL, lpiCtrl);
|
|
|
|
|
|
|
|
release:
|
|
|
|
hw->phy.ops.release(hw);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2016-08-27 00:59:27 +02:00
|
|
|
|
|
|
|
|