Olivier Martin
2015-06-17 16:19:03 UTC
The original driver comes the package "Intel Undi UEFI Source 4606.zip"
downloaded on from http://tianocore.sourceforge.net/wiki/EDK.
The driver has been ported to EDK2.
It builds but it has not been tested.
Change-Id: If7f81cc53d87c4ef224ced1ba995f1f84a6715bf
Signed-off-by: Olivier Martin <***@arm.com>
---
.../Drivers/LanIntelE1000Dxe/ComponentName.c | 407 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c | 1751 +++++++++
.../Drivers/LanIntelE1000Dxe/DriverConfiguration.c | 666 ++++
.../Drivers/LanIntelE1000Dxe/DriverDiagnostics.c | 1553 ++++++++
.../Drivers/LanIntelE1000Dxe/FirmwareManagement.c | 1126 ++++++
.../Drivers/LanIntelE1000Dxe/FirmwareManagement.h | 216 ++
.../Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf | 99 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h | 68 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h | 159 +
.../LanIntelE1000Dxe/build_instructions.txt | 63 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c | 514 +++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h | 100 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c | 2222 +++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h | 680 ++++
.../Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c | 1561 ++++++++
.../Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h | 103 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c | 2042 ++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h | 66 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c | 2030 ++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h | 423 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c | 1248 ++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h | 175 +
.../Drivers/LanIntelE1000Dxe/e1000_defines.h | 1772 +++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h | 868 +++++
.../Drivers/LanIntelE1000Dxe/e1000_ich8lan.c | 4070 ++++++++++++++++++++
.../Drivers/LanIntelE1000Dxe/e1000_ich8lan.h | 233 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c | 2203 +++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h | 102 +
.../Drivers/LanIntelE1000Dxe/e1000_manage.c | 409 ++
.../Drivers/LanIntelE1000Dxe/e1000_manage.h | 87 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c | 1063 +++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h | 75 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c | 693 ++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h | 180 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c | 3579 +++++++++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h | 268 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h | 576 +++
.../Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf | 97 +
.../Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf | 98 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c | 1973 ++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h | 87 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h | 33 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c | 1505 ++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr | 138 +
.../Drivers/LanIntelE1000Dxe/inventorystrings.uni | Bin 0 -> 47396 bytes
EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c | 118 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h | 74 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c | 138 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h | 73 +
49 files changed, 37784 insertions(+)
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventorystrings.uni
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c
new file mode 100755
index 0000000..bc47d53
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c
@@ -0,0 +1,407 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "brand.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+//
+// Version and Branding Information
+//
+
+CHAR16 VersionNumber[36];
+
+CHAR16* PrefixString = L"Intel(R) PRO/1000 ";
+CHAR16* PlatformName = L" PCI-E ";
+
+static EFI_UNICODE_STRING_TABLE mGigUndiDriverNameTable[] = {
+ { "eng", VersionNumber},
+ { "en-US", VersionNumber},
+ { NULL, NULL }
+};
+
+#define WILD_CARD 0x0000
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+GigUndiComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+GigUndiComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+
+EFI_COMPONENT_NAME_PROTOCOL gGigUndiComponentName = {
+ GigUndiComponentNameGetDriverName,
+ GigUndiComponentNameGetControllerName,
+ "eng"
+};
+
+EFI_COMPONENT_NAME2_PROTOCOL gGigUndiComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GigUndiComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GigUndiComponentNameGetControllerName,
+ "en-US"
+};
+
+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gGigUndiSupportedEFIVersion = {
+ sizeof(EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL),
+ EFI_2_10_SYSTEM_TABLE_REVISION
+};
+
+VOID
+GetUndiControllerName (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+ Routine Description:
+ Searches through the branding string list for the best possible match for the controller
+ associated with GigUndiPrivateData.
+
+ Arguments:
+ GigUndiPrivateData - Stores the PCI IDs and component name table for the device.
+
+ Returns:
+ VOID
+--*/
+{
+ struct e1000_hw *Nic;
+ CHAR16 *Brand;
+ UINTN i;
+ INTN VendorMatch;
+ INTN DeviceIdMatch;
+ INTN SubVendorMatch;
+ INTN SubSystemMatch;
+
+ i = 0;
+ VendorMatch = -1;
+ DeviceIdMatch = -1;
+ SubVendorMatch = -1;
+ SubSystemMatch = -1;
+ Brand = NULL;
+
+ Nic = &GigUndiPrivateData->NicInfo.hw;
+
+ for (i = 0; branding_table[i].vendor_id != 0xFFFF; i++) {
+ if (Nic->vendor_id == branding_table[i].vendor_id) {
+ if (Nic->device_id == branding_table[i].device_id) {
+ if (Nic->subsystem_vendor_id == branding_table[i].subvendor_id) {
+ if (Nic->subsystem_device_id == branding_table[i].subsystem_id) {
+ //
+ // Found the best possible match
+ //
+ SubSystemMatch = i;
+ break;
+ }
+ else if (branding_table[i].subsystem_id == WILD_CARD) {
+ SubVendorMatch = i;
+ }
+ }
+ else if (branding_table[i].subvendor_id == WILD_CARD) {
+ DeviceIdMatch = i;
+ }
+ }
+ else if (branding_table[i].device_id == WILD_CARD) {
+ //
+ // Worst match: Vendor ID only, everything else wildcard
+ //
+ VendorMatch = i;
+ }
+ }
+ }
+
+ //
+ // Pick the best possible match
+ //
+ do {
+ if (SubSystemMatch != -1) {
+ Brand = branding_table[SubSystemMatch].brand_string;
+ break;
+ }
+ if (SubVendorMatch != -1) {
+ Brand = branding_table[SubVendorMatch].brand_string;
+ break;
+ }
+ if (DeviceIdMatch != -1) {
+ Brand = branding_table[DeviceIdMatch].brand_string;
+ break;
+ }
+ if (VendorMatch != -1) {
+ Brand = branding_table[VendorMatch].brand_string;
+ break;
+ }
+ } while(0);
+
+ if (Brand == NULL) {
+ return;
+ }
+
+ GigUndiPrivateData->Brand = Brand;
+ AddUnicodeString (
+ "en-US",
+ gGigUndiComponentName2.SupportedLanguages,
+ &GigUndiPrivateData->ControllerNameTable,
+ Brand
+ );
+
+ AddUnicodeString (
+ "eng",
+ gGigUndiComponentName.SupportedLanguages,
+ &GigUndiPrivateData->ControllerNameTable,
+ Brand
+ );
+}
+
+
+EFI_STATUS
+GigUndiComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ Language - A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ DriverName - A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ Returns:
+ EFI_SUCCES - The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - DriverName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT(INIT, ("GigUndiComponentNameGetDriverName\n"));
+
+ //
+ // First lets put together the branding string
+ //
+ CopyMem(&VersionNumber[0], PrefixString, 18 * sizeof(CHAR16));
+
+ VersionNumber[18] = '0' + MAJORVERSION;
+ VersionNumber[19] = '.';
+ VersionNumber[20] = '0' + MINORVERSION;
+ VersionNumber[21] = '.';
+ VersionNumber[22] = '0' + BUILDNUMBER/10;
+ VersionNumber[23] = '0' + BUILDNUMBER%10;
+
+ CopyMem(&VersionNumber[24], PlatformName, 7 * sizeof(CHAR16));
+ VersionNumber[31] = '\0';
+
+ if (This == (EFI_COMPONENT_NAME_PROTOCOL *)&gGigUndiComponentName2) {
+ Language = "en-US";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName2.SupportedLanguages,
+ mGigUndiDriverNameTable,
+ DriverName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+ return Status;
+ }
+
+ Language = "eng";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName.SupportedLanguages,
+ mGigUndiDriverNameTable,
+ DriverName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+GigUndiComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ ControllerHandle - The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ ChildHandle - The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ ControllerName - A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language from the point of view of the driver specified
+ by This.
+
+ Returns:
+ EFI_SUCCESS - The Unicode string for the user readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - ControllerName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_STATUS Status;
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ if (ChildHandle == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ else {
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **)&NIIProtocol,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (NIIProtocol);
+
+ if (This == (EFI_COMPONENT_NAME_PROTOCOL *)&gGigUndiComponentName2) {
+ Language = "en-US";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName2.SupportedLanguages,
+ GigUndiPrivateData->ControllerNameTable,
+ ControllerName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+ return Status;
+ }
+
+ Language = "eng";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName.SupportedLanguages,
+ GigUndiPrivateData->ControllerNameTable,
+ ControllerName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+ return Status;
+ }
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c
new file mode 100755
index 0000000..a860113
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c
@@ -0,0 +1,1751 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+//
+// Global variables defined outside this file
+//
+extern PXE_SW_UNDI *e1000_pxe_31;
+extern GIG_UNDI_PRIVATE_DATA *e1000_UNDI32DeviceList[MAX_NIC_INTERFACES];
+
+//
+// Global variables defined in this file
+//
+UNDI_CALL_TABLE e1000_api_table[PXE_OPCODE_LAST_VALID + 1] = {
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ (UINT16) (ANY_STATE),
+ e1000_UNDI_GetState
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ (UINT16) (ANY_STATE),
+ e1000_UNDI_Start
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ MUST_BE_STARTED,
+ e1000_UNDI_Stop
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ sizeof (PXE_DB_GET_INIT_INFO),
+ 0,
+ MUST_BE_STARTED,
+ e1000_UNDI_GetInitInfo
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ sizeof (PXE_DB_GET_CONFIG_INFO),
+ 0,
+ MUST_BE_STARTED,
+ e1000_UNDI_GetConfigInfo
+ },
+ {
+ sizeof (PXE_CPB_INITIALIZE),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_STARTED,
+ e1000_UNDI_Initialize
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Reset
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Shutdown
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Interrupt
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_RecFilter
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_StnAddr
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Statistics
+ },
+ {
+ sizeof (PXE_CPB_MCAST_IP_TO_MAC),
+ sizeof (PXE_DB_MCAST_IP_TO_MAC),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_ip2mac
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_NVData
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Status
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_FillHeader
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Transmit
+ },
+ {
+ sizeof (PXE_CPB_RECEIVE),
+ sizeof (PXE_DB_RECEIVE),
+ 0,
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Receive
+ }
+};
+
+//
+// External Functions
+//
+extern
+UINTN
+e1000_Reset (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 Opflags
+ );
+
+extern
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+extern
+UINTN
+e1000_SetFilter (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 NewFilter,
+ UINT64 cpb,
+ UINT32 cpbsize
+ );
+
+extern
+int
+e1000_Statistics (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 db,
+ UINT16 dbsize
+ );
+
+extern
+BOOLEAN
+e1000_WaitForAutoNeg (
+ IN GIG_DRIVER_DATA *GigAdapter
+ );
+
+extern
+int
+e1000_SetInterruptState (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+VOID
+e1000_UNDI_GetState (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine determines the operational state of the UNDI. It updates the state flags in the
+ Command Descriptor Block based on information derived from the AdapterInfo instance data.
+
+ To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of
+ the command execution.
+
+ The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command
+ has successfully completed.
+
+ Keep in mind the AdapterInfo->State is the active state of the adapter (based on software
+ interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected
+ to the caller of the UNDI API.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ DEBUGPRINT(DECODE, ("e1000_UNDI_GetState\n"));
+ DEBUGWAIT(DECODE);
+
+ CdbPtr->StatFlags |= GigAdapter->State;
+ CdbPtr->StatFlags |= PXE_STATFLAGS_COMMAND_COMPLETE;
+
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Start (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to change the operational state of the Gigabit UNDI from stopped to started.
+ It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise
+ the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
+ UNDI as having already been started.
+
+ This routine is modified to reflect the undi 1.1 specification changes. The
+ changes in the spec are mainly in the callback routines, the new spec adds
+ 3 more callbacks and a unique id.
+ Since this UNDI supports both old and new undi specifications,
+ The NIC's data structure is filled in with the callback routines (depending
+ on the version) pointed to in the caller's CpbPtr. This seeds the Delay,
+ Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem
+ and Sync_Mem routines and a unique id variable for the new version.
+ This is the function which an external entity (SNP, O/S, etc) would call
+ to provide it's I/O abstraction to the UNDI.
+
+ It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_START_31 *CpbPtr_31;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Start\n"));
+ DEBUGWAIT(DECODE);
+
+ //
+ // check if it is already started.
+ //
+ if (GigAdapter->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_ALREADY_STARTED;
+ return ;
+ }
+
+ if (CdbPtr->CPBsize != sizeof (PXE_CPB_START_30) && CdbPtr->CPBsize != sizeof (PXE_CPB_START_31)) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr);
+
+ GigAdapter->Delay = (bsptr) (UINTN) CpbPtr_31->Delay;
+ GigAdapter->Virt2Phys = (virtphys) (UINTN) CpbPtr_31->Virt2Phys;
+ GigAdapter->Block = (block) (UINTN) CpbPtr_31->Block;
+ GigAdapter->MemIo = (mem_io) (UINTN) CpbPtr_31->Mem_IO;
+ GigAdapter->MapMem = (map_mem) (UINTN) CpbPtr_31->Map_Mem;
+ GigAdapter->UnMapMem = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem;
+ GigAdapter->SyncMem = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem;
+ GigAdapter->Unique_ID = CpbPtr_31->Unique_ID;
+ DEBUGPRINT(DECODE, ("CpbPtr_31->Unique_ID = %x\n", CpbPtr_31->Unique_ID));
+
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STARTED;
+
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Stop (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to change the operational state of the UNDI from started to stopped.
+ It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise
+ the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
+ UNDI as having already not been shut down.
+
+ The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out..
+
+ It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Stop\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
+ return ;
+ }
+
+ GigAdapter->Delay = 0;
+ GigAdapter->Virt2Phys = 0;
+ GigAdapter->Block = 0;
+
+ GigAdapter->MapMem = 0;
+ GigAdapter->UnMapMem = 0;
+ GigAdapter->SyncMem = 0;
+
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STOPPED;
+
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_GetInitInfo (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to retrieve the initialization information that is needed by drivers and
+ applications to initialize the UNDI. This will fill in data in the Data Block structure that is
+ pointed to by the caller's CdbPtr->DBaddr. The fields filled in are as follows:
+
+ MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen,
+ MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack.
+
+ In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection. (APRIORI knowledge)
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_GET_INIT_INFO *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_GetInitInfo\n"));
+ DEBUGWAIT(DECODE);
+
+ DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr);
+
+ DbPtr->MemoryRequired = 0;
+ DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
+ //
+ // First check for FIBER, Links are 1000,0,0,0
+ //
+ if (GigAdapter->hw.phy.media_type == e1000_media_type_copper ) {
+ DbPtr->LinkSpeeds[0] = 10;
+ DbPtr->LinkSpeeds[1] = 100;
+ DbPtr->LinkSpeeds[2] = 1000;
+ DbPtr->LinkSpeeds[3] = 0;
+ } else {
+ DbPtr->LinkSpeeds[0] = 1000;
+ DbPtr->LinkSpeeds[1] = 0;
+ DbPtr->LinkSpeeds[2] = 0;
+ DbPtr->LinkSpeeds[3] = 0;
+ }
+
+ DbPtr->NvCount = MAX_EEPROM_LEN;
+ DbPtr->NvWidth = 4;
+ DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
+ DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER;
+ DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
+
+ DbPtr->TxBufCnt = DEFAULT_TX_DESCRIPTORS;
+ DbPtr->TxBufSize = sizeof (E1000_TRANSMIT_DESCRIPTOR);
+ DbPtr->RxBufCnt = DEFAULT_RX_DESCRIPTORS;
+ DbPtr->RxBufSize = sizeof (E1000_RECEIVE_DESCRIPTOR) + sizeof (LOCAL_RX_BUFFER);
+
+ DbPtr->IFtype = PXE_IFTYPE_ETHERNET;
+ DbPtr->SupportedDuplexModes = PXE_DUPLEX_ENABLE_FULL_SUPPORTED | PXE_DUPLEX_FORCE_FULL_SUPPORTED;
+ DbPtr->SupportedLoopBackModes = 0;
+
+ CdbPtr->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
+ PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
+
+ CdbPtr->StatFlags |= PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_GetConfigInfo (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to retrieve the configuration information about the NIC being controlled by
+ this driver. This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr.
+ The fields filled in are as follows:
+
+ DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci.
+
+ In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_GET_CONFIG_INFO *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_GetConfigInfo\n"));
+ DEBUGWAIT(DECODE);
+
+ DbPtr = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr);
+
+ DbPtr->pci.BusType = PXE_BUSTYPE_PCI;
+ DbPtr->pci.Bus = (UINT16) GigAdapter->Bus;
+ DbPtr->pci.Device = (UINT8) GigAdapter->Device;
+ DbPtr->pci.Function = (UINT8) GigAdapter->Function;
+ DEBUGPRINT(DECODE, (
+ "Bus %x, Device %x, Function %x\n",
+ GigAdapter->Bus,
+ GigAdapter->Device,
+ GigAdapter->Function
+ ));
+
+ CopyMem (DbPtr->pci.Config.Dword, &GigAdapter->PciConfig, MAX_PCI_CONFIG_LEN * sizeof (UINT32));
+
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Initialize (
+ IN PXE_CDB *CdbPtr,
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine resets the network adapter and initializes the Gigabit UNDI using the parameters
+ supplied in the CPB. This command must be issued before the network adapter can be setup to
+ transmit and receive packets.
+
+ Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block
+ of non-swappable memory may need to be allocated. The address of this memory must be passed to
+ UNDI during the Initialize in the CPB. This memory is used primarily for transmit and receive buffers.
+
+ The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with
+ information that was passed in the CPB and the NIC is initialized.
+
+ If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
+ Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of
+ the UNDI is now initialized.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_INITIALIZE *CpbPtr;
+ PXE_DB_INITIALIZE *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Initialize\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Initialize called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
+ (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)
+ ) {
+ DEBUGPRINT(CRITICAL, ("INVALID CDB\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ //
+ // Check if it is already initialized
+ //
+ if (GigAdapter->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ DEBUGPRINT(DECODE, ("ALREADY INITIALIZED\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
+ return ;
+ }
+
+ CpbPtr = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;
+ DbPtr = (PXE_DB_INITIALIZE *) (UINTN) CdbPtr->DBaddr;
+
+ //
+ // Default behaviour is to detect the cable, if the 3rd param is 1,
+ // do not do that
+ //
+ GigAdapter->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);
+ DEBUGPRINT(DECODE, ("CdbPtr->OpFlags = %X\n", CdbPtr->OpFlags));
+ GigAdapter->LinkSpeed = (UINT16) CpbPtr->LinkSpeed;
+
+ GigAdapter->DuplexMode = CpbPtr->DuplexMode;
+ GigAdapter->LoopBack = CpbPtr->LoopBackMode;
+
+ DEBUGPRINT(DECODE, ("CpbPtr->TxBufCnt = %X\n", CpbPtr->TxBufCnt));
+ DEBUGPRINT(DECODE, ("CpbPtr->TxBufSize = %X\n", CpbPtr->TxBufSize));
+ DEBUGPRINT(DECODE, ("CpbPtr->RxBufCnt = %X\n", CpbPtr->RxBufCnt));
+ DEBUGPRINT(DECODE, ("CpbPtr->RxBufSize = %X\n", CpbPtr->RxBufSize));
+
+ if (GigAdapter->CableDetect != 0) {
+ DEBUGPRINT(DECODE, ("Setting wait_autoneg_complete\n"));
+ GigAdapter->hw.phy.autoneg_wait_to_complete = TRUE;
+ } else {
+ GigAdapter->hw.phy.autoneg_wait_to_complete = FALSE;
+ }
+
+ CdbPtr->StatCode = (PXE_STATCODE) e1000_Inititialize (GigAdapter);
+
+ //
+ // We allocate our own memory for transmit and receive so set MemoryUsed to 0.
+ //
+ DbPtr->MemoryUsed = 0;
+ DbPtr->TxBufCnt = DEFAULT_TX_DESCRIPTORS;
+ DbPtr->TxBufSize = sizeof (E1000_TRANSMIT_DESCRIPTOR);
+ DbPtr->RxBufCnt = DEFAULT_RX_DESCRIPTORS;
+ DbPtr->RxBufSize = sizeof (E1000_RECEIVE_DESCRIPTOR) + sizeof (LOCAL_RX_BUFFER);
+
+ if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("e1000_Inititialize failed! Statcode = %X\n", CdbPtr->StatCode));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ } else {
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
+ }
+
+ //
+ // If no link is detected we want to set the driver state back to _GET_STATE_STARTED so
+ // that the SNP will not try to restart the driver.
+ //
+ if (e1000_WaitForAutoNeg (GigAdapter) == TRUE) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ } else {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STARTED;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Reset (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine resets the network adapter and initializes the Gigabit UNDI using the
+ parameters supplied in the CPB. The transmit and receive queues are emptied and any
+ pending interrupts are cleared.
+
+ If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver
+ is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Reset\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Reset called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED &&
+ CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS &&
+ CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS
+ ) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS; //(UINT16) e1000_Reset (GigAdapter, CdbPtr->OpFlags);
+
+ if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ } else {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ }
+}
+
+VOID
+e1000_UNDI_Shutdown (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine resets the network adapter and leaves it in a safe state for another driver to
+ initialize. Any pending transmits or receives are lost. Receive filters and external
+ interrupt enables are disabled. Once the UNDI has been shutdown, it can then be stopped
+ or initialized again.
+
+ If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
+
+ Otherwise, GigAdapter->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing
+ the state of the NIC as being started.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ //
+ // do the shutdown stuff here
+ //
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Shutdown\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Shutdown called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ CdbPtr->StatCode = (UINT16) e1000_Shutdown (GigAdapter);
+
+ if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ } else {
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STARTED;
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Interrupt (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine can be used to read and/or change the current external interrupt enable
+ settings. Disabling an external interrupt enable prevents and external (hardware)
+ interrupt from being signaled by the network device. Internally the interrupt events
+ can still be polled by using the UNDI_GetState command.
+
+ The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on.
+
+Returns:
+ None
+
+--*/
+{
+ UINT8 IntMask;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Interrupt\n"));
+
+ IntMask = (UINT8) (UINTN)
+ (
+ CdbPtr->OpFlags &
+ (
+ PXE_OPFLAGS_INTERRUPT_RECEIVE |
+ PXE_OPFLAGS_INTERRUPT_TRANSMIT |
+ PXE_OPFLAGS_INTERRUPT_COMMAND |
+ PXE_OPFLAGS_INTERRUPT_SOFTWARE
+ )
+ );
+
+ switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) {
+ case PXE_OPFLAGS_INTERRUPT_READ:
+ break;
+
+ case PXE_OPFLAGS_INTERRUPT_ENABLE:
+ if (IntMask == 0) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ GigAdapter->int_mask = IntMask;
+ e1000_SetInterruptState (GigAdapter);
+ break;
+
+ case PXE_OPFLAGS_INTERRUPT_DISABLE:
+ if (IntMask != 0) {
+ GigAdapter->int_mask &= ~(IntMask);
+ e1000_SetInterruptState (GigAdapter);
+ break;
+ }
+
+ //
+ // else fall thru.
+ //
+ default:
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ if ((GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE;
+ }
+
+ if ((GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT;
+ }
+
+ if ((GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_RecFilter (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to read and change receive filters and, if supported, read
+ and change multicast MAC address filter list.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI
+ driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+
+ UINT16 NewFilter;
+ UINT16 OpFlags;
+ PXE_DB_RECEIVE_FILTERS *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_RecFilter\n"));
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_RecFilter called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ OpFlags = CdbPtr->OpFlags;
+ NewFilter = (UINT16) (OpFlags & 0x1F);
+
+ switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
+ case PXE_OPFLAGS_RECEIVE_FILTER_READ:
+ //
+ // not expecting a cpb, not expecting any filter bits
+ //
+ if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {
+ goto BadCdb;
+ }
+
+ if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
+ goto JustRead;
+ }
+
+ NewFilter |= GigAdapter->Rx_Filter;
+
+ //
+ // all other flags are ignored except mcast_reset
+ //
+ break;
+
+ case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
+ //
+ // there should be atleast one other filter bit set.
+ //
+ if (NewFilter == 0) {
+ //
+ // nothing to enable
+ //
+ goto BadCdb;
+ }
+
+ if (CdbPtr->CPBsize != 0) {
+ //
+ // this must be a multicast address list!
+ // don't accept the list unless selective_mcast is set
+ // don't accept confusing mcast settings with this
+ //
+ if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
+ ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
+ ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0)
+ ) {
+ goto BadCdb;
+ }
+ }
+
+ //
+ // check selective mcast case enable case
+ //
+ if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
+ ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0)
+ ) {
+ goto BadCdb;
+
+ }
+
+ //
+ // if no cpb, make sure we have an old list
+ //
+ if ((CdbPtr->CPBsize == 0) && (GigAdapter->McastList.Length == 0)) {
+ goto BadCdb;
+ }
+ }
+
+ //
+ // if you want to enable anything, you got to have unicast
+ // and you have what you already enabled!
+ //
+ NewFilter |= (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | GigAdapter->Rx_Filter);
+
+ break;
+
+ case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
+ //
+ // mcast list not expected, i.e. no cpb here!
+ //
+ if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {
+ goto BadCdb; // db with all_multi??
+ }
+
+ NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & GigAdapter->Rx_Filter);
+
+ break;
+
+ default:
+ goto BadCdb;
+ }
+
+ if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {
+ GigAdapter->McastList.Length = 0;
+ NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ }
+
+ e1000_SetFilter (GigAdapter, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);
+
+JustRead:
+ DEBUGPRINT(DECODE, ("Read current filter\n"));
+ //
+ // give the current mcast list
+ //
+ if ((CdbPtr->DBsize != 0) && (GigAdapter->McastList.Length != 0)) {
+ //
+ // copy the mc list to db
+ //
+ UINT16 i;
+ UINT16 copy_len;
+ UINT8 *ptr1;
+ UINT8 *ptr2;
+
+ DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;
+ ptr1 = (UINT8 *) (&DbPtr->MCastList[0]);
+
+ copy_len = (UINT16) (GigAdapter->McastList.Length * PXE_MAC_LENGTH);
+
+ if (copy_len > CdbPtr->DBsize) {
+ copy_len = CdbPtr->DBsize;
+
+ }
+
+ ptr2 = (UINT8 *) (&GigAdapter->McastList.McAddr[0]);
+ for (i = 0; i < copy_len; i++) {
+ ptr1[i] = ptr2[i];
+ }
+ }
+
+ //
+ // give the stat flags here
+ //
+ if (GigAdapter->ReceiveStarted) {
+ CdbPtr->StatFlags |= (GigAdapter->Rx_Filter | PXE_STATFLAGS_COMMAND_COMPLETE);
+ }
+
+ return ;
+
+BadCdb:
+ DEBUGPRINT(CRITICAL, ("ERROR: Bad CDB!\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+}
+
+VOID
+e1000_UNDI_StnAddr (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to get the current station and broadcast MAC addresses, and to change the
+ current station MAC address.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver
+ is layering on.
+
+Returns:
+ None
+
+--*/
+{
+
+ PXE_CPB_STATION_ADDRESS *CpbPtr;
+ PXE_DB_STATION_ADDRESS *DbPtr;
+ UINT16 i;
+
+ DbPtr = NULL;
+ DEBUGPRINT(DECODE, ("e1000_UNDI_StnAddr\n"));
+
+ if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
+ //
+ // configure the permanent address.
+ // change the AdapterInfo->CurrentNodeAddress field.
+ //
+ if (CompareMem (
+ GigAdapter->hw.mac.addr,
+ GigAdapter->hw.mac.perm_addr,
+ PXE_HWADDR_LEN_ETHER
+ ) != 0) {
+ CopyMem (
+ GigAdapter->hw.mac.addr,
+ GigAdapter->hw.mac.perm_addr,
+ PXE_HWADDR_LEN_ETHER
+ );
+ e1000_rar_set (&GigAdapter->hw, GigAdapter->hw.mac.addr, 0);
+ }
+ }
+
+ if (CdbPtr->CPBaddr != (UINT64) 0) {
+ CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);
+ GigAdapter->MacAddrOverride = TRUE;
+
+ //
+ // configure the new address
+ //
+ CopyMem (
+ GigAdapter->hw.mac.addr,
+ CpbPtr->StationAddr,
+ PXE_HWADDR_LEN_ETHER
+ );
+
+ DEBUGPRINT(DECODE, ("Reassigned address:\n"));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(DECODE, ("%2x ", CpbPtr->StationAddr[i]));
+ }
+
+ e1000_rar_set (&GigAdapter->hw, GigAdapter->hw.mac.addr, 0);
+ }
+
+ if (CdbPtr->DBaddr != (UINT64) 0) {
+ DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);
+
+ //
+ // fill it with the new values
+ //
+ ZeroMem (DbPtr->StationAddr, PXE_MAC_LENGTH);
+ ZeroMem (DbPtr->PermanentAddr, PXE_MAC_LENGTH);
+ ZeroMem (DbPtr->BroadcastAddr, PXE_MAC_LENGTH);
+ CopyMem (DbPtr->StationAddr, GigAdapter->hw.mac.addr, PXE_HWADDR_LEN_ETHER);
+ CopyMem (DbPtr->PermanentAddr, GigAdapter->hw.mac.perm_addr, PXE_HWADDR_LEN_ETHER);
+ CopyMem (DbPtr->BroadcastAddr, GigAdapter->BroadcastNodeAddress, PXE_MAC_LENGTH);
+ }
+
+ DEBUGPRINT(DECODE, ("DbPtr->BroadcastAddr ="));
+ for (i = 0; i < PXE_MAC_LENGTH; i++) {
+ DEBUGPRINT(DECODE, (" %x", DbPtr->BroadcastAddr[i]));
+ }
+
+ DEBUGPRINT(DECODE, ("\n"));
+ DEBUGWAIT(DECODE);
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+ return ;
+}
+
+VOID
+e1000_UNDI_Statistics (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to read and clear the NIC traffic statistics. This command is supported only
+ if the !PXE structure's Implementation flags say so.
+
+ Results will be parsed out in the following manner:
+ CdbPtr->DBaddr.Data[0] R Total Frames (Including frames with errors and dropped frames)
+ CdbPtr->DBaddr.Data[1] R Good Frames (All frames copied into receive buffer)
+ CdbPtr->DBaddr.Data[2] R Undersize Frames (Frames below minimum length for media <64 for ethernet)
+ CdbPtr->DBaddr.Data[4] R Dropped Frames (Frames that were dropped because receive buffers were full)
+ CdbPtr->DBaddr.Data[8] R CRC Error Frames (Frames with alignment or CRC errors)
+ CdbPtr->DBaddr.Data[A] T Total Frames (Including frames with errors and dropped frames)
+ CdbPtr->DBaddr.Data[B] T Good Frames (All frames copied into transmit buffer)
+ CdbPtr->DBaddr.Data[C] T Undersize Frames (Frames below minimum length for media <64 for ethernet)
+ CdbPtr->DBaddr.Data[E] T Dropped Frames (Frames that were dropped because of collisions)
+ CdbPtr->DBaddr.Data[14] T Total Collision Frames (Total collisions on this subnet)
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+// GC_TODO: GigAdapter - add argument and description to function comment
+{
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Statistics\n"));
+
+ if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {
+ //
+ // Reset the statistics
+ //
+ CdbPtr->StatCode = (UINT16) e1000_Statistics (GigAdapter, 0, 0);
+ } else {
+ CdbPtr->StatCode = (UINT16) e1000_Statistics (GigAdapter, CdbPtr->DBaddr, CdbPtr->DBsize);
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_ip2mac (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to translate a multicast IP address to a multicast MAC address.
+
+ This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP
+ address being appended to it. Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;
+ PXE_DB_MCAST_IP_TO_MAC *DbPtr;
+ UINT32 IPAddr;
+ UINT8 *TmpPtr;
+
+ CpbPtr = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;
+ DbPtr = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_ip2mac\n"));
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
+ //
+ // for now this is not supported
+ //
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED;
+ return ;
+ }
+
+ //
+ // Take the last 23 bits of IP to generate a multicase IP address.
+ //
+ IPAddr = CpbPtr->IP.IPv4;
+ TmpPtr = (UINT8 *) (&IPAddr);
+
+ DbPtr->MAC[0] = 0x01;
+ DbPtr->MAC[1] = 0x00;
+ DbPtr->MAC[2] = 0x5e;
+ DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);
+ DbPtr->MAC[4] = (UINT8) TmpPtr[2];
+ DbPtr->MAC[5] = (UINT8) TmpPtr[3];
+
+ return ;
+}
+
+VOID
+e1000_UNDI_NVData (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to read and write non-volatile storage on the NIC (if supported). The NVRAM
+ could be EEPROM, FLASH, or battery backed RAM.
+
+ This is an optional function according to the UNDI specification (or will be......)
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_NVDATA *DbPtr;
+ PXE_CPB_NVDATA_BULK *PxeCpbNvdata;
+ UINT32 Result;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_NVData\n"));
+
+ if ((GigAdapter->State != PXE_STATFLAGS_GET_STATE_STARTED) &&
+ (GigAdapter->State != PXE_STATFLAGS_GET_STATE_INITIALIZED)
+ ) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {
+ DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;
+ Result = e1000_read_nvm (&GigAdapter->hw, 0, 256, &DbPtr->Data.Word[0]);
+ } else {
+ //
+ // Begin the write at word 40h so we do not overwrite any vital data
+ // All data from address 00h to address CFh will be ignored
+ //
+ PxeCpbNvdata = (PXE_CPB_NVDATA_BULK *) (UINTN) CdbPtr->CPBaddr;
+ Result = e1000_write_nvm (&GigAdapter->hw, 0x40, 0xBF, &PxeCpbNvdata->Word[0x40]);
+ }
+
+ if (Result == E1000_SUCCESS) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+ } else {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Status (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine returns the current interrupt status and/or the transmitted buffer addresses.
+ If the current interrupt status is returned, pending interrupts will be acknowledged by this
+ command. Transmitted buffer addresses that are written to the DB are removed from the transmit
+ buffer queue.
+
+ Normally, this command would be polled with interrupts disabled.
+
+ The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].
+ The interrupt status is returned in CdbPtr->StatFlags.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the Gigabit UNDI
+ driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_GET_STATUS *DbPtr;
+ UINT16 Status;
+ UINT16 NumEntries;
+ E1000_RECEIVE_DESCRIPTOR *RxPtr;
+#if (DBG_LVL&CRITICAL)
+ UINT32 Rdh;
+ UINT32 Rdt;
+#endif
+ UINT32 Reg;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Status\n"));
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Status called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ //
+ // If the size of the DB is not large enough to store at least one 64 bit
+ // complete transmit buffer address and size of the next available receive
+ // packet we will return an error. Per E.4.16 of the EFI spec the DB should
+ // have enough space for at least 1 completed transmit buffer.
+ //
+ if (CdbPtr->DBsize < (sizeof (UINT64) * 2)) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ DEBUGPRINT(CRITICAL, ("Invalid CDB\n"));
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN;
+ }
+
+ return ;
+ }
+
+ DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;
+
+ //
+ // Fill in size of next available receive packet and
+ // reserved field in caller's DB storage.
+ //
+ RxPtr = &GigAdapter->rx_ring[GigAdapter->cur_rx_ind];
+
+#if (DBG_LVL&CRITICAL)
+ if (RxPtr->buffer_addr != GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind]) {
+ DEBUGPRINT(CRITICAL, ("GetStatus ERROR: Rx buff mismatch on desc %d: expected %X, actual %X\n",
+ GigAdapter->cur_rx_ind,
+ GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind],
+ RxPtr->buffer_addr
+ ));
+ }
+
+ Rdt = E1000_READ_REG (&GigAdapter->hw, E1000_RDT(0));
+ Rdh = E1000_READ_REG (&GigAdapter->hw, E1000_RDH(0));
+ if (Rdt == Rdh) {
+ DEBUGPRINT(CRITICAL, ("GetStatus ERROR: RX Buffers Full!\n"));
+ }
+#endif
+
+ if ((RxPtr->status & (E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD)) != 0) {
+ DEBUGPRINT(DECODE, ("Get Status->We have a Rx Frame at %x\n", GigAdapter->cur_rx_ind));
+ DEBUGPRINT(DECODE, ("Frame length = %X\n", RxPtr->length));
+ DbPtr->RxFrameLen = RxPtr->length;
+ } else {
+ DbPtr->RxFrameLen = 0;
+ }
+
+ //
+ // Fill in the completed transmit buffer addresses so they can be freed by
+ // the calling application or driver
+ //
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
+ //
+ // Calculate the number of entries available in the DB to save the addresses
+ // of completed transmit buffers.
+ //
+ NumEntries = (UINT16) ((CdbPtr->DBsize - sizeof (UINT64)) / sizeof (UINT64));
+ DEBUGPRINT(DECODE, ("CdbPtr->DBsize = %d\n", CdbPtr->DBsize));
+ DEBUGPRINT(DECODE, ("NumEntries in DbPtr = %d\n", NumEntries));
+
+ //
+ // On return NumEntries will be the number of TX buffers written into the DB
+ //
+ NumEntries = e1000_FreeTxBuffers(GigAdapter, NumEntries, DbPtr->TxBuffer);
+ if (NumEntries == 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN;
+ }
+
+ //
+ // The receive buffer size and reserved fields take up the first 64 bits of the DB
+ // The completed transmit buffers take up the rest
+ //
+ CdbPtr->DBsize = (UINT16) (sizeof (UINT64) + NumEntries * sizeof (UINT64));
+ DEBUGPRINT(DECODE, ("Return DBsize = %d\n", CdbPtr->DBsize));
+ }
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
+ Status = (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_ICR);
+ GigAdapter->Int_Status |= Status;
+
+ //
+ // Acknowledge the interrupts.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_IMC, 0xFFFFFFFF);
+
+ //
+ // Report all the outstanding interrupts.
+ //
+ if (GigAdapter->Int_Status &
+ (E1000_ICR_RXT0 | E1000_ICR_RXSEQ | E1000_ICR_RXDMT0 | E1000_ICR_RXO | E1000_ICR_RXCFG)
+ ) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
+ }
+
+ if (GigAdapter->int_mask & (E1000_ICR_TXDW | E1000_ICR_TXQE)) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TRANSMIT;
+ }
+
+ if (GigAdapter->int_mask &
+ (E1000_ICR_GPI_EN0 | E1000_ICR_GPI_EN1 | E1000_ICR_GPI_EN2 | E1000_ICR_GPI_EN3 | E1000_ICR_LSC)
+ ) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;
+ }
+ }
+
+ //
+ // Return current media status
+ //
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
+ Reg = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ if ((Reg & E1000_STATUS_LU) == 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
+ }
+ }
+
+ CdbPtr->StatFlags |= PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_FillHeader (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to fill media header(s) in transmit packet(s).
+ Copies the MAC address into the media header whether it is dealing
+ with fragmented or non-fragmented packets.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_FILL_HEADER *Cpb;
+ PXE_CPB_FILL_HEADER_FRAGMENTED *Cpbf;
+ ETHER_HEADER *MacHeader;
+ UINTN i;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_FillHeader\n"));
+
+ if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
+ Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;
+
+ //
+ // Assume 1st fragment is big enough for the mac header.
+ //
+ if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
+ //
+ // No buffers given.
+ //
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ MacHeader = (ETHER_HEADER *) (UINTN) Cpbf->FragDesc[0].FragAddr;
+
+ //
+ // We don't swap the protocol bytes.
+ //
+ MacHeader->type = Cpbf->Protocol;
+
+ DEBUGPRINT(DECODE, ("MacHeader->src_addr = "));
+ for (i = 0; i < PXE_HWADDR_LEN_ETHER; i++) {
+ MacHeader->dest_addr[i] = Cpbf->DestAddr[i];
+ MacHeader->src_addr[i] = Cpbf->SrcAddr[i];
+ DEBUGPRINT(DECODE, ("%x ", MacHeader->src_addr[i]));
+ }
+
+ DEBUGPRINT(DECODE, ("\n"));
+ } else {
+ Cpb = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;
+ MacHeader = (ETHER_HEADER *) (UINTN) Cpb->MediaHeader;
+
+ //
+ // We don't swap the protocol bytes.
+ //
+ MacHeader->type = Cpb->Protocol;
+
+ DEBUGPRINT(DECODE, ("MacHeader->src_addr = "));
+ for (i = 0; i < PXE_HWADDR_LEN_ETHER; i++) {
+ MacHeader->dest_addr[i] = Cpb->DestAddr[i];
+ MacHeader->src_addr[i] = Cpb->SrcAddr[i];
+ DEBUGPRINT(DECODE, ("%x ", MacHeader->src_addr[i]));
+ }
+
+ DEBUGPRINT(DECODE, ("\n"));
+ }
+
+ DEBUGWAIT(DECODE);
+ return ;
+}
+
+VOID
+e1000_UNDI_Transmit (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to place a packet into the transmit queue. The data buffers given to
+ this command are to be considered locked and the application or network driver loses
+ ownership of these buffers and must not free or relocate them until the ownership returns.
+
+ When the packets are transmitted, a transmit complete interrupt is generated (if interrupts
+ are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status
+ command.
+
+ Some implementations and adapters support transmitting multiple packets with one transmit
+ command. If this feature is supported, the transmit CPBs can be linked in one transmit
+ command.
+
+ All UNDIs support fragmented frames, now all network devices or protocols do. If a fragmented
+ frame CPB is given to UNDI and the network device does not support fragmented frames
+ (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer
+ before transmitting.
+
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Transmit called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ CdbPtr->StatCode = (PXE_STATCODE) e1000_Transmit (GigAdapter, CdbPtr->CPBaddr, CdbPtr->OpFlags);
+
+ CdbPtr->StatCode == PXE_STATCODE_SUCCESS ? (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE) : (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED);
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Receive (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ When the network adapter has received a frame, this command is used to copy the frame
+ into the driver/application storage location. Once a frame has been copied, it is
+ removed from the receive queue.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Receive called while driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ //
+ // Check if RU has started.
+ //
+ if (GigAdapter->ReceiveStarted == FALSE) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;
+ return ;
+ }
+
+ CdbPtr->StatCode = (UINT16) e1000_Receive (GigAdapter, CdbPtr->CPBaddr, CdbPtr->DBaddr);
+
+ CdbPtr->StatCode == PXE_STATCODE_SUCCESS ? (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE) : (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED);
+
+ return ;
+}
+
+
+VOID
+e1000_UNDI_APIEntry (
+ IN UINT64 cdb
+ )
+/*++
+
+Routine Description:
+ This is the main SW UNDI API entry using the newer nii protocol.
+ The parameter passed in is a 64 bit flat model virtual
+ address of the cdb. We then jump into the common routine for both old and
+ new nii protocol entries.
+
+Arguments:
+ cdb - Pointer to the command descriptor block.
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CDB *CdbPtr;
+ GIG_DRIVER_DATA *GigAdapter;
+ UNDI_CALL_TABLE *tab_ptr;
+
+ if (cdb == (UINT64) 0) {
+ return ;
+ }
+
+ CdbPtr = (PXE_CDB *) (UINTN) cdb;
+
+ if (CdbPtr->IFnum > e1000_pxe_31->IFcnt) {
+ DEBUGPRINT(DECODE, ("Invalid IFnum %d\n", CdbPtr->IFnum));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ GigAdapter = &(e1000_UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
+ GigAdapter->VersionFlag = 0x31; // entering from new entry point
+
+ //
+ // Check the OPCODE range.
+ //
+ if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||
+ (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||
+ (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE)
+ ) {
+ DEBUGPRINT(DECODE, ("Invalid StatCode, OpCode, or StatFlags.\n", CdbPtr->IFnum));
+ goto badcdb;
+ }
+
+ if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
+ if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {
+ goto badcdb;
+ }
+ } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {
+ goto badcdb;
+ }
+
+ if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {
+ if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {
+ goto badcdb;
+ }
+ } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {
+ goto badcdb;
+ }
+
+ //
+ // Check if cpbsize and dbsize are as needed.
+ // Check if opflags are as expected.
+ //
+ tab_ptr = &e1000_api_table[CdbPtr->OpCode];
+
+ if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {
+ goto badcdb;
+ }
+
+ if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {
+ goto badcdb;
+ }
+
+ if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {
+ goto badcdb;
+ }
+
+ GigAdapter = &(e1000_UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
+
+ //
+ // Check if UNDI_State is valid for this call.
+ //
+ if (tab_ptr->state != (UINT16) (-1)) {
+ //
+ // Should atleast be started.
+ //
+ if (GigAdapter->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
+ return ;
+ }
+
+ //
+ // Check if it should be initialized.
+ //
+ if (tab_ptr->state == 2) {
+ if (GigAdapter->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ return ;
+ }
+ }
+ }
+
+ //
+ // Set the return variable for success case here.
+ //
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ tab_ptr->api_ptr (CdbPtr, GigAdapter);
+ return ;
+
+badcdb:
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c
new file mode 100755
index 0000000..70531c1
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c
@@ -0,0 +1,666 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+extern EFI_GUID gEfiPro1000ComGuid;
+
+EFI_STATUS
+GigUndiDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+EFI_STATUS
+GigUndiDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+EFI_STATUS
+GigUndiDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+EFI_DRIVER_CONFIGURATION_PROTOCOL gGigUndiDriverConfiguration = {
+ GigUndiDriverConfigurationSetOptions,
+ GigUndiDriverConfigurationOptionsValid,
+ GigUndiDriverConfigurationForceDefaults,
+ "eng"
+};
+
+#define MENU_AUTONEG 0
+#define MENU_100_FULL 1
+#define MENU_100_HALF 2
+#define MENU_10_FULL 3
+#define MENU_10_HALF 4
+#define MENU_SAVE 5
+#define MENU_EXIT 6
+
+CHAR16 *ConfigMenu[] = {
+ L"Set adapter to Autonegotiate (recommended)",
+ L"Set adapter to 100Mbps full duplex",
+ L"Set adapter to 100Mbps half duplex",
+ L"Set adapter to 10Mbps full duplex",
+ L"Set adapter to 10Mbps half duplex",
+ L"Save settings to NVRAM",
+ L"Exit (maintain current settings)",
+ NULL
+};
+
+
+VOID
+GigUndiDriverConfigurationDisplayMenu (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+Routine Description:
+
+ Displays the options for the configuration menu to allow the user to change the speed/duplex settings
+
+Arguments:
+
+ hw - adapter to configure
+
+Returns:
+
+ VOID
+
+--*/
+{
+ UINTN Active;
+ UINT16 Selection;
+ UINT16 i;
+ EFI_INPUT_KEY Key;
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+ UINT16 Word0;
+ CHAR16 *SpeedDuplexString = L"";
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ Selection = 0; // Tracks which menu item is highligted
+ i = 0;
+ Active = 0; // Tracks current speed/duplex setting so '*' can be drawn next to it
+
+ //
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ return;
+ }
+
+ e1000_read_nvm(hw, SetupOffset, 1, &SetupWord);
+
+ //
+ // Save the original setup word value so we can tell if the user changed it
+ //
+ Word0 = SetupWord;
+
+ //
+ // If the boot agent EEPROM signature is not set properly then we will initialize
+ // the words to default values and assume a default autonegotiation setting
+ //
+ e1000_read_nvm(hw, ConfigOffset, 1, &CustomConfigWord);
+
+
+ if ((CustomConfigWord & SIG_MASK) != SIG) {
+ CustomConfigWord = SIG;
+ SetupWord = DISPLAY_SETUP_MESSAGE;
+ } else {
+ //
+ // The signature bits are set so get the speed duplex settings
+ // Mask of the speed and duplex setting bits so that we can determine
+ // what the settings are
+ //
+ switch (SetupWord & (FSP_MASK | FDP_FULL_DUPLEX_BIT))
+ {
+ case (FDP_FULL_DUPLEX_BIT | FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ SpeedDuplexString = L"100Mbps full duplex";
+ Active = MENU_100_FULL;
+ break;
+ case (FDP_FULL_DUPLEX_BIT | FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ SpeedDuplexString = L"10Mbps full duplex";
+ Active = MENU_10_FULL;
+ break;
+ case (FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ SpeedDuplexString = L"100Mbps half duplex";
+ Active = MENU_100_HALF;
+ break;
+ case (FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ SpeedDuplexString = L"10Mbps half duplex";
+ Active = MENU_10_HALF;
+ break;
+ default:
+ hw->mac.autoneg = 1;
+ SpeedDuplexString = L"Autonegotiation";
+ Active = MENU_AUTONEG;
+ }
+ }
+
+ while (1) {
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BACKGROUND_BLACK);
+ gST->ConOut->OutputString (gST->ConOut, L"Configure adapter speed and duplex\n\r");
+
+ gST->ConOut->OutputString (gST->ConOut, L"Current setting: ");
+ gST->ConOut->OutputString (gST->ConOut, SpeedDuplexString);
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n");
+
+ //
+ // Print out the menu items with the current selection highlighted
+ //
+ for (i = 0; ConfigMenu[i] != NULL; i++) {
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n ");
+ if (i == Selection) {
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_BLACK | EFI_BACKGROUND_LIGHTGRAY);
+ }
+
+ //
+ // Draw an asterisk next to the current speed/duplex selection
+ //
+ if (i == Active) {
+ gST->ConOut->OutputString(gST->ConOut, L"*");
+ } else {
+ gST->ConOut->OutputString(gST->ConOut, L" ");
+ }
+
+ gST->ConOut->OutputString (gST->ConOut, ConfigMenu[i]);
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+
+ //
+ // Capture the user input
+ //
+ while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) != EFI_SUCCESS);
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+
+ //
+ // Check to see if user made a change to the speed/duplex settings
+ //
+ switch (Selection)
+ {
+ case MENU_AUTONEG:
+ //
+ // Speed mask has already been cleared
+ //
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FSP_AUTONEG);
+ hw->mac.autoneg = 1;
+ Active = Selection;
+ break;
+ case MENU_100_FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_100MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ Active = Selection;
+ break;
+ case MENU_100_HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_100MBS;
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ Active = Selection;
+ break;
+ case MENU_10_FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_10MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ Active = Selection;
+ break;
+ case MENU_10_HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_10MBS;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ hw->mac.autoneg = 0;
+ Active = Selection;
+ break;
+ default:
+ break;
+ }
+ gBS->Stall(1000000);
+
+ if (Selection == MENU_SAVE) {
+ //
+ // Only write the EEPROM if the speed/duplex value has changed
+ //
+ if (SetupWord != Word0) {
+ gST->ConOut->OutputString (gST->ConOut, L"\n\n\rSaving settings...");
+ gBS->Stall(1000000);
+ if (e1000_write_nvm (hw, ConfigOffset, 1, &CustomConfigWord) != E1000_SUCCESS) {
+ gST->ConOut->OutputString (gST->ConOut, L"EEPROM write error\n\r");
+ } else
+ if (e1000_write_nvm (hw, SetupOffset, 1, &SetupWord) != E1000_SUCCESS) {
+ gST->ConOut->OutputString (gST->ConOut, L"EEPROM write error\n\r");
+ } else {
+ //
+ // Success
+ //
+ e1000_update_nvm_checksum (hw);
+ Word0 = SetupWord;
+ gST->ConOut->OutputString (gST->ConOut, L"done\n\r");
+ }
+ gBS->Stall(1000000);
+ } else {
+ gST->ConOut->OutputString (gST->ConOut, L"\n\n\rSettings have not changed\n");
+ gBS->Stall(1000000);
+ }
+ }
+
+ if (Selection == MENU_EXIT) {
+ if (Word0 != SetupWord) {
+ gST->ConOut->OutputString (gST->ConOut, L"\n\n\n\n\n\n\rChanged settings have not been saved. Do you want to exit anyway? (y/n)");
+ do {
+ while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) != EFI_SUCCESS);
+ if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y' || Key.UnicodeChar == 'n' || Key.UnicodeChar == 'N')
+ break;
+ } while (1);
+ }
+ //
+ // Always exit unless the users selects N
+ //
+ if ((Key.UnicodeChar != 'n') && (Key.UnicodeChar != 'N')) {
+ break;
+ }
+ }
+ }
+
+ if (Key.ScanCode == SCAN_UP) {
+ if (Selection > 0) {
+ Selection--;
+ }
+ } else if (Key.ScanCode == SCAN_DOWN) {
+ if (ConfigMenu[Selection + 1] != NULL) {
+ Selection++;
+ }
+ } else if (Key.ScanCode == SCAN_ESC) {
+ break;
+ }
+ } // end while(1)
+
+
+ return;
+}
+
+EFI_STATUS
+GigUndiDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+/*++
+
+Routine Description:
+
+ Callback function for Driver Configuration protocol. Finds the NII adapter handle for
+ Controller handle and then calls the setup menu
+
+Arguments:
+
+ This - Driver configuration protocol instance
+ ControllerHandle - The network driver controller handle
+ ChildHandle - The NII child handle (not used)
+ Language - Always english
+ ActionRequired - Not used
+
+Returns:
+
+ EFI_UNSUPPORTED - Unable to open the driver configuration protocol for ControllerHandle
+ EFI_SUCCESS - Configuration was successful
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ EFI_STATUS Status;
+
+ UINT8 ReceiveStarted;
+
+ GigUndiPrivateData = NULL;
+ *ActionRequired = EfiDriverConfigurationActionNone;
+
+ if (ControllerHandle == NULL) {
+ DEBUGPRINT (CRITICAL, ("ControllerHandle == NULL\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ DEBUGPRINT (CRITICAL, ("OpenProtocol Status != EFI_ALREADY_STARTED %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (CFG, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("OpenProtocol error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+ //
+ // Speed duplex configuration is not supported on fiber or serdes cards.
+ //
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type != e1000_media_type_copper) {
+ DEBUGPRINT (CRITICAL, ("Phy media type not copper\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Remember receiver state, so we can leave it in the same state as it was before settings were made.
+ //
+ ReceiveStarted = GigUndiPrivateData->NicInfo.ReceiveStarted;
+
+ GigUndiDriverConfigurationDisplayMenu (GigUndiPrivateData);
+
+ //
+ // After speed/duplex setting completes we need to perform a full reset of the adapter.
+ // If the adapter was initialized on entry then force a full reset of the adapter.
+ // Also reenable the receive unit if it was enabled before we started the PHY loopback test.
+ //
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (GigUndiPrivateData->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigUndiPrivateData->NicInfo);
+ DEBUGPRINT(DIAG, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(DIAG, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigUndiPrivateData->NicInfo);
+ }
+ }
+ DEBUGPRINT(DIAG, ("ADAPTER RESET COMPLETE\n"));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GigUndiDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Not implemented
+
+Arguments:
+
+ This - GC_TODO: add argument description
+ ControllerHandle - GC_TODO: add argument description
+ ChildHandle - GC_TODO: add argument description
+
+Returns:
+
+ EFI_UNSUPPORTED - GC_TODO: Add description for return value
+
+--*/
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GigUndiDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+/*++
+
+Routine Description:
+
+ Restores the speed/duplex settings to the autonegotiation default value
+
+Arguments:
+
+ This - Driver configuration protocol instance
+ ControllerHandle - The network driver controller handle
+ ChildHandle - The NII child handle (not used)
+ DefaultType - Not used
+ ActionRequired - Not used
+
+Returns:
+
+ EFI_UNSUPPORTED - Unable to open the driver configuration protocol for ControllerHandle
+ EFI_SUCCESS - Configuration was successful
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ EFI_STATUS Status;
+ struct e1000_hw *hw;
+ UINT16 ConfigOffset;
+ UINT16 SetupOffset;
+ UINT16 CustomConfigWord;
+ UINT16 SetupWord;
+
+ GigUndiPrivateData = NULL;
+ *ActionRequired = EfiDriverConfigurationActionNone;
+
+ if (ControllerHandle == NULL) {
+ DEBUGPRINT (CRITICAL, ("ControllerHandle == NULL\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ DEBUGPRINT (CRITICAL, ("OpenProtocol Status != EFI_ALREADY_STARTED %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (CFG, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("OpenProtocol error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+ //
+ // Speed duplex configuration is not supported on fiber or serdes cards.
+ //
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type != e1000_media_type_copper) {
+ DEBUGPRINT (CRITICAL, ("Phy media type not copper\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ e1000_read_nvm (hw, ConfigOffset, 1, &CustomConfigWord);
+ e1000_read_nvm (hw, SetupOffset, 1, &SetupWord);
+
+ //
+ // If the signature word is not set then we will always assume the default values
+ // so do not change anything. If the signature bits are set then set the adapter
+ // back to autonegotiate
+ //
+ if ((CustomConfigWord & SIG_MASK) == SIG) {
+ //
+ // Only write the setup word if the adapter is not already set to autonegotiate
+ //
+ if ((SetupWord & FSP_MASK) != FSP_AUTONEG) {
+ SetupWord = (UINT16) ((SetupWord & ~FSP_MASK) | FSP_AUTONEG);
+ e1000_write_nvm (hw, SetupOffset, 1, &SetupWord);
+ e1000_update_nvm_checksum (hw);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c
new file mode 100755
index 0000000..1d1b9a3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c
@@ -0,0 +1,1553 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+extern EFI_GUID gEfiPro1000ComGuid;
+
+
+#define MAX_ETHERNET_SIZE 1518
+#define TEST_PACKET_SIZE 1024
+
+#if (DBG_LVL & DIAG)
+#define PHY_LOOPBACK_ITERATIONS 10
+#else
+#define PHY_LOOPBACK_ITERATIONS 10000
+#endif
+
+#define PHY_PHLBKC 19
+#define PHY_PHCTRL1 23
+#define PHY_PHSTAT 26
+
+EFI_STATUS
+GigUndiDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ );
+
+EFI_STATUS
+GigUndiRunPhyLoopback (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ PXE_CPB_TRANSMIT PxeCpbTransmit
+ );
+
+BOOLEAN
+_SetIntegratedM88PhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ );
+
+BOOLEAN
+_SetNinevehPhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ );
+
+BOOLEAN
+_SetIgpPhyLoopback(
+ IN struct e1000_hw *hw,
+ IN UINT16 Speed
+ );
+
+EFI_DRIVER_DIAGNOSTICS_PROTOCOL gGigUndiDriverDiagnostics = {
+ GigUndiDriverDiagnosticsRunDiagnostics,
+ "eng"
+};
+
+EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gGigUndiDriverDiagnostics2 = {
+ (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) GigUndiDriverDiagnosticsRunDiagnostics,
+ "en-US"
+};
+
+
+#define E1000_RCTL_LBM_MASK (0x000000C0) /* bitmask to retrieve LBM bits */
+
+typedef enum {
+ e1000_lbm_none = 0,
+ e1000_lbm_mac,
+ e1000_lbm_phy_1000,
+ e1000_lbm_phy_100,
+ e1000_lbm_phy_10,
+ e1000_lbm_transceiver,
+ e1000_lbm_count,
+ e1000_lbm_invalid = 0xFF
+} e1000_lbm_type;
+
+UINT8 Packet[MAX_ETHERNET_SIZE];
+
+#pragma pack(1)
+typedef struct {
+ UINT8 DestAddr[6];
+ UINT8 SourceAddr[6];
+ UINT8 Length[2];
+} ETHERNET_HDR;
+#pragma pack()
+
+/***************************************************************************
+**
+** Name: _NalGenericReadPhyRegister16Ex()
+**
+** Description: Writes a 16bit value to the Phy. - allows user to
+** set PHY Page
+**
+** Author: GVR
+**
+** Born on Date: 06/01/2005
+**
+** Arguments: Handle = Handle to this adapter.
+** Page = PHY Page # or device #
+** Offset = The register to read from the PHY. This is a
+** numeric offset value.
+** Value = The value read to return.
+**
+** Returns: NAL_STATUS
+**
+****************************************************************************/
+INT32
+_ReadPhyRegister16Ex(
+ IN struct e1000_hw *hw,
+ IN UINT32 Page,
+ IN UINT32 Offset,
+ OUT UINT16* Value
+ )
+{
+ //
+ // See e1000_hw.c and e1000_hw.h for bit field specifications for PHY page register
+ //
+ Page = (Page & 0x07FF) << 5;
+ Offset = ((Offset & 0x1F) | Page);
+
+ return e1000_read_phy_reg(hw, Offset, Value);
+}
+
+/***************************************************************************
+**
+** Name: _NalGenericWritePhyRegister16Ex()
+**
+** Description: Writes a 16bit value to the Phy. - allows user to
+** set PHY Page
+**
+** Author: GVR
+**
+** Born on Date: 06/01/2005
+**
+** Arguments: Handle = Handle to this adapter.
+** Page = PHY Page #
+** Register = The register to write to the PHY. This is a
+** numeric offset value.
+** Data = The value read to write.
+**
+** Returns: NAL_STATUS
+**
+****************************************************************************/
+INT32
+_WritePhyRegister16Ex(
+ IN struct e1000_hw *hw,
+ IN UINT32 Page,
+ IN UINT32 Offset,
+ IN UINT16 Data
+ )
+{
+ /* see sdk/adapters/module0/e1000_hw.c and e1000_hw.h for bit field
+ * specifications for PHY page register */
+ Page = (Page & 0x07FF) << 5;
+ Offset = ((Offset & 0x1F) | Page);
+
+ return e1000_write_phy_reg(hw, Offset, Data);
+}
+
+
+VOID
+_BuildPacket (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ )
+/*++
+
+Routine Description:
+ Build a packet to transmit in the phy loopback test.
+
+Arguments:
+ GigAdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on so that we can
+ get the MAC address
+Returns:
+ Sets the global array Packet[] with the packet to send out during PHY loopback.
+
+--*/
+{
+ ETHERNET_HDR *EthernetHdr;
+ UINT16 Length;
+ UINT16 i;
+
+ EthernetHdr = NULL;
+ Length = 0;
+ i = 0;
+
+ ZeroMem ((char *) Packet, MAX_ETHERNET_SIZE);
+
+ //
+ // First copy the source and destination addresses
+ //
+ EthernetHdr = (ETHERNET_HDR *) Packet;
+ CopyMem ((char *) &EthernetHdr->SourceAddr, (char *) GigAdapterInfo->hw.mac.addr, ETH_ADDR_LEN);
+ CopyMem ((char *) &EthernetHdr->DestAddr, (char *) GigAdapterInfo->BroadcastNodeAddress, ETH_ADDR_LEN);
+
+ //
+ // Calculate the data segment size and store it in the header big Endian style
+ //
+ Length = TEST_PACKET_SIZE - sizeof (ETHERNET_HDR);
+ EthernetHdr->Length[0] = (UINT8) (Length >> 8);
+ EthernetHdr->Length[1] = (UINT8) Length;
+
+ //
+ // Generate Packet data
+ //
+ for (i = 0; i < Length; i++) {
+ Packet[i + sizeof (ETHERNET_HDR)] = (UINT8) i;
+ }
+}
+
+VOID
+_DisplayBuffersAndDescriptors (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ )
+/*++
+
+Routine Description:
+ Display the buffer and descriptors for debuging the PHY loopback test.
+
+Arguments:
+ GigAdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on so that we can
+ get the MAC address
+Returns:
+ Sets the global array Packet[] with the packet to send out during PHY loopback.
+
+--*/
+{
+ E1000_RECEIVE_DESCRIPTOR *ReceiveDesc;
+ E1000_TRANSMIT_DESCRIPTOR *TransmitDesc;
+ UINT32 j;
+
+ DEBUGPRINT (DIAG, ("Receive Descriptor\n"));
+ DEBUGPRINT(DIAG, ("RCTL=%X ", E1000_READ_REG(&GigAdapterInfo->hw, E1000_RCTL)));
+ DEBUGPRINT(DIAG, ("RDH0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_RDH(0))));
+ DEBUGPRINT(DIAG, ("RDT0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_RDT(0))));
+ DEBUGPRINT(DIAG, ("cur_rx_ind=%X\n", GigAdapterInfo->cur_rx_ind));
+
+ ReceiveDesc = GigAdapterInfo->rx_ring;
+ for (j = 0; j < DEFAULT_RX_DESCRIPTORS; j++) {
+ DEBUGPRINT (DIAG, ("Buff=%x,", ReceiveDesc->buffer_addr));
+ DEBUGPRINT (DIAG, ("Len=%x,", ReceiveDesc->length));
+ DEBUGPRINT (DIAG, ("Stat=%x,", ReceiveDesc->status));
+ DEBUGPRINT (DIAG, ("Csum=%x,", ReceiveDesc->csum));
+ DEBUGPRINT (DIAG, ("Special=%x\n", ReceiveDesc->special));
+ ReceiveDesc++;
+ }
+
+ DEBUGWAIT (DIAG);
+ DEBUGPRINT (DIAG, ("Transmit Descriptor\n"));
+ DEBUGPRINT(DIAG, ("TCTL=%X ", E1000_READ_REG(&GigAdapterInfo->hw, E1000_TCTL)));
+ DEBUGPRINT(DIAG, ("TDH0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_TDH(0))));
+ DEBUGPRINT(DIAG, ("TDT0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_TDT(0))));
+ DEBUGPRINT(DIAG, ("cur_tx_ind=%X\n", GigAdapterInfo->cur_tx_ind));
+
+ TransmitDesc = GigAdapterInfo->tx_ring;
+ for (j = 0; j < DEFAULT_TX_DESCRIPTORS; j++) {
+ DEBUGPRINT (DIAG, ("Buff=%x,", TransmitDesc->buffer_addr));
+ DEBUGPRINT (DIAG, ("Cmd=%x,", TransmitDesc->lower.flags.cmd));
+ DEBUGPRINT (DIAG, ("Cso=%x,", TransmitDesc->lower.flags.cso));
+ DEBUGPRINT (DIAG, ("Length=%x,", TransmitDesc->lower.flags.length));
+ DEBUGPRINT (DIAG, ("Status= %x,", TransmitDesc->upper.fields.status));
+ DEBUGPRINT (DIAG, ("Special=%x,", TransmitDesc->upper.fields.special));
+ DEBUGPRINT (DIAG, ("Css=%x\n", TransmitDesc->upper.fields.css));
+ TransmitDesc++;
+ }
+
+ DEBUGWAIT (DIAG);
+}
+
+BOOLEAN
+_SetIntegratedM88PhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ )
+/*++
+ Description: This routine is used by diagnostic software to put
+ the 82544, 82540, 82545, and 82546 MAC based network
+ cards and the M88E1000 PHY into loopback mode.
+
+ Loopback speed is determined by the Speed value
+ passed into this routine.
+
+ Valid values are 1000, 100, and 10 Mbps
+
+ Current procedure is to:
+ 1) Disable auto-MDI/MDIX
+ 2) Perform SW phy reset (bit 15 of PHY_CONTROL)
+ 3) Disable autoneg and reset
+ 4) For the specified speed, set the loopback
+ mode for that speed. Also force the MAC
+ to the correct speed and duplex for the
+ specified operation.
+ 5) If this is an 82543, setup the TX_CLK and
+ TX_CRS again.
+ 6) Disable the receiver so a cable disconnect
+ and reconnect will not cause autoneg to
+ begin.
+
+ Arguments: Adapter - Ptr to this card's adapter data structure
+ Speed - desired loopback speed
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+{
+ UINT32 CtrlReg = 0;
+ UINT32 StatusReg = 0;
+ UINT16 PhyReg = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ hw->mac.autoneg = FALSE;
+
+ /*******************************************************************
+ ** Set up desired loopback speed and duplex depending on input
+ ** into this function.
+ *******************************************************************/
+ switch(Speed)
+ {
+ case SPEED_1000:
+ DEBUGPRINT(DIAG, ("Setting M88E1000 PHY into loopback at 1000 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ if (hw->phy.type == e1000_phy_igp)
+ {
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ }
+ else if (hw->phy.type == e1000_phy_m88)
+ {
+ e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8140); /* autoneg off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ }
+ else if (hw->phy.type == e1000_phy_gg82563)
+ {
+ e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CE); /* Force Link Up */
+ e1000_write_phy_reg(hw, GG82563_REG(0, 0), 0x4140); /* bit 14 = IEEE loopback, force 1000, full duplex */
+ }
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ /* For some SerDes we'll need to commit the writes now so that the
+ * status register is updated on link. */
+ if (hw->phy.media_type == e1000_media_type_internal_serdes)
+ {
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ msec_delay(100);
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ }
+
+ if (hw->phy.media_type == e1000_media_type_copper)
+ {
+ /* For Marvel Phy, inverts Loss-Of-Signal */
+ if (hw->phy.type == e1000_phy_m88)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS); /* Invert Loss-Of-Signal */
+ }
+ }
+ else
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ DEBUGPRINT(DIAG, ("Link seems unstable in PHY Loopback setup\n"));
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_100:
+ DEBUGPRINT(DIAG, ("Setting M88E1000 PHY into loopback at 100 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8140); /* autoneg off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8100); /* reset to update autoneg */
+ e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, 0x0c14); /* MAC interface speed to 100Mbps */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0xe100); /* reset to update MAC interface speed */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x6100); /* force 100, set loopback */
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg =E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */
+ E1000_CTRL_SLU | /* Set the Force Link Bit */
+ E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 | /* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_10:
+ DEBUGPRINT(DIAG, ("Setting M88E1000 PHY into loopback at 10 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8140); /* autoneg off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8100); /* reset to update autoneg */
+ e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, 0x0c04); /* MAC interface speed to 10Mbps */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8100); /* reset to update MAC interface speed */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4100); /* force 10, set loopback */
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_SLU | /* Set the Force Link Bit */
+ E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_10 | /* Force Speed to 10 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ default:
+ DEBUGPRINT(DIAG, ("Invalid speed value loopback mode \"%d\"\n", Speed));
+ LoopbackModeSet = FALSE;
+ break;
+ }
+
+ e1000_read_phy_reg(hw, PHY_CONTROL, &PhyReg);
+ if (hw->phy.type == e1000_phy_m88)
+ {
+
+ /****************************************************************
+ * Disable the receiver on the PHY so when a cable is plugged
+ * in, the PHY does not begin to autoneg when a cable is
+ * reconnected to the NIC.
+ ***************************************************************/
+ e1000_write_phy_reg(hw, 29, 0x001F);
+ e1000_write_phy_reg(hw, 30, 0x8FFC);
+ e1000_write_phy_reg(hw, 29, 0x001A);
+ e1000_write_phy_reg(hw, 30, 0x8FF0);
+
+ /****************************************************************
+ * This delay is necessary with some nics on some machines after
+ * the PHY receiver is disabled.
+ ***************************************************************/
+ usec_delay(500);
+
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &PhyReg);
+ e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &PhyReg);
+ }
+ //
+ // The following delay is necessary for the PHY loopback mode to take on ESB2 based LOMs
+ //
+ msec_delay(100);
+
+ return LoopbackModeSet;
+}
+
+#ifndef NO_82571_SUPPORT
+VOID
+_SetI82571SerdesLoopback(
+ struct e1000_hw *hw
+ )
+/*++
+ Description: This routine is used to set fiber and serdes based 82571
+ and 82575 adapters into loopback mode.
+
+ Arguments: hw - Ptr to this card's adapter data structure
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+
+{
+ UINT32 CtrlReg = 0;
+ UINT32 TxctlReg = 0;
+ UINT32 StatusReg = 0;
+ BOOLEAN LinkUp = FALSE;
+
+ DEBUGPRINT(DIAG, ("Setting PHY loopback on I82571 fiber/serdes.\n"));
+ /* I82571 transceiver loopback */
+ CtrlReg = E1000_READ_REG (hw, E1000_CTRL);
+ CtrlReg |= E1000_CTRL_SLU;
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+
+ /* Disable autoneg by setting bit 31 of TXCW to zero */
+ TxctlReg = E1000_READ_REG (hw, E1000_TXCW);
+ TxctlReg &= ~(1 << 31);
+ E1000_WRITE_REG (hw, E1000_TXCW, TxctlReg);
+
+ /* Read status register link up */
+ StatusReg = E1000_READ_REG (hw, E1000_STATUS);
+ LinkUp = ((StatusReg & E1000_STATUS_LU) == 0) ? FALSE : TRUE;
+
+ /* Set ILOS if link is not up */
+ if(LinkUp == FALSE)
+ {
+ /* Set bit 7 (Invert Loss) and set link up in bit 6. */
+ CtrlReg = E1000_READ_REG (hw, E1000_CTRL);
+ CtrlReg |= (E1000_CTRL_ILOS);
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ }
+
+ /* Write 0x410 to Serdes control register to enable SerDes analog loopback */
+ E1000_WRITE_REG (hw, E1000_SCTL, 0x0410);
+ msec_delay(10);
+}
+#endif
+
+#ifndef NO_82575_SUPPORT
+VOID
+_SetI82575SerdesLoopback(
+ struct e1000_hw *hw
+ )
+/*++
+ Description: This routine is used to set fiber and serdes based 82571
+ and 82575 adapters into loopback mode.
+
+ Arguments: hw - Ptr to this card's adapter data structure
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+
+{
+ UINT32 CtrlReg = 0;
+ UINT32 CtrlExtReg = 0;
+ UINT32 PcsLctl = 0;
+ UINT32 ConnSwReg = 0;
+
+ DEBUGPRINT(DIAG, ("Setting PHY loopback on I82575 fiber/serdes.\n"));
+
+ /* I82575 transceiver loopback per EAS */
+ /* Write 0x410 to Serdes control register to enable SerDes analog loopback */
+ E1000_WRITE_REG (hw, E1000_SCTL, 0x0410);
+ msec_delay(10);
+
+ CtrlExtReg = E1000_READ_REG (hw, E1000_CTRL_EXT);
+ CtrlExtReg |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
+ E1000_WRITE_REG (hw, E1000_CTRL_EXT, CtrlExtReg);
+ msec_delay(10);
+
+ CtrlReg = E1000_READ_REG (hw, E1000_CTRL);
+ CtrlReg |= E1000_CTRL_SLU | E1000_CTRL_FD;
+ CtrlReg &= ~(E1000_CTRL_RFCE | E1000_CTRL_TFCE | E1000_CTRL_LRST);
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ msec_delay(10);
+
+ PcsLctl = E1000_READ_REG(hw, E1000_PCS_LCTL);
+ PcsLctl |= E1000_PCS_LCTL_FORCE_LINK | E1000_PCS_LCTL_FSD
+ | E1000_PCS_LCTL_FDV_FULL| E1000_PCS_LCTL_FLV_LINK_UP;
+ PcsLctl &= ~E1000_PCS_LCTL_AN_ENABLE;
+ E1000_WRITE_REG (hw, E1000_PCS_LCTL, PcsLctl);
+ msec_delay(10);
+
+ /* Read status register link up */
+ ConnSwReg = E1000_READ_REG (hw, E1000_CONNSW);
+ ConnSwReg &= ~E1000_CONNSW_ENRGSRC;
+ E1000_WRITE_REG (hw, E1000_CONNSW, ConnSwReg);
+ msec_delay(10);
+
+}
+#endif
+
+VOID
+_SetI82580SerdesLoopback(
+ struct e1000_hw *hw
+ )
+/*++
+ Description: This routine is used to set fiber and serdes based 82571
+ and 82575 adapters into loopback mode.
+
+ Arguments: hw - Ptr to this card's adapter data structure
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+
+{
+ UINT32 RctlReg = 0;
+ UINT32 CtrlReg = 0;
+ UINT32 PcsLctl = 0;
+ UINT32 ConnSwReg = 0;
+
+ DEBUGPRINT(DIAG, ("Setting PHY loopback on 82580 fiber/serdes.\n"));
+
+ /* Write 0x410 to Serdes control register to enable SerDes analog loopback */
+ E1000_WRITE_REG (hw, E1000_SCTL, 0x0410);
+
+ /* Configure SerDes to loopback */
+ RctlReg = E1000_READ_REG(hw, E1000_RCTL);
+ RctlReg |= E1000_RCTL_LBM_TCVR;
+ E1000_WRITE_REG(hw, E1000_RCTL, RctlReg);
+
+ /* Move to Force mode */
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg |= E1000_CTRL_SLU | E1000_CTRL_FD;
+ CtrlReg &= ~(E1000_CTRL_RFCE | E1000_CTRL_TFCE);
+ E1000_WRITE_REG(hw, E1000_CTRL, CtrlReg);
+
+ PcsLctl = E1000_READ_REG(hw, E1000_PCS_LCTL);
+ PcsLctl |= E1000_PCS_LCTL_FORCE_LINK | E1000_PCS_LCTL_FSD
+ | E1000_PCS_LCTL_FDV_FULL| E1000_PCS_LCTL_FLV_LINK_UP;
+ PcsLctl &= ~E1000_PCS_LCTL_AN_ENABLE;
+ E1000_WRITE_REG(hw, E1000_PCS_LCTL, PcsLctl);
+
+ ConnSwReg = E1000_READ_REG (hw, E1000_CONNSW);
+ ConnSwReg &= ~E1000_CONNSW_ENRGSRC;
+ E1000_WRITE_REG (hw, E1000_CONNSW, ConnSwReg);
+
+ msec_delay(10); // Need this delay or SerDes loopback will fail.
+}
+
+/**********************************************************************
+** Procedure: _NalI8254xSetBoazmanPhyLoopback
+**
+** Description: This routine is used by diagnostic software to put
+** the Intel Gigabit PHY into loopback mode.
+**
+** Loopback speed is determined by the Speed value
+** passed into this routine.
+**
+** Valid values are 1000, 100, and 10 Mbps
+**
+** Author: MVM
+**
+** Born on Date: 04/02/2007
+**
+** Arguments: Adapter - Ptr to this card's adapter data structure
+** Speed - desired loopback speed
+**
+** Returns: TRUE - Success, FALSE - Failure
+**********************************************************************/
+BOOLEAN
+_SetBoazmanPhyLoopback(
+ IN struct e1000_hw* hw,
+ IN UINT16 Speed
+ )
+{
+ UINT16 PhyValue = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+#ifndef NO_82571_SUPPORT
+#ifndef NO_82574_SUPPORT
+ UINT32 Reg = 0;
+ /* 82574 requires ILOS set */
+ if(hw->mac.type == e1000_82574
+ || hw->mac.type == e1000_82583
+ )
+ {
+ DEBUGPRINT(DIAG, ( "Setting ILOS on 82574.\n"));
+ Reg = E1000_READ_REG(hw, E1000_CTRL);
+ E1000_WRITE_REG(hw, E1000_CTRL, Reg | E1000_CTRL_ILOS);
+ }
+#endif
+#endif
+
+ if(Speed == SPEED_1000)
+ {
+ DEBUGPRINT(DIAG, ( "Setting Boazman PHY into loopback at 1000 Mbps\n"));
+ /* set 21_2.2:0 to the relevant speed (1G ?3b110, 100Mb ?3b101, 10Mb ? 3b100) */
+ _ReadPhyRegister16Ex(hw, 2, 21, &PhyValue);
+ PhyValue = (PhyValue & (~(7))) | 6;
+ }
+ else if(Speed == SPEED_100)
+ {
+ DEBUGPRINT(DIAG, ( "Setting Boazman PHY into loopback at 100 Mbps\n"));
+ /* set 21_2.2:0 to the relevant speed (1G ?3b110, 100Mb ?3b101, 10Mb ? 3b100) */
+ _ReadPhyRegister16Ex(hw, 2, 21, &PhyValue);
+ PhyValue = (PhyValue & (~(7))) | 5;
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ( "Setting Boazman PHY into loopback at 10 Mbps\n"));
+ /* set 21_2.2:0 to the relevant speed (1G ?3b110, 100Mb ?3b101, 10Mb ? 3b100) */
+ _ReadPhyRegister16Ex(hw, 2, 21, &PhyValue);
+ PhyValue = (PhyValue & (~(7))) | 4;
+ }
+
+ _WritePhyRegister16Ex(hw, 2, 21, PhyValue);
+
+ /* assert sw reset (so settings will take effect). */
+ e1000_read_phy_reg(hw, PHY_CONTROL, &PhyValue);
+ e1000_write_phy_reg(hw, PHY_CONTROL, PhyValue | (1 << 15));
+ msec_delay(1);
+
+#ifndef NO_82571_SUPPORT
+#ifndef NO_82574_SUPPORT
+ /* ICH9 and ICH10 version requires all these undocumented writes */
+ if (hw->mac.type != e1000_82574
+ || hw->mac.type != e1000_82583
+ )
+ {
+ /* force duplex to FD: 16_769.3:2=3. */
+ _ReadPhyRegister16Ex(hw, 769, 16, &PhyValue);
+ PhyValue |= (3 << 2);
+ _WritePhyRegister16Ex(hw, 769, 16, PhyValue);
+
+ /* set 16_776.6= state (link up when in force link) */
+ _ReadPhyRegister16Ex(hw, 776, 16, &PhyValue);
+ PhyValue |= (1 << 6);
+ _WritePhyRegister16Ex(hw, 776, 16, PhyValue);
+
+ /* set 16_769.6= state (force link) */
+ _ReadPhyRegister16Ex(hw, 769, 16, &PhyValue);
+ PhyValue |= (1 << 6);
+ _WritePhyRegister16Ex(hw, 769, 16, PhyValue);
+
+ /* Set Early Link Enable - 20_769.10 = 1 */
+ _ReadPhyRegister16Ex(hw, 769, 20, &PhyValue);
+ PhyValue |= (1 << 10);
+ _WritePhyRegister16Ex(hw, 769, 20, PhyValue);
+ }
+#endif
+#endif
+
+ LoopbackModeSet = _SetIgpPhyLoopback(hw, Speed);
+
+ return LoopbackModeSet;
+}
+
+
+BOOLEAN
+_SetNinevehPhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ )
+/*++
+ Description: This routine is used by diagnostic software to put
+ the Intel Gigabit PHY into loopback mode.
+
+ Loopback speed is determined by the Speed value
+ passed into this routine.
+
+ Valid values are 1000, 100, and 10 Mbps
+
+ Arguments: Adapter - Ptr to this card's adapter data structure
+ Speed - desired loopback speed
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+{
+ UINT32 StatusReg = 0;
+ UINT32 DelayValue = 10;
+ UINT32 DelayMax = 5000;
+ UINT32 i = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ if(Speed == SPEED_1000)
+ {
+ DEBUGPRINT(DIAG, ("Setting Nineveh PHY into loopback at 1000 Mbps\n"));
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ LoopbackModeSet = TRUE;
+ }
+ else if(Speed == SPEED_100)
+ {
+ DEBUGPRINT(DIAG, ( "Setting Nineveh PHY into loopback at 100 Mbps\n"));
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x6100); /* force 100, set loopback */
+ }
+ else
+ {
+ LoopbackModeSet = _SetIgpPhyLoopback(hw, Speed);
+ }
+
+ /* Poll for link to be stable */
+ for(i = 0; i < DelayMax; i += DelayValue)
+ {
+ msec_delay(DelayValue);
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if(StatusReg & (E1000_STATUS_LU | E1000_STATUS_FD))
+ {
+ DEBUGPRINT(DIAG, ("Nineveh link up indication after %d iterations\n", i));
+ if(Speed == SPEED_1000)
+ {
+ if(StatusReg & E1000_STATUS_SPEED_1000)
+ {
+ DEBUGPRINT(DIAG, ("Nineveh 1gb loopback link detected after %d iterations\n", i));
+ break;
+ }
+ }
+ else if(Speed == SPEED_100)
+ {
+ if(StatusReg & E1000_STATUS_SPEED_100)
+ {
+ DEBUGPRINT(DIAG, ("Nineveh 100mbit loopback link detected after %d iterations\n", i));
+ break;
+ }
+ }
+
+ /* Don't bother reading the status register data for 10mbit. We force this up in
+ * _SetIgpPhyLoopback */
+ else
+ {
+ DEBUGPRINT(DIAG, ("Nineveh 10mbit loopback link detected after %d iterations\n", i));
+ break;
+ }
+ }
+ }
+
+ return LoopbackModeSet;
+}
+
+
+BOOLEAN
+_SetIgpPhyLoopback(
+ IN struct e1000_hw *hw,
+ IN UINT16 Speed
+ )
+/*++
+ Description: This routine is used by diagnostic software to put
+ the Intel Gigabit PHY into loopback mode.
+
+ Loopback speed is determined by the Speed value
+ passed into this routine.
+
+ Valid values are 1000, 100, and 10 Mbps
+
+ Arguments: Adapter - Ptr to this card's adapter data structure
+ Speed - desired loopback speed
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+{
+ UINT32 CtrlReg = 0;
+ UINT32 StatusReg = 0;
+ UINT16 PhyReg = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ hw->mac.autoneg = FALSE;
+
+ /*******************************************************************
+ ** Set up desired loopback speed and duplex depending on input
+ ** into this function.
+ *******************************************************************/
+ switch(Speed)
+ {
+ case SPEED_1000:
+ DEBUGPRINT(DIAG, ("Setting IGP01E1000 PHY into loopback at 1000 Mbps\n"));
+
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ msec_delay(250);
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_100:
+ DEBUGPRINT(DIAG, ("Setting IGP01E1000 PHY into loopback at 100 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x6100); /* force 100, set loopback */
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 | /* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is */
+ /* detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_10:
+ DEBUGPRINT(DIAG, ("Setting IGP01E1000 PHY into loopback at 10 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4100); /* force 10, set loopback */
+ /* For 10mbps loopback we need to assert the "Force link pass" bit in
+ the Port Configuration register */
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &PhyReg);
+ PhyReg |= 0x4000;
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, PhyReg);
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_10 | /* Force Speed to 10 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is */
+ /* detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ default:
+ DEBUGPRINT(DIAG, ("Invalid speed value loopback mode \"%d\"\n", Speed));
+ LoopbackModeSet = FALSE;
+ break;
+ }
+
+ usec_delay(500);
+ return LoopbackModeSet;
+}
+
+BOOLEAN
+_SetPhyLoopback82580 (
+ struct e1000_hw *hw
+ )
+{
+ UINT32 Reg;
+ UINT16 PhyReg = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ DEBUGPRINT(DIAG, ("_SetPhyLoopback82580\n"));
+
+ /* Set Link Mode to Internal */
+ Reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ DEBUGPRINT(DIAG, ("_SetPhyLoopback82580: E1000_CTRL_EXT = 0x%x\n", Reg));
+ Reg = (~E1000_CTRL_EXT_LINK_MODE_MASK) & Reg;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, Reg);
+
+ /* Disable PHY power management in case the cable is unplugged and the PHY is asleep */
+ DEBUGPRINT(DIAG, ("PHPM = %08x\n", E1000_READ_REG(hw, 0x0E14)));
+ Reg = E1000_READ_REG(hw, 0x0E14);
+ Reg &= ~0x0005; /* SPD_EN and LPLU */
+ E1000_WRITE_REG(hw, 0x0E14, Reg);
+
+ /* Set 1000 Mbps loopback mode in PHY */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140);
+
+ /* Set 1000 Mbps mode in MAC */
+ Reg = E1000_READ_REG(hw, E1000_CTRL);
+ Reg &= ~E1000_CTRL_SPD_SEL; // Clear the Speed selection bits
+ Reg |= (E1000_CTRL_FRCSPD | // Set the Force Speed Bit
+ E1000_CTRL_FRCDPX | // Set the Force Duplex Bit
+ E1000_CTRL_SPD_1000 | // Force Speed to 1000
+ E1000_CTRL_FD); // Force Duplex to FULL
+ E1000_WRITE_REG (hw, E1000_CTRL, Reg);
+
+
+ /* Enable PHY loopback mode */
+ e1000_read_phy_reg(hw, PHY_PHLBKC, &PhyReg);
+ DEBUGPRINT(DIAG, ("PHY_PHLBKC = %04x\n", PhyReg));
+ PhyReg = 0x8001; /* MII and Force Link Status */
+ e1000_write_phy_reg(hw, PHY_PHLBKC, PhyReg);
+
+ e1000_read_phy_reg(hw, PHY_PHCTRL1, &PhyReg);
+ DEBUGPRINT(DIAG, ("PHY_PHCTRL1 = %04x\n", PhyReg));
+ PhyReg |= 0x2000; /* LNK_EN */
+ e1000_write_phy_reg(hw, PHY_PHCTRL1, PhyReg);
+
+ msec_delay(500);
+
+ LoopbackModeSet = TRUE;
+ return LoopbackModeSet;
+}
+
+BOOLEAN
+e1000_set_phy_loopback (
+ struct e1000_hw *hw,
+ UINT16 speed
+ )
+/*++
+
+Routine Description:
+
+ Set the PHY into loopback mode. This routine integrates any errata workarounds that might exist.
+
+Arguments:
+
+ hw - Pointer to the shared code adapter structure
+ speed - Select speed to perform loopback test
+
+Returns:
+ True if PHY has been configured for loopback mode
+ False otherwise
+
+--*/
+{
+ BOOLEANean_t status;
+
+ DEBUGPRINT(DIAG, ("e1000_set_phy_loopback\n"));
+
+ switch (hw->mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82573:
+ DEBUGPRINT(DIAG, ("Enabling M88E1000 loopback mode.\n"));
+ status = _SetIntegratedM88PhyLoopback (hw, speed);
+ break;
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+ DEBUGPRINT(DIAG, ("Enabling M88E1000 loopback mode.\n"));
+ status = _SetIntegratedM88PhyLoopback (hw, speed);
+ break;
+#endif
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ case e1000_82572:
+ /* I82571 sets a special loopback mode through the SERDES register. This is only for Fiber
+ * adapters and is used because MAC and PHY loopback are broken on these adapters */
+ if(hw->phy.media_type != e1000_media_type_copper)
+ {
+ _SetI82571SerdesLoopback(hw);
+ status = TRUE;
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ("I82571: Enabling IGP01E100 loopback mode.\n"));
+ status = _SetIgpPhyLoopback (hw, speed);
+ }
+ break;
+#endif
+
+#ifndef NO_82571_SUPPORT
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ DEBUGPRINT(DIAG, ("Enabling Boazman for 82574, 82583 loopback mode.\n"));
+ status = _SetBoazmanPhyLoopback(hw, speed);
+ break;
+#endif
+#endif
+
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich9lan:
+ DEBUGPRINT(DIAG, ("Enabling Boazman for ICH9 loopback mode.\n"));
+ status = _SetBoazmanPhyLoopback(hw, speed);
+ break;
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ DEBUGPRINT(DIAG, ("Enabling Hanksville for PCH loopback mode.\n"));
+ status = _SetBoazmanPhyLoopback(hw, speed);
+ break;
+#endif
+
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+ if(hw->phy.media_type != e1000_media_type_copper)
+ {
+ _SetI82575SerdesLoopback(hw);
+ status = TRUE;
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ("Enabling 82575, 82576 loopback\n"));
+ status = _SetNinevehPhyLoopback (hw, speed);
+ }
+ break;
+#endif
+#ifndef NO_82576_SUPPORT
+ case e1000_82576:
+#endif
+ case e1000_82580:
+ if(hw->phy.media_type == e1000_media_type_copper && hw->dev_spec._82575.sgmii_active == FALSE)
+ {
+ DEBUGPRINT(DIAG, ("Enabling 82580 loopback for copper\n"));
+ status = _SetPhyLoopback82580(hw);
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ("Enabling 82580 loopback for SerDes/SGMII/1000BASE-KX\n"));
+ _SetI82580SerdesLoopback(hw);
+ status = TRUE;
+ }
+ break;
+
+ default:
+ DEBUGPRINT(DIAG, ("Unknown MAC type.\n"));
+ DEBUGWAIT(DIAG);
+ status = FALSE;
+ break;
+ }
+
+
+ return status;
+}
+
+EFI_STATUS
+GigUndiRunPhyLoopback (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ PXE_CPB_TRANSMIT PxeCpbTransmit
+ )
+/*++
+
+Routine Description:
+ Run the PHY loopback test for N iterations. This routine transmits a packet, waits a bit, and then
+ checks to see if it was received. If any of the packets are not received then it will be interpreted as
+ a failure.
+
+Arguments:
+ GigAdapterInfo - Pointer to the NIC data structure the PHY loopback test will be run on.
+ PxeCpbTransmit - Pointer to the packet to transmit.
+
+Returns:
+ EFI_SUCCESS - All packets were received successfully
+ other - An error occured.
+
+--*/
+{
+ PXE_CPB_RECEIVE CpbReceive;
+ PXE_DB_RECEIVE DbReceive;
+ EFI_STATUS Status;
+ UINT64 FreeTxBuffer[DEFAULT_TX_DESCRIPTORS];
+ UINT32 j;
+ UINT32 i;
+
+ Status = EFI_SUCCESS;
+ j = 0;
+
+ while (j < PHY_LOOPBACK_ITERATIONS) {
+ Status = e1000_Transmit (
+ GigAdapterInfo,
+ (UINT64) &PxeCpbTransmit,
+ PXE_OPFLAGS_TRANSMIT_WHOLE
+ );
+ _DisplayBuffersAndDescriptors (GigAdapterInfo);
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("e1000_Transmit error Status %X. Iteration=%d\n", Status, j));
+ DEBUGWAIT (CRITICAL);
+ break;
+ }
+
+ //
+ // Wait a little, then check to see if the packet has arrived
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ RX_BUFFER_SIZE,
+ (VOID **) &CpbReceive.BufferAddr
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("AllocatePool error Status %X. Iteration=%d\n", Status, j));
+ DEBUGWAIT (CRITICAL);
+ break;
+ }
+
+ CpbReceive.BufferLen = RX_BUFFER_SIZE;
+ i = 0;
+ do {
+ Status = e1000_Receive (
+ GigAdapterInfo,
+ (UINT64) &CpbReceive,
+ (UINT64) &DbReceive
+ );
+ gBS->Stall (10);
+ i++;
+ if (i > 100000) {
+ DEBUGPRINT(CRITICAL, ("ERROR: No receive data timeout! Iteration=%d\n", i));
+ break;
+ }
+ } while (Status == PXE_STATCODE_NO_DATA);
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("e1000_Receive Status %X\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ if (CompareMem ((VOID *) (UINTN) CpbReceive.BufferAddr, (VOID *) (UINTN) Packet, TEST_PACKET_SIZE) == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUGPRINT (CRITICAL, ("PHY LOOPBACK FAILED, Corrupt Packet Data!\n"));
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ e1000_FreeTxBuffers (
+ GigAdapterInfo,
+ DEFAULT_TX_DESCRIPTORS,
+ FreeTxBuffer
+ );
+
+ j++;
+ gBS->FreePool ((VOID *) ((UINTN) CpbReceive.BufferAddr));
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+GigUndiPhyLoopback (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Sets up the adapter to run the Phy loopback test and then calls
+ the loop which will iterate through the test.
+
+ Arguments: GigUndiPrivateData - Pointer to adapter data.
+
+ Returns:
+ EFI_SUCCESS - The Phy loopback test passed.
+ EFI_DEVICE_ERROR - Phy loopback test failed
+ EFI_INVALID_PARAMETER - Some other error occured.
+--*/
+{
+ PXE_CPB_TRANSMIT PxeCpbTransmit;
+ UINT8 ReceiveStarted;
+ EFI_STATUS Status;
+
+ ReceiveStarted = GigUndiPrivateData->NicInfo.ReceiveStarted;
+ GigUndiPrivateData->NicInfo.DriverBusy = TRUE;
+
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.Block %X\n", (UINTN) GigUndiPrivateData->NicInfo.Block));
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.MapMem %X\n", (UINTN) GigUndiPrivateData->NicInfo.MapMem));
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.Delay %X\n", (UINTN) GigUndiPrivateData->NicInfo.Delay));
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.MemIo %X\n", (UINTN) GigUndiPrivateData->NicInfo.MemIo));
+ DEBUGWAIT (DIAG);
+
+ //
+ // Initialize and start the UNDI driver if it has not already been done
+ //
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (e1000_Inititialize (&GigUndiPrivateData->NicInfo) != PXE_STATCODE_SUCCESS) {
+ DEBUGPRINT (CRITICAL, ("Error initializing adapter!\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto error;
+ }
+
+ //
+ // Put the PHY into loopback mode,
+ //
+ if (e1000_set_phy_loopback (&GigUndiPrivateData->NicInfo.hw, SPEED_1000)) {
+ DEBUGPRINT (DIAG, ("PHY loopback mode set successful\n"));
+ } else {
+ DEBUGPRINT (CRITICAL, ("ERROR: PHY loopback not set!\n"));
+ DEBUGWAIT (CRITICAL);
+ Status = EFI_UNSUPPORTED;
+ goto error;
+ }
+
+ DEBUGWAIT (DIAG);
+
+ //
+ // Enable the receive unit
+ //
+ e1000_ReceiveEnable (&GigUndiPrivateData->NicInfo);
+
+ //
+ // Build our packet, and send it out the door.
+ //
+ DEBUGPRINT (DIAG, ("Building Packet\n"));
+ _BuildPacket (&GigUndiPrivateData->NicInfo);
+
+ PxeCpbTransmit.MediaheaderLen = sizeof (ETHERNET_HDR);
+ PxeCpbTransmit.DataLen = TEST_PACKET_SIZE - sizeof (ETHERNET_HDR);
+ PxeCpbTransmit.FrameAddr = (UINTN) Packet;
+ PxeCpbTransmit.reserved = 0;
+ DEBUGPRINT (DIAG, ("Packet length = %d\n", PxeCpbTransmit.DataLen));
+ DEBUGPRINT (DIAG, ("Packet = %X FrameAddr = %X\n", (UINTN) Packet, PxeCpbTransmit.FrameAddr));
+ DEBUGPRINT (DIAG, ("Packet data:\n"));
+// for (i = 0; i < PxeCpbTransmit.DataLen; i++) {
+// DEBUGPRINT (DIAG, ("%d: %x ", i, ((UINT8 *) ((UINTN) PxeCpbTransmit.FrameAddr))[i]));
+// }
+
+ DEBUGWAIT (DIAG);
+
+ Status = GigUndiRunPhyLoopback (&GigUndiPrivateData->NicInfo, PxeCpbTransmit);
+ DEBUGPRINT (DIAG, ("PHY Loopback test returns %r\n", Status));
+
+ e1000_ReceiveDisable(&GigUndiPrivateData->NicInfo);
+
+ DEBUGWAIT (DIAG);
+
+error:
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("Error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ //
+ // After PHY loopback test completes we need to perform a full reset of the adapter.
+ // If the adapter was initialized on entry then force a full reset of the adapter.
+ // Also reenable the receive unit if it was enabled before we started the PHY loopback test.
+ //
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (GigUndiPrivateData->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigUndiPrivateData->NicInfo);
+ DEBUGPRINT(DIAG, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(DIAG, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigUndiPrivateData->NicInfo);
+ }
+ }
+ DEBUGPRINT(DIAG, ("ADAPTER RESET COMPLETE\n"));
+
+ GigUndiPrivateData->NicInfo.DriverBusy = FALSE;
+
+ return Status;
+}
+
+EFI_STATUS
+GigUndiDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ )
+/*++
+
+ Routine Description:
+ Runs diagnostics on a controller.
+
+ Arguments:
+ This - A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL instance.
+ ControllerHandle - The handle of the controller to run diagnostics on.
+ ChildHandle - The handle of the child controller to run diagnostics on
+ This is an optional parameter that may be NULL. It will
+ be NULL for device drivers. It will also be NULL for a
+ bus drivers that wish to run diagnostics on the bus
+ controller. It will not be NULL for a bus driver that
+ wishes to run diagnostics on one of its child controllers.
+ DiagnosticType - Indicates type of diagnostics to perform on the controller
+ specified by ControllerHandle and ChildHandle. See
+ "Related Definitions" for the list of supported types.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language in which the optional
+ error message should be returned in Buffer, and it must
+ match one of the languages specified in SupportedLanguages.
+ The number of languages supported by a driver is up to
+ the driver writer.
+ ErrorType - A GUID that defines the format of the data returned in
+ Buffer.
+ BufferSize - The size, in bytes, of the data returned in Buffer.
+ Buffer - A buffer that contains a Null-terminated Unicode string
+ plus some additional data whose format is defined by
+ ErrorType. Buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility
+ to free it with a call to FreePool().
+
+ Returns:
+ EFI_SUCCESS - The controller specified by ControllerHandle and
+ ChildHandle passed the diagnostic.
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - ErrorType is NULL.
+ EFI_INVALID_PARAMETER - BufferType is NULL.
+ EFI_INVALID_PARAMETER - Buffer is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support
+ running diagnostics for the controller specified
+ by ControllerHandle and ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ type of diagnostic specified by DiagnosticType.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+ EFI_OUT_OF_RESOURCES - There are not enough resources available to complete
+ the diagnostics.
+ EFI_OUT_OF_RESOURCES - There are not enough resources available to return
+ the status information in ErrorType, BufferSize,
+ and Buffer.
+ EFI_DEVICE_ERROR - The controller specified by ControllerHandle and
+ ChildHandle did not pass the diagnostic.
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ GigUndiPrivateData = NULL;
+
+ if (DiagnosticType == EfiDriverDiagnosticTypeManufacturing) {
+ DEBUGPRINT (CRITICAL, ("DiagnosticType == EfiDriverDiagnosticTypeManufacturing\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ DEBUGPRINT (DIAG, (" OpenProtocol Status = %8X\n", Status));
+
+ if (Status != EFI_ALREADY_STARTED) {
+ DEBUGPRINT (CRITICAL, ("EFI_ALREADY_STARTED\n"));
+ DEBUGWAIT (CRITICAL);
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (DIAG, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("OpenProtocol error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+
+ switch (DiagnosticType) {
+ case EfiDriverDiagnosticTypeStandard:
+ if (e1000_validate_nvm_checksum(&GigUndiPrivateData->NicInfo.hw) == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUGPRINT (CRITICAL, ("e1000_validate_nvm_checksum error!\n"));
+ DEBUGWAIT (CRITICAL);
+ Status = EFI_DEVICE_ERROR;
+ }
+ break;
+ case EfiDriverDiagnosticTypeExtended:
+ Status = GigUndiPhyLoopback(GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("GigUndiPhyLoopback error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+ break;
+ default:
+ DEBUGPRINT (CRITICAL, ("DiagnosticType unsupported!\n"));
+ DEBUGWAIT (CRITICAL);
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c
new file mode 100755
index 0000000..a22b183
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c
@@ -0,0 +1,1126 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "FirmwareManagement.h"
+
+EFI_STATUS
+GetImageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ );
+
+EFI_STATUS
+FrmGetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ );
+
+EFI_STATUS
+SetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ );
+
+EFI_STATUS
+CheckImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ );
+
+EFI_STATUS
+GetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ );
+
+EFI_STATUS
+SetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ );
+
+EFI_GUID gEfiFirmwareManagementProtocolGuid = EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
+
+#define HAF_ROM_PCI_DATA_STRUCT_SIG "PCIR"
+
+#pragma pack(1)
+typedef struct {
+ UINT8 PciSignature[4]; /* PCIR */
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 VpdOffset; /* Pointer to optional Vital Product Data */
+ UINT16 DataStructLength;
+ UINT8 DataStructRev;
+ UINT8 ClassCode[3];
+ UINT16 ImageLength;
+ UINT16 CodeRevision;
+ UINT8 CodeType;
+ UINT8 IndicatorByte;
+ UINT16 Reserved;
+} PCI_ROM_STRUCTURE;
+
+#pragma pack(1)
+typedef struct {
+ UINT16 Signature; /* 0xAA55 */
+ UINT16 InitializationSize; /* Overall Size of Image */
+ UINT32 EfiSignature; /* EF1 */
+ UINT16 EfiSubsystem;
+ UINT16 EfiMachineType;
+ UINT16 CompressionType;
+ UINT8 Reserved[8];
+ UINT16 ImageHeaderOffset;
+ UINT16 PciOffset; /* Pointer to the PCI ROM Data Structure */
+ UINT8 Padding[2];
+} EFI_ROM_HEADER;
+
+#pragma pack(1)
+typedef struct _CLP_ROM_HEADER
+{
+ UINT16 Signature;
+ UINT8 InitializationSize;
+ UINT8 Entry[4];
+ UINT8 Checksum;
+ UINT8 RomSignature[4];
+ UINT8 LomBit;
+ UINT8 reserved1;
+ UINT32 pxe_offset;
+ UINT8 pxe_size;
+ UINT32 iscsi_offset;
+ UINT8 iscsi_size;
+ UINT16 PciDsOffset;
+ UINT16 PnpOffset;
+ UINT16 reserved2;
+ UINT16 VersionOffset;
+} CLP_ROM_HEADER;
+
+#pragma pack(1)
+typedef struct _PXE_ROM_HEADER
+{
+ UINT16 Signature;
+ UINT8 InitializationSize;
+ UINT8 Entry[4];
+ UINT8 Checksum;
+ UINT16 VendorOffset;
+ UINT8 reserved[12];
+ UINT16 RomIdOffset;
+ UINT16 PciDsOffset;
+ UINT16 PnpOffset;
+ UINT16 RplOffset;
+ UINT16 VersionOffset;
+} PXE_ROM_HEADER;
+
+#pragma pack(1)
+typedef struct _FLB_HEADER
+{
+ UINT32 FlbTag;
+ UINT8 Length;
+ UINT8 Checksum;
+ UINT32 ImageSize;
+ UINT16 PciVendor;
+ UINT16 PciDevice[16];
+ UINT8 FileName[14];
+ UINT8 MajVersion;
+ UINT8 MinVersion;
+ UINT8 BldNumber;
+ UINT8 ImageType;
+} FLB_HEADER;
+
+#pragma pack(1)
+typedef struct _PNP_ROM_HEADER
+{
+ UINT8 PnpSignature[4];
+ UINT8 StructRev;
+ UINT8 StructLength;
+ UINT16 NextStruct;
+ UINT8 reserved1;
+ UINT8 StructCksum;
+ UINT32 DeviceID;
+ UINT16 MFGString;
+ UINT16 ProdString;
+ UINT8 BaseClass;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 DevInd;
+ UINT16 BC;
+ UINT16 DV;
+ UINT16 BEV;
+ UINT8 reserved2[2];
+ UINT16 SRIV;
+} PNP_ROM_HEADER;
+#pragma pack()
+
+
+#pragma pack()
+
+#define FLB_TAG 0x21424C46
+#define CLP_SIG "$CLP"
+#define PXE_ROM_SIG "!PXE"
+#define UNDI_ROMID_SIG "UNDI"
+#define EFI_ROM_SIG 0x0EF1
+#define PCI_DATA_STRUCT_SIG "PCIR"
+
+
+#define PCI_ROM_BLOCK_SIZE 512
+#define PCI_ROM_LAST_INDICATOR 0x80
+
+
+//
+// Macro to return the offset of a member within a struct. This
+// looks like it dereferences a null pointer, but it doesn't really.
+//
+#define STRUCT_OFFSET(Structure,Member) ((UINTN)&(((Structure *)0)->Member))
+
+
+
+EFI_STATUS
+GetImageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ )
+/*++
+
+ Routine Description:
+ Returns information about the current firmware image(s) of the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageInfoSize - A pointer to the size, in bytes, of the ImageInfo buffer.
+ ImageInfo - A pointer to the buffer in which firmware places the current image(s) information.
+ DescriptorVersion - A pointer to the location in which firmware returns the version number
+ associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ DescriptorCount - A pointer to the location in which firmware returns the number of descriptors or
+ firmware images within this device.
+ DescriptorSize - A pointer to the location in which firmware returns the size, in bytes,
+ of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+ Returns:
+ EFI Status code.
+
+--*/
+
+{
+ DEBUGPRINT (IMAGE, ("GetImageInfo\n"));
+
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+FrmGetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ )
+/*++
+
+ Routine Description:
+ Retrieves a copy of the firmware image from the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageIndex - A unique number identifying the firmware image(s) within the device.
+ Image - Points to the buffer where the current image is copied to.
+ ImageSize - On entry, points to the size of the buffer pointed to by
+ Image, in bytes. On return, points to the length of the image, in bytes.
+
+ Returns:
+ EFI Status code.
+
+--*/
+{
+ DEBUGPRINT (IMAGE, ("FrmGetImage\n"));
+
+ return EFI_UNSUPPORTED;
+}
+
+BOOLEAN
+_VerifyImageSize (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINTN ImageSize
+ )
+/*++
+
+ Routine Description:
+ Verifies image will fit in device flash.
+
+ Arguments:
+ GigUndiPrivateData - Pointer to adapter structure
+ ImageSize - Size of image to flash to adapter
+
+ Returns:
+ TRUE - image will fit on flash
+ FALSE - Image is too big
+
+--*/
+{
+ UINT16 Word;
+ UINTN FlashSize;
+
+ e1000_read_nvm (&GigUndiPrivateData->NicInfo.hw, INIT_CONTROL_WORD_2, 1, &Word);
+ DEBUGPRINT (IMAGE, ("INIT_CONTROL_WORD_2 %x\n", Word));
+
+ //
+ // Calculate flash size in bytes
+ //
+ FlashSize = (Word & FLASH_SIZE_MASK) >> FLASH_SIZE_SHIFT;
+ DEBUGPRINT (IMAGE, ("FlashSize bitmask = %x\n", FlashSize));
+ FlashSize = (64 * 1024) << FlashSize;
+ DEBUGPRINT (IMAGE, ("Usable FlashSize in bytes %d\n", FlashSize));
+
+ if (FlashSize < ImageSize) {
+ DEBUGPRINT (CRITICAL, ("ERROR: Flash size too small. ImageSize=%d > FlashSize=%d\n", ImageSize, FlashSize));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOLEAN
+_CheckFlashImageSupport (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINT8 *Image,
+ IN UINTN ImageSize,
+ OUT UINT8 **ImageToProgram,
+ OUT UINTN *SizeToProgram
+ )
+/*++
+
+ Routine Description:
+ Checks that the FLB image has support for this device ID, and makes sure the
+ image type is the same as what is currently programmed on the adapter.
+
+ Arguments:
+ GigUndiPrivateData - Pointer to adapter structure
+ Image - Pointer to the image to program
+ ImageSize - Size of image to flash to adapter
+ ImageToProgram - Returned pointer to the image to program to the flash
+ SizeToProgram - Size of the image contained in the FLB to program
+
+ Returns:
+ TRUE - Image is compatible with device
+ FALSE - Image is not compatible
+
+--*/
+{
+ EFI_ROM_HEADER *EfiRomHeader;
+ CLP_ROM_HEADER *ClpRomHeader;
+ FLB_HEADER *FlbHeader;
+ PXE_ROM_HEADER *PxeRomHeader;
+ PCI_ROM_STRUCTURE *PciRomStructure;
+ UINTN i;
+ UINTN Offset;
+ UINT16 ImageType;
+ UINT16 EepromCapabilities;
+
+ Offset = 0;
+ ImageType = 0;
+
+ do {
+ //
+ // Check the FLB header to make sure this it supports this device
+ //
+ FlbHeader = (FLB_HEADER*) &Image[Offset];
+ if (FlbHeader->FlbTag != FLB_TAG) {
+ DEBUGPRINT (CRITICAL, ("ERROR: Invalid FLB tag.\n"));
+ return FALSE;
+ }
+
+
+ DEBUGPRINT (IMAGE, ("FLB Device ID list: "));
+ for (i = 0; i < 16; i++) {
+ DEBUGPRINT (IMAGE, ("%04x ", FlbHeader->PciDevice[i]));
+ if (FlbHeader->PciDevice[i] == GigUndiPrivateData->NicInfo.hw.device_id) {
+ DEBUGPRINT (IMAGE, ("\nFound FLB device ID match: %04x\n", FlbHeader->PciDevice[i]));
+ goto ImageFound;
+ }
+ }
+
+ if (i == 16) {
+ DEBUGPRINT (CRITICAL, ("\nERROR: FLB does not support device\n"));
+ }
+
+ //
+ // Check for concatenated FLB image
+ //
+ Offset += FlbHeader->ImageSize + sizeof (FLB_HEADER);
+ DEBUGPRINT (IMAGE, ("Checking for next FLB header. Curent FLB image size: %d\n", FlbHeader->ImageSize));
+ if ((Offset + sizeof (FLB_HEADER)) >= ImageSize) {
+ DEBUGPRINT (IMAGE, ("No concatenated FLB header, bailing.\n"));
+ return FALSE;
+ }
+ }while (1);
+
+ImageFound:
+ Offset += sizeof(FLB_HEADER);
+ *ImageToProgram = &Image[Offset];
+ *SizeToProgram = FlbHeader->ImageSize;
+
+ do {
+
+ //
+ // Check if this is a SMCLP header
+ //
+ ClpRomHeader = (CLP_ROM_HEADER*) &Image[Offset];
+ DEBUGPRINT (IMAGE, ("Offset = %d\n", Offset));
+
+ if (ClpRomHeader->Signature != 0xAA55) {
+ DEBUGPRINT (CRITICAL, ("Invalid PCI option ROM signature: %04x\n", ClpRomHeader->Signature));
+ return FALSE;
+ }
+
+ if (CompareMem(ClpRomHeader->RomSignature, CLP_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found CLP header\n"));
+ ImageType |= EEPROM_SMCLP_BIT;
+
+ if (ClpRomHeader->pxe_offset != 0) {
+ DEBUGPRINT(IMAGE, ("Found PXE image\n"));
+ ImageType |= EEPROM_PXE_BIT;
+ }
+
+ if (ClpRomHeader->iscsi_offset != 0) {
+ DEBUGPRINT(IMAGE, ("Found iSCSI image"));
+ ImageType |= EEPROM_ISCSI_BIT;
+ }
+ }
+
+ //
+ // Check if this is a PXE header
+ //
+ PxeRomHeader = (PXE_ROM_HEADER*) &Image[Offset];
+ if (CompareMem((VOID*) &Image[Offset + PxeRomHeader->RomIdOffset], UNDI_ROMID_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found PXE header\n"));
+ ImageType |= EEPROM_PXE_BIT;
+ }
+
+ //
+ // Check if this is a EFI header
+ //
+ EfiRomHeader = (EFI_ROM_HEADER*) &Image[Offset];
+ if (EfiRomHeader->EfiSignature == EFI_ROM_SIG) {
+ DEBUGPRINT(IMAGE, ("Found EFI image\n"));
+ ImageType |= EEPROM_EFI_BIT;
+ }
+
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &Image[Offset + EfiRomHeader->PciOffset];
+ if (CompareMem(PciRomStructure->PciSignature, PCI_DATA_STRUCT_SIG, 4) != 0) {
+ DEBUGPRINT(CRITICAL, ("Invalid PCI ROM Structure.\n"));
+ return FALSE;
+ }
+
+ if ((PciRomStructure->IndicatorByte & PCI_ROM_LAST_INDICATOR) == PCI_ROM_LAST_INDICATOR) {
+ DEBUGPRINT(IMAGE, ("PCI last image indicator byte set.\n"));
+ break;
+ }
+
+ Offset += (PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE);
+ } while (1);
+
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, EEPROM_CAPABILITIES_WORD, 1, &EepromCapabilities);
+ DEBUGPRINT(IMAGE, ("EepromCapabilities = %04x, ImageType = %04x\n", EepromCapabilities, ImageType));
+ if ((ImageType & EEPROM_TYPE_MASK) == (EepromCapabilities & EEPROM_TYPE_MASK)) {
+ DEBUGPRINT(IMAGE, ("Imagetypes match!\n"));
+ return TRUE;
+ }
+ DEBUGPRINT(CRITICAL, ("FLB image type different from image programmed to card!\n"));
+ return FALSE;
+}
+
+VOID
+_UpdateFlashFwChecksumRom(
+ IN UINT8* Buffer,
+ IN UINT32 Len,
+ IN UINT32 Offset
+ )
+/*++
+
+ Routine Description:
+ Calculates a checksum for a image
+
+ Arguments:
+ Buffer - image to checksum
+ Len - length of image
+ Offset - location to put the checksum
+
+ Returns:
+ VOID
+
+--*/
+{
+ UINT8 *MyBuffer;
+ UINT16 Sum = 0;
+ UINT32 Count = 0;
+
+ if (Buffer == NULL)
+ {
+ return;
+ }
+
+ MyBuffer = (UINT8*) Buffer;
+
+ //
+ // first, clear anything in the checksum field
+ //
+ MyBuffer[Offset] = 0;
+
+ //
+ // add it up
+ //
+ for (Count = 0; Count < Len; Count++)
+ {
+ Sum += MyBuffer[Count];
+ }
+
+ //
+ // stuff it in
+ //
+ MyBuffer[Offset] = 0 - (UINT8)(Sum & 0xFF);
+}
+
+
+VOID
+_UpdateFlashFwChecksumPnP(
+ IN UINT8* Buffer
+ )
+/*++
+
+ Routine Description:
+ Updates the checksum and PNP header of the image
+
+ Arguments:
+ Buffer - Pointer to the option ROM image to update
+
+ Returns:
+ VOID
+
+--*/
+{
+ PXE_ROM_HEADER* RomHeader;
+ PNP_ROM_HEADER* PnpHeader;
+
+ if (Buffer == NULL)
+ {
+ return;
+ }
+
+ //
+ // The PXE ROM header and CLP ROM header both have the PnPOffset member
+ //
+ RomHeader = (PXE_ROM_HEADER *)Buffer;
+ if (RomHeader->PnpOffset)
+ {
+ DEBUGPRINT (IMAGE, ("Updating PNP checksum\n"));
+ PnpHeader = (PNP_ROM_HEADER *)&Buffer[RomHeader->PnpOffset];
+ _UpdateFlashFwChecksumRom(
+ (UINT8 *)PnpHeader,
+ PnpHeader->StructLength * 16,
+ STRUCT_OFFSET(PNP_ROM_HEADER, StructCksum)
+ );
+ }
+}
+
+BOOLEAN
+_UpdateChecksumAndId(
+ IN OUT UINT8 *ImageBuffer,
+ IN UINTN SizeToProgram,
+ IN UINT16 DeviceId
+ )
+/*++
+
+ Routine Description:
+ Updates the checksum and device ID of the image.
+
+ Arguments:
+ ImageBuffer - Pointer to the option ROM image to update
+ SizeToProgram - Size of image pointed to by ImageBuffer
+ DeviceId - PCI device ID to set in the PCI ROM header
+
+ Returns:
+ TRUE if successful, FALSE if image is invalid
+
+--*/
+{
+ EFI_ROM_HEADER *EfiRomHeader;
+ CLP_ROM_HEADER *ClpRomHeader;
+ PXE_ROM_HEADER *PxeRomHeader;
+ PCI_ROM_STRUCTURE *PciRomStructure;
+ UINTN Offset;
+
+ Offset = 0;
+
+ do {
+
+ //
+ // Check if this is a SMCLP header
+ //
+ ClpRomHeader = (CLP_ROM_HEADER*) &ImageBuffer[Offset];
+ DEBUGPRINT (IMAGE, ("Offset = %d\n", Offset));
+
+ if (ClpRomHeader->Signature != 0xAA55) {
+ DEBUGPRINT (CRITICAL, ("Invalid PCI option ROM signature: %04x\n", ClpRomHeader->Signature));
+ return FALSE;
+ }
+
+ if (CompareMem(ClpRomHeader->RomSignature, CLP_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found CLP header, setting device ID %04x\n", DeviceId));
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + ClpRomHeader->PciDsOffset];
+ PciRomStructure->DeviceId = DeviceId;
+ _UpdateFlashFwChecksumPnP((UINT8*) ClpRomHeader);
+ _UpdateFlashFwChecksumRom(
+ (UINT8*) ClpRomHeader,
+ PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE,
+ STRUCT_OFFSET(CLP_ROM_HEADER, Checksum)
+ );
+ }
+
+ //
+ // Check if this is a PXE header
+ //
+ PxeRomHeader = (PXE_ROM_HEADER*) &ImageBuffer[Offset];
+ if (CompareMem((VOID*) &ImageBuffer[Offset + PxeRomHeader->RomIdOffset], UNDI_ROMID_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found PXE header, setting device ID %04x\n", DeviceId));
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + PxeRomHeader->PciDsOffset];
+ PciRomStructure->DeviceId = DeviceId;
+ _UpdateFlashFwChecksumPnP((UINT8*) PxeRomHeader);
+ _UpdateFlashFwChecksumRom(
+ (UINT8*) PxeRomHeader,
+ PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE,
+ STRUCT_OFFSET(PXE_ROM_HEADER, Checksum)
+ );
+ }
+
+ //
+ // Check if this is a EFI header
+ //
+ EfiRomHeader = (EFI_ROM_HEADER*) &ImageBuffer[Offset];
+ if (EfiRomHeader->EfiSignature == EFI_ROM_SIG) {
+ DEBUGPRINT(IMAGE, ("Found EFI image, setting device ID %04x\n", DeviceId));
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + EfiRomHeader->PciOffset];
+ PciRomStructure->DeviceId = DeviceId;
+ }
+
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + EfiRomHeader->PciOffset];
+ if (CompareMem(PciRomStructure->PciSignature, PCI_DATA_STRUCT_SIG, 4) != 0) {
+ DEBUGPRINT(CRITICAL, ("Invalid PCI ROM Structure.\n"));
+ return FALSE;
+ }
+
+ if ((PciRomStructure->IndicatorByte & PCI_ROM_LAST_INDICATOR) == PCI_ROM_LAST_INDICATOR) {
+ DEBUGPRINT(IMAGE, ("PCI last image indicator byte set.\n"));
+ break;
+ }
+
+ Offset += (PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE);
+ } while (1);
+
+ return TRUE;
+
+}
+
+EFI_STATUS
+ProgramFlashImage(
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ UINT8 *ImageBuffer,
+ UINTN SizeToProgram
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIoProtocol;
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Reg;
+ UINTN BarIndex;
+ UINTN FlashOffset;
+ UINTN i;
+ UINT8 Byte;
+
+ PciIoProtocol = GigUndiPrivateData->NicInfo.PciIo;
+
+ //
+ // Clear the FWE bits to enable the flash erase
+ //
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLASHOP);
+ DEBUGPRINT(IMAGE, ("E1000_FLASHOP=%08x\n", Reg));
+
+ DEBUGPRINT (IMAGE, ("ProgramFlashImage: Beginning flash erase\n"));
+ DEBUGWAIT(IMAGE);
+ e1000_ClearRegBits(&GigUndiPrivateData->NicInfo, E1000_EECD, FLASH_WRITE_MASK);
+ gBS->Stall(1);
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD);
+ DEBUGPRINT(IMAGE, ("E1000_EECD=%08x\n", Reg));
+
+ e1000_SetRegBits(&GigUndiPrivateData->NicInfo, E1000_FLA, E1000_FLA_FL_ER);
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ DEBUGPRINT(IMAGE, ("E1000_FLA=%08x\n", Reg));
+ gBS->Stall(1);
+ DEBUGPRINT (IMAGE, ("Wait for flash erase completion\n"));
+
+ i = 0;
+ do {
+ gBS->Stall(1000);
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ i++;
+ if (i > 20000) {
+ DEBUGPRINT (IMAGE, ("Flash erase failed, E1000_FLA=%08x\n", Reg));
+ return EFI_DEVICE_ERROR;
+ }
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+ DEBUGPRINT (IMAGE, ("Flash erase complete\n"));
+
+ //
+ // Enable flash writes
+ //
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD);
+ Reg = (Reg & ~FLASH_WRITE_MASK) | FLASH_WRITE_ENABLE;
+ E1000_WRITE_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD, Reg);
+
+ do {
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+
+ //
+ // Begin writing to the flash.
+ //
+ BarIndex = 1; // On pre-82580 the flash is memory mapped to PCI BAR 1
+ FlashOffset = 0;
+ if (GigUndiPrivateData->NicInfo.hw.mac.type == e1000_82580) {
+ BarIndex = 0; // On 82580 the flash is memory mapped to PCI BAR 0
+ FlashOffset = FLASH_OFFSET_82580;
+ }
+
+ DEBUGPRINT (IMAGE, ("Beginning flash write\n"));
+ //
+ // On 82580 the flash is memory mapped after the devices general register set in BAR 0
+ //
+ for (i = 0; i < SizeToProgram; i++) {
+
+ PciIoProtocol->Mem.Write (
+ PciIoProtocol,
+ EfiPciIoWidthUint8,
+ BarIndex,
+ i + FlashOffset,
+ 1,
+ (VOID *) &ImageBuffer[i]
+ );
+
+ do {
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+
+ PciIoProtocol->Mem.Read (
+ PciIoProtocol,
+ EfiPciIoWidthUint8,
+ BarIndex,
+ i + FlashOffset,
+ 1,
+ (VOID *) &Byte
+ );
+
+ //
+ // If the value read back does not match the value written, erase the flash so we do
+ // not leave a bad image on the card, and return an error.
+ //
+ if (ImageBuffer[i] != Byte) {
+ DEBUGPRINT (CRITICAL, ("Error writing flash at offset %x. Wrote=%02x, Read=%02x\n", i, ImageBuffer[i], Byte));
+ e1000_ClearRegBits(&GigUndiPrivateData->NicInfo, E1000_EECD, FLASH_WRITE_MASK);
+ e1000_SetRegBits(&GigUndiPrivateData->NicInfo, E1000_FLA, E1000_FLA_FL_ER);
+
+ do {
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+ DEBUGPRINT (CRITICAL, ("Flash erase complete\n"));
+
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ }
+
+ gBS->FreePool(ImageBuffer);
+
+ DEBUGPRINT (IMAGE, ("Flash write complete\n"));
+
+ //
+ // Disable flash writes
+ //
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD);
+ Reg = (Reg & ~FLASH_WRITE_MASK) | FLASH_WRITE_DISABLE;
+ E1000_WRITE_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD, Reg);
+
+ return Status;
+}
+
+
+EFI_STATUS
+SetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ )
+/*++
+
+ Routine Description:
+ Updates the firmware image of the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageIndex - A unique number identifying the firmware image(s) within the device. The number is
+ between 1 and DescriptorCount.
+ Image - Points to the new image.
+ ImageSize - Size of the new image in bytes.
+ VendorCode - This enables vendor to implement vendor-specific firmware image update policy.
+ Progress - A function used by the driver to report the progress of the firmware update.
+ AbortReason - A pointer to a pointer to a null-terminated Unicode string providing more
+ details for the aborted operation. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller�s responsibility to free it with a call to FreePool().
+
+ Returns:
+ EFI Status code.
+
+--*/
+{
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ UINT8 *ImageToProgram;
+ UINTN SizeToProgram;
+ BOOLEAN Supported;
+ UINT8 *ImageBuffer;
+ EFI_STATUS Status;
+
+ ImageToProgram = NULL;
+ SizeToProgram = 0;
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_FIRMWARE_MANAGEMENT(This);
+
+ Supported = _CheckFlashImageSupport (
+ GigUndiPrivateData,
+ (UINT8*) Image,
+ ImageSize,
+ &ImageToProgram,
+ &SizeToProgram
+ );
+
+ if (!Supported) {
+ if (gBS->AllocatePool (EfiBootServicesData, 80, (VOID **) AbortReason) == EFI_SUCCESS) {
+ UnicodeSPrint(*AbortReason, 80, L"ERROR: Incorrect image type for adapter");
+ }
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUGPRINT (IMAGE, ("ImageToProgram = %02X %02X, ImageSize %d\n", ImageToProgram[0], ImageToProgram[1], SizeToProgram));
+
+ //
+ // Verify the image will fit in flash
+ //
+ if (_VerifyImageSize ( GigUndiPrivateData, SizeToProgram) == FALSE) {
+ if (gBS->AllocatePool (EfiBootServicesData, 80, (VOID **) AbortReason) == EFI_SUCCESS) {
+ UnicodeSPrint(*AbortReason, 80, L"ERROR: Image too large for adapter flash");
+ }
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate malleable buffer to copy image into so we can set checksum and device ID
+ // in image headers
+ //
+ Status = gBS->AllocatePool (EfiBootServicesData, ImageSize, (VOID **) &ImageBuffer);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT (CRITICAL, ("AllocatePool failed %r\n", Status));
+ return Status;
+ }
+
+ CopyMem (ImageBuffer, ImageToProgram, SizeToProgram);
+
+ if (_UpdateChecksumAndId(ImageBuffer, SizeToProgram, GigUndiPrivateData->NicInfo.hw.device_id) == FALSE) {
+ DEBUGPRINT (CRITICAL, ("_UpdateChecksumAndId failed.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ProgramFlashImage(GigUndiPrivateData, ImageBuffer, SizeToProgram);
+
+ if (Status == EFI_DEVICE_ERROR) {
+ if ( gBS->AllocatePool (EfiBootServicesData, 80, (VOID **) AbortReason)== EFI_SUCCESS ) {
+ UnicodeSPrint(*AbortReason, 80, (L"ERROR: flash write failed"));
+ }
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+CheckImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ )
+/*++
+
+ Routine Description:
+ Checks if the firmware image is valid for the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageIndex - A unique number identifying the firmware image(s) within the device. The number is between 1 and DescriptorCount.
+ Image - Points to the new image.
+ ImageSize - Size of the new image in bytes.
+ ImageUpdatable - Indicates if the new image is valid for update. It also provides, if available, additional information if the
+ image is invalid.
+
+ Returns:
+ EFI Status code.
+
+--*/
+{
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ UINT8 *ImageToProgram;
+ UINTN SizeToProgram;
+ BOOLEAN Supported;
+
+ ImageToProgram = NULL;
+ SizeToProgram = 0;
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_FIRMWARE_MANAGEMENT(This);
+
+ DEBUGPRINT (IMAGE, ("CheckImage\n"));
+
+ Supported = _CheckFlashImageSupport (
+ GigUndiPrivateData,
+ (UINT8*) Image,
+ ImageSize,
+ &ImageToProgram,
+ &SizeToProgram
+ );
+
+ if (!Supported) {
+ DEBUGPRINT (IMAGE, ("Image invalid.\n"));
+ *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUGPRINT (IMAGE, ("Image valid.\n"));
+ *ImageUpdatable = IMAGE_UPDATABLE_VALID;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ )
+/*++
+
+ Routine Description:
+ Returns information about the firmware package.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ PackageVersion - A version number that represents all the firmware images in the device.
+ PackageVersionName - A pointer to a pointer to a null-terminated Unicode string
+ representing the package version name.
+ PackageVersionNameMaxLen - The maximum length of package version name if device supports
+ update of package version name.
+ AttributesSupported - Package attributes that are supported by this device. See �Package
+ Attribute Definitions� for possible returned values of this parameter. A value of 1
+ indicates the attribute is supported and the current setting value is indicated in
+ AttributesSetting.
+ AttributesSetting - Package attributes. See �Package Attribute Definitions� for possible
+ returned values of this parameter.
+
+ Returns:
+ EFI_SUCCESS - The package information was successfully returned.
+ EFI_UNSUPPORTED - The operation is not supported.
+
+--*/
+{
+ DEBUGPRINT (IMAGE, ("GetPackageInfo\n"));
+
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+SetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ )
+/*++
+
+ Routine Description:
+ Updates information about the firmware package.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ Image - Points to the authentication image. Null if authentication is not required.
+ ImageSize - Size of the authentication image in bytes. 0 if authentication is not required.
+ VendorCode - This enables vendor to implement vendor-specific firmware image update policy.
+ Null indicates the caller did not specify this policy or use the default policy.
+ PackageVersion - The new package version.
+ PackageVersionName - A pointer to the new null-terminated Unicode string representing the
+ package version name. The string length is equal to or less than the value returned in
+ PackageVersionNameMaxLen.
+
+ Returns:
+ EFI_SUCCESS - The device was successfully updated with the new package information
+ EFI_INVALID_PARAMETER - The PackageVersionName length is longer than the value returned
+ in PackageVersionNameMaxLen.
+ EFI_UNSUPPORTED - The operation is not supported.
+ EFI_SECURITY_VIOLATION - The operation could not be performed due to an authentication
+ failure.
+--*/
+{
+ DEBUGPRINT (IMAGE, ("SetPackageInfo\n"));
+
+ return EFI_UNSUPPORTED;
+
+}
+
+EFI_STATUS
+InitFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Installs the Firmware Management protocol on the device handle.
+
+ Arguments:
+ XgbeUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if Firmware Management protocol interface installed
+ correctly, otherwise EFI error code is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT (IMAGE, ("InitFirmwareManagementProtocol\n"));
+
+ GigUndiPrivateData->FirmwareManagement.GetImageInfo = GetImageInfo;
+ GigUndiPrivateData->FirmwareManagement.GetImage = FrmGetImage;
+ GigUndiPrivateData->FirmwareManagement.SetImage = SetImage;
+ GigUndiPrivateData->FirmwareManagement.CheckImage = CheckImage;
+ GigUndiPrivateData->FirmwareManagement.GetPackageInfo = GetPackageInfo;
+ GigUndiPrivateData->FirmwareManagement.SetPackageInfo = SetPackageInfo;
+
+ Status = gBS->InstallProtocolInterface (
+ &GigUndiPrivateData->DeviceHandle,
+ &gEfiFirmwareManagementProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &GigUndiPrivateData->FirmwareManagement
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("InstallProtocolInterface error: %r\n", Status));
+ return Status;
+ }
+ DEBUGPRINT (IMAGE, ("Install Firmware Management Protocol success: %r\n", Status));
+
+ return Status;
+}
+
+
+EFI_STATUS
+UninstallFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Installs the Firmware Management protocol on the device handle.
+
+ Arguments:
+ XgbeUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if Firmware Management protocol interface installed
+ correctly, otherwise EFI error code is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT (IMAGE, ("InitFirmwareManagementProtocol\n"));
+
+ Status = gBS->UninstallProtocolInterface (
+ GigUndiPrivateData->DeviceHandle,
+ &gEfiFirmwareManagementProtocolGuid,
+ &GigUndiPrivateData->FirmwareManagement
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("UninstallProtocolInterface error: %r\n", Status));
+ return Status;
+ }
+ DEBUGPRINT (IMAGE, ("Uninstall Firmware Management Protocol success: %r\n", Status));
+
+ return Status;
+}
+
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h
new file mode 100755
index 0000000..7c9e224
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h
@@ -0,0 +1,216 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _FRMMGMT_H_
+#define _FRMMGMT_H_
+
+#include "e1000.h"
+
+#define EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID \
+{ 0x86c77a67, 0xb97, 0x4633, { 0xa1, 0x87, 0x49, 0x10, \
+0x4d, 0x6, 0x85, 0xc7 } }
+
+//**************************************************************
+// Image Attribute Definitions
+//**************************************************************
+#define IMAGE_ATTRIBUTE_IMAGE_UPDATABLE 0x0000000000000001
+#define IMAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002
+#define IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004
+#define IMAGE_ATTRIBUTE_IN_USE 0x0000000000000008
+
+//**************************************************************
+// Image Compatibility Definitions
+//**************************************************************
+#define IMAGE_COMPATIBILITY_CHECK_SUPPORTED 0x0000000000000001
+
+//**************************************************************
+// Package Attribute Definitions
+//**************************************************************
+#define PACKAGE_ATTRIBUTE_VERSION_UPDATABLE 0x0000000000000001
+#define PACKAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002
+#define PACKAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004
+
+//**************************************************************
+// ImageUpdatable Definitions
+//**************************************************************
+#define IMAGE_UPDATABLE_VALID 0x0000000000000001
+#define IMAGE_UPDATABLE_INVALID 0x0000000000000002
+#define IMAGE_UPDATABLE_INVALID_TYPE 0x0000000000000004
+#define IMAGE_UPDATABLE_INVALID_OLD 0x0000000000000008
+
+//**************************************************************
+// Descriptor Version
+//**************************************************************
+#define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION 1
+
+#define E1000_FLASHOP 0x103C
+
+//
+// EEC register FLASH commands
+//
+#define FLASH_WRITE_DISABLE 0x0010
+#define FLASH_WRITE_ENABLE 0x0020
+#define FLASH_WRITE_ERASE 0x0000
+#define FLASH_WRITE_MASK 0x0030
+
+//
+// Flash Access Register
+//
+#define E1000_FLA_FL_SCK 0x00000001 /* Serial Flash Clock */
+#define E1000_FLA_FL_CS 0x00000002 /* Serial Flash Chip Select (CS) */
+#define E1000_FLA_FL_SI 0x00000004 /* Serial Flash Serial Data In */
+#define E1000_FLA_FL_SO 0x00000008 /* Serial Flash Serial Data Out */
+#define E1000_FLA_FL_REQ 0x00000010 /* Request flash access */
+#define E1000_FLA_FL_GNT 0x00000020 /* Grant flash access */
+#define E1000_FLA_FL_BUSY 0x40000000 /* Flash busy */
+#define E1000_FLA_FL_ER 0x80000000 /* Flash erase */
+
+//
+// Start of flash memory in memory mapped IO BAR on 82580
+//
+#define FLASH_OFFSET_82580 (128 * 1024)
+
+//**************************************************************
+// Image Attribute � Authentication Required
+//**************************************************************
+//typedef struct {
+// UINT64 MonotonicCount;
+// WIN_CERTIFICATE_UEFI_GUID AuthInfo;
+//} EFI_FIRMWARE_IMAGE_AUTHENTICATION;
+
+//**************************************************************
+// EFI_FIRMWARE_IMAGE_DESCRIPTOR
+//**************************************************************
+typedef struct {
+ UINT8 ImageIndex;
+ EFI_GUID ImageTypeId;
+ UINT64 ImageId;
+ CHAR16 *ImageIdName;
+ UINT32 Version;
+ CHAR16 *VersionName;
+ UINTN Size;
+ UINT64 AttributesSupported;
+ UINT64 AttributesSetting;
+ UINT64 Compatibilities;
+} EFI_FIRMWARE_IMAGE_DESCRIPTOR;
+
+//
+// Anonymous declarations to get the rest of the file to compile
+//
+typedef struct _EFI_FIRMWARE_MANAGEMENT_PROTOCOL EFI_FIRMWARE_MANAGEMENT_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE_INFO) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS) (
+ IN UINTN Completion
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_IMAGE) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_CHECK_IMAGE) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_PACKAGE_INFO) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_PACKAGE_INFO) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ );
+
+typedef struct _EFI_FIRMWARE_MANAGEMENT_PROTOCOL {
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE_INFO GetImageInfo;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE GetImage;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_IMAGE SetImage;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_CHECK_IMAGE CheckImage;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_PACKAGE_INFO GetPackageInfo;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_PACKAGE_INFO SetPackageInfo;
+} EFI_FIRMWARE_MANAGEMENT_PROTOCOL;
+
+
+
+#endif /* _FRMMGMT_H_ */
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf
new file mode 100755
index 0000000..8b1ef62
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf
@@ -0,0 +1,99 @@
+#/*++
+#
+# Copyright (c) 2008, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+# Module Name:
+#
+# LanIntelE1000Dxe.inf
+#
+# Abstract:
+#
+# Component description file for Undi module
+#
+#--*/
+
+[defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LanIntelE1000Dxe
+ FILE_GUID = BB801A52-C90F-4EDE-91B2-82520888CBC3
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 0.1
+
+ ENTRY_POINT = InitializeGigUNDIDriver
+
+[sources.common]
+ inventorystrings.uni
+ inventory.vfr
+ brand.h
+ clp.h
+ clp.c
+ ComponentName.c
+ Decode.c
+ DriverConfiguration.c
+ DriverDiagnostics.c
+ e1000.h
+ e1000.c
+ e1000_80003es2lan.h
+ e1000_80003es2lan.c
+ e1000_82571.h
+ e1000_82571.c
+ e1000_82575.h
+ e1000_82575.c
+ e1000_api.h
+ e1000_api.c
+ e1000_defines.h
+ e1000_hw.h
+ e1000_ich8lan.h
+ e1000_ich8lan.c
+ e1000_mac.h
+ e1000_mac.c
+ e1000_manage.h
+ e1000_manage.c
+ e1000_nvm.h
+ e1000_nvm.c
+ e1000_osdep.h
+ e1000_osdep.c
+ e1000_phy.h
+ e1000_phy.c
+ e1000_regs.h
+ FirmwareManagement.h
+ FirmwareManagement.c
+ hii.h
+ hii.c
+ ieee_define.h
+ init.c
+ NVDataStruc.h
+ startstop.h
+ startstop.c
+ vlan.h
+ vlan.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ HiiLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiDriverSupportedEfiVersionProtocolGuid
+ gEfiHiiConfigAccessProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiNetworkInterfaceIdentifierProtocolGuid_31
+ gEfiPciIoProtocolGuid
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h
new file mode 100755
index 0000000..f4964a5
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 2007-2010, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ NVDataStruc.h
+
+Abstract:
+
+ NVData structure used by the sample driver
+
+Revision History:
+
+--*/
+
+#ifndef _NVDATASTRUC_H
+#define _NVDATASTRUC_H
+
+#define E1000_HII_FORM_GUID \
+ { \
+ 0x77f2ea2f, 0x4312, 0x4569, { 0x85, 0xc4, 0x58, 0x3a, 0xcd, 0x8d, 0xb7, 0xe2 } \
+ }
+
+#define E1000_HII_DATA_GUID \
+ { \
+ 0xa31abb16, 0xc627, 0x475b, { 0x98, 0x8e, 0x7e, 0xe0, 0x77, 0x67, 0x40, 0xf3 } \
+ }
+
+#define VAR_EQ_TEST_NAME 0x100
+
+#define FORM_2 0x1235
+
+#define LABEL_START 0x1236
+#define LABEL_END 0x2223
+
+#define LINK_SPEED_AUTO_NEG 0x00
+#define LINK_SPEED_10HALF 0x01
+#define LINK_SPEED_10FULL 0x02
+#define LINK_SPEED_100HALF 0x03
+#define LINK_SPEED_100FULL 0x04
+#define LINK_SPEED_NO_CONFIGURE_AUTO 0x10
+
+#define WOL_DISABLE 0x00
+#define WOL_ENABLE 0x01
+#define WOL_NA 0x02
+
+#define OROM_DISABLE 0x00
+#define OROM_ENABLE 0x01
+
+
+#pragma pack(1)
+typedef struct {
+ UINT8 OptionRomEnable;
+ UINT8 LinkSpeed;
+ UINT8 WolEnable;
+} GIG_DRIVER_CONFIGURATION;
+#pragma pack()
+
+#endif
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h
new file mode 100755
index 0000000..377c590
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h
@@ -0,0 +1,159 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+typedef struct {
+ UINT16 vendor_id;
+ UINT16 subvendor_id;
+ UINT16 device_id;
+ UINT16 subsystem_id;
+ CHAR16 *brand_string;
+} BRAND_STRUCT;
+
+BRAND_STRUCT branding_table[] =
+{
+#ifndef NO_BRANDING_SUPPORT
+
+#ifndef NO_82571_SUPPORT
+ {0x8086, 0x0000, 0x105E, 0x0000, L"Intel(R) PRO/1000 PT Dual Port Network Connection"},
+ {0x8086, 0x8086, 0x105E, 0x005E, L"Intel(R) PRO/1000 PT Dual Port Server Connection"},
+ {0x8086, 0x8086, 0x105E, 0x115E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x8086, 0x105E, 0x125E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x8086, 0x105E, 0x135E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x103C, 0x105E, 0x704E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x103C, 0x105E, 0x7044, L"HP NC360T PCIe DP Gigabit Server Adapter"},
+ {0x8086, 0x0000, 0x105F, 0x0000, L"Intel(R) PRO/1000 PF Dual Port Server Adapter"},
+ {0x8086, 0x103C, 0x105F, 0x704F, L"Intel(R) PRO/1000 PF Dual Port Server Adapter"},
+ {0x8086, 0x0000, 0x1060, 0x0000, L"Intel(R) PRO/1000 PB Dual Port Server Connection"},
+ {0x8086, 0x0000, 0x10A4, 0x0000, L"Intel(R) PRO/1000 PT Quad Port Server Adapter"},
+ {0x8086, 0x108E, 0x10D5, 0xF1BC, L"Intel(R) Gigabit PT Quad Port Server ExpressModule"},
+ {0x8086, 0x0000, 0x10A5, 0x0000, L"Intel(R) PRO/1000 PF Quad Port Server Adapter"},
+ {0x8086, 0x0000, 0x10BC, 0x0000, L"Intel(R) PRO/1000 PT Quad Port LP server Adapter"},
+ {0x8086, 0x103C, 0x10BC, 0x704B, L"HP NC364T PCIe Quad Port Gigabit Server Adapter"},
+ {0x8086, 0x8086, 0x107D, 0x1082, L"Intel(R) PRO/1000 PT Server Adapter"},
+ {0x8086, 0x8086, 0x107D, 0x1092, L"Intel(R) PRO/1000 PT Server Adapter"},
+ {0x8086, 0x8086, 0x107D, 0x1084, L"Intel(R) PRO/1000 PT Server Adapter"},
+ {0x8086, 0x0000, 0x107D, 0x0000, L"Intel(R) PRO/1000 PT Network Connection"},
+ {0x8086, 0x0000, 0x107E, 0x0000, L"Intel(R) PRO/1000 PF Network Connection"},
+ {0x8086, 0x8086, 0x107E, 0x1084, L"Intel(R) PRO/1000 PF Server Adapter"},
+ {0x8086, 0x8086, 0x107E, 0x1094, L"Intel(R) PRO/1000 PF Server Adapter"},
+ {0x8086, 0x8086, 0x107E, 0x1085, L"Intel(R) PRO/1000 PF Server Adapter"},
+ {0x8086, 0x0000, 0x107F, 0x0000, L"Intel(R) PRO/1000 PB Server Connection"},
+ {0x8086, 0x0000, 0x10B9, 0x0000, L"Intel(R) PRO/1000 PT Desktop Adapter"},
+ {0x8086, 0x103C, 0x10B9, 0x704A, L"HP NC110T PCIe Gigabit Server Adapter"},
+ {0x8086, 0x0000, 0x108B, 0x0000, L"Intel(R) PRO/1000 PM Network Connection"},
+ {0x8086, 0x0000, 0x108C, 0x0000, L"Intel(R) PRO/1000 PM Network Connection"},
+ {0x8086, 0x0000, 0x109A, 0x0000, L"Intel(R) PRO/1000 PL Network Connection"},
+#ifndef NO_82574_SUPPORT
+ {0x8086, 0x0000, 0x10D3, 0x0000, L"Intel(R) 82574L Gigabit Network Connection"},
+ {0x8086, 0x8086, 0x10D3, 0xA01F, L"Intel(R) Gigabit CT Desktop Adapter"},
+ {0x8086, 0x8086, 0x10D3, 0x0001, L"Intel(R) Gigabit CT2 Desktop Adapter"},
+ {0x8086, 0x103C, 0x10D3, 0x1785, L"HP NC112i 1-port Ethernet Server Adapter"},
+ {0x8086, 0x0000, 0x10F6, 0x0000, L"Intel(R) 82574L Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x150C, 0x0000, L"Intel(R) 82583V Gigabit Network Connection"},
+#endif
+#endif /* NO_82571_SUPPORT */
+
+#ifndef NO_80003ES2LAN_SUPPORT
+ {0x8086, 0x0000, 0x1096, 0x0000, L"Intel(R) PRO/1000 EB Network Connection "},
+ {0x8086, 0x10F1, 0x1096, 0x2692, L"Intel(R) PRO/1000 EB1 Network Connection "},
+ {0x8086, 0x1734, 0x1096, 0x10A8, L"Intel(R) PRO/1000 EB1 Network Connection "},
+ {0x8086, 0x0000, 0x1098, 0x0000, L"Intel(R) PRO/1000 EB Backplane Connection "},
+ {0x8086, 0x0000, 0x10BA, 0x0000, L"Intel(R) PRO/1000 EB1 Network Connection "},
+ {0x8086, 0x0000, 0x10BB, 0x0000, L"Intel(R) PRO/1000 EB1 Backplane Connection "},
+#endif /* NO_80003ES2LAN_SUPPORT */
+
+#ifndef NO_ICH8LAN_SUPPORT
+ {0x8086, 0x1179, 0x1049, 0x0001, L"82566MM Network Connection"},
+ {0x8086, 0x0000, 0x1049, 0x0000, L"Intel(R) 82566MM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x104A, 0x0000, L"Intel(R) 82566DM Gigabit Network Connection"},
+ {0x8086, 0x17AA, 0x104A, 0x1012, L"Intel(R) 82566DM Gigabit Platform LAN Connect"},
+ {0x8086, 0x17AA, 0x104A, 0x100F, L"Intel(R) 82566DM Gigabit Platform LAN Connect"},
+ {0x8086, 0x0000, 0x104B, 0x0000, L"Intel(R) 82566DC Gigabit Network Connection"},
+ {0x8086, 0x1179, 0x104C, 0x0001, L"82562V Network Connection"},
+ {0x8086, 0x1179, 0x104D, 0x0001, L"82566MC Network Connection"},
+ {0x8086, 0x0000, 0x104D, 0x0000, L"Intel(R) 82566MC Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10BF, 0x0000, L"Intel(R) 82567LF Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10F5, 0x0000, L"Intel(R) 82567LM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CB, 0x0000, L"Intel(R) 82567V Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10BD, 0x0000, L"Intel(R)82566DM-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10E5, 0x0000, L"Intel(R) 82567LM-4 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x294C, 0x0000, L"Intel(R) 82566DC-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CC, 0x0000, L"Intel(R) 82567LM-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CD, 0x0000, L"Intel(R) 82567LF-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CE, 0x0000, L"Intel(R) 82567V-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10EA, 0x0000, L"Intel(R) 82577LM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10EB, 0x0000, L"Intel(R) 82577LC Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10EF, 0x0000, L"Intel(R) 82578DM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10F0, 0x0000, L"Intel(R) 82578DC Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x1502, 0x0000, L"Intel(R) 82579LM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x1503, 0x0000, L"Intel(R) 82579V Gigabit Network Connection"},
+#endif /* NO_ICH8LAN_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+#ifndef NO_82576_SUPPORT
+ {0x8086, 0x0000, 0x10C9, 0x0000, L"Intel(R) 82576 Gigabit Dual Port Network Connection"},
+ {0x8086, 0x8086, 0x10C9, 0x0000, L"Intel(R) Gigabit ET Dual Port Server Adapter"},
+ {0x8086, 0x0000, 0x10E6, 0x0000, L"Intel(R) 82576 Gigabit Dual Port Network Connection"},
+ {0x8086, 0x8086, 0x10E6, 0x0000, L"Intel(R) Gigabit EF Dual Port Server Adapter"},
+ {0x8086, 0x0000, 0x10E7, 0x0000, L"Intel(R) 82576 Gigabit Dual Port Server Network Connection"},
+ {0x8086, 0x8086, 0x10E8, 0xA02B, L"Intel(R) Gigabit ET Quad Port Server Adapter"},
+ {0x8086, 0x8086, 0x10E8, 0xA02C, L"Intel(R) Gigabit ET Quad Port Server Adapter"},
+ {0x8086, 0x8086, 0x1526, 0xA05C, L"Intel(R) Gigabit ET2 Quad Port Server Adapter"},
+ {0x8086, 0x8086, 0x1526, 0xA06C, L"Intel(R) Gigabit ET2 Quad Port Server Adapter"},
+ {0x8086, 0x0000, 0x150A, 0x0000, L"Intel(R) 82576NS Gigabit Ethernet Controller"},
+ {0x8086, 0x0000, 0x1518, 0x0000, L"Intel(R) 82576NS SerDes Gigabit Ethernet Controller"},
+ {0x8086, 0x0000, 0x150D, 0xA10C, L"Intel(R) Gigabit ET Quad Port Mezzanine Card"},
+#endif /* NO_82576_SUPPORT */
+ {0x8086, 0x0000, 0x10A7, 0x0000, L"Intel(R) 82575EB Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10A9, 0x0000, L"Intel(R) 82575EB Gigabit Backplane Connection"},
+ {0x8086, 0x0000, 0x10D6, 0x0000, L"Intel(R) Gigabit VT Quad Port Server Adapter"},
+#endif /* NO_82575_SUPPORT */
+
+ {0x8086, 0x0000, 0x150E, 0x0000, L"Intel(R) 82580 Gigabit Network Connection"},
+ {0x8086, 0x103C, 0x150E, 0x1780, L"HP NC365T PCIe Quad Port Gigabit Server Adapter"},
+ {0x8086, 0x0000, 0x150F, 0x0000, L"Intel(R) 82580 Gigabit Fiber Network Connection"},
+ {0x8086, 0x0000, 0x1510, 0x0000, L"Intel(R) 82580 Gigabit Backplane Connection"},
+ {0x8086, 0x0000, 0x1511, 0x0000, L"Intel(R) 82580 Gigabit SFP Connection"},
+ {0x8086, 0x8086, 0x150E, 0x12A1, L"Intel(R) Ethernet Server Adapter I340-T4"},
+ {0x8086, 0x8086, 0x150E, 0x12A2, L"Intel(R) Ethernet Server Adapter I340-T4"},
+ {0x8086, 0x8086, 0x1516, 0x12B1, L"Intel(R) Ethernet Server Adapter I340-T2"},
+ {0x8086, 0x8086, 0x1516, 0x12B2, L"Intel(R) Ethernet Server Adapter I340-T2"},
+ {0x8086, 0x8086, 0x1527, 0x0001, L"Intel(R) Ethernet Server Adapter I340-F4"},
+ {0x8086, 0x8086, 0x1527, 0x0002, L"Intel(R) Ethernet Server Adapter I340-F4"},
+
+
+#else /* N0_BRANDING_SUPPORT */
+ {0x8086, 0x8086, 0x0000, 0x0000, L"Intel(R) PRO/1000 Network Connection"},
+#endif /* N0_BRANDING_SUPPORT */
+ {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, L" "}
+};
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt
new file mode 100755
index 0000000..ec30705
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt
@@ -0,0 +1,63 @@
+Tiano EDK1 Build Instructions for Intel(R) PRO/1000 Network Connections Driver
+Copyright 2008-2010, Intel Corporation, All Rights Reserved
+
+
+INSTRUCTIONS
+============
+ The make files included in this source package allow the PRO/1000 driver
+ binary to be built as part of the Tiano Core EDK1 source tree. Before
+ building the driver you must download the Tiano Core EDK1 release source
+ from www.tianocore.org and build the tree for your target architecture
+ following the instructions from that site.
+ Follow the below steps to integrate the PRO/1000 driver into the Tiano Core
+ source tree:
+
+ 1. Unzip all files into the following EDK1 sub-directory:
+ \Sample\Bus\Pci\GigUndi
+
+ 2a. (x86-64 or x86 UEFI builds) Open the file X64.dsc in the sub-directory
+ \Sample\Platform\X64\Build. Add the following line to the file in the
+ section labeled "# Network Boot": Sample\Bus\Pci\GigUndi\gig_edk1.inf
+ This will add the PRO/1000 driver to the list of targets for the EDK1 build
+ process. The X64.dsc file has separate sections for x86 and x86-64 builds.
+ The reference to the gig_edk1.inf file must be placed in the correct section
+ for the target architecture, or placed in both sections to build for both
+ x86 and x86-64 architectures.
+
+ 2b. (Itanium IPF Build) Open the file IPF.dsc in the sub-directory
+ \Sample\Platform\IPF\Build. Add the following line to the list of targets in
+ the file: Sample\Bus\Pci\GigUndi\gig_edk1.inf
+
+ 3. Run "nmake" from the platform \Sample\Platform\<ARCH> directory. This
+ will build the EDK1 source tree including the PRO/1000 driver. The resultant
+ executable, gigundi.efi, will be created in the .UEFI\IPF, .UEFI\X64, or
+ .UEFI\IA32 sub-directory depending on the target architecture.
+
+
+CONTROLLER SPECIFIC BUILD INSTRUCTIONS (OPTIONAL)
+=================================================
+ Two example *.inf build files are included with the PRO/1000 source which
+ create a driver binary supporting only a specific network controller family.
+ These *.inf file will result in a smaller binary size by excluding code not
+ needed by the controller.
+
+ gig_82575_edk1.inf: This file will generate a driver specific to the 82575
+ family of network controllers. To build a driver specific to the 82575
+ controller, follow the build instructions in the previous section, but
+ replace "gig_edk1.inf" with "gig_82575_edk1.inf".
+
+ gig_ich_edk1.inf: This file will generate a driver specific to the ICH
+ LAN-On-Motherboard network connections such as ICH8, and ICH9. To build a
+ driver specific to ICH network connections, follow the build instructions in
+ the previous section, but replace "gig_edk1.inf" with "gig_ich_edk1.inf".
+
+ gig_edk1.inf: This file will generate a driver supporting all Intel PRO/1000
+ network connections. To generate this driver binary follow the build
+ instructions in the previous section.
+
+
+
+
+
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c
new file mode 100755
index 0000000..0ed2b34
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c
@@ -0,0 +1,514 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "clp.h"
+
+
+EFI_GUID gEfiPlatformToDriverConfigurationProtocolGuid = EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL_GUID;
+
+VOID
+EepromMacAddressSet(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 *MacAddress
+);
+
+
+INTN
+FindKey(
+ IN CHAR8 *Key,
+ IN EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock
+ )
+/*++
+
+Routine Description:
+ Find key in CLP command line.
+
+Arguments:
+ Key - Key to find on CLP command line.
+ ClpBlock - Pointer to the CLP structure.
+
+Returns:
+ If key found, returns the index of the last character in the key.
+ If key not found, returns -1.
+
+--*/
+{
+ UINTN i = 0;
+ UINTN j = 0;
+ CHAR8 *CharPtr = ClpBlock->CLPCommand;
+
+ DEBUGPRINT(CLP, ("FindKey()\n"));
+ DEBUGPRINT(CLP, ("CLPCommandLength=%d \n", ClpBlock->CLPCommandLength));
+
+ for (; i < ClpBlock->CLPCommandLength; i++) {
+ if (Key[j] == CharPtr[i]) {
+ DEBUGPRINT(CLP, ("Match j=%d i=%d ", j, i));
+ DEBUGPRINT(CLP, ("Key[j]=%c CharPtr[i]=%c\n", Key[j], CharPtr[i]));
+ j++;
+ }
+ else
+ j = 0;
+
+ if (Key[j] == '\0' && j > 0) {
+ j=0;
+ DEBUGPRINT(CLP, ("Found key: "));
+ while (Key[j] != '\0') {
+ DEBUGPRINT(CLP, ("%c", Key[j]));
+ j++;
+ }
+ DEBUGPRINT(CLP, ("\n"));
+ break;
+ }
+ }
+
+ if (i >= ClpBlock->CLPCommandLength) {
+ j=0;
+ DEBUGPRINT(CLP, ("Did not find key!: "));
+ while (Key[j] != '\0') {
+ DEBUGPRINT(CLP, ("%c", Key[j]));
+ j++;
+ }
+ DEBUGPRINT(CLP, ("\n"));
+ return -1;
+ }
+ DEBUGPRINT(CLP, ("Returning index=%d\n", i));
+ return i;
+}
+
+
+BOOLEAN
+ProcessAddressKey(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock
+ )
+/*++
+
+Routine Description:
+ Processes alternate MAC address with the "Address" key present.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+ ClpBlock - Pointer to the CLP structure.
+
+Returns:
+ FALSE - MAC Address not set.
+ TRUE - Successfully set MAC Address.
+
+--*/
+{
+ INTN i = -1;
+ UINTN j = 0;
+ CHAR8 *CharPtr = ClpBlock->CLPCommand;
+ UINT8 Uint8 = 0;
+ UINT16 MacAddr[3] = {0};
+ UINT8 *MacAddress = (UINT8*) MacAddr; // Necessary to preserve 16-bit alignment on IA64 for call to e1000_read_nvm
+
+ //
+ // Process MAC address
+ //
+ DEBUGPRINT(CLP, ("ProcessAddressKey()\n"));
+ DEBUGPRINT(CLP, ("CLPCommandLength=%d \n", ClpBlock->CLPCommandLength));
+
+ DEBUGPRINT(CLP, ("Search for equals sign\n"));
+ i = FindKey("=", ClpBlock);
+ if (i == -1) {
+ return FALSE;
+ }
+
+ DEBUGPRINT(CLP, ("FindKey returned index=%d\n", i));
+
+ while (CharPtr[i] != '\0') {
+ if (CharPtr[i] >= '0' && CharPtr[i] <= '9') {
+ Uint8 = CharPtr[i] - '0';
+ DEBUGPRINT(CLP, ("%X ", Uint8));
+ }
+ else
+ if (CharPtr[i] >= 'A' && CharPtr[i] <= 'F') {
+ Uint8 = CharPtr[i] - 'A' + 10;
+ DEBUGPRINT(CLP, ("%X ", Uint8));
+ }
+ else
+ if (CharPtr[i] >= 'a' && CharPtr[i] <= 'f') {
+ Uint8 = CharPtr[i] - 'a' + 10;
+ DEBUGPRINT(CLP, ("%X ", Uint8));
+ }
+ else {
+ i++;
+ continue;
+ }
+
+ //
+ // Assign the MAC address to the final value.
+ //
+ if (j & 1) {
+ MacAddress[j/2] |= Uint8;
+ }
+ else
+ {
+ MacAddress[j/2] |= Uint8 << 4;
+ }
+ j++;
+ if (j >= 12) {
+ break;
+ }
+ i++;
+ }
+
+ DEBUGPRINT(CLP, ("\n"));
+
+ if (j < 6) {
+ DEBUGPRINT(CLP, ("Incomplete MAC address\n"));
+ return FALSE;
+ } else {
+ DEBUGPRINT(CLP, ("MAC=%X-%X-%X-%X-%X-%X\n", MacAddress[0], MacAddress[1], MacAddress[2],
+ MacAddress[3], MacAddress[4], MacAddress[5]));
+ }
+
+ DEBUGPRINT(CLP, ("Calling EepromMacAddressSet\n"));
+ EepromMacAddressSet(GigAdapter, MacAddr);
+ return TRUE;
+}
+
+
+BOOLEAN
+ProcessClp(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock
+ )
+/*++
+
+Routine Description:
+ Processes CLP command line parameters.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+ ClpBlock - Pointer to the CLP structure.
+
+Returns:
+ PXE_STATCODE
+
+--*/
+{
+ DEBUGPRINT(CLP, ("ProcessClp()\n"));
+
+ DEBUGPRINT(CLP, ("Search for key\n"));
+ if (FindKey("Address", ClpBlock) != -1) {
+ return ProcessAddressKey(GigAdapter, ClpBlock);
+ }
+ return FALSE;
+}
+
+
+VOID
+EepromMacAddressSet(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 *MacAddress
+)
+/*++
+
+Routine Description:
+ Sets the override MAC address to the default value.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+ MacAddress - Value to set the MAC address to.
+
+Returns:
+ VOID
+
+--*/
+{
+ UINT16 MacOffset;
+ UINT16 OldMacAddress[3];
+#if (DBG_LVL&CLP)
+ UINT8 *MacAddr = (UINT8*) MacAddress;
+#endif
+
+ DEBUGPRINT(CLP, ("MAC=%X-%X-%X-%X-%X-%X\n", MacAddr[0], MacAddr[1], MacAddr[2],
+ MacAddr[3], MacAddr[4], MacAddr[5]));
+
+ //
+ // Determine the location of the card.
+ //
+ GigAdapter->PciIo->GetLocation (
+ GigAdapter->PciIo,
+ &GigAdapter->Segment,
+ &GigAdapter->Bus,
+ &GigAdapter->Device,
+ &GigAdapter->Function
+ );
+
+ //
+ // Read the address where the override MAC address is stored.
+ //
+ e1000_read_nvm (&GigAdapter->hw, NVM_ALT_MAC_ADDR_PTR, 1, &MacOffset);
+
+ if (MacOffset == 0xFFFF) {
+ DEBUGPRINT(CLP, ("Invalid offset for alt MAC address\n"));
+ return;
+ }
+
+ DEBUGPRINT(CLP, ("MAC addresses at offset %X\n", MacOffset));
+
+ //
+ // Adjust the MAC address offset if this is the second port (function 1), or the
+ // third or fourth port (Barton Hills)
+ //
+ MacOffset = MacOffset + (UINT16) (3*GigAdapter->Function);
+
+ //
+ // Read the current stored MAC address to see if it needs to be changed
+ //
+ e1000_read_nvm (&GigAdapter->hw, MacOffset, 3, OldMacAddress);
+
+ if ((MacAddress[0] != OldMacAddress[0]) || (MacAddress[1] != OldMacAddress[1]) ||
+ (MacAddress[2] != OldMacAddress[2])) {
+ DEBUGPRINT(CLP, ("Updating MAC addresses in EEPROM\n"));
+ e1000_write_nvm(&GigAdapter->hw, MacOffset, 3, MacAddress);
+ } else {
+ DEBUGPRINT(CLP, ("No need to update MAC addresses in EEPROM\n"));
+ }
+
+}
+
+
+VOID
+EepromMacAddressDefault(
+ IN GIG_DRIVER_DATA *GigAdapter
+)/*++
+
+Routine Description:
+ Sets the override MAC address back to FF-FF-FF-FF-FF-FF to disable.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ PXE_STATCODE
+
+--*/
+{
+ UINT16 MacOffset;
+ UINT16 MacAddress[3];
+ UINT16 MacDefault[3] = {0xFFFF, 0xFFFF, 0xFFFF};
+
+ //
+ // Determine the location of the card.
+ //
+ GigAdapter->PciIo->GetLocation (
+ GigAdapter->PciIo,
+ &GigAdapter->Segment,
+ &GigAdapter->Bus,
+ &GigAdapter->Device,
+ &GigAdapter->Function
+ );
+
+ //
+ // Read the address where the override MAC address is stored.
+ //
+ e1000_read_nvm (&GigAdapter->hw, NVM_ALT_MAC_ADDR_PTR, 1, &MacOffset);
+
+ if (MacOffset == 0xFFFF) {
+ DEBUGPRINT(CLP, ("Invalid offset for alt MAC address\n"));
+ return;
+ }
+
+ DEBUGPRINT(CLP, ("MAC addresses at offset %X\n", MacOffset));
+
+ //
+ // Adjust the MAC address offset if this is the second port (function 1)
+ //
+ MacOffset = MacOffset + (UINT16) (3*GigAdapter->Function);
+
+ //
+ // Read the current stored MAC address to see if it needs to be changed
+ //
+ e1000_read_nvm (&GigAdapter->hw, MacOffset, 3, (UINT16*) MacAddress);
+
+ if ((MacAddress[0] != 0xFFFF) || (MacAddress[1] != 0xFFFF) || (MacAddress[2] != 0xFFFF)) {
+ DEBUGPRINT(CLP, ("Setting default MAC addresses in EEPROM\n"));
+ e1000_write_nvm(&GigAdapter->hw, MacOffset, 3, MacDefault);
+ } else {
+ DEBUGPRINT(CLP, ("No need to update MAC addresses in EEPROM\n"));
+ }
+
+}
+
+
+EFI_STATUS
+ClpEntry(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Entry point for EFI CLP code. Searches for CLP interface and attempts to get CLP parameters.
+
+Arguments:
+ This - Handle to driver binding protocol
+ Controller - Controller handle associated with the CLP instance
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ EFI_STATUS
+
+--*/
+{
+ EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL *ClpProt;
+ EFI_STATUS Status;
+ UINTN Instance = 0;
+ EFI_GUID *ParameterTypeGuid;
+ UINTN ParameterBlockSize;
+ EFI_PLATFORM_CONFIGURATION_ACTION Action;
+ EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ BOOLEAN AltMacSet = FALSE;
+ UINTN i;
+
+ DEBUGPRINT(CLP, ("ClpEntry()\n"));
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPlatformToDriverConfigurationProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CLP, ("LocateHandleBuffer returns %r\n", Status));
+ return Status;
+ }
+
+ if (HandleCount == 0) {
+ DEBUGPRINT(CLP, ("CLP Interface not found, restoring default MAC address.\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUGPRINT(CLP, ("HandleCount=%d\n", HandleCount));
+
+ Status = gBS->OpenProtocol (
+ HandleBuffer[0],
+ &gEfiPlatformToDriverConfigurationProtocolGuid,
+ (VOID **) &ClpProt,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CLP, ("Error finding CLP protocol: %r\n", Status));
+ return Status;
+ }
+ DEBUGPRINT(CLP, ("HandleCount=%d\n", HandleCount));
+
+ while (Instance < 10) {
+ DEBUGPRINT(CLP, ("Calling CLP->Query\n"));
+ Status = ClpProt->Query(
+ ClpProt,
+ Controller,
+ NULL,
+ &Instance,
+ &ParameterTypeGuid,
+ (VOID*) &ClpBlock,
+ &ParameterBlockSize
+ );
+
+ DEBUGPRINT(CLP, ("CLP Query returns: %r\n", Status));
+ if (Status == EFI_NOT_FOUND || EFI_ERROR(Status)) {
+ break;
+ }
+
+ DEBUGPRINT(CLP, ("Instance=%d\n", Instance));
+ DEBUGPRINT(CLP, ("ParameterBlockSize=%d\n", ParameterBlockSize));
+
+ DEBUGPRINT(CLP, ("CLPCommandLength=%d \n", ClpBlock->CLPCommandLength));
+ DEBUGPRINT(CLP, ("CLPCommand="));
+ for (i = 0; i < ClpBlock->CLPCommandLength; i++) {
+ DEBUGPRINT(CLP, ("%c", ClpBlock->CLPCommand[i]));
+ }
+ DEBUGPRINT(CLP, ("\n"));
+
+ DEBUGPRINT(CLP, ("Calling ProcessCLP\n"));
+ if (ProcessClp(GigAdapter, ClpBlock) == TRUE) {
+ DEBUGPRINT(CLP, ("Set Alt MAC address\n"));
+ AltMacSet = TRUE;
+ }
+
+ Action = EfiPlatformConfigurationActionNone;
+ ClpBlock->CLPReturnString = "Success";
+ ClpBlock->CLPReturnStringLength = 8;
+ ClpBlock->CLPCmdStatus = 0;
+ ClpBlock->CLPErrorValue = 2;
+ ClpBlock->CLPMsgCode = 0;
+
+ DEBUGPRINT(CLP, ("Calling CLP Response @ %X...", ClpProt->Response));
+ Status = ClpProt->Response (
+ ClpProt,
+ Controller,
+ NULL,
+ &Instance,
+ ParameterTypeGuid,
+ (VOID*) ClpBlock,
+ sizeof(EFI_CONFIGURE_CLP_PARAMETER_BLK),
+ Action
+ );
+
+ DEBUGPRINT(CLP, ("CLP Response returns: %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ Instance++;
+ }
+
+ if (AltMacSet == FALSE) {
+ DEBUGPRINT(CLP, ("Setting CLP back to default.\n"));
+ EepromMacAddressDefault(GigAdapter);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPlatformToDriverConfigurationProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ DEBUGWAIT(CLP);
+
+ return Status;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h
new file mode 100755
index 0000000..9405942
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h
@@ -0,0 +1,100 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _CLP_H_
+#define _CLP_H_
+
+#define EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL_GUID \
+ { 0x642cd590, 0x8059, 0x4c0a, { 0xa9, 0x58, 0xc5, 0xec, 0x7, 0xd2, 0x3c, 0x4b } }
+
+typedef enum {
+ EfiPlatformConfigurationActionNone = 0,
+ EfiPlatformConfigurationActionStopController = 1,
+ EfiPlatformConfigurationActionRestartController = 2,
+ EfiPlatformConfigurationActionRestartPlatform = 3,
+ EfiPlatformConfigurationActionNvramFailed = 4,
+ EfiPlatformConfigurationActionMaximum
+} EFI_PLATFORM_CONFIGURATION_ACTION;
+
+#define EFI_PLATFORM_TO_DRIVER_CONFIGURATION_CLP_GUID \
+ {0x345ecc0e, 0xcb6, 0x4b75, 0xbb, 0x57, 0x1b, 0x12, 0x9c, 0x47, 0x33,0x3e)
+
+typedef struct _EFI_CONFIGURE_CLP_PARAMETER_BLK {
+ CHAR8 *CLPCommand;
+ UINT32 CLPCommandLength;
+ CHAR8 *CLPReturnString;
+ UINT32 CLPReturnStringLength;
+ UINT8 CLPCmdStatus;
+ UINT8 CLPErrorValue;
+ UINT16 CLPMsgCode;
+} EFI_CONFIGURE_CLP_PARAMETER_BLK;
+
+typedef struct _EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PLATFORM_TO_DRIVER_CONFIGURATION_QUERY) (
+ IN EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINTN *Instance,
+ OUT EFI_GUID **ParameterTypeGuid,
+ OUT VOID **ParameterBlock,
+ OUT UINTN *ParameterBlockSize
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PLATFORM_TO_DRIVER_CONFIGURATION_RESPONSE) (
+ IN EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINTN *Instance,
+ IN EFI_GUID *ParameterTypeGuid,
+ IN VOID *ParameterBlock,
+ IN UINTN ParameterBlockSize,
+ IN EFI_PLATFORM_CONFIGURATION_ACTION ConfigurationAction
+ );
+
+struct _EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL {
+ EFI_PLATFORM_TO_DRIVER_CONFIGURATION_QUERY Query;
+ EFI_PLATFORM_TO_DRIVER_CONFIGURATION_RESPONSE Response;
+};
+
+EFI_STATUS
+ClpEntry(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ GIG_DRIVER_DATA *GigAdapter
+ );
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c
new file mode 100755
index 0000000..e215d41
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c
@@ -0,0 +1,2222 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern GIG_DRIVER_DATA *e1000_NIC_Data; // is actually an array of structures
+
+//
+// Global variables for blocking IO
+//
+STATIC BOOLEAN gInitializeLock = TRUE;
+STATIC EFI_LOCK gLock;
+
+
+VOID
+_DisplayBuffersAndDescriptors (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+
+//
+// Local Functions
+//
+BOOLEAN
+e1000_DownShift (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+UINTN
+e1000_SetFilter (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 NewFilter,
+ UINT64 cpb,
+ UINT32 cpbsize
+ );
+
+UINTN
+e1000_Statistics (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 DBaddr,
+ UINT16 DBsize
+ );
+
+VOID
+e1000_TxRxConfigure (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+UINTN
+e1000_SetInterruptState (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+BOOLEAN
+e1000_WaitForAutoNeg (
+ IN GIG_DRIVER_DATA *GigAdapter
+ );
+
+//
+// end function prototypes
+//
+
+VOID
+e1000_BlockIt (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ UINT32 flag
+ )
+/*++
+
+Routine Description:
+ Implements IO blocking when reading DMA memory.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on.
+ flag - Block flag
+Returns:
+
+--*/
+{
+ if (GigAdapter->Block != NULL) {
+ (*GigAdapter->Block) (GigAdapter->Unique_ID, flag);
+ } else {
+ if (gInitializeLock) {
+ EfiInitializeLock (&gLock, TPL_NOTIFY);
+ gInitializeLock = FALSE;
+ }
+
+ if (flag != 0) {
+ EfiAcquireLock (&gLock);
+ } else {
+ EfiReleaseLock (&gLock);
+ }
+ }
+}
+
+VOID
+e1000_MapMem (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT64 VirtualAddress,
+ IN UINT32 Size,
+ OUT UINTN *MappedAddress
+ )
+/*++
+
+Routine Description:
+ Maps a virtual address to a physical address. This is necessary for runtime functionality and also
+ on some platforms that have a chipset that cannot allow DMAs above 4GB.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on.
+ VirtualAddress - Virtual Address of the data buffer to map.
+ Size - Minimum size of the buffer to map.
+ MappedAddress - Pointer to store the address of the mapped buffer.
+Returns:
+
+--*/
+{
+ if (GigAdapter->MapMem != NULL) {
+ (*GigAdapter->MapMem) (
+ GigAdapter->Unique_ID,
+ VirtualAddress,
+ Size,
+ TO_DEVICE,
+ (UINT64) MappedAddress
+ );
+ //
+ // Workaround: on some systems mapmem may not be implemented correctly, so just
+ // pass back the original address
+ //
+ if (*MappedAddress == 0) {
+ *((UINTN*) MappedAddress) = (UINTN) VirtualAddress;
+ }
+ } else {
+ *((UINTN*) MappedAddress) = (UINTN) VirtualAddress;
+ }
+}
+
+VOID
+e1000_UnMapMem (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT64 VirtualAddress,
+ IN UINT32 Size,
+ IN UINT64 MappedAddress
+ )
+/*++
+
+Routine Description:
+ Maps a virtual address to a physical address. This is necessary for runtime functionality and also
+ on some platforms that have a chipset that cannot allow DMAs above 4GB.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on.
+ VirtualAddress - Virtual Address of the data buffer to map.
+ Size - Minimum size of the buffer to map.
+ MappedAddress - Pointer to store the address of the mapped buffer.
+Returns:
+
+--*/
+{
+ if (GigAdapter->UnMapMem != NULL) {
+ (*GigAdapter->UnMapMem) (
+ GigAdapter->Unique_ID,
+ VirtualAddress,
+ Size,
+ TO_DEVICE,
+ (UINT64) MappedAddress
+ );
+ }
+}
+
+VOID
+e1000_MemCopy (
+ IN UINT8* Dest,
+ IN UINT8* Source,
+ IN UINT32 Count
+ )
+/*++
+Routine Description:
+ This is the drivers copy function so it does not need to rely on the BootServices
+ copy which goes away at runtime. This copy function allows 64-bit or 32-bit copies
+ depending on platform architecture. On Itanium we must check that both addresses
+ are naturally aligned before attempting a 64-bit copy.
+
+Arguments:
+ Dest - Destination memory pointer to copy data to.
+ Source - Source memory pointer.
+Returns:
+ VOID
+--*/
+
+{
+ UINT32 BytesToCopy;
+ UINT32 IntsToCopy;
+ UINTN* SourcePtr;
+ UINTN* DestPtr;
+ UINT8* SourceBytePtr;
+ UINT8* DestBytePtr;
+
+
+ IntsToCopy = Count / sizeof(UINTN);
+ BytesToCopy = Count % sizeof(UINTN);
+#ifdef EFI64
+ //
+ // Itanium cannot handle memory accesses that are not naturally aligned. Determine
+ // if 64-bit copy is even possible with these start addresses.
+ //
+ if (( ( ((UINTN) Source) & 0x0007) != 0) || (( ((UINTN) Dest) & 0x0007) != 0) ) {
+ IntsToCopy = 0;
+ BytesToCopy = Count;
+ }
+#endif
+
+ SourcePtr = (UINTN*) Source;
+ DestPtr = (UINTN*) Dest;
+
+ while (IntsToCopy > 0) {
+ *DestPtr = *SourcePtr;
+ SourcePtr++;
+ DestPtr++;
+ IntsToCopy--;
+ }
+
+ //
+ // Copy the leftover bytes.
+ //
+ SourceBytePtr = (UINT8*) SourcePtr;
+ DestBytePtr = (UINT8*) DestPtr;
+ while (BytesToCopy > 0) {
+ *DestBytePtr = *SourceBytePtr;
+ SourceBytePtr++;
+ DestBytePtr++;
+ BytesToCopy--;
+ }
+}
+
+
+BOOLEAN
+e1000_DownShift (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Wait for up to 30 seconds for two pair downshift to complete
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+
+Returns:
+ TRUE if two pair downshift was successful and link was established
+ FALSE otherwise
+
+--*/
+{
+ UINTN i;
+ UINT32 Status;
+
+ DEBUGPRINT (E1000, ("e1000_DownShift: Attempting downshift\n"));
+
+ i = 0;
+ for (i = 0; i < 30; i++) {
+ DelayInMilliseconds (1000);
+ Status = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ DEBUGPRINT(E1000, ("Status = %x\n", Status));
+ if ((Status & E1000_STATUS_LU) != 0) {
+ DEBUGPRINT(E1000, ("Successfully established link\n"));
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+UINTN
+e1000_Statistics (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 DBaddr,
+ UINT16 DBsize
+ )
+/*++
+
+Routine Description:
+ copies the stats from our local storage to the protocol storage.
+ which means it will read our read and clear numbers, so some adding is required before
+ we copy it over to the protocol.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+ DBaddr - The data block address
+ DBsize - The data block size
+
+Returns:
+ PXE Status code
+
+--*/
+{
+ PXE_DB_STATISTICS *DbPtr;
+ struct e1000_hw *hw;
+ struct e1000_hw_stats *st;
+ UINTN stat;
+
+ hw = &GigAdapter->hw;
+ st = &GigAdapter->stats;
+
+#define UPDATE_OR_RESET_STAT(sw_reg, hw_reg) \
+ do { \
+ st->sw_reg = DBaddr ? st->sw_reg + E1000_READ_REG (hw, hw_reg) : 0; \
+ } while (0)
+
+ {
+ UPDATE_OR_RESET_STAT (crcerrs, E1000_CRCERRS);
+ }
+
+ UPDATE_OR_RESET_STAT (gprc, E1000_GPRC);
+ UPDATE_OR_RESET_STAT (bprc, E1000_BPRC);
+ UPDATE_OR_RESET_STAT (mprc, E1000_MPRC);
+ UPDATE_OR_RESET_STAT (roc, E1000_ROC);
+ UPDATE_OR_RESET_STAT (prc64, E1000_PRC64);
+ UPDATE_OR_RESET_STAT (prc127, E1000_PRC127);
+ UPDATE_OR_RESET_STAT (prc255, E1000_PRC255);
+ UPDATE_OR_RESET_STAT (prc511, E1000_PRC511);
+ UPDATE_OR_RESET_STAT (prc1023, E1000_PRC1023);
+ UPDATE_OR_RESET_STAT (prc1522, E1000_PRC1522);
+
+ UPDATE_OR_RESET_STAT (symerrs, E1000_SYMERRS);
+ UPDATE_OR_RESET_STAT (mpc, E1000_MPC);
+ UPDATE_OR_RESET_STAT (scc, E1000_SCC);
+ UPDATE_OR_RESET_STAT (ecol, E1000_ECOL);
+ UPDATE_OR_RESET_STAT (mcc, E1000_MCC);
+ UPDATE_OR_RESET_STAT (latecol, E1000_LATECOL);
+ UPDATE_OR_RESET_STAT (dc, E1000_DC);
+ UPDATE_OR_RESET_STAT (sec, E1000_SEC);
+ UPDATE_OR_RESET_STAT (rlec, E1000_RLEC);
+ UPDATE_OR_RESET_STAT (xonrxc, E1000_XONRXC);
+ UPDATE_OR_RESET_STAT (xontxc, E1000_XONTXC);
+ UPDATE_OR_RESET_STAT (xoffrxc, E1000_XOFFRXC);
+ UPDATE_OR_RESET_STAT (xofftxc, E1000_XOFFTXC);
+ UPDATE_OR_RESET_STAT (fcruc, E1000_FCRUC);
+ UPDATE_OR_RESET_STAT (gptc, E1000_GPTC);
+ UPDATE_OR_RESET_STAT (rnbc, E1000_RNBC);
+ UPDATE_OR_RESET_STAT (ruc, E1000_RUC);
+ UPDATE_OR_RESET_STAT (rfc, E1000_RFC);
+ UPDATE_OR_RESET_STAT (rjc, E1000_RJC);
+ UPDATE_OR_RESET_STAT (tpr, E1000_TPR);
+ UPDATE_OR_RESET_STAT (ptc64, E1000_PTC64);
+ UPDATE_OR_RESET_STAT (ptc127, E1000_PTC127);
+ UPDATE_OR_RESET_STAT (ptc255, E1000_PTC255);
+ UPDATE_OR_RESET_STAT (ptc511, E1000_PTC511);
+ UPDATE_OR_RESET_STAT (ptc1023, E1000_PTC1023);
+ UPDATE_OR_RESET_STAT (ptc1522, E1000_PTC1522);
+ UPDATE_OR_RESET_STAT (mptc, E1000_MPTC);
+ UPDATE_OR_RESET_STAT (bptc, E1000_BPTC);
+
+ //
+ // used for adaptive IFS
+ //
+ hw->mac.tx_packet_delta = E1000_READ_REG (hw, E1000_TPT);
+ st->tpt = DBaddr ? st->tpt + hw->mac.tx_packet_delta : 0;
+ hw->mac.collision_delta = E1000_READ_REG (hw, E1000_COLC);
+ st->colc = DBaddr ? st->colc + hw->mac.collision_delta : 0;
+
+ {
+ UPDATE_OR_RESET_STAT (algnerrc, E1000_ALGNERRC);
+ UPDATE_OR_RESET_STAT (rxerrc, E1000_RXERRC);
+ UPDATE_OR_RESET_STAT (tncrs, E1000_TNCRS);
+ UPDATE_OR_RESET_STAT (cexterr, E1000_CEXTERR);
+ UPDATE_OR_RESET_STAT (tsctc, E1000_TSCTC);
+ UPDATE_OR_RESET_STAT (tsctfc, E1000_TSCTFC);
+ }
+
+ if (!DBaddr) {
+ return PXE_STATCODE_SUCCESS;
+ }
+
+ DbPtr = (PXE_DB_STATISTICS *) (UINTN) DBaddr;
+
+ //
+ // Fill out the OS statistics structure
+ // To Add/Subtract stats, include/delete the lines in pairs.
+ // E.g., adding a new stat would entail adding these two lines:
+ // stat = PXE_STATISTICS_NEW_STAT_XXX; SET_SUPPORT;
+ // DbPtr->Data[stat] = st->xxx;
+ //
+ DbPtr->Supported = 0;
+
+#define SET_SUPPORT(S) \
+ do { \
+ stat = PXE_STATISTICS_##S; \
+ DbPtr->Supported |= (1 << stat); \
+ } while (0)
+#define UPDATE_EFI_STAT(S, b) \
+ do { \
+ SET_SUPPORT (S); \
+ DbPtr->Data[stat] = st->b; \
+ } while (0)
+
+ {
+ UPDATE_EFI_STAT (RX_TOTAL_FRAMES, tpr);
+ }
+
+ UPDATE_EFI_STAT (RX_GOOD_FRAMES, gprc);
+ UPDATE_EFI_STAT (RX_UNDERSIZE_FRAMES, ruc);
+ UPDATE_EFI_STAT (RX_OVERSIZE_FRAMES, roc);
+ UPDATE_EFI_STAT (RX_DROPPED_FRAMES, rnbc);
+ SET_SUPPORT (RX_UNICAST_FRAMES);
+ DbPtr->Data[stat] = (st->gprc - st->bprc - st->mprc);
+ UPDATE_EFI_STAT (RX_BROADCAST_FRAMES, bprc);
+ UPDATE_EFI_STAT (RX_MULTICAST_FRAMES, mprc);
+ SET_SUPPORT (RX_CRC_ERROR_FRAMES);
+ DbPtr->Data[stat] = (st->crcerrs + st->algnerrc);
+ UPDATE_EFI_STAT (TX_TOTAL_FRAMES, tpt);
+ UPDATE_EFI_STAT (TX_GOOD_FRAMES, gptc);
+ SET_SUPPORT (TX_UNICAST_FRAMES);
+ DbPtr->Data[stat] = (st->gptc - st->bptc - st->mptc);
+ UPDATE_EFI_STAT (TX_BROADCAST_FRAMES, bptc);
+ UPDATE_EFI_STAT (TX_MULTICAST_FRAMES, mptc);
+ UPDATE_EFI_STAT (COLLISIONS, colc);
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+
+UINTN
+e1000_Transmit (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 cpb,
+ UINT16 opflags
+ )
+/*++
+
+Routine Description:
+ Takes a command block pointer (cpb) and sends the frame. Takes either one fragment or many
+ and places them onto the wire. Cleanup of the send happens in the function UNDI_Status in DECODE.C
+
+Arguments:
+ GigAdapter - Pointer to the instance data
+ cpb - The command parameter block address. 64 bits since this is Itanium(tm)
+ processor friendly
+ opflags - The operation flags, tells if there is any special sauce on this transmit
+
+Returns:
+ PXE_STATCODE_SUCCESS if the frame goes out,
+ PXE_STATCODE_DEVICE_FAILURE if it didn't
+ PXE_STATCODE_BUSY if they need to call again later.
+
+--*/
+{
+ PXE_CPB_TRANSMIT_FRAGMENTS *TxFrags;
+ PXE_CPB_TRANSMIT *TxBuffer;
+ E1000_TRANSMIT_DESCRIPTOR *TransmitDescriptor;
+ UINT32 i;
+ INT16 WaitMsec;
+
+/* DEBUGPRINT(E1000, ("e1000_Transmit\n"));
+ DEBUGPRINT(E1000, ("TCTL=%X\r\n", E1000_READ_REG(&GigAdapter->hw, E1000_TCTL)));
+ for (i = 0; i < DEFAULT_TX_DESCRIPTORS; i++) {
+ DEBUGPRINT(E1000, ("buffer=%X ", GigAdapter->tx_ring[i].buffer_addr));
+ DEBUGPRINT(E1000, ("len=%X ", GigAdapter->tx_ring[i].lower.flags.length));
+ DEBUGPRINT(E1000, ("cmd=%X ", GigAdapter->tx_ring[i].lower.flags.cmd));
+ DEBUGPRINT(E1000, ("status=%X ", GigAdapter->tx_ring[i].upper.fields.status));
+ DEBUGPRINT(E1000, ("special=%X\n", GigAdapter->tx_ring[i].upper.fields.special));
+ }
+*/
+
+ //
+ // Transmit buffers must be freed by the upper layer before we can transmit any more.
+ //
+ if (GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind] != 0) {
+ DEBUGPRINT(CRITICAL, ("TX buffers have all been used! cur_tx=%d\n", GigAdapter->cur_tx_ind));
+ for (i = 0; i < DEFAULT_TX_DESCRIPTORS; i++) {
+ DEBUGPRINT(CRITICAL, ("%x ", GigAdapter->TxBufferUnmappedAddr[i]));
+ }
+ DEBUGWAIT(CRITICAL);
+
+ //
+ // According to UEFI spec we should return PXE_STATCODE_BUFFER_FULL, but SNP is not implemented to recognize this
+ // callback.
+ //
+ return PXE_STATCODE_QUEUE_FULL;
+ }
+
+ //
+ // Make some short cut pointers so we don't have to worry about typecasting later.
+ // If the TX has fragments we will use the
+ // tx_tpr_f pointer, otherwise the tx_ptr_l (l is for linear)
+ //
+ TxBuffer = (PXE_CPB_TRANSMIT *) (UINTN) cpb;
+ TxFrags = (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb;
+
+ //
+ // quicker pointer to the next available Tx descriptor to use.
+ //
+ TransmitDescriptor = &GigAdapter->tx_ring[GigAdapter->cur_tx_ind];
+
+ //
+ // Opflags will tell us if this Tx has fragments
+ // So far the linear case (the no fragments case, the else on this if) is the majority
+ // of all frames sent.
+ //
+ if (opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) {
+ //
+ // this count cannot be more than 8;
+ //
+ DEBUGPRINT(E1000, ("Fragments %x\n", TxFrags->FragCnt));
+
+ //
+ // for each fragment, give it a descriptor, being sure to keep track of the number used.
+ //
+ for (i = 0; i < TxFrags->FragCnt; i++) {
+ //
+ // Put the size of the fragment in the descriptor
+ //
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind] = TxFrags->FragDesc[i].FragAddr;
+ e1000_MapMem(
+ GigAdapter,
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind],
+ TxFrags->FragDesc[i].FragLen,
+ (UINTN*) &TransmitDescriptor->buffer_addr
+ );
+
+ TransmitDescriptor->lower.flags.length = (UINT16) TxFrags->FragDesc[i].FragLen;
+ TransmitDescriptor->lower.data = (E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS);
+
+ if (GigAdapter->VlanEnable) {
+ DEBUGPRINT (VLAN, ("1: Setting VLAN tag = %d\n", GigAdapter->VlanTag));
+ TransmitDescriptor->upper.fields.special = GigAdapter->VlanTag;
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_VLE;
+ }
+
+ //
+ // If this is the last fragment we must also set the EOP bit
+ //
+ if ((i + 1) == TxFrags->FragCnt) {
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_EOP;
+ }
+ //
+ // move our software counter passed the frame we just used, watching for wrapping
+ //
+ DEBUGPRINT(E1000, ("Advancing TX pointer %x\n", GigAdapter->cur_tx_ind));
+ GigAdapter->cur_tx_ind++;
+ if (GigAdapter->cur_tx_ind >= DEFAULT_TX_DESCRIPTORS) {
+ GigAdapter->cur_tx_ind = 0;
+ }
+ TransmitDescriptor = &GigAdapter->tx_ring[GigAdapter->cur_tx_ind];
+ }
+ } else {
+ DEBUGPRINT(E1000, ("No Fragments\n"));
+
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind] = TxBuffer->FrameAddr;
+ e1000_MapMem(
+ GigAdapter,
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind],
+ TxBuffer->DataLen + TxBuffer->MediaheaderLen,
+ (UINTN*) &TransmitDescriptor->buffer_addr
+ );
+
+ DEBUGPRINT(E1000, ("Packet buffer at %x\n", TransmitDescriptor->buffer_addr));
+
+ //
+ // Set the proper bits to tell the chip that this is the last descriptor in the send,
+ // and be sure to tell us when its done.
+ // EOP - End of packet
+ // IFCs - Insert FCS (Ethernet CRC)
+ // RS - Report Status
+ //
+ TransmitDescriptor->lower.data = (E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS);
+ TransmitDescriptor->upper.fields.status = 0;
+ if (GigAdapter->VlanEnable) {
+ DEBUGPRINT (VLAN, ("2: Setting VLAN tag = %d\n", GigAdapter->VlanTag));
+ TransmitDescriptor->upper.fields.special = GigAdapter->VlanTag;
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_VLE;
+ }
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_EOP;
+ TransmitDescriptor->lower.flags.length = (UINT16) ((UINT16) TxBuffer->DataLen + TxBuffer->MediaheaderLen);
+
+ DEBUGPRINT(E1000, ("BuffAddr=%x, ", TransmitDescriptor->buffer_addr));
+ DEBUGPRINT(E1000, ("Cmd=%x,", TransmitDescriptor->lower.flags.cmd));
+ DEBUGPRINT(E1000, ("Cso=%x,", TransmitDescriptor->lower.flags.cso));
+ DEBUGPRINT(E1000, ("Len=%x,", TransmitDescriptor->lower.flags.length));
+ DEBUGPRINT(E1000, ("Status=%x,", TransmitDescriptor->upper.fields.status));
+ DEBUGPRINT(E1000, ("Special=%x,", TransmitDescriptor->upper.fields.special));
+ DEBUGPRINT(E1000, ("Css=%x\n", TransmitDescriptor->upper.fields.css));
+
+ //
+ // In the zero fragment case, we need to add the header size to the payload size to accurately tell the hw how big is the packet.
+ //
+ //
+ // Move our software counter passed the frame we just used, watching for wrapping
+ //
+ GigAdapter->cur_tx_ind++;
+ if (GigAdapter->cur_tx_ind >= DEFAULT_TX_DESCRIPTORS) {
+ GigAdapter->cur_tx_ind = 0;
+ }
+ }
+
+#if (DBG_LVL&TX)
+ DEBUGPRINT(TX, ("Packet length = %d\n", TransmitDescriptor->lower.flags.length));
+ DEBUGPRINT(TX, ("Packet data:\n"));
+ for (i = 0; i < 32; i++) {
+ DEBUGPRINT(TX, ("%x ", ((UINT16 *) ((UINTN) TransmitDescriptor->buffer_addr))[i]));
+ }
+#endif
+
+ //
+ // Turn on the blocking function so we don't get swapped out
+ // Then move the Tail pointer so the HW knows to start processing the TX we just setup.
+ //
+ DEBUGWAIT(E1000);
+ e1000_BlockIt (GigAdapter, TRUE);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDT(0), GigAdapter->cur_tx_ind);
+ e1000_BlockIt (GigAdapter, FALSE);
+
+ //
+ // If the opflags tells us to wait for the packet to hit the wire, we will wait.
+ //
+ if ((opflags & PXE_OPFLAGS_TRANSMIT_BLOCK) != 0) {
+ WaitMsec = 1000;
+
+ while ((TransmitDescriptor->upper.fields.status & E1000_TXD_STAT_DD) == 0) {
+ DelayInMilliseconds (10);
+ WaitMsec -= 10;
+ if (WaitMsec <= 0) {
+ break;
+ }
+ }
+
+ //
+ // If we waited for a while, and it didn't finish then the HW must be bad.
+ //
+ if ((TransmitDescriptor->upper.fields.status & E1000_TXD_STAT_DD) == 0) {
+ DEBUGPRINT(CRITICAL, ("ERROR: Network device transmit failure\n"));
+ return PXE_STATCODE_DEVICE_FAILURE;
+ } else {
+ DEBUGPRINT(E1000, ("Transmit success\n"));
+ }
+ }
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+UINTN
+e1000_Receive (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 cpb,
+ UINT64 db
+ )
+/*++
+
+Routine Description:
+ Copies the frame from our internal storage ring (As pointed to by GigAdapter->rx_ring) to the command block
+ passed in as part of the cpb parameter. The flow: Ack the interrupt, setup the pointers, find where the last
+ block copied is, check to make sure we have actually received something, and if we have then we do a lot of work.
+ The packet is checked for errors, size is adjusted to remove the CRC, adjust the amount to copy if the buffer is smaller
+ than the packet, copy the packet to the EFI buffer, and then figure out if the packet was targetted at us, broadcast, multicast
+ or if we are all promiscuous. We then put some of the more interesting information (protocol, src and dest from the packet) into the
+ db that is passed to us. Finally we clean up the frame, set the return value to _SUCCESS, and inc the cur_rx_ind, watching
+ for wrapping. Then with all the loose ends nicely wrapped up, fade to black and return.
+
+Arguments:
+ GigAdapter - pointer to the driver data
+ cpb - Pointer (Ia-64 friendly) to the command parameter block. The frame will be placed inside of it.
+ db - The data buffer. The out of band method of passing pre-digested information to the protocol.
+
+Returns:
+ PXE_STATCODE, either _NO_DATA if there is no data, or _SUCCESS if we passed the goods to the protocol.
+
+--*/
+{
+ PXE_CPB_RECEIVE *CpbReceive;
+ PXE_DB_RECEIVE *DbReceive;
+ PXE_FRAME_TYPE PacketType;
+ E1000_RECEIVE_DESCRIPTOR *ReceiveDescriptor;
+ ETHER_HEADER *EtherHeader;
+ PXE_STATCODE StatCode;
+ UINT16 TempLen;
+#if (DBG_LVL&CRITICAL)
+#if (DBG_LVL&RX)
+ UINT32 Rdh;
+ UINT32 Rdt;
+#endif
+#endif
+
+ PacketType = PXE_FRAME_TYPE_NONE;
+ StatCode = PXE_STATCODE_NO_DATA;
+
+
+ //
+ // acknowledge the interrupts
+ //
+ E1000_READ_REG (&GigAdapter->hw, E1000_ICR);
+
+/*
+ DEBUGPRINT(E1000, ("e1000_Receive\n"));
+ DEBUGPRINT(E1000, ("RCTL=%X ", E1000_READ_REG(&GigAdapter->hw, E1000_RCTL)));
+ DEBUGPRINT(E1000, ("RDH0=%x ", (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_RDH(0))));
+ DEBUGPRINT(E1000, ("RDT0=%x\n", (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_RDT(0))));
+ DEBUGPRINT(E1000, ("RDBAL=%x desc=%X\n", E1000_READ_REG (&GigAdapter->hw, E1000_RDBAL),
+ (UINTN) GigAdapter->rx_ring));
+ rar_low = E1000_READ_REG_ARRAY(&GigAdapter->hw, E1000_RA, 0);
+ rar_high = E1000_READ_REG_ARRAY(&GigAdapter->hw, E1000_RA, 1);
+ DEBUGPRINT(E1000, ("Receive Addr = %X %X\n", rar_high, rar_low));
+
+ for (i = 0; i < DEFAULT_RX_DESCRIPTORS; i++) {
+ DEBUGPRINT(E1000, ("buffer=%X ", GigAdapter->rx_ring[i].buffer_addr));
+ DEBUGPRINT(E1000, ("csum=%X ", GigAdapter->rx_ring[i].csum));
+ DEBUGPRINT(E1000, ("special=%X ", GigAdapter->rx_ring[i].special));
+ DEBUGPRINT(E1000, ("status=%X ", GigAdapter->rx_ring[i].status));
+ DEBUGPRINT(E1000, ("len=%X ", GigAdapter->rx_ring[i].length));
+ DEBUGPRINT(E1000, ("err=%X\n", GigAdapter->rx_ring[i].errors));
+ }
+*/
+
+ //
+ // Make quick copies of the buffer pointers so we can use them without fear of corrupting the originals
+ //
+ CpbReceive = (PXE_CPB_RECEIVE *) (UINTN) cpb;
+ DbReceive = (PXE_DB_RECEIVE *) (UINTN) db;
+
+ //
+ // Get a pointer to the buffer that should have a rx in it, IF one is really there.
+ //
+ ReceiveDescriptor = &GigAdapter->rx_ring[GigAdapter->cur_rx_ind];
+
+#if (DBG_LVL&CRITICAL)
+#if (DBG_LVL&RX)
+ if (ReceiveDescriptor->buffer_addr != GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind]) {
+ DEBUGPRINT(CRITICAL, ("GetStatus ERROR: Rx buff mismatch on desc %d: expected %X, actual %X\n",
+ GigAdapter->cur_rx_ind,
+ GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind],
+ ReceiveDescriptor->buffer_addr
+ ));
+ }
+
+ Rdt = E1000_READ_REG (&GigAdapter->hw, E1000_RDT(0));
+ Rdh = E1000_READ_REG (&GigAdapter->hw, E1000_RDH(0));
+ if (Rdt == Rdh) {
+ DEBUGPRINT(CRITICAL, ("Receive ERROR: RX Buffers Full!\n"));
+ }
+#endif
+#endif
+
+ if ((ReceiveDescriptor->status & (E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD)) != 0) {
+ //
+ // Just to make sure we don't try to copy a zero length, only copy a positive sized packet.
+ //
+ if ((ReceiveDescriptor->length != 0) && (ReceiveDescriptor->errors == 0)) {
+
+ //
+ // If the buffer passed us is smaller than the packet, only copy the size of the buffer.
+ //
+ TempLen = ReceiveDescriptor->length;
+ if (ReceiveDescriptor->length > (INT16) CpbReceive->BufferLen) {
+ TempLen = (UINT16) CpbReceive->BufferLen;
+ }
+
+ //
+ // Copy the packet from our list to the EFI buffer.
+ //
+ e1000_MemCopy ((UINT8 *) (UINTN) CpbReceive->BufferAddr, (UINT8 *) (UINTN) ReceiveDescriptor->buffer_addr, TempLen);
+
+#if (DBG_LVL & RX)
+ DEBUGPRINT(RX, ("Packet Data \n"));
+ for (i = 0; i < TempLen; i++) {
+ DEBUGPRINT(RX, ("%x ", PacketPtr[i]));
+ }
+ DEBUGPRINT(RX, ("\n"));
+#endif
+ //
+ // Fill the DB with needed information
+ //
+ DbReceive->FrameLen = ReceiveDescriptor->length; // includes header
+ DbReceive->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
+
+ EtherHeader = (ETHER_HEADER *) (UINTN) ReceiveDescriptor->buffer_addr;
+
+ //
+ // Figure out if the packet was meant for us, was a broadcast, multicast or we
+ // recieved a frame in promiscuous mode.
+ //
+ if (E1000_COMPARE_MAC(EtherHeader->dest_addr, GigAdapter->hw.mac.addr) == 0) {
+ PacketType = PXE_FRAME_TYPE_UNICAST;
+ DEBUGPRINT(E1000, ("unicast packet for us.\n"));
+ } else
+ if (E1000_COMPARE_MAC(EtherHeader->dest_addr, GigAdapter->BroadcastNodeAddress) == 0) {
+ PacketType = PXE_FRAME_TYPE_BROADCAST;
+ DEBUGPRINT(E1000, ("broadcast packet.\n"));
+ } else {
+ //
+ // That leaves multicast or we must be in promiscuous mode. Check for the Mcast bit in the address.
+ // otherwise its a promiscuous receive.
+ //
+ if ((EtherHeader->dest_addr[0] & 1) == 1) {
+ PacketType = PXE_FRAME_TYPE_MULTICAST;
+ DEBUGPRINT(E1000, ("multicast packet.\n"));
+ } else {
+ PacketType = PXE_FRAME_TYPE_PROMISCUOUS;
+ DEBUGPRINT(E1000, ("unicast promiscuous.\n"));
+ }
+ }
+ DbReceive->Type = PacketType;
+ DEBUGPRINT(E1000, ("PacketType %x\n", PacketType));
+
+ //
+ // Put the protocol (UDP, TCP/IP) in the data buffer.
+ //
+ DbReceive->Protocol = EtherHeader->type;
+ DEBUGPRINT(E1000, ("protocol %x\n", EtherHeader->type));
+
+ E1000_COPY_MAC(DbReceive->SrcAddr, EtherHeader->src_addr);
+ E1000_COPY_MAC(DbReceive->DestAddr, EtherHeader->dest_addr);
+
+ StatCode = PXE_STATCODE_SUCCESS;
+ } else {
+ DEBUGPRINT(CRITICAL, ("ERROR: Received zero sized packet or receive error!\n"));
+ }
+ //
+ // Clean up the packet
+ //
+ ReceiveDescriptor->status = 0;
+ ReceiveDescriptor->length = 0;
+
+ //
+ // Move the current cleaned buffer pointer, being careful to wrap it as needed. Then update the hardware,
+ // so it knows that an additional buffer can be used.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), GigAdapter->cur_rx_ind);
+ GigAdapter->cur_rx_ind++;
+ if (GigAdapter->cur_rx_ind == DEFAULT_RX_DESCRIPTORS) {
+ GigAdapter->cur_rx_ind = 0;
+ }
+ }
+
+ return StatCode;
+};
+
+UINTN
+e1000_SetInterruptState (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Allows the protocol to control our interrupt behaviour.
+
+Arguments:
+ GigAdapter - Pointer to the driver structure
+
+Returns:
+ PXE_STATCODE_SUCCESS
+
+--*/
+{
+ UINT32 SetIntMask;
+
+ SetIntMask = 0;
+
+ DEBUGPRINT(E1000, ("e1000_SetInterruptState\n"));
+
+ //
+ // Start with no Interrupts.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_IMC, 0xFFFFFFFF);
+
+ //
+ // Mask the RX interrupts
+ //
+ if (GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) {
+ SetIntMask = (E1000_ICR_RXT0 | E1000_ICR_RXSEQ | E1000_ICR_RXDMT0 | E1000_ICR_RXO | E1000_ICR_RXCFG | SetIntMask);
+ DEBUGPRINT(E1000, ("Mask the RX interrupts\n"));
+ }
+
+ //
+ // Mask the TX interrupts
+ //
+ if (GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) {
+ SetIntMask = (E1000_ICR_TXDW | E1000_ICR_TXQE | SetIntMask);
+ DEBUGPRINT(E1000, ("Mask the TX interrupts\n"));
+ }
+
+ //
+ // Mask the CMD interrupts
+ //
+ if (GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) {
+ SetIntMask =
+ (
+ E1000_ICR_GPI_EN0 |
+ E1000_ICR_GPI_EN1 |
+ E1000_ICR_GPI_EN2 |
+ E1000_ICR_GPI_EN3 |
+ E1000_ICR_LSC |
+ SetIntMask
+ );
+ DEBUGPRINT(E1000, ("Mask the CMD interrupts\n"));
+ }
+
+ //
+ // Now we have all the Ints we want, so let the hardware know.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_IMS, SetIntMask);
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Stop the hardware and put it all (including the PHY) into a known good state.
+
+Arguments:
+ GigAdapter - Pointer to the driver structure
+
+Returns:
+ PXE_STATCODE_SUCCESS
+
+--*/
+{
+ UINT32 Reg;
+
+ DEBUGPRINT(E1000, ("e1000_Shutdown - adapter stop\n"));
+
+ //
+ // Disable the transmit and receive DMA
+ //
+ e1000_ReceiveDisable (GigAdapter);
+
+ Reg = E1000_READ_REG (&GigAdapter->hw, E1000_TCTL);
+ Reg = (Reg & ~E1000_TCTL_EN);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TCTL, Reg);
+
+ //
+ // Disable the receive unit so the hardware does not continue to DMA packets to memory.
+ // Also release the software semaphore.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_SWSM, 0);
+ e1000_PciFlush(&GigAdapter->hw);
+
+ //
+ // This delay is to ensure in flight DMA and receive descriptor flush
+ // have time to complete.
+ //
+ DelayInMilliseconds (10);
+
+ GigAdapter->ReceiveStarted = FALSE;
+ GigAdapter->Rx_Filter = 0;
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+UINTN
+e1000_Reset (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 OpFlags
+ )
+/*++
+
+Routine Description:
+ Resets the hardware and put it all (including the PHY) into a known good state.
+
+Arguments:
+ GigAdapter - The pointer to our context data
+ OpFlags - The information on what else we need to do.
+
+Returns:
+ PXE_STATCODE_SUCCESS
+
+--*/
+{
+
+ UINT32 TempReg;
+
+ DEBUGPRINT(E1000, ("e1000_Reset\n"));
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+
+ //
+ // Spanning Tree Workaround:
+ // If link is up and valid then we will not do a PHY reset. This ensures
+ // we do not need to drop link and spanning tree does not need to restart.
+ // If link is up and we see Gigabit Half-Duplex then we know link is invalid
+ // and we need to do a PHY reset.
+ //
+ GigAdapter->hw.phy.reset_disable = TRUE;
+
+ if ((TempReg & E1000_STATUS_LU) != 0) {
+ if (((TempReg & E1000_STATUS_FD) == 0) && ((TempReg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_1000)) {
+ DEBUGPRINT(E1000, ("BAD LINK - 1Gig/Half - Enabling PHY reset\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ //
+ // Since link is in a bad state we also need to make sure that we do a full reset down below
+ //
+ GigAdapter->HwInitialized = FALSE;
+ }
+ }
+
+ //
+ // Put the E1000 into a known state by resetting the transmit
+ // and receive units of the E1000 and masking/clearing all
+ // interrupts.
+ // If the hardware has already been started then don't bother with a reset
+ // We want to make sure we do not have to restart autonegotiation and two-pair
+ // downshift.
+ //
+ if (GigAdapter->HwInitialized == FALSE) {
+ e1000_reset_hw (&GigAdapter->hw);
+
+ //
+ // Now that the structures are in place, we can configure the hardware to use it all.
+ //
+ if (e1000_init_hw (&GigAdapter->hw) == 0) {
+ DEBUGPRINT(E1000, ("e1000_init_hw success\n"));
+ } else {
+ DEBUGPRINT(CRITICAL, ("Hardware Init failed\n"));
+ return PXE_STATCODE_NOT_STARTED;
+ }
+ }
+ else
+ {
+ DEBUGPRINT(E1000, ("Skipping adapter reset\n"));
+ }
+
+
+ if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
+ UINT16 SaveFilter;
+
+ SaveFilter = GigAdapter->Rx_Filter;
+
+ //
+ // if we give the filter same as Rx_Filter, this routine will not set mcast list
+ // (it thinks there is no change)
+ // to force it, we will reset that flag in the Rx_Filter
+ //
+ GigAdapter->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ e1000_SetFilter (GigAdapter, SaveFilter, (UINT64) 0, (UINT32) 0);
+ }
+
+ if (OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) {
+ GigAdapter->int_mask = 0; // disable the interrupts
+ }
+
+ e1000_SetInterruptState (GigAdapter);
+
+ return PXE_STATCODE_SUCCESS;
+}
+
+VOID
+e1000_SetSpeedDuplex(
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ GigAdapter - Sets the force speed and duplex settings for the adapter based on
+ EEPROM settings and data set by the SNP
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ VOID
+
+--*/
+{
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+
+ DEBUGPRINT(E1000, ("e1000_SetSpeedDuplex\n"));
+
+ //
+ // Copy forced speed and duplex settings to shared code structure
+ //
+ if ((GigAdapter->LinkSpeed == 10) && (GigAdapter->DuplexMode == PXE_FORCE_HALF_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 10-Half\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ if ((GigAdapter->LinkSpeed == 100) && (GigAdapter->DuplexMode == PXE_FORCE_HALF_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 100-Half\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ if ((GigAdapter->LinkSpeed == 10) && (GigAdapter->DuplexMode == PXE_FORCE_FULL_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 10-Full\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ if ((GigAdapter->LinkSpeed == 100) && (GigAdapter->DuplexMode == PXE_FORCE_FULL_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 100-Full\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ //
+ // Check for forced speed and duplex
+ // The EEPROM settings will override settings passed by the SNP
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ if(E1000_READ_REG(&GigAdapter->hw, E1000_STATUS) & E1000_STATUS_FUNC_1) {
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ } else {
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ }
+
+ e1000_read_nvm(&GigAdapter->hw, SetupOffset, 1, &SetupWord);
+ e1000_read_nvm(&GigAdapter->hw, ConfigOffset, 1, &CustomConfigWord);
+
+ if ((CustomConfigWord & SIG_MASK) == SIG) {
+ switch (SetupWord & (FSP_MASK | FDP_FULL_DUPLEX_BIT))
+ {
+ case (FDP_FULL_DUPLEX_BIT | FSP_100MBS):
+ DEBUGPRINT(E1000, ("Forcing 100 Full from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ case (FDP_FULL_DUPLEX_BIT | FSP_10MBS):
+ DEBUGPRINT(E1000, ("Forcing 10 Full from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ case (FSP_100MBS):
+ DEBUGPRINT(E1000, ("Forcing 100 Half from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ case (FSP_10MBS):
+ DEBUGPRINT(E1000, ("Forcing 10 Half from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ default:
+ GigAdapter->hw.mac.autoneg = 1;
+ break;
+ }
+ }
+}
+
+
+EFI_STATUS
+e1000_FirstTimeInit (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This function is called as early as possible during driver start to ensure the
+ hardware has enough time to autonegotiate when the real SNP device initialize call
+ is made.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ EFI_STATUS
+
+--*/
+{
+ PCI_CONFIG_HEADER *PciConfigHeader;
+ UINT32 *TempBar;
+ UINT8 BarIndex;
+ EFI_STATUS Status;
+ UINT32 ScStatus;
+ UINT32 Reg;
+ UINT16 i;
+
+ DEBUGPRINT(E1000, ("e1000_FirstTimeInit\n"));
+
+ GigAdapter->DriverBusy = FALSE;
+
+ //
+ // Read all the registers from the device's PCI Configuration space
+ //
+ GigAdapter->PciIo->Pci.Read (
+ GigAdapter->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ MAX_PCI_CONFIG_LEN,
+ GigAdapter->PciConfig
+ );
+
+ PciConfigHeader = (PCI_CONFIG_HEADER *) GigAdapter->PciConfig;
+
+ //
+ // Enumerate through the PCI BARs for the device to determine which one is
+ // the IO BAR. Save the index of the BAR into the adapter info structure.
+ //
+ TempBar = &PciConfigHeader->BaseAddressReg_0;
+ for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
+ DEBUGPRINT(E1000, ("BAR = %X\n", *TempBar));
+ if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {
+ //
+ // This is a 64-bit memory bar, skip this and the
+ // next bar as well.
+ //
+ TempBar++;
+ }
+
+ //
+ // Find the IO BAR and save it's number into IoBar
+ //
+ if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {
+ //
+ // Here is the IO Bar - save it to the Gigabit adapter struct.
+ //
+ GigAdapter->IoBarIndex = BarIndex;
+ break;
+ }
+
+ //
+ // Advance the pointer to the next bar in PCI config space
+ //
+ TempBar++;
+ }
+
+ GigAdapter->PciIo->GetLocation (
+ GigAdapter->PciIo,
+ &GigAdapter->Segment,
+ &GigAdapter->Bus,
+ &GigAdapter->Device,
+ &GigAdapter->Function
+ );
+
+ DEBUGPRINT(INIT, ("GigAdapter->IoBarIndex = %X\n", GigAdapter->IoBarIndex));
+ DEBUGPRINT(INIT, ("PCI Command Register = %X\n", PciConfigHeader->Command));
+ DEBUGPRINT(INIT, ("PCI Status Register = %X\n", PciConfigHeader->Status));
+ DEBUGPRINT(INIT, ("PCI VendorID = %X\n", PciConfigHeader->VendorID));
+ DEBUGPRINT(INIT, ("PCI DeviceID = %X\n", PciConfigHeader->DeviceID));
+ DEBUGPRINT(INIT, ("PCI SubVendorID = %X\n", PciConfigHeader->SubVendorID));
+ DEBUGPRINT(INIT, ("PCI SubSystemID = %X\n", PciConfigHeader->SubSystemID));
+ DEBUGPRINT(INIT, ("PCI Segment = %X\n", GigAdapter->Segment));
+ DEBUGPRINT(INIT, ("PCI Bus = %X\n", GigAdapter->Bus));
+ DEBUGPRINT(INIT, ("PCI Device = %X\n", GigAdapter->Device));
+ DEBUGPRINT(INIT, ("PCI Function = %X\n", GigAdapter->Function));
+
+ ZeroMem (GigAdapter->BroadcastNodeAddress, PXE_MAC_LENGTH);
+ SetMem (GigAdapter->BroadcastNodeAddress, PXE_HWADDR_LEN_ETHER, 0xFF);
+
+ //
+ // Initialize all parameters needed for the shared code
+ //
+ GigAdapter->hw.hw_addr = (UINT8*) (UINTN) PciConfigHeader->BaseAddressReg_0;
+ GigAdapter->hw.back = GigAdapter;
+ GigAdapter->hw.vendor_id = PciConfigHeader->VendorID;
+ GigAdapter->hw.device_id = PciConfigHeader->DeviceID;
+ GigAdapter->hw.revision_id = (UINT8) PciConfigHeader->RevID;
+ GigAdapter->hw.subsystem_vendor_id = PciConfigHeader->SubVendorID;
+ GigAdapter->hw.subsystem_device_id = PciConfigHeader->SubSystemID;
+ GigAdapter->hw.revision_id = (UINT8) PciConfigHeader->RevID;
+
+ GigAdapter->hw.mac.autoneg = TRUE;
+ GigAdapter->hw.fc.current_mode = e1000_fc_full;
+ GigAdapter->hw.fc.requested_mode = e1000_fc_full;
+
+ GigAdapter->hw.phy.autoneg_wait_to_complete = FALSE;
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.phy.autoneg_advertised = E1000_ALL_SPEED_DUPLEX;
+ GigAdapter->hw.phy.autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ //
+ // We need to set the IO bar to zero for the shared code because the EFI PCI protocol
+ // gets the BAR for us.
+ //
+ GigAdapter->hw.io_base = 0;
+
+ //
+ //
+ // This variable is set only to make the flash shared code work on ICH8.
+ // Set to 1 because the flash BAR will always be BAR 1.
+ //
+ GigAdapter->hw.flash_address = (UINT8*) ((UINTN)1);
+
+ if (e1000_set_mac_type (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Unsupported MAC type!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (e1000_setup_init_funcs (&GigAdapter->hw, TRUE) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("e1000_setup_init_funcs failed!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Reg = E1000_READ_REG(&GigAdapter->hw, E1000_CTRL_EXT);
+ if ((Reg & E1000_CTRL_EXT_DRV_LOAD) != 0) {
+ DEBUGPRINT (CRITICAL, ("iSCSI Boot detected on port!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(E1000, ("Calling e1000_get_bus_info\n"));
+ if (e1000_get_bus_info (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Could not read bus information\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(E1000, ("Calling e1000_read_mac_addr\n"));
+ if (e1000_read_mac_addr (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Could not read MAC address\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(INIT, ("MAC Address: "));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(INIT, ("%2x ", GigAdapter->hw.mac.perm_addr[i]));
+ }
+ DEBUGPRINT(INIT, ("\n"));
+
+
+ ScStatus = e1000_reset_hw (&GigAdapter->hw);
+ if (ScStatus != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("e1000_reset_hw returns %d\n", ScStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Now that the structures are in place, we can configure the hardware to use it all.
+ //
+ ScStatus = e1000_init_hw (&GigAdapter->hw);
+ if (ScStatus == E1000_SUCCESS) {
+ DEBUGPRINT(E1000, ("e1000_init_hw success\n"));
+ Status = EFI_SUCCESS;
+ GigAdapter->HwInitialized = TRUE;
+ } else {
+ DEBUGPRINT(CRITICAL, ("Hardware Init failed status=%x\n", ScStatus));
+ GigAdapter->HwInitialized = FALSE;
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ //
+ // According to EAS the transmit and receive head and tail can only be written by
+ // software after a hardware reset and before enabling transmit and receive units.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDH(0), 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDH(0), 0);
+ GigAdapter->cur_tx_ind = 0;
+ GigAdapter->xmit_done_head = 0;
+ GigAdapter->cur_rx_ind = 0;
+
+#ifndef NO_82571_SUPPORT
+ //
+ // On 82571 based adapters if either port is reset then the MAC address will be loaded into the EEPROM
+ // If the user overrides the default MAC address using the StnAddr command then the 82571 will reset the MAC address
+ // the next time either port is reset. This check resets the MAC address to the default value specified by the user.
+ //
+ if (GigAdapter->hw.mac.type == e1000_82571 && GigAdapter->MacAddrOverride) {
+ DEBUGPRINT(E1000, ("RESETING STATION ADDRESS\n"));
+ e1000_rar_set (&GigAdapter->hw, GigAdapter->hw.mac.addr, 0);
+ }
+#endif
+
+ Reg = E1000_READ_REG(&GigAdapter->hw, E1000_CTRL_EXT);
+ Reg |= E1000_CTRL_EXT_DRV_LOAD;
+ E1000_WRITE_REG(&GigAdapter->hw, E1000_CTRL_EXT, Reg);
+
+ return Status;
+};
+
+
+PXE_STATCODE
+e1000_Inititialize (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Initializes the gigabit adapter, setting up memory addresses, MAC Addresses,
+ Type of card, etc.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ PXE_STATCODE
+
+--*/
+{
+ PXE_STATCODE PxeStatcode;
+
+ DEBUGPRINT(E1000, ("e1000_Inititialize\n"));
+
+ PxeStatcode = PXE_STATCODE_SUCCESS;
+
+ ZeroMem ((VOID *) ((UINTN) GigAdapter->MemoryPtr), MEMORY_NEEDED);
+
+
+ DEBUGWAIT (E1000);
+
+ e1000_SetSpeedDuplex(GigAdapter);
+
+ //
+ // If the hardware has already been initialized then don't bother with a reset
+ // We want to make sure we do not have to restart autonegotiation and two-pair
+ // downshift.
+ //
+ if (GigAdapter->HwInitialized == FALSE) {
+ DEBUGPRINT(E1000, ("Initializing hardware!\n"));
+
+ if (e1000_init_hw (&GigAdapter->hw) == 0) {
+ DEBUGPRINT(E1000, ("e1000_init_hw success\n"));
+ PxeStatcode = PXE_STATCODE_SUCCESS;
+ GigAdapter->HwInitialized = TRUE;
+ } else {
+ DEBUGPRINT(CRITICAL, ("Hardware Init failed\n"));
+ PxeStatcode = PXE_STATCODE_NOT_STARTED;
+ }
+ }
+ else
+ {
+ DEBUGPRINT(E1000, ("Skipping adapter reset\n"));
+ PxeStatcode = PXE_STATCODE_SUCCESS;
+ }
+
+ if (PxeStatcode == PXE_STATCODE_SUCCESS) {
+ e1000_TxRxConfigure (GigAdapter);
+ }
+
+ //
+ // Re-read the MAC address. The CLP configured MAC address is being reset by
+ // hardware to the factory address after init, so we need to reset it here.
+ //
+ if (e1000_read_mac_addr (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Could not read MAC address.\n"));
+ }
+
+ DEBUGWAIT (E1000);
+
+ return PxeStatcode;
+};
+
+VOID
+e1000_TxRxConfigure (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Initializes the transmit and receive resources for the adapter.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ VOID
+
+--*/
+{
+ UINT32 TempReg;
+ UINT32 *MemPtr;
+ UINT16 i;
+
+ DEBUGPRINT(E1000, ("e1000_TxRxConfigure\n"));
+
+ e1000_ReceiveDisable(GigAdapter);
+
+ //
+ // Setup the receive ring
+ //
+ GigAdapter->rx_ring = (E1000_RECEIVE_DESCRIPTOR *) (UINTN)
+ ( (GigAdapter->MemoryPtr + BYTE_ALIGN_64) & 0xFFFFFFFFFFFFFF80 );
+
+ //
+ // Setup TX ring
+ //
+ GigAdapter->tx_ring = (E1000_TRANSMIT_DESCRIPTOR *) ((UINT8 *) GigAdapter->rx_ring + (sizeof (E1000_RECEIVE_DESCRIPTOR) * DEFAULT_RX_DESCRIPTORS));
+ DEBUGPRINT(E1000, (
+ "Rx Ring %x Tx Ring %X RX size %X \n",
+ GigAdapter->rx_ring,
+ GigAdapter->tx_ring,
+ (sizeof (E1000_RECEIVE_DESCRIPTOR) * DEFAULT_RX_DESCRIPTORS)
+ ));
+
+ ZeroMem ((VOID *) GigAdapter->TxBufferUnmappedAddr, DEFAULT_TX_DESCRIPTORS * sizeof(UINT64));
+
+ //
+ // Since we already have the size of the TX Ring, use it to setup the local receive buffers
+ //
+ GigAdapter->local_rx_buffer = (LOCAL_RX_BUFFER *) ((UINT8 *) GigAdapter->tx_ring + (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS));
+ DEBUGPRINT(E1000, (
+ "Tx Ring %x Added %x\n",
+ GigAdapter->tx_ring,
+ ((UINT8 *) GigAdapter->tx_ring + (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS))
+ ));
+ DEBUGPRINT(E1000, (
+ "Local Rx Buffer %X size %X\n",
+ GigAdapter->local_rx_buffer,
+ (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS)
+ ));
+
+ //
+ // now to link the RX Ring to the local buffers
+ //
+ for (i = 0; i < DEFAULT_RX_DESCRIPTORS; i++) {
+ GigAdapter->rx_ring[i].buffer_addr = (UINT64) ((UINTN)GigAdapter->local_rx_buffer[i].RxBuffer);
+ GigAdapter->DebugRxBuffer[i] = GigAdapter->rx_ring[i].buffer_addr;
+ GigAdapter->rx_ring[i].status = E1000_RXD_STAT_IXSM;
+ DEBUGPRINT(E1000, ("Rx Local Buffer %X\n", (GigAdapter->rx_ring[i]).buffer_addr));
+ }
+ //
+ // Setup the RDBA, RDLEN
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDBAL(0), (UINT32) (UINTN) (GigAdapter->rx_ring));
+
+#if 0 //OM
+ //
+ // Set the MemPtr to the high dword of the rx_ring so we can store it in RDBAH0.
+ // Right shifts do not seem to work with the EFI compiler so we do it like this for now.
+ //
+ MemAddr = (UINT64) (UINTN) GigAdapter->rx_ring;
+ MemPtr = &((UINT32) MemAddr);
+ MemPtr++;
+#else
+ MemPtr = (UINT32*)(((UINTN)GigAdapter->rx_ring) >> 32);
+#endif
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDBAH(0), *MemPtr);
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDLEN(0), (sizeof (E1000_RECEIVE_DESCRIPTOR) * DEFAULT_RX_DESCRIPTORS));
+
+ DEBUGPRINT(E1000, ("Rdbal0 %X\n", (UINT32) E1000_READ_REG(&GigAdapter->hw, E1000_RDBAL(0))));
+ DEBUGPRINT(E1000, ("RdBah0 %X\n", (UINT32) E1000_READ_REG(&GigAdapter->hw, E1000_RDBAH(0))));
+ DEBUGPRINT(E1000, ("Rx Ring %X\n", GigAdapter->rx_ring));
+ //
+ // Set the transmit tail equal to the head pointer (we do not want hardware to try to
+ // transmit packets yet).
+ //
+ GigAdapter->cur_tx_ind = (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_TDH(0));
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDT(0), GigAdapter->cur_tx_ind);
+ GigAdapter->xmit_done_head = GigAdapter->cur_tx_ind;
+
+ GigAdapter->cur_rx_ind = (UINT16) E1000_READ_REG(&GigAdapter->hw, E1000_RDH(0));
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), GigAdapter->cur_rx_ind);
+
+ if (GigAdapter->hw.mac.type != e1000_82575 &&
+ GigAdapter->hw.mac.type != e1000_82576 &&
+ GigAdapter->hw.mac.type != e1000_82580
+ )
+ {
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_SRRCTL (0), E1000_SRRCTL_DESCTYPE_LEGACY);
+
+ e1000_SetRegBits (GigAdapter, E1000_RXDCTL (0), E1000_RXDCTL_QUEUE_ENABLE);
+ i = 0;
+ do {
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RXDCTL (0));
+ i++;
+ if ((TempReg & E1000_RXDCTL_QUEUE_ENABLE) != 0) {
+ DEBUGPRINT (E1000, ("RX queue enabled, after attempt i = %d\n", i));
+ break;
+ }
+
+ DelayInMicroseconds (GigAdapter, 1);
+ } while (i < 1000);
+
+ if (i >= 1000) {
+ DEBUGPRINT (CRITICAL, ("Enable RX queue failed!\n"));
+ }
+ }
+
+
+#ifndef NO_82575_SUPPORT
+ if (GigAdapter->hw.mac.type != e1000_82575 &&
+ GigAdapter->hw.mac.type != e1000_82576 &&
+ GigAdapter->hw.mac.type != e1000_82580
+ )
+#endif
+ {
+ //
+ // Set the software tail pointer just behind head to give hardware the entire ring
+ //
+ if (GigAdapter->cur_rx_ind == 0) {
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), DEFAULT_RX_DESCRIPTORS - 1);
+ } else {
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), GigAdapter->cur_rx_ind - 1);
+ }
+ }
+
+ //
+ // Zero out PSRCTL to use default packet size settings in RCTL
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_PSRCTL, 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_MRQC, 0);
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDBAL(0), (UINT32) (UINTN) (GigAdapter->tx_ring));
+#if 0 //OM
+ MemAddr = (UINT64) (UINTN) GigAdapter->tx_ring;
+ MemPtr = &((UINT32) MemAddr);
+ MemPtr++;
+#else
+ MemPtr = (UINT32*)(((UINTN)GigAdapter->tx_ring) >> 32);
+#endif
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDBAH(0), *MemPtr);
+ DEBUGPRINT(E1000, ("TdBah0 %X\n", *MemPtr));
+ DEBUGWAIT(E1000);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDLEN(0), (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS));
+
+ if (GigAdapter->hw.mac.type == e1000_82580) {
+ e1000_SetRegBits (GigAdapter, E1000_TXDCTL (0), E1000_TXDCTL_QUEUE_ENABLE);
+
+ for (i = 0; i < 1000; i++) {
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_TXDCTL (0));
+ if ((TempReg & E1000_TXDCTL_QUEUE_ENABLE) != 0) {
+ DEBUGPRINT (E1000, ("TX queue enabled, after attempt i = %d\n", i));
+ break;
+ }
+
+ DelayInMicroseconds (GigAdapter, 1);
+ }
+ if (i >= 1000) {
+ DEBUGPRINT (CRITICAL, ("Enable TX queue failed!\n"));
+ }
+ }
+
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_TCTL);
+ TempReg = (TempReg | E1000_TCTL_EN | E1000_TCTL_PSP);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TCTL, TempReg);
+
+ e1000_PciFlush(&GigAdapter->hw);
+}
+
+UINTN
+e1000_SetFilter (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 NewFilter,
+ UINT64 cpb,
+ UINT32 cpbsize
+ )
+/*++
+
+Routine Description:
+ Stops the receive unit.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+ NewFilter - A PXE_OPFLAGS bit field indicating what filters to use.
+ cpb -
+Returns:
+ None
+
+--*/
+// GC_TODO: cpbsize - add argument and description to function comment
+{
+ PXE_CPB_RECEIVE_FILTERS *CpbReceiveFilter;
+ UINT32 UpdateRCTL;
+ UINT16 CfgFilter;
+ UINT16 OldFilter;
+ UINT16 MulticastCount;
+ UINT16 i;
+ UINT16 j;
+
+ DEBUGPRINT(E1000, ("e1000_SetFilter\n"));
+
+ CpbReceiveFilter = (PXE_CPB_RECEIVE_FILTERS *) (UINTN) cpb;
+ OldFilter = GigAdapter->Rx_Filter;
+
+ //
+ // only these bits need a change in the configuration
+ // actually change in bcast requires configure but we ignore that change
+ //
+ CfgFilter = PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
+ PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST |
+ PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+
+ if ((OldFilter & CfgFilter) != (NewFilter & CfgFilter)) {
+ //
+ // Put the card into the proper mode...
+ //
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ e1000_ReceiveDisable (GigAdapter);
+
+ }
+
+ UpdateRCTL = E1000_READ_REG (&GigAdapter->hw, E1000_RCTL);
+
+ if (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS) {
+ //
+ // add the UPE bit to the variable to be written to the RCTL
+ //
+ UpdateRCTL |= E1000_RCTL_UPE;
+ }
+
+ if (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) {
+ //
+ // add the BAM bit to the variable to be written to the RCTL
+ //
+ UpdateRCTL |= E1000_RCTL_BAM;
+ }
+
+ if (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) {
+ //
+ // add the MPE bit to the variable to be written to the RCTL
+ //
+ UpdateRCTL |= E1000_RCTL_MPE;
+ }
+
+ UpdateRCTL |= E1000_RCTL_BAM;
+ GigAdapter->Rx_Filter = NewFilter;
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, UpdateRCTL);
+ }
+
+ //
+ // check if mcast setting changed
+ //
+ if ((
+ (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=
+ (OldFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST)
+ ) ||
+ (CpbReceiveFilter != NULL)
+ ) {
+
+
+ //
+ // copy the list
+ //
+ if (CpbReceiveFilter != NULL) {
+ UINT8 McAddrList[MAX_MCAST_ADDRESS_CNT][ETH_ADDR_LEN];
+
+ MulticastCount = GigAdapter->McastList.Length = (UINT16) (cpbsize / PXE_MAC_LENGTH);
+ DEBUGPRINT(E1000, ("E1000: MulticastCount=%d\n", MulticastCount));
+
+ ZeroMem(GigAdapter->McastList.McAddr, MAX_MCAST_ADDRESS_CNT*PXE_MAC_LENGTH);
+ CopyMem(
+ GigAdapter->McastList.McAddr,
+ (VOID*)(UINTN) CpbReceiveFilter->MCastList,
+ cpbsize
+ );
+
+ //
+ // Copy the multicast address list into a form that can be accepted by the
+ // shared code.
+ //
+ for (i = 0; (i < MulticastCount && i < MAX_MCAST_ADDRESS_CNT); i++) {
+ DEBUGPRINT(E1000, ("E1000: MulticastAddress %d:", i));
+ for (j = 0; j < ETH_ADDR_LEN; j++) {
+ McAddrList[i][j] = GigAdapter->McastList.McAddr[i][j];
+ DEBUGPRINT(E1000, ("%02x", CpbReceiveFilter->MCastList[i][j]));
+ }
+ DEBUGPRINT(E1000, ("\n"));
+ }
+
+ e1000_BlockIt (GigAdapter, TRUE);
+ e1000_update_mc_addr_list (
+ &GigAdapter->hw,
+ &McAddrList[0][0],
+ MulticastCount
+ );
+ e1000_BlockIt (GigAdapter, FALSE);
+
+ }
+
+ //
+ // are we setting the list or resetting??
+ //
+ if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ DEBUGPRINT(E1000, ("E1000: Creating new multicast list.\n"));
+ GigAdapter->Rx_Filter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ } else {
+ DEBUGPRINT(E1000, ("E1000: Disabling multicast list.\n"));
+ GigAdapter->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ }
+
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ e1000_ReceiveDisable (GigAdapter);
+ }
+ }
+
+ if (NewFilter != 0) {
+ //
+ // Enable unicast and start the RU
+ //
+ GigAdapter->Rx_Filter |= (NewFilter | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST);
+ e1000_ReceiveEnable (GigAdapter);
+ } else {
+ //
+ // may be disabling everything!
+ //
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ e1000_ReceiveDisable (GigAdapter);
+ }
+
+ GigAdapter->Rx_Filter = NewFilter;
+ }
+
+ return 0;
+};
+
+VOID
+e1000_ReceiveDisable (
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Stops the receive unit.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ E1000_RECEIVE_DESCRIPTOR *ReceiveDesc;
+ UINT32 TempReg;
+ UINTN i;
+ UINT32 RxdCtl;
+
+
+ DEBUGPRINT(E1000, ("e1000_ReceiveDisable\n"));
+
+ if (GigAdapter->ReceiveStarted == FALSE) {
+ DEBUGPRINT(CRITICAL, ("Receive unit already disabled!\n"));
+ return;
+ }
+
+ if (GigAdapter->hw.mac.type == e1000_82571) {
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RCTL);
+ TempReg &= ~E1000_RCTL_EN;
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, TempReg);
+ }
+
+ //
+ // On I82575 the ring must be reset when the recieve unit is disabled.
+ //
+ if (GigAdapter->hw.mac.type == e1000_82575
+ || GigAdapter->hw.mac.type == e1000_82576
+ || GigAdapter->hw.mac.type == e1000_82580
+ )
+ {
+ e1000_ClearRegBits(GigAdapter, E1000_RXDCTL(0), E1000_RXDCTL_QUEUE_ENABLE);
+ do {
+ gBS->Stall(1);
+ RxdCtl = E1000_READ_REG (&GigAdapter->hw, E1000_RXDCTL(0));
+ } while((RxdCtl & E1000_RXDCTL_QUEUE_ENABLE) != 0);
+ DEBUGPRINT (E1000, ("Receiver Disabled\n"));
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDH(0), 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), 0);
+ GigAdapter->cur_rx_ind = 0;
+ }
+
+ if (GigAdapter->hw.mac.type == e1000_82575
+ || GigAdapter->hw.mac.type == e1000_82576
+ || GigAdapter->hw.mac.type == e1000_82580
+ || GigAdapter->hw.mac.type == e1000_82571) {
+ // Clean up any left over packets
+ //
+ ReceiveDesc = GigAdapter->rx_ring;
+ for (i = 0; i < DEFAULT_RX_DESCRIPTORS; i++) {
+ ReceiveDesc->length = 0;
+ ReceiveDesc->status = 0;
+ ReceiveDesc->errors = 0;
+ ReceiveDesc++;
+ }
+ }
+
+ GigAdapter->ReceiveStarted = FALSE;
+ return ;
+}
+
+VOID
+e1000_ReceiveEnable (
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Starts the receive unit.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ UINT32 TempReg;
+
+ DEBUGPRINT(E1000, ("e1000_ReceiveEnable\n"));
+
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ DEBUGPRINT(CRITICAL, ("Receive unit already started!\n"));
+ return;
+ }
+
+ GigAdapter->Int_Status = 0;
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RCTL);
+ TempReg |= (E1000_RCTL_EN | E1000_RCTL_BAM);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, TempReg);
+
+ //
+ // Move the tail descriptor to begin receives on I82575
+ //
+#ifndef NO_82575_SUPPORT
+ if (GigAdapter->hw.mac.type == e1000_82575
+#ifndef NO_82576_SUPPORT
+ || GigAdapter->hw.mac.type == e1000_82576
+ || GigAdapter->hw.mac.type == e1000_82580
+#endif
+ ) {
+ if (GigAdapter->hw.mac.type == e1000_82575) {
+ e1000_rx_fifo_flush_82575(&GigAdapter->hw);
+ }
+
+ e1000_SetRegBits(GigAdapter, E1000_RXDCTL(0), E1000_RXDCTL_QUEUE_ENABLE);
+ do {
+ gBS->Stall(1);
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RXDCTL(0));
+ } while((TempReg & E1000_RXDCTL_QUEUE_ENABLE) == 0);
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), DEFAULT_RX_DESCRIPTORS - 1);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDH(0), 0);
+ GigAdapter->cur_rx_ind = (UINT16) E1000_READ_REG(&GigAdapter->hw, E1000_RDH(0));
+
+ }
+#endif
+
+ GigAdapter->ReceiveStarted = TRUE;
+}
+
+BOOLEAN
+e1000_WaitForAutoNeg (
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine blocks until auto-negotiation completes or times out (after 4.5 seconds).
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ TRUE - Auto-negotiation completed successfully,
+ FALSE - Auto-negotiation did not complete (i.e., timed out)
+
+--*/
+{
+ BOOLEAN AutoNegComplete;
+ UINTN i;
+ UINT16 Reg;
+ UINT32 Status;
+
+ AutoNegComplete = FALSE;
+ Status = 0;
+
+ DEBUGPRINT(E1000, ("e1000_WaitForAutoNeg\n"));
+
+ if (!GigAdapter->CableDetect) {
+ //
+ // Caller specified not to detect cable, so we return TRUE.
+ //
+ DEBUGPRINT(E1000, ("Cable detection disabled.\n"));
+ return TRUE;
+ }
+
+ //
+ // The shared code will wait for autonegotiation, so if link is not up by the time
+ // we reach this function then either we have no link, or are trying to two-pair
+ // downshift. In the case of a two pair downshift we will wait up to 30 seconds for
+ // link to come back up.
+ //
+ for (i=0; i<500; i++) {
+ Status = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ if ((Status & E1000_STATUS_LU) != 0) {
+ DEBUGPRINT(E1000, ("Successfully established link on retry %d\n", i));
+ return TRUE;
+ }
+ DelayInMilliseconds (10);
+ }
+ DEBUGPRINT(E1000, ("Link up not detected\n"));
+
+ if (GigAdapter->hw.phy.type == e1000_phy_igp) {
+ DEBUGPRINT(E1000, ("IGP PHY\n"));
+ //
+ // Workaround: read the PHY register up to three times to see if it comes up
+ // if not then we exit.
+ //
+ for (i = 5; i != 0; i--) {
+ e1000_read_phy_reg (&GigAdapter->hw, PHY_1000T_STATUS, &Reg);
+ if (Reg != 0) {
+ AutoNegComplete = e1000_DownShift (GigAdapter);
+ break;
+ }
+ DelayInMilliseconds (1000);
+ Status = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ if ((Status & E1000_STATUS_LU) != 0) {
+ AutoNegComplete = TRUE;
+ break;
+ }
+ }
+
+ } else if (GigAdapter->hw.phy.type == e1000_phy_m88){
+
+ //
+ // We are on a Marvel PHY that supports 2-pair downshift
+ // Check the real time link status bit to see if there is actually a cable connected
+ // If so then we will attempt to downshift, if not then we will report failure
+ // Wait for up to 30 seconds for real time link detected
+ //
+ for (i = 3000; i != 0; i--) {
+ DEBUGPRINT(E1000, ("."));
+ e1000_read_phy_reg (&GigAdapter->hw, M88E1000_PHY_SPEC_STATUS, &Reg);
+ if ((Reg & M88E1000_PSSR_LINK) != 0) {
+ DEBUGPRINT(E1000, ("e1000_DownShift - Real Time Link Detected\n"));
+ AutoNegComplete = e1000_DownShift (GigAdapter);
+ break;
+ }
+
+ DelayInMilliseconds (10);
+ }
+ }
+
+ DEBUGPRINT(E1000, ("Return %d\n", AutoNegComplete));
+ DEBUGWAIT (E1000);
+ return AutoNegComplete;
+}
+
+UINT16
+e1000_FreeTxBuffers(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 NumEntries,
+ OUT UINT64 *TxBuffer
+ )
+ /*++
+
+Routine Description:
+ Free TX buffers that have been transmitted by the hardware.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on.
+ NumEntries - Number of entries in the array which can be freed.
+ TxBuffer - Array to pass back free TX buffer
+
+Returns:
+ Number of TX buffers written.
+
+--*/
+
+{
+ E1000_TRANSMIT_DESCRIPTOR *TransmitDescriptor;
+ UINT32 Tdh;
+ UINT16 i;
+
+ DEBUGPRINT(E1000, ("e1000_FreeTxBuffers\n"));
+
+ //
+ // Read the TX head posistion so we can see which packets have been sent out on the wire.
+ //
+ Tdh = E1000_READ_REG (&GigAdapter->hw, E1000_TDH(0));
+ DEBUGPRINT(E1000, ("TDH = %d, GigAdapter->xmit_done_head = %d\n", Tdh, GigAdapter->xmit_done_head));
+
+ //
+ // If Tdh does not equal xmit_done_head then we will fill all the transmitted buffer
+ // addresses between Tdh and xmit_done_head into the completed buffers array
+ //
+ i = 0;
+ do {
+ if (i >= NumEntries) {
+ DEBUGPRINT(E1000, ("Exceeded number of DB entries, i=%d, NumEntries=%d\n", i, NumEntries));
+ break;
+ }
+
+ TransmitDescriptor = &GigAdapter->tx_ring[GigAdapter->xmit_done_head];
+ if ((TransmitDescriptor->upper.fields.status & E1000_TXD_STAT_DD) != 0) {
+
+ if (GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head] == 0) {
+ DEBUGPRINT(CRITICAL, ("ERROR: TX buffer complete without being marked used!\n"));
+ break;
+ }
+
+ DEBUGPRINT(E1000, ("Writing buffer address %d, %x\n", i, TxBuffer[i]));
+ TxBuffer[i] = GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head];
+ i++;
+
+ e1000_UnMapMem (
+ GigAdapter,
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head],
+ TransmitDescriptor->lower.flags.length,
+ TransmitDescriptor->buffer_addr
+ );
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head] = 0;
+ TransmitDescriptor->upper.fields.status = 0;
+
+ GigAdapter->xmit_done_head++;
+ if (GigAdapter->xmit_done_head >= DEFAULT_TX_DESCRIPTORS) {
+ GigAdapter->xmit_done_head = 0;
+ }
+ } else {
+ DEBUGPRINT(E1000, ("TX Descriptor %d not done\n", GigAdapter->xmit_done_head));
+ break;
+ }
+ } while (Tdh != GigAdapter->xmit_done_head);
+ return i;
+}
+
+UINT32
+e1000_SetRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ )
+/*++
+
+Routine Description:
+ Sets specified bits in a device register
+
+Arguments:
+ GigAdapter - Pointer to the device instance
+ Register - Register to write
+ BitMask - Bits to set
+
+Returns:
+ Data - Returns the value read from the PCI register.
+
+--*/
+{
+ UINT32 TempReg;
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, Register);
+ TempReg |= BitMask;
+ E1000_WRITE_REG (&GigAdapter->hw, Register, TempReg);
+
+ return TempReg;
+}
+
+UINT32
+e1000_ClearRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ )
+/*++
+
+Routine Description:
+ Clears specified bits in a device register
+
+Arguments:
+ GigAdapter - Pointer to the device instance
+ Register - Register to write
+ BitMask - Bits to clear
+
+Returns:
+ Data - Returns the value read from the PCI register.
+
+--*/
+
+{
+ UINT32 TempReg;
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, Register);
+ TempReg &= ~BitMask;
+ E1000_WRITE_REG (&GigAdapter->hw, Register, TempReg);
+
+ return TempReg;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h
new file mode 100755
index 0000000..3d88093
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h
@@ -0,0 +1,680 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+#define MAJORVERSION 4
+#define MINORVERSION 4
+#define BUILDNUMBER 6
+
+
+#include "e1000_api.h"
+#include "vlan.h"
+#include "hii.h"
+#include "FirmwareManagement.h"
+#include "startstop.h"
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DriverSupportedEfiVersion.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/NetworkInterfaceIdentifier.h>
+#include <Protocol/PciIo.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+//
+// Debug levels for driver DEBUG_PRINT statements
+//
+#define NONE 0
+#define INIT (1 << 0)
+#define DECODE (1 << 1)
+#define E1000 (1 << 2)
+#define SHARED (1 << 3)
+#define DIAG (1 << 4)
+#define CFG (1 << 5)
+#define IO (1 << 6)
+#define VLAN (1 << 7)
+#define CRITICAL (1 << 8)
+#define CLP (1 << 9)
+#define TX (1 << 10)
+#define RX (1 << 11)
+#define HW (1 << 12)
+#define HII (1 << 13)
+#define IMAGE (1 << 14)
+#define WAIT (1 << 15)
+
+#ifndef DBG_LVL
+#define DBG_LVL (NONE)
+#endif
+
+#define MAX_NIC_INTERFACES 256
+
+//
+// Device and Vendor IDs
+//
+#define INTEL_VENDOR_ID 0x8086
+#define E1000_VENDOR_ID INTEL_VENDOR_ID
+#define E1000_SUBVENDOR_ID 0x8086
+
+
+#define TWO_PAIR_DOWNSHIFT_TIMEOUT 30
+
+//
+// PCI Base Address Register Bits
+//
+#define PCI_BAR_IO_MASK 0x00000003
+#define PCI_BAR_IO_MODE 0x00000001
+
+#define PCI_BAR_MEM_MASK 0x0000000F
+#define PCI_BAR_MEM_MODE 0x00000000
+#define PCI_BAR_MEM_64BIT 0x00000004
+
+//
+// Bit fields for the PCI command register
+//
+#define PCI_COMMAND_MWI 0x10
+#define PCI_COMMAND_MASTER 0x04
+#define PCI_COMMAND_MEM 0x02
+#define PCI_COMMAND_IO 0x01
+#define PCI_COMMAND 0x04
+#define PCI_LATENCY_TIMER 0x0D
+
+//
+// PCI Capability IDs
+//
+#define PCI_EX_CAP_ID 0x10
+#define PCI_CAP_PTR_ENDPOINT 0x00
+
+//
+// PCI Configuration Space Register Offsets
+//
+#define PCI_CAP_PTR 0x34 // PCI Capabilities pointer
+
+//
+// Register offsets for IO Mode read/write
+//
+#define IO_MODE_IOADDR 0x00
+#define IO_MODE_IODATA 0x04
+
+#define ETHER_MAC_ADDR_LEN 6
+
+//
+// PBA constants
+//
+#define E1000_PBA_16K 0x0010 // 16KB, default TX allocation
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030 // 48KB, default RX allocation
+
+
+//
+// EEPROM Word Defines:
+//
+#define INIT_CONTROL_WORD_2 0x0F
+
+//
+// Initialization Control Word 2 indicates flash size
+// 000: 64KB, 001: 128KB, 010: 256KB, 011: 512KB, 100: 1MB, 101: 2MB, 110: 4MB, 111: 8MB
+// The Flash size impacts the requested memory space for the Flash and expansion ROM BARs.
+//
+#define FLASH_SIZE_MASK 0x0700
+#define FLASH_SIZE_SHIFT 8
+
+//
+// "Main Setup Options Word"
+//
+#define SETUP_OPTIONS_WORD 0x30
+#define SETUP_OPTIONS_WORD_LANB 0x34
+#define SETUP_OPTIONS_WORD_LANC 0x38
+#define SETUP_OPTIONS_WORD_LAND 0x3A
+
+#define FDP_FULL_DUPLEX_BIT 0x1000
+#define FSP_100MBS 0x0800
+#define FSP_10MBS 0x0400
+#define FSP_AUTONEG 0x0000
+#define FSP_MASK 0x0C00
+#define DISPLAY_SETUP_MESSAGE 0x0100
+
+// UEFI 2.3 spec (Errata B) add following new definitions to UNDI interface:
+
+//
+// Return current media status.
+//
+#define PXE_OPFLAGS_GET_MEDIA_STATUS 0x0004
+
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK 0x0002
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED 0x0000
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED 0x0002
+
+//
+// This flag is set if there is no media detected.
+//
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA 0x0040
+
+//
+// "Configuration Customization Word"
+//
+#define CONFIG_CUSTOM_WORD 0x31
+#define CONFIG_CUSTOM_WORD_LANB 0x35
+#define CONFIG_CUSTOM_WORD_LANC 0x39
+#define CONFIG_CUSTOM_WORD_LAND 0x3B
+
+#define SIG 0x4000
+#define SIG_MASK 0xC000
+
+#define EEPROM_CAPABILITIES_WORD 0x33
+#define EEPROM_CAPABILITIES_SIG 0x4000
+#define EEPROM_CAPABILITIES_SIG_MASK 0xC000
+#define EEPROM_BC_BIT 0x0001
+#define EEPROM_UNDI_BIT 0x0002
+#define EEPROM_PXE_BIT (EEPROM_BC_BIT | EEPROM_UNDI_BIT)
+#define EEPROM_RPL_BIT 0x0004
+#define EEPROM_EFI_BIT 0x0008
+#define EEPROM_FCOE_BIT 0x0020
+#define EEPROM_ISCSI_BIT 0x0010
+#define EEPROM_LEGACY_BIT (EEPROM_PXE_BIT | EEPROM_ISCSI_BIT)
+#define EEPROM_SMCLP_BIT 0x0040
+#define EEPROM_TYPE_MASK (EEPROM_BC_BIT | EEPROM_UNDI_BIT | EEPROM_EFI_BIT | EEPROM_ISCSI_BIT)
+#define EEPROM_ALL_BITS (EEPROM_TYPE_MASK | EEPROM_RPL_BIT)
+
+#define COMPATIBILITY_WORD 0x03
+#define COMPATABILITY_LOM_BIT 0x0800 // bit 11
+//
+// UNDI_CALL_TABLE.state can have the following values
+//
+#define DONT_CHECK -1
+#define ANY_STATE -1
+#define MUST_BE_STARTED 1
+#define MUST_BE_INITIALIZED 2
+
+#define EFI_OPTIONAL_PTR 0x00000001
+#define EFI_INTERNAL_PTR 0x00000004 // Pointer to internal runtime data
+#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
+
+#define GIG_UNDI_DEV_SIGNATURE SIGNATURE_32('P','R','0','g')
+#define GIG_UNDI_PRIVATE_DATA_FROM_THIS(a) CR(a, GIG_UNDI_PRIVATE_DATA, NIIProtocol_31, GIG_UNDI_DEV_SIGNATURE)
+#define GIG_UNDI_PRIVATE_DATA_FROM_DEVICE_PATH(a) \
+ CR(a, GIG_UNDI_PRIVATE_DATA, Undi32BaseDevPath, GIG_UNDI_DEV_SIGNATURE)
+#define GIG_UNDI_PRIVATE_DATA_FROM_FIRMWARE_MANAGEMENT(a) \
+ CR(a, GIG_UNDI_PRIVATE_DATA, FirmwareManagement, GIG_UNDI_DEV_SIGNATURE)
+#define GIG_UNDI_PRIVATE_DATA_FROM_DRIVER_STOP(a) \
+ CR(a, GIG_UNDI_PRIVATE_DATA, DriverStop, GIG_UNDI_DEV_SIGNATURE)
+
+//
+// Macro to compare MAC addresses. Returns TRUE if the MAC addresses match.
+// a and b must be UINT8 pointers to the first byte of MAC address.
+//
+#ifdef EFI64
+#define E1000_COMPARE_MAC(a, b) \
+ ( (a[0]==b[0]) && (a[1]==b[1]) && (a[2]==b[2]) && (a[3]==b[3]) && (a[4]==b[4]) && (a[5]==b[5]))
+#else
+#define E1000_COMPARE_MAC(a, b) \
+ ( *((UINT32*) a) == *((UINT32*) b) ) && ( *((UINT16*) (a+4)) == *((UINT16*) (b+4)) )
+#endif
+
+#ifdef EFI64
+#define E1000_COPY_MAC(a, b) \
+ a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; a[3]=b[3]; a[4]=b[4]; a[5]=b[5];
+#else
+#define E1000_COPY_MAC(a, b) \
+ *((UINT32*) a) = *((UINT32*) b); *((UINT16*) (a+4)) = *((UINT16*) (b+4))
+#endif
+
+
+typedef struct {
+ UINT16 cpbsize;
+ UINT16 dbsize;
+ UINT16 opflags;
+ UINT16 state;
+ void (*api_ptr)();
+} UNDI_CALL_TABLE;
+
+typedef struct {
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *InterfacePointer;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathPointer;
+} NII_ENTRY;
+
+typedef struct NII_CONFIG_ENTRY {
+ UINT32 NumEntries;
+ UINT32 Reserved;
+ struct NII_CONFIG_ENTRY *NextLink;
+ NII_ENTRY NiiEntry[MAX_NIC_INTERFACES];
+} NII_TABLE;
+
+typedef struct _EFI_PRO1000_COM_PROTOCOL {
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol_31;
+} EFI_PRO1000_COM_PROTOCOL;
+
+typedef VOID (*ptr)(VOID);
+typedef VOID (*bsptr_30)(UINTN);
+typedef VOID (*virtphys_30)(UINT64, UINT64);
+typedef VOID (*block_30)(UINT32);
+typedef VOID (*mem_io_30)(UINT8, UINT8, UINT64, UINT64);
+
+typedef VOID (*bsptr)(UINT64, UINTN);
+typedef VOID (*virtphys)(UINT64, UINT64, UINT64);
+typedef VOID (*block)(UINT64, UINT32);
+typedef VOID (*mem_io)(UINT64, UINT8, UINT8, UINT64, UINT64);
+
+typedef VOID (*map_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);
+typedef VOID (*unmap_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);
+typedef VOID (*sync_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);
+
+//
+// Global Variable
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gGigUndiDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gGigUndiComponentName;
+EFI_TIME gTime;
+
+#pragma pack(1)
+typedef struct eth {
+ UINT8 dest_addr[PXE_HWADDR_LEN_ETHER];
+ UINT8 src_addr[PXE_HWADDR_LEN_ETHER];
+ UINT16 type;
+} ETHER_HEADER;
+
+#pragma pack(1)
+typedef struct PCI_CONFIG_HEADER_s {
+ UINT16 VendorID;
+ UINT16 DeviceID;
+ UINT16 Command;
+ UINT16 Status;
+ UINT16 RevID;
+ UINT16 ClassID;
+ UINT8 CacheLineSize;
+ UINT8 LatencyTimer;
+ UINT8 HeaderType;
+ UINT8 BIST;
+ UINT32 BaseAddressReg_0;
+ UINT32 BaseAddressReg_1;
+ UINT32 BaseAddressReg_2;
+ UINT32 BaseAddressReg_3;
+ UINT32 BaseAddressReg_4;
+ UINT32 BaseAddressReg_5;
+ UINT32 CardBusCISPtr;
+ UINT16 SubVendorID;
+ UINT16 SubSystemID;
+ UINT32 ExpansionROMBaseAddr;
+ UINT8 CapabilitiesPtr;
+ UINT8 reserved1;
+ UINT16 Reserved2;
+ UINT32 Reserved3;
+ UINT8 int_line;
+ UINT8 int_pin;
+ UINT8 Min_gnt;
+ UINT8 Max_lat;
+} PCI_CONFIG_HEADER;
+#pragma pack()
+
+typedef struct e1000_rx_desc E1000_RECEIVE_DESCRIPTOR;
+
+
+//
+// TX Buffer size including crc and padding
+//
+#define RX_BUFFER_SIZE 2048
+
+#define DEFAULT_RX_DESCRIPTORS 8
+#define DEFAULT_TX_DESCRIPTORS 8
+
+//
+// Macro to conver byte memory requirement into pages
+//
+#define UNDI_MEM_PAGES(x) (((x) - 1) / 4096 + 1)
+
+#pragma pack(1)
+typedef struct _LocalReceiveBuffer {
+ UINT8 RxBuffer[RX_BUFFER_SIZE - (sizeof(UINT64))];
+ UINT64 BufferUsed;
+} LOCAL_RX_BUFFER, *PLOCAL_RX_BUFFER;
+#pragma pack()
+
+typedef struct e1000_tx_desc E1000_TRANSMIT_DESCRIPTOR;
+
+//
+// If using a serial flash, this struct will be filled with the
+// proper offsets, since I82540 and I82541 use different registers
+// for Flash manipulation.
+//
+typedef struct _SERIAL_FLASH_OFFSETS
+{
+ struct
+ {
+ UINT32 RegisterOffset;
+ UINT32 Sck;
+ UINT32 Cs;
+ } FlashClockRegister;
+ struct
+ {
+ UINT32 RegisterOffset;
+ UINT32 Si;
+ UINT32 So;
+ UINT8 SoPosition;
+ } FlashDataRegister;
+
+} SERIAL_FLASH_OFFSETS;
+
+
+typedef struct _DRIVER_DATA_ {
+ UINT16 State; // stopped, started or initialized
+
+ struct e1000_hw hw;
+ struct e1000_hw_stats stats;
+
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+
+ SERIAL_FLASH_OFFSETS SerialFlashOffsets;
+
+ UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
+
+ UINT32 PciConfig[MAX_PCI_CONFIG_LEN];
+ UINT32 NVData[MAX_EEPROM_LEN];
+
+ UINTN HwInitialized;
+ UINTN DriverBusy;
+ UINT16 LinkSpeed; // requested (forced) link speed
+ UINT8 DuplexMode; // requested duplex
+ UINT8 CableDetect; // 1 to detect and 0 not to detect the cable
+ UINT8 LoopBack;
+
+ UINT16 SetupWord;
+ UINT16 BackupSetupWord;
+ UINT16 CustomConfigWord;
+
+ UINT64 Unique_ID;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ VOID (*Delay)(UINT64, UINTN);
+ VOID (*Virt2Phys)(UINT64 unq_id, UINT64 virtual_addr, UINT64 physical_ptr);
+ VOID (*Block)(UINT64 unq_id, UINT32 enable);
+ VOID (*MemIo)(UINT64 unq_id, UINT8 read_write, UINT8 len, UINT64 port,
+ UINT64 buf_addr);
+ VOID (*MapMem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ UINT32 Direction, UINT64 mapped_addr);
+ VOID (*UnMapMem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ UINT32 Direction, UINT64 mapped_addr);
+ VOID (*SyncMem)(UINT64 unq_id, UINT64 virtual_addr,
+ UINT32 size, UINT32 Direction, UINT64 mapped_addr);
+
+ UINT8 IoBarIndex;
+
+ UINT64 MemoryPtr;
+ UINT32 MemoryLength;
+
+ UINT16 Rx_Filter;
+ UINT16 int_mask;
+ UINT16 Int_Status;
+
+ struct _McastList{
+ UINT16 Length;
+ UINT8 McAddr[MAX_MCAST_ADDRESS_CNT][PXE_MAC_LENGTH]; // 8*32 is the size
+ } McastList;
+
+ UINT16 cur_rx_ind;
+ UINT16 cur_tx_ind;
+ UINT8 ReceiveStarted;
+ E1000_RECEIVE_DESCRIPTOR *rx_ring;
+ E1000_TRANSMIT_DESCRIPTOR *tx_ring;
+ LOCAL_RX_BUFFER *local_rx_buffer;
+ UINT16 xmit_done_head;
+ UINT64 TxBufferUnmappedAddr[DEFAULT_TX_DESCRIPTORS];
+ BOOLEAN MacAddrOverride;
+ UINT64 DebugRxBuffer[DEFAULT_RX_DESCRIPTORS];
+ BOOLEAN VlanEnable;
+ UINT16 VlanTag;
+ BOOLEAN FlashWriteInProgress;
+
+ UINTN VersionFlag; // Indicates UNDI version 3.0 or 3.1
+} GIG_DRIVER_DATA, *PADAPTER_STRUCT;
+
+typedef struct {
+ UINTN Signature;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NIIProtocol_31;
+ EFI_PRO1000_COM_PROTOCOL EfiPro1000Com;
+ EFI_HANDLE ControllerHandle;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *Undi32BaseDevPath;
+ EFI_DEVICE_PATH_PROTOCOL *Undi32DevPath;
+ GIG_DRIVER_DATA NicInfo;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ CHAR16 *Brand;
+
+ // HII Configuration
+ EFI_HII_HANDLE HiiHandle;
+ GIG_DRIVER_CONFIGURATION Configuration;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ EFI_GUID HiiFormGuid;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_DRIVER_STOP_PROTOCOL DriverStop;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL FirmwareManagement;
+
+} GIG_UNDI_PRIVATE_DATA;
+
+struct GIG_UNDI_DMA_RESOURCES {
+ E1000_RECEIVE_DESCRIPTOR rx_ring[DEFAULT_RX_DESCRIPTORS];
+ E1000_TRANSMIT_DESCRIPTOR tx_ring[DEFAULT_TX_DESCRIPTORS];
+ LOCAL_RX_BUFFER rx_buffer[DEFAULT_RX_DESCRIPTORS];
+};
+
+#define BYTE_ALIGN_64 0x7F
+
+//
+// We need enough space to store TX descriptors, RX descriptors,
+// RX buffers, and enough left over to do a 64 byte alignment.
+//
+#define MEMORY_NEEDED (sizeof(struct GIG_UNDI_DMA_RESOURCES)+BYTE_ALIGN_64)
+
+#define FOUR_GIGABYTE (UINT64)0x100000000
+
+//
+// functions defined in init.c
+//
+
+VOID
+GetUndiControllerName (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+//
+// functions defined in decode.c
+//
+VOID e1000_UNDI_GetState();
+VOID e1000_UNDI_Start();
+VOID e1000_UNDI_Stop();
+VOID e1000_UNDI_GetInitInfo();
+VOID e1000_UNDI_GetConfigInfo();
+VOID e1000_UNDI_Initialize();
+VOID e1000_UNDI_Reset();
+VOID e1000_UNDI_Shutdown();
+VOID e1000_UNDI_Interrupt();
+VOID e1000_UNDI_RecFilter();
+VOID e1000_UNDI_StnAddr();
+VOID e1000_UNDI_Statistics();
+VOID e1000_UNDI_ip2mac();
+VOID e1000_UNDI_NVData();
+VOID e1000_UNDI_Status();
+
+VOID
+e1000_UNDI_FillHeader (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+VOID e1000_UNDI_Transmit();
+VOID e1000_UNDI_Receive();
+
+VOID e1000_UNDI_APIEntry();
+
+VOID WaitForEnter(VOID);
+
+PXE_STATCODE
+e1000_Inititialize (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+EFI_STATUS
+e1000_FirstTimeInit (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+VOID
+e1000_ReceiveEnable (
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+VOID
+e1000_ReceiveDisable (
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+UINTN
+e1000_Transmit (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ UINT64 cpb,
+ UINT16 opflags
+ );
+
+UINTN
+e1000_Receive (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ UINT64 cpb,
+ UINT64 db
+ );
+
+UINTN
+e1000_Reset (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ UINT16 OpFlags
+ );
+
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+
+UINT16
+e1000_FreeTxBuffers (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 NumEntries,
+ OUT UINT64 *TxBuffer
+ );
+
+VOID
+EepromMacAddressDefault(
+ IN GIG_DRIVER_DATA *GigAdapter
+ );
+
+VOID
+e1000_MemCopy (
+ IN UINT8* Dest,
+ IN UINT8* Source,
+ IN UINT32 Count
+ );
+
+UINT32
+e1000_SetRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ );
+
+UINT32
+e1000_ClearRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ );
+
+//
+// This is the Macro Section
+//
+#if DBG_LVL
+#define DEBUGPRINT(lvl, msg) \
+ if ((DBG_LVL & lvl) != 0) Aprint msg;
+#define DEBUGWAIT(lvl) \
+ if (((DBG_LVL | WAIT) & lvl) == (DBG_LVL | WAIT)) WaitForEnter();
+#define DEBUGPRINTTIME(lvl) \
+ if ((DBG_LVL & lvl) != 0) gRT->GetTime (&gTime, NULL);; \
+ DEBUGPRINT(lvl, ("Timestamp - %dH:%dM:%dS:%dNS\n", \
+ gTime.Hour, gTime.Minute, gTime.Second, gTime.Nanosecond));
+#else
+// Comment out the debug stuff
+#define DEBUGPRINT(lvl, msg)
+#define DEBUGWAIT(lvl)
+#endif
+
+//
+// Time translations.
+//
+VOID DelayInMicroseconds (IN GIG_DRIVER_DATA *GigAdapter, UINTN MicroSeconds);
+#define DelayInMilliseconds(x) DelayInMicroseconds(GigAdapter, x*1000)
+
+#endif // _E1000_H_
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c
new file mode 100755
index 0000000..1233479
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c
@@ -0,0 +1,1561 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 80003ES2LAN Gigabit Ethernet Controller (Copper)
+ * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_release_phy_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset,
+ UINT16 *data);
+STATIC INT32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset,
+ UINT16 data);
+STATIC INT32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+STATIC INT32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_hw_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
+static INT32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask);
+static INT32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, UINT16 duplex);
+static INT32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
+static INT32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
+static INT32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data);
+static INT32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 data);
+static INT32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask);
+STATIC INT32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
+
+/*
+ * A table for the GG82563 cable length where the range is defined
+ * with a lower bound at "index" and the upper bound at
+ * "index + 5".
+ */
+static const UINT16 e1000_gg82563_cable_length_table[] =
+ { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+#define GG82563_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_gg82563_cable_length_table) / \
+ sizeof(e1000_gg82563_cable_length_table[0]))
+
+/**
+ * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_init_phy_params_80003es2lan");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ goto out;
+ } else {
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+ phy->type = e1000_phy_gg82563;
+
+ phy->ops.acquire = e1000_acquire_phy_80003es2lan;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.check_reset_block = e1000_check_reset_block_generic;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_80003es2lan;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.release = e1000_release_phy_80003es2lan;
+ phy->ops.reset = e1000_phy_hw_reset_generic;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
+
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan;
+ phy->ops.get_cable_length = e1000_get_cable_length_80003es2lan;
+ phy->ops.read_reg = e1000_read_phy_reg_gg82563_80003es2lan;
+ phy->ops.write_reg = e1000_write_phy_reg_gg82563_80003es2lan;
+
+ phy->ops.cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan;
+
+ /* This can only be done after all function pointers are setup. */
+ ret_val = e1000_get_phy_id(hw);
+
+ /* Verify phy id */
+ if (phy->id != GG82563_E_PHY_ID) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT16 size;
+
+ DEBUGFUNC("e1000_init_nvm_params_80003es2lan");
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ nvm->type = e1000_nvm_eeprom_spi;
+
+ size = (UINT16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+
+ /*
+ * Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+
+ /* EEPROM access above 16k is unsupported */
+ if (size > 14)
+ size = 14;
+ nvm->word_size = 1 << size;
+
+ /* Function Pointers */
+ nvm->ops.acquire = e1000_acquire_nvm_80003es2lan;
+ nvm->ops.read = e1000_read_nvm_eerd;
+ nvm->ops.release = e1000_release_nvm_80003es2lan;
+ nvm->ops.update = e1000_update_nvm_checksum_generic;
+ nvm->ops.valid_led_default = e1000_valid_led_default_generic;
+ nvm->ops.validate = e1000_validate_nvm_checksum_generic;
+ nvm->ops.write = e1000_write_nvm_80003es2lan;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ DEBUGFUNC("e1000_init_mac_params_80003es2lan");
+
+ /* Set media type and media-dependent function pointers */
+ switch (hw->device_id) {
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
+ mac->ops.setup_physical_interface =
+ e1000_setup_fiber_serdes_link_generic;
+ break;
+ default:
+ hw->phy.media_type = e1000_media_type_copper;
+ mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+ mac->ops.setup_physical_interface =
+ e1000_setup_copper_link_80003es2lan;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /* ARC supported; valid only if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+ ? TRUE : FALSE;
+ /* Adaptive IFS not supported */
+ mac->adaptive_ifs = FALSE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+ /* reset */
+ mac->ops.reset_hw = e1000_reset_hw_80003es2lan;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_80003es2lan;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_generic;
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* writing VFTA */
+ mac->ops.write_vfta = e1000_write_vfta_generic;
+ /* clearing VFTA */
+ mac->ops.clear_vfta = e1000_clear_vfta_generic;
+ /* read mac address */
+ mac->ops.read_mac_addr = e1000_read_mac_addr_80003es2lan;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_generic;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_generic;
+ mac->ops.led_off = e1000_led_off_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan;
+ /* link info */
+ mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan;
+
+ /* set lan id for port to determine which phy lock to use */
+ hw->mac.ops.set_lan_id(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_function_pointers_80003es2lan - Init ESB2 func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_80003es2lan");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan;
+ hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan;
+}
+
+/**
+ * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to acquire access rights to the correct PHY.
+ **/
+STATIC INT32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_acquire_phy_80003es2lan");
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_release_phy_80003es2lan - Release rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to release access rights to the correct PHY.
+ **/
+STATIC void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_release_phy_80003es2lan");
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the semaphore to access the Kumeran interface.
+ *
+ **/
+STATIC INT32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_acquire_mac_csr_80003es2lan");
+
+ mask = E1000_SWFW_CSR_SM;
+
+ return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_release_mac_csr_80003es2lan - Release rights to access Kumeran Register
+ * @hw: pointer to the HW structure
+ *
+ * Release the semaphore used to access the Kumeran interface
+ **/
+STATIC void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_release_mac_csr_80003es2lan");
+
+ mask = E1000_SWFW_CSR_SM;
+
+ e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the semaphore to access the EEPROM.
+ **/
+STATIC INT32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_acquire_nvm_80003es2lan");
+
+ ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_acquire_nvm_generic(hw);
+
+ if (ret_val)
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Release the semaphore used to access the EEPROM.
+ **/
+STATIC void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_80003es2lan");
+
+ e1000_release_nvm_generic(hw);
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+static INT32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+ UINT32 swmask = mask;
+ UINT32 fwmask = mask << 16;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 i = 0, timeout = 50;
+
+ DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan");
+
+ while (i < timeout) {
+ if (e1000_get_hw_semaphore_generic(hw)) {
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask)
+ * or other software thread using resource (swmask)
+ */
+ e1000_put_hw_semaphore_generic(hw);
+ msec_delay_irq(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+
+ DEBUGFUNC("e1000_release_swfw_sync_80003es2lan");
+
+ while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS)
+ ; /* Empty */
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+}
+
+/**
+ * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: pointer to the data returned from the operation
+ *
+ * Read the GG82563 PHY register.
+ **/
+STATIC INT32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+ UINT32 page_select;
+ UINT16 temp;
+
+ DEBUGFUNC("e1000_read_phy_reg_gg82563_80003es2lan");
+
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+ page_select = GG82563_PHY_PAGE_SELECT;
+ } else {
+ /*
+ * Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+ }
+
+ temp = (UINT16)((UINT16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
+ if (ret_val) {
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) {
+ /*
+ * The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ usec_delay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+
+ if (((UINT16)offset >> GG82563_PAGE_SHIFT) != temp) {
+ ret_val = -E1000_ERR_PHY;
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ usec_delay(200);
+
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ usec_delay(200);
+ } else {
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+ }
+
+ e1000_release_phy_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: value to write to the register
+ *
+ * Write to the GG82563 PHY register.
+ **/
+STATIC INT32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+ UINT32 page_select;
+ UINT16 temp;
+
+ DEBUGFUNC("e1000_write_phy_reg_gg82563_80003es2lan");
+
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+ page_select = GG82563_PHY_PAGE_SELECT;
+ } else {
+ /*
+ * Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+ }
+
+ temp = (UINT16)((UINT16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
+ if (ret_val) {
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) {
+ /*
+ * The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ usec_delay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+
+ if (((UINT16)offset >> GG82563_PAGE_SHIFT) != temp) {
+ ret_val = -E1000_ERR_PHY;
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ usec_delay(200);
+
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ usec_delay(200);
+ } else {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+ }
+
+ e1000_release_phy_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_80003es2lan - Write to ESB2 NVM
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @words: number of words to write
+ * @data: buffer of data to write to the NVM
+ *
+ * Write "words" of data to the ESB2 NVM.
+ **/
+STATIC INT32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data)
+{
+ DEBUGFUNC("e1000_write_nvm_80003es2lan");
+
+ return e1000_write_nvm_spi(hw, offset, words, data);
+}
+
+/**
+ * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete
+ * @hw: pointer to the HW structure
+ *
+ * Wait a specific amount of time for manageability processes to complete.
+ * This is a function pointer entry point called by the phy module.
+ **/
+STATIC INT32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+ DEBUGFUNC("e1000_get_cfg_done_80003es2lan");
+
+ if (hw->bus.func == 1)
+ mask = E1000_NVM_CFG_DONE_PORT_1;
+
+ while (timeout) {
+ if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
+ break;
+ msec_delay(1);
+ timeout--;
+ }
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+ ret_val = -E1000_ERR_RESET;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
+ * @hw: pointer to the HW structure
+ *
+ * Force the speed and duplex settings onto the PHY. This is a
+ * function pointer entry point called by the phy module.
+ **/
+STATIC INT32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_80003es2lan");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ /*
+ * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("GG82563 PSCR: %X\n", phy_data);
+
+ ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ /* Reset the phy to commit changes. */
+ phy_data |= MII_CR_RESET;
+
+ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ usec_delay(1);
+
+ if (hw->phy.autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link "
+ "on GG82563 phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ /*
+ * We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = e1000_phy_reset_dsp_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Resetting the phy means we need to verify the TX_CLK corresponds
+ * to the link speed. 10Mbps -> 2.5MHz, else 25MHz.
+ */
+ phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+ if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
+ phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
+ else
+ phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
+
+ /*
+ * In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_80003es2lan - Set approximate cable length
+ * @hw: pointer to the HW structure
+ *
+ * Find the approximate cable length as measured by the GG82563 PHY.
+ * This is a function pointer entry point called by the phy module.
+ **/
+STATIC INT32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data, index;
+
+ DEBUGFUNC("e1000_get_cable_length_80003es2lan");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
+ if (ret_val)
+ goto out;
+
+ index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+
+ if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+ phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_link_up_info_80003es2lan - Report speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to speed buffer
+ * @duplex: pointer to duplex buffer
+ *
+ * Retrieve the current speed and duplex configuration.
+ **/
+STATIC INT32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_link_up_info_80003es2lan");
+
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw,
+ speed,
+ duplex);
+ hw->phy.ops.cfg_on_link_up(hw);
+ } else {
+ ret_val = e1000_get_speed_and_duplex_fiber_serdes_generic(hw,
+ speed,
+ duplex);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_80003es2lan - Reset the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Perform a global reset to the ESB2 controller.
+ **/
+STATIC INT32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_80003es2lan");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+ e1000_release_phy_80003es2lan(hw);
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ goto out;
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_80003es2lan - Initialize the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
+ **/
+STATIC INT32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 reg_data;
+ INT32 ret_val;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_init_hw_80003es2lan");
+
+ e1000_initialize_hw_bits_80003es2lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val)
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+
+ /* Disabling VLAN filtering */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ mac->ops.clear_vfta(hw);
+
+ /* Setup the receive address. */
+ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
+
+ /* ...for both queues. */
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
+
+ /* Enable retransmit on late collisions */
+ reg_data = E1000_READ_REG(hw, E1000_TCTL);
+ reg_data |= E1000_TCTL_RTLC;
+ E1000_WRITE_REG(hw, E1000_TCTL, reg_data);
+
+ /* Configure Gigabit Carry Extend Padding */
+ reg_data = E1000_READ_REG(hw, E1000_TCTL_EXT);
+ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+ reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TCTL_EXT, reg_data);
+
+ /* Configure Transmit Inter-Packet Gap */
+ reg_data = E1000_READ_REG(hw, E1000_TIPG);
+ reg_data &= ~E1000_TIPG_IPGT_MASK;
+ reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TIPG, reg_data);
+
+ reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
+ reg_data &= ~0x00100000;
+ E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
+
+ /* default to TRUE to enable the MDIC W/A */
+ hw->dev_spec._80003es2lan.mdic_wa_enable = TRUE;
+
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET >>
+ E1000_KMRNCTRLSTA_OFFSET_SHIFT,
+ &i);
+ if (!ret_val) {
+ if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) ==
+ E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
+ hw->dev_spec._80003es2lan.mdic_wa_enable = FALSE;
+ }
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_80003es2lan(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_initialize_hw_bits_80003es2lan");
+
+ /* Transmit Descriptor Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TARC(0));
+ reg &= ~(0xF << 27); /* 30:27 */
+ if (hw->phy.media_type != e1000_media_type_copper)
+ reg &= ~(1 << 20);
+ E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TARC(1));
+ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+
+ return;
+}
+
+/**
+ * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
+ * @hw: pointer to the HW structure
+ *
+ * Setup some GG82563 PHY registers for obtaining link
+ **/
+static INT32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT32 ctrl_ext;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_copper_link_setup_gg82563_80003es2lan");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (phy->reset_disable)
+ goto skip_reset;
+
+#endif
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ /* Use 25MHz for both link down and 1000Base-T for Tx clock. */
+ data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
+
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+ switch (phy->mdix) {
+ case 1:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+ break;
+ case 2:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+ break;
+ case 0:
+ default:
+ data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ break;
+ }
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ if (phy->disable_polarity_correction)
+ data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data);
+ if (ret_val)
+ goto out;
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = hw->phy.ops.commit(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ goto out;
+ }
+
+#ifndef NO_PHY_RESET_DISABLE
+skip_reset:
+#endif
+ /* Bypass Rx and Tx FIFO's */
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+ E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+ E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+ &data);
+ if (ret_val)
+ goto out;
+ data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+ data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL_2, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL_2, data);
+ if (ret_val)
+ goto out;
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Do not init these registers when the HW is in IAMT mode, since the
+ * firmware will have already initialized them. We only initialize
+ * them if the HW is not in IAMT mode.
+ */
+ if (!(hw->mac.ops.check_mng_mode(hw))) {
+ /* Enable Electrical Idle on the PHY */
+ data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_PWR_MGMT_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Workaround: Disable padding in Kumeran interface in the MAC
+ * and in the PHY to avoid CRC errors.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_INBAND_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data |= GG82563_ICR_DIS_PADDING;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_INBAND_CTRL, data);
+ if (ret_val)
+ goto out;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Essentially a wrapper for setting up all things "copper" related.
+ * This is a function pointer entry point called by the mac module.
+ **/
+STATIC INT32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+ UINT16 reg_data;
+
+ DEBUGFUNC("e1000_setup_copper_link_80003es2lan");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /*
+ * Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps.
+ */
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
+ 0xFFFF);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+ reg_data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cfg_on_link_up_80003es2lan - es2 link configuration after link-up
+ * @hw: pointer to the HW structure
+ * @duplex: current duplex setting
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * 10/100 operation.
+ **/
+static INT32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 speed;
+ UINT16 duplex;
+
+ DEBUGFUNC("e1000_configure_on_link_up");
+
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw,
+ &speed,
+ &duplex);
+ if (ret_val)
+ goto out;
+
+ if (speed == SPEED_1000)
+ ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
+ else
+ ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, duplex);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
+ * @hw: pointer to the HW structure
+ * @duplex: current duplex setting
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * 10/100 operation.
+ **/
+static INT32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, UINT16 duplex)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 tipg;
+ UINT32 i = 0;
+ UINT16 reg_data, reg_data2;
+
+ DEBUGFUNC("e1000_configure_kmrn_for_10_100");
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, E1000_TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TIPG, tipg);
+
+ do {
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data2);
+ if (ret_val)
+ goto out;
+ i++;
+ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
+ * @hw: pointer to the HW structure
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * gigabit operation.
+ **/
+static INT32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 reg_data, reg_data2;
+ UINT32 tipg;
+ UINT32 i = 0;
+
+ DEBUGFUNC("e1000_configure_kmrn_for_1000");
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, E1000_TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TIPG, tipg);
+
+ do {
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data2);
+ if (ret_val)
+ goto out;
+ i++;
+ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_kmrn_reg_80003es2lan - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquire semaphore, then read the PHY register at offset
+ * using the kumeran interface. The information retrieved is stored in data.
+ * Release the semaphore before exiting.
+ **/
+static INT32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_kmrn_reg_80003es2lan");
+
+ ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
+ *data = (UINT16)kmrnctrlsta;
+
+ e1000_release_mac_csr_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_kmrn_reg_80003es2lan - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquire semaphore, then write the data to PHY register
+ * at the offset using the kumeran interface. Release semaphore
+ * before exiting.
+ **/
+static INT32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 data)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_kmrn_reg_80003es2lan");
+
+ ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | data;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ e1000_release_mac_csr_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_mac_addr_80003es2lan - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_mac_addr_80003es2lan");
+
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw)
+{
+ /* If the management interface is not enabled, then power down */
+ if (!(hw->mac.ops.check_mng_mode(hw) ||
+ hw->phy.ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+STATIC void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_80003es2lan");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_PRC64);
+ E1000_READ_REG(hw, E1000_PRC127);
+ E1000_READ_REG(hw, E1000_PRC255);
+ E1000_READ_REG(hw, E1000_PRC511);
+ E1000_READ_REG(hw, E1000_PRC1023);
+ E1000_READ_REG(hw, E1000_PRC1522);
+ E1000_READ_REG(hw, E1000_PTC64);
+ E1000_READ_REG(hw, E1000_PTC127);
+ E1000_READ_REG(hw, E1000_PTC255);
+ E1000_READ_REG(hw, E1000_PTC511);
+ E1000_READ_REG(hw, E1000_PTC1023);
+ E1000_READ_REG(hw, E1000_PTC1522);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ E1000_READ_REG(hw, E1000_ICRXPTC);
+ E1000_READ_REG(hw, E1000_ICRXATC);
+ E1000_READ_REG(hw, E1000_ICTXPTC);
+ E1000_READ_REG(hw, E1000_ICTXATC);
+ E1000_READ_REG(hw, E1000_ICTXQEC);
+ E1000_READ_REG(hw, E1000_ICTXQMTC);
+ E1000_READ_REG(hw, E1000_ICRXDMTC);
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h
new file mode 100755
index 0000000..252905d
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h
@@ -0,0 +1,103 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_80003ES2LAN_H_
+#define _E1000_80003ES2LAN_H_
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
+#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
+#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000
+
+#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C
+#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disabled */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000
+ /* 1=Reverse Auto-Negotiation */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_2_5 0x0006
+#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-100M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define GG82563_DSPD_CABLE_LENGTH 0x0007
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+
+/* Max number of times Kumeran read/write should be validated */
+#define GG82563_MAX_KMRN_RETRY 0x5
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
+ /* 1=Enable SERDES Electrical Idle */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c
new file mode 100755
index 0000000..2140738
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c
@@ -0,0 +1,2042 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 82571EB Gigabit Ethernet Controller
+ * 82571EB Gigabit Ethernet Controller (Copper)
+ * 82571EB Gigabit Ethernet Controller (Fiber)
+ * 82571PT Gigabit PT Quad Port Server ExpressModule
+ * 82572EI Gigabit Ethernet Controller (Copper)
+ * 82572EI Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller
+ * 82573V Gigabit Ethernet Controller (Copper)
+ * 82573E Gigabit Ethernet Controller (Copper)
+ * 82573L Gigabit Ethernet Controller
+#ifndef NO_82574_SUPPORT
+ * 82574L Gigabit Network Connection
+ * 82583V Gigabit Network Connection
+#endif
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_82571(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_write_nvm_82571(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_get_cfg_done_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_reset_hw_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_init_hw_82571(struct e1000_hw *hw);
+STATIC void e1000_clear_vfta_82571(struct e1000_hw *hw);
+#ifndef NO_82574_SUPPORT
+STATIC BOOLEAN e1000_check_mng_mode_82574(struct e1000_hw *hw);
+STATIC INT32 e1000_led_on_82574(struct e1000_hw *hw);
+#endif /* NO_82574_SUPPORT */
+STATIC INT32 e1000_setup_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_valid_led_default_82571(struct e1000_hw *hw, UINT16 *data);
+STATIC void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+static INT32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw);
+static INT32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
+static INT32 e1000_get_phy_id_82571(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
+static INT32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw);
+#ifndef NO_82574_SUPPORT
+static INT32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw);
+#endif /* NO_82574_SUPPORT */
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
+static INT32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_read_mac_addr_82571(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_82571(struct e1000_hw *hw);
+
+/**
+ * e1000_init_phy_params_82571 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_phy_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_init_phy_params_82571");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ goto out;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+
+ phy->ops.check_reset_block = e1000_check_reset_block_generic;
+ phy->ops.reset = e1000_phy_hw_reset_generic;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82571;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_82571;
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ phy->type = e1000_phy_igp_2;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_82571;
+ phy->ops.get_info = e1000_get_phy_info_igp;
+ phy->ops.check_polarity = e1000_check_polarity_igp;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
+ phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
+ phy->ops.read_reg = e1000_read_phy_reg_igp;
+ phy->ops.write_reg = e1000_write_phy_reg_igp;
+ phy->ops.acquire = e1000_get_hw_semaphore_82571;
+ phy->ops.release = e1000_put_hw_semaphore_82571;
+
+ /* This uses above function pointers */
+ ret_val = e1000_get_phy_id_82571(hw);
+
+ /* Verify PHY ID */
+ if (phy->id != IGP01E1000_I_PHY_ID) {
+ ret_val = -E1000_ERR_PHY;
+ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+ goto out;
+ }
+ break;
+ case e1000_82573:
+ phy->type = e1000_phy_m88;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.read_reg = e1000_read_phy_reg_m88;
+ phy->ops.write_reg = e1000_write_phy_reg_m88;
+ phy->ops.acquire = e1000_get_hw_semaphore_82571;
+ phy->ops.release = e1000_put_hw_semaphore_82571;
+
+ /* This uses above function pointers */
+ ret_val = e1000_get_phy_id_82571(hw);
+
+ /* Verify PHY ID */
+ if (phy->id != M88E1111_I_PHY_ID) {
+ ret_val = -E1000_ERR_PHY;
+ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+ goto out;
+ }
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ //E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
+
+ phy->type = e1000_phy_bm;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.read_reg = e1000_read_phy_reg_bm2;
+ phy->ops.write_reg = e1000_write_phy_reg_bm2;
+ phy->ops.acquire = e1000_get_hw_semaphore_82574;
+ phy->ops.release = e1000_put_hw_semaphore_82574;
+
+ /* This uses above function pointers */
+ ret_val = e1000_get_phy_id_82571(hw);
+ /* Verify PHY ID */
+ if (phy->id != BME1000_E_PHY_ID_R2) {
+ ret_val = -E1000_ERR_PHY;
+ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+ goto out;
+ }
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_82571 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT16 size;
+
+ DEBUGFUNC("e1000_init_nvm_params_82571");
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (((eecd >> 15) & 0x3) == 0x3) {
+ nvm->type = e1000_nvm_flash_hw;
+ nvm->word_size = 2048;
+ /*
+ * Autonomous Flash update bit must be cleared due
+ * to Flash update issue.
+ */
+ eecd &= ~E1000_EECD_AUPDEN;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ break;
+ }
+ /* Fall Through */
+ default:
+ nvm->type = e1000_nvm_eeprom_spi;
+ size = (UINT16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ /*
+ * Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+
+ /* EEPROM access above 16k is unsupported */
+ if (size > 14)
+ size = 14;
+ nvm->word_size = 1 << size;
+ break;
+ }
+
+ /* Function Pointers */
+ switch (hw->mac.type) {
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ nvm->ops.acquire = e1000_get_hw_semaphore_82574;
+ nvm->ops.release = e1000_put_hw_semaphore_82574;
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ nvm->ops.acquire = e1000_acquire_nvm_82571;
+ nvm->ops.release = e1000_release_nvm_82571;
+ break;
+ }
+ nvm->ops.read = e1000_read_nvm_eerd;
+ nvm->ops.update = e1000_update_nvm_checksum_82571;
+ nvm->ops.validate = e1000_validate_nvm_checksum_82571;
+ nvm->ops.valid_led_default = e1000_valid_led_default_82571;
+ nvm->ops.write = e1000_write_nvm_82571;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_mac_params_82571 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_mac_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 swsm = 0;
+ UINT32 swsm2 = 0;
+ BOOLEAN force_clear_smbi = FALSE;
+
+ DEBUGFUNC("e1000_init_mac_params_82571");
+
+ /* Set media type and media-dependent function pointers */
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ hw->phy.media_type = e1000_media_type_fiber;
+ mac->ops.setup_physical_interface =
+ e1000_setup_fiber_serdes_link_82571;
+ mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
+ mac->ops.get_link_up_info =
+ e1000_get_speed_and_duplex_fiber_serdes_generic;
+ break;
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82572EI_SERDES:
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ mac->ops.setup_physical_interface =
+ e1000_setup_fiber_serdes_link_82571;
+ mac->ops.check_for_link = e1000_check_for_serdes_link_82571;
+ mac->ops.get_link_up_info =
+ e1000_get_speed_and_duplex_fiber_serdes_generic;
+ break;
+#ifndef NO_82574_SUPPORT
+#endif /* NO_82574_SUPPORT */
+ default:
+ hw->phy.media_type = e1000_media_type_copper;
+ mac->ops.setup_physical_interface =
+ e1000_setup_copper_link_82571;
+ mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+ mac->ops.get_link_up_info =
+ e1000_get_speed_and_duplex_copper_generic;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* Adaptive IFS supported */
+ mac->adaptive_ifs = TRUE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+ /* reset */
+ mac->ops.reset_hw = e1000_reset_hw_82571;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_82571;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_82571;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* writing VFTA */
+ mac->ops.write_vfta = e1000_write_vfta_generic;
+ /* clearing VFTA */
+ mac->ops.clear_vfta = e1000_clear_vfta_82571;
+ /* read mac address */
+ mac->ops.read_mac_addr = e1000_read_mac_addr_82571;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_generic;
+ /* turn off LED */
+ mac->ops.led_off = e1000_led_off_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82571;
+
+ /* MAC-specific function pointers */
+ switch (hw->mac.type) {
+ case e1000_82573:
+ mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+ mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+ mac->ops.led_on = e1000_led_on_generic;
+
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /*
+ * ARC supported; valid only if manageability features are
+ * enabled.
+ */
+ mac->arc_subsystem_valid =
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+ ? TRUE : FALSE;
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+ mac->ops.check_mng_mode = e1000_check_mng_mode_82574;
+ mac->ops.led_on = e1000_led_on_82574;
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+ mac->ops.led_on = e1000_led_on_generic;
+
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ break;
+ }
+
+ /*
+ * Ensure that the inter-port SWSM.SMBI lock bit is clear before
+ * first NVM or PHY acess. This should be done for single-port
+ * devices, and for one port only on dual-port devices so that
+ * for those devices we can still use the SMBI lock to synchronize
+ * inter-port accesses to the PHY & NVM.
+ */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ swsm2 = E1000_READ_REG(hw, E1000_SWSM2);
+
+ if (!(swsm2 & E1000_SWSM2_LOCK)) {
+ /* Only do this for the first interface on this card */
+ E1000_WRITE_REG(hw, E1000_SWSM2,
+ swsm2 | E1000_SWSM2_LOCK);
+ force_clear_smbi = TRUE;
+ } else
+ force_clear_smbi = FALSE;
+ break;
+ default:
+ force_clear_smbi = TRUE;
+ break;
+ }
+
+ if (force_clear_smbi) {
+ /* Make sure SWSM.SMBI is clear */
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ if (swsm & E1000_SWSM_SMBI) {
+ /* This bit should not be set on a first interface, and
+ * indicates that the bootagent or EFI code has
+ * improperly left this bit enabled
+ */
+ DEBUGOUT("Please update your 82571 Bootagent\n");
+ }
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm & ~E1000_SWSM_SMBI);
+ }
+
+ /*
+ * Initialze device specific counter of SMBI acquisition
+ * timeouts.
+ */
+ hw->dev_spec._82571.smb_counter = 0;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_function_pointers_82571 - Init func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_82571");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_82571;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_82571;
+ hw->phy.ops.init_params = e1000_init_phy_params_82571;
+}
+
+/**
+ * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+static INT32 e1000_get_phy_id_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+#ifndef NO_82574_SUPPORT
+ UINT16 phy_id = 0;
+#endif /* NO_82574_SUPPORT */
+
+ DEBUGFUNC("e1000_get_phy_id_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /*
+ * The 82571 firmware may still be configuring the PHY.
+ * In this case, we cannot access the PHY until the
+ * configuration is done. So we explicitly set the
+ * PHY ID.
+ */
+ phy->id = IGP01E1000_I_PHY_ID;
+ break;
+ case e1000_82573:
+ ret_val = e1000_get_phy_id(hw);
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id = (UINT32)(phy_id << 16);
+ usec_delay(20);
+ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id |= (UINT32)(phy_id);
+ phy->revision = (UINT32)(phy_id & ~PHY_REVISION_MASK);
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+#ifndef NO_82574_SUPPORT
+out:
+#endif /* NO_82574_SUPPORT */
+ return ret_val;
+}
+
+/**
+ * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+static INT32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 sw_timeout = hw->nvm.word_size + 1;
+ INT32 fw_timeout = hw->nvm.word_size + 1;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_82571");
+
+ /*
+ * If we have timedout 3 times on trying to acquire
+ * the inter-port SMBI semaphore, there is old code
+ * operating on the other port, and it is not
+ * releasing SMBI. Modify the number of times that
+ * we try for the semaphore to interwork with this
+ * older code.
+ */
+ if (hw->dev_spec._82571.smb_counter > 2)
+ sw_timeout = 1;
+
+ /* Get the SW semaphore */
+ while (i < sw_timeout) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ usec_delay(50);
+ i++;
+ }
+
+ if (i == sw_timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ hw->dev_spec._82571.smb_counter++;
+ }
+ /* Get the FW semaphore. */
+ for (i = 0; i < fw_timeout; i++) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ usec_delay(50);
+ }
+
+ if (i == fw_timeout) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_82571(hw);
+ DEBUGOUT("Driver can't access the NVM\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82571 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_generic");
+
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ * e1000_get_hw_semaphore_82573 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore during reset.
+ *
+ **/
+static INT32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_82573");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+ do {
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ break;
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ msec_delay(2);
+ i++;
+ } while (i < MDIO_OWNERSHIP_TIMEOUT);
+
+ if (i == MDIO_OWNERSHIP_TIMEOUT) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_82573(hw);
+ DEBUGOUT("Driver can't access the PHY\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82573 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used during reset.
+ *
+ **/
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_82573");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+}
+
+#ifndef NO_82574_SUPPORT
+/**
+ * e1000_get_hw_semaphore_82574 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM.
+ *
+ **/
+static INT32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_get_hw_semaphore_82574");
+
+ //E1000_MUTEX_LOCK(&hw->dev_spec._82571.swflag_mutex);
+ return e1000_get_hw_semaphore_82573(hw);
+}
+
+/**
+ * e1000_put_hw_semaphore_82574 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ *
+ **/
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_put_hw_semaphore_82574");
+
+ e1000_put_hw_semaphore_82573(hw);
+ //E1000_MUTEX_UNLOCK(&hw->dev_spec._82571.swflag_mutex);
+}
+
+#endif /* NO_82574_SUPPORT */
+/**
+ * e1000_acquire_nvm_82571 - Request for access to the EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * To gain access to the EEPROM, first we must obtain a hardware semaphore.
+ * Then for non-82573 hardware, set the EEPROM access request bit and wait
+ * for EEPROM access grant bit. If the access grant bit is not set, release
+ * hardware semaphore.
+ **/
+STATIC INT32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_acquire_nvm_82571");
+
+ ret_val = e1000_get_hw_semaphore_82571(hw);
+ if (ret_val)
+ goto out;
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+ break;
+ default:
+ ret_val = e1000_acquire_nvm_generic(hw);
+ break;
+ }
+
+ if (ret_val)
+ e1000_put_hw_semaphore_82571(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_82571 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+STATIC void e1000_release_nvm_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_82571");
+
+ e1000_release_nvm_generic(hw);
+ e1000_put_hw_semaphore_82571(hw);
+}
+
+/**
+ * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * For non-82573 silicon, write data to EEPROM at offset using SPI interface.
+ *
+ * If e1000_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+STATIC INT32 e1000_write_nvm_82571(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_nvm_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ ret_val = e1000_write_nvm_spi(hw, offset, words, data);
+ break;
+ default:
+ ret_val = -E1000_ERR_NVM;
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_82571 - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+STATIC INT32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ UINT32 eecd;
+ INT32 ret_val;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_update_nvm_checksum_82571");
+
+ ret_val = e1000_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * If our nvm is an EEPROM, then we're done
+ * otherwise, commit the checksum to the flash NVM.
+ */
+ if (hw->nvm.type != e1000_nvm_flash_hw)
+ goto out;
+
+ /* Check for pending operations. */
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msec_delay(1);
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Reset the firmware if using STM opcode. */
+ if ((E1000_READ_REG(hw, E1000_FLOP) & 0xFF00) == E1000_STM_OPCODE) {
+ /*
+ * The enabling of and the actual reset must be done
+ * in two write cycles.
+ */
+ E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET_ENABLE);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET);
+ }
+
+ /* Commit the write to flash */
+ eecd = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msec_delay(1);
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+STATIC INT32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_validate_nvm_checksum_82571");
+
+ if (hw->nvm.type == e1000_nvm_flash_hw)
+ e1000_fix_nvm_checksum_82571(hw);
+
+ return e1000_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * After checking for invalid values, poll the EEPROM to ensure the previous
+ * command has completed before trying to write the next word. After write
+ * poll for completion.
+ *
+ * If e1000_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+static INT32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 i, eewr = 0;
+ INT32 ret_val = 0;
+
+ DEBUGFUNC("e1000_write_nvm_eewr_82571");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
+ ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+ E1000_NVM_RW_REG_START;
+
+ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+
+ E1000_WRITE_REG(hw, E1000_EEWR, eewr);
+
+ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cfg_done_82571 - Poll for configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Reads the management control register for the config done bit to be set.
+ **/
+STATIC INT32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
+{
+ INT32 timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_get_cfg_done_82571");
+
+ while (timeout) {
+ if (E1000_READ_REG(hw, E1000_EEMNGCTL) &
+ E1000_NVM_CFG_DONE_PORT_0)
+ break;
+ msec_delay(1);
+ timeout--;
+ }
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+ ret_val = -E1000_ERR_RESET;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When activating LPLU
+ * this function also disables smart speed and vice versa. LPLU will not be
+ * activated unless the device autonegotiation advertisement meets standards
+ * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function
+ * pointer entry point only called by PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d0_lplu_state_82571");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(phy->ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ goto out;
+
+ if (active) {
+ data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else {
+ data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_82571 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state.
+ **/
+STATIC INT32 e1000_reset_hw_82571(struct e1000_hw *hw)
+{
+ UINT32 ctrl, ctrl_ext;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_82571");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ /*
+ * Must acquire the MDIO ownership before MAC reset.
+ * Ownership defaults to firmware after a reset.
+ */
+ switch (hw->mac.type) {
+ case e1000_82573:
+ ret_val = e1000_get_hw_semaphore_82573(hw);
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ ret_val = e1000_get_hw_semaphore_82574(hw);
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ break;
+ }
+ if (ret_val)
+ DEBUGOUT("Cannot acquire MDIO ownership\n");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+#ifndef NO_82574_SUPPORT
+ /* Must release MDIO ownership and mutex after MAC reset. */
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ e1000_put_hw_semaphore_82574(hw);
+ break;
+ default:
+ break;
+ }
+
+#endif /* NO_82574_SUPPORT */
+ if (hw->nvm.type == e1000_nvm_flash_hw) {
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ goto out;
+
+ /*
+ * Phy configuration from NVM just starts after EECD_AUTO_RD is set.
+ * Need to wait for Phy configuration completion before accessing
+ * NVM and Phy.
+ */
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ msec_delay(25);
+ break;
+ default:
+ break;
+ }
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ if (hw->mac.type == e1000_82571) {
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ e1000_set_laa_state_82571(hw, TRUE);
+ }
+
+ /* Reinitialize the 82571 serdes link state machine */
+ if (hw->phy.media_type == e1000_media_type_internal_serdes)
+ hw->mac.serdes_link_state = e1000_serdes_link_down;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_82571 - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation.
+ **/
+STATIC INT32 e1000_init_hw_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 reg_data;
+ INT32 ret_val;
+ UINT16 i, rar_count = mac->rar_entry_count;
+
+ DEBUGFUNC("e1000_init_hw_82571");
+
+ e1000_initialize_hw_bits_82571(hw);
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val)
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+
+ /* Disabling VLAN filtering */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ mac->ops.clear_vfta(hw);
+
+ /* Setup the receive address. */
+ /*
+ * If, however, a locally administered address was assigned to the
+ * 82571, we must reserve a RAR for it to work around an issue where
+ * resetting one port will reload the MAC on the other port.
+ */
+ if (e1000_get_laa_state_82571(hw))
+ rar_count--;
+ e1000_init_rx_addrs_generic(hw, rar_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
+
+ /* ...for both queues. */
+ switch (mac->type) {
+ case e1000_82573:
+ e1000_enable_tx_pkt_filtering_generic(hw);
+#ifndef NO_82574_SUPPORT
+ /* fall through */
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ reg_data = E1000_READ_REG(hw, E1000_GCR);
+ reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ E1000_WRITE_REG(hw, E1000_GCR, reg_data);
+ break;
+ default:
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
+ break;
+ }
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_82571(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_initialize_hw_bits_82571");
+
+ /* Transmit Descriptor Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TARC(0));
+ reg &= ~(0xF << 27); /* 30:27 */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
+ break;
+ default:
+ break;
+ }
+ E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TARC(1));
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg &= ~((1 << 29) | (1 << 30));
+ reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
+ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+ break;
+ default:
+ break;
+ }
+
+ /* Device Control */
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ reg = E1000_READ_REG(hw, E1000_CTRL);
+ reg &= ~(1 << 29);
+ E1000_WRITE_REG(hw, E1000_CTRL, reg);
+ break;
+ default:
+ break;
+ }
+
+ /* Extended Device Control */
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg &= ~(1 << 23);
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+ break;
+ default:
+ break;
+ }
+
+ if (hw->mac.type == e1000_82571) {
+ reg = E1000_READ_REG(hw, E1000_PBA_ECC);
+ reg |= E1000_PBA_ECC_CORR_EN;
+ E1000_WRITE_REG(hw, E1000_PBA_ECC, reg);
+ }
+
+ /*
+ * Workaround for hardware errata.
+ * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572
+ */
+ if ((hw->mac.type == e1000_82571) ||
+ (hw->mac.type == e1000_82572)) {
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_DMA_DYN_CLK_EN;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+ }
+
+#ifndef NO_82574_SUPPORT
+ /* PCI-Ex Control Registers */
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ reg = E1000_READ_REG(hw, E1000_GCR);
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_GCR, reg);
+
+ /*
+ * Workaround for hardware errata.
+ * apply workaround for hardware errata documented in errata
+ * docs Fixes issue where some error prone or unreliable PCIe
+ * completions are occurring, particularly with ASPM enabled.
+ * Without fix, issue can cause tx timeouts.
+ */
+ reg = E1000_READ_REG(hw, E1000_GCR2);
+ reg |= 1;
+ E1000_WRITE_REG(hw, E1000_GCR2, reg);
+ break;
+ default:
+ break;
+ }
+
+#endif /* NO_82574_SUPPORT */
+ return;
+}
+
+/**
+ * e1000_clear_vfta_82571 - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * Clears the register array which contains the VLAN filter table by
+ * setting all the values to 0.
+ **/
+STATIC void e1000_clear_vfta_82571(struct e1000_hw *hw)
+{
+ UINT32 offset;
+ UINT32 vfta_value = 0;
+ UINT32 vfta_offset = 0;
+ UINT32 vfta_bit_in_reg = 0;
+
+ DEBUGFUNC("e1000_clear_vfta_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (hw->mng_cookie.vlan_id != 0) {
+ /*
+ * The VFTA is a 4096b bit-field, each identifying
+ * a single VLAN ID. The following operations
+ * determine which 32b entry (i.e. offset) into the
+ * array we want to set the VLAN ID (i.e. bit) of
+ * the manageability unit.
+ */
+ vfta_offset = (hw->mng_cookie.vlan_id >>
+ E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
+ vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+ E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+ }
+ break;
+ default:
+ break;
+ }
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ /*
+ * If the offset we want to clear is the same offset of the
+ * manageability VLAN ID, then clear all bits except that of
+ * the manageability unit.
+ */
+ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
+ E1000_WRITE_FLUSH(hw);
+ }
+}
+
+#ifndef NO_82574_SUPPORT
+/**
+ * e1000_check_mng_mode_82574 - Check manageability is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Reads the NVM Initialization Control Word 2 and returns TRUE
+ * (>0) if any manageability is enabled, else FALSE (0).
+ **/
+STATIC BOOLEAN e1000_check_mng_mode_82574(struct e1000_hw *hw)
+{
+ UINT16 data;
+
+ DEBUGFUNC("e1000_check_mng_mode_82574");
+
+ hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+ return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
+}
+
+/**
+ * e1000_led_on_82574 - Turn LED on
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED on.
+ **/
+STATIC INT32 e1000_led_on_82574(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ UINT32 i;
+
+ DEBUGFUNC("e1000_led_on_82574");
+
+ ctrl = hw->mac.ledctl_mode2;
+ if (!(E1000_STATUS_LU & E1000_READ_REG(hw, E1000_STATUS))) {
+ /*
+ * If no link, then turn LED on by setting the invert bit
+ * for each LED that's "on" (0x0E) in ledctl_mode2.
+ */
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
+ }
+ E1000_WRITE_REG(hw, E1000_LEDCTL, ctrl);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_check_phy_82574 - check 82574 phy hung state
+ * @hw: pointer to the HW structure
+ *
+ * Returns whether phy is hung or not
+ **/
+BOOLEAN e1000_check_phy_82574(struct e1000_hw *hw)
+{
+ UINT16 status_1kbt = 0;
+ UINT16 receive_errors = 0;
+ BOOLEAN phy_hung = FALSE;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_phy_82574");
+
+ /*
+ * Read PHY Receive Error counter first, if its is max - all F's then
+ * read the Base1000T status register If both are max then PHY is hung.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, E1000_RECEIVE_ERROR_COUNTER,
+ &receive_errors);
+ if (ret_val)
+ goto out;
+ if (receive_errors == E1000_RECEIVE_ERROR_MAX) {
+ ret_val = hw->phy.ops.read_reg(hw, E1000_BASE1000T_STATUS,
+ &status_1kbt);
+ if (ret_val)
+ goto out;
+ if ((status_1kbt & E1000_IDLE_ERROR_COUNT_MASK) ==
+ E1000_IDLE_ERROR_COUNT_MASK)
+ phy_hung = TRUE;
+ }
+out:
+ return phy_hung;
+}
+
+#endif /* NO_82574_SUPPORT */
+
+/**
+ * e1000_setup_link_82571 - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+STATIC INT32 e1000_setup_link_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_setup_link_82571");
+
+ /*
+ * 82573 does not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (hw->fc.requested_mode == e1000_fc_default)
+ hw->fc.requested_mode = e1000_fc_full;
+ break;
+ default:
+ break;
+ }
+ return e1000_setup_link_generic(hw);
+}
+
+/**
+ * e1000_setup_copper_link_82571 - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Configures the link for auto-neg or forced speed and duplex. Then we check
+ * for link, once link is established calls to configure collision distance
+ * and flow control are called.
+ **/
+STATIC INT32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_setup_copper_link_82571");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
+#ifndef NO_82574_SUPPORT
+ case e1000_phy_bm:
+#endif /* NO_82574_SUPPORT */
+ ret_val = e1000_copper_link_setup_m88(hw);
+ break;
+ case e1000_phy_igp_2:
+ ret_val = e1000_copper_link_setup_igp(hw);
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes links.
+ * Upon successful setup, poll for link.
+ **/
+STATIC INT32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_setup_fiber_serdes_link_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /*
+ * If SerDes loopback mode is entered, there is no form
+ * of reset to take the adapter out of that mode. So we
+ * have to explicitly take the adapter out of loopback
+ * mode. This prevents drivers from twiddling their thumbs
+ * if another tool failed to take it out of loopback mode.
+ */
+ E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+ break;
+ default:
+ break;
+ }
+
+ return e1000_setup_fiber_serdes_link_generic(hw);
+}
+
+/**
+ * e1000_check_for_serdes_link_82571 - Check for link (Serdes)
+ * @hw: pointer to the HW structure
+ *
+ * Reports the link state as up or down.
+ *
+ * If autonegotiation is supported by the link partner, the link state is
+ * determined by the result of autonegotiation. This is the most likely case.
+ * If autonegotiation is not supported by the link partner, and the link
+ * has a valid signal, force the link up.
+ *
+ * The link state is represented internally here by 4 states:
+ *
+ * 1) down
+ * 2) autoneg_progress
+ * 3) autoneg_complete (the link sucessfully autonegotiated)
+ * 4) forced_up (the link has been forced up, it did not autonegotiate)
+ *
+ **/
+STATIC INT32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 rxcw;
+ UINT32 ctrl;
+ UINT32 status;
+ UINT32 txcw;
+ UINT32 i;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_for_serdes_link_82571");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+ if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
+
+ /* Receiver is synchronized with no invalid bits. */
+ switch (mac->serdes_link_state) {
+ case e1000_serdes_link_autoneg_complete:
+ if (!(status & E1000_STATUS_LU)) {
+ /*
+ * We have lost link, retry autoneg before
+ * reporting link failure
+ */
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("AN_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = TRUE;
+ }
+ break;
+
+ case e1000_serdes_link_forced_up:
+ /*
+ * If we are receiving /C/ ordered sets, re-enable
+ * auto-negotiation in the TXCW register and disable
+ * forced link in the Device Control register in an
+ * attempt to auto-negotiate with our link partner.
+ * If the partner code word is null, stop forcing
+ * and restart auto negotiation.
+ */
+ if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW)) {
+ /* Enable autoneg, and unforce link up */
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL,
+ (ctrl & ~E1000_CTRL_SLU));
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("FORCED_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = TRUE;
+ }
+ break;
+
+ case e1000_serdes_link_autoneg_progress:
+ if (rxcw & E1000_RXCW_C) {
+ /*
+ * We received /C/ ordered sets, meaning the
+ * link partner has autonegotiated, and we can
+ * trust the Link Up (LU) status bit.
+ */
+ if (status & E1000_STATUS_LU) {
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_complete;
+ DEBUGOUT("AN_PROG -> AN_UP\n");
+ mac->serdes_has_link = TRUE;
+ } else {
+ /* Autoneg completed, but failed. */
+ mac->serdes_link_state =
+ e1000_serdes_link_down;
+ DEBUGOUT("AN_PROG -> DOWN\n");
+ }
+ } else {
+ /*
+ * The link partner did not autoneg.
+ * Force link up and full duplex, and change
+ * state to forced.
+ */
+ E1000_WRITE_REG(hw, E1000_TXCW,
+ (mac->txcw & ~E1000_TXCW_ANE));
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Configure Flow Control after link up. */
+ ret_val =
+ e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error config flow control\n");
+ break;
+ }
+ mac->serdes_link_state =
+ e1000_serdes_link_forced_up;
+ mac->serdes_has_link = TRUE;
+ DEBUGOUT("AN_PROG -> FORCED_UP\n");
+ }
+ break;
+
+ case e1000_serdes_link_down:
+ default:
+ /*
+ * The link was down but the receiver has now gained
+ * valid sync, so lets see if we can bring the link
+ * up.
+ */
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL,
+ (ctrl & ~E1000_CTRL_SLU));
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("DOWN -> AN_PROG\n");
+ break;
+ }
+ } else {
+ if (!(rxcw & E1000_RXCW_SYNCH)) {
+ mac->serdes_has_link = FALSE;
+ mac->serdes_link_state = e1000_serdes_link_down;
+ DEBUGOUT("ANYSTATE -> DOWN\n");
+ } else {
+ /*
+ * Check several times, if Sync and Config
+ * both are consistently 1 then simply ignore
+ * the Invalid bit and restart Autoneg
+ */
+ for (i = 0; i < AN_RETRY_COUNT; i++) {
+ usec_delay(10);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+ if ((rxcw & E1000_RXCW_IV) &&
+ !((rxcw & E1000_RXCW_SYNCH) &&
+ (rxcw & E1000_RXCW_C))) {
+ mac->serdes_has_link = FALSE;
+ mac->serdes_link_state =
+ e1000_serdes_link_down;
+ DEBUGOUT("ANYSTATE -> DOWN\n");
+ break;
+ }
+ }
+
+ if (i == AN_RETRY_COUNT) {
+ txcw = E1000_READ_REG(hw, E1000_TXCW);
+ txcw |= E1000_TXCW_ANE;
+ E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("ANYSTATE -> AN_PROG\n");
+ }
+ }
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_valid_led_default_82571 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+STATIC INT32 e1000_valid_led_default_82571(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_82571");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (*data == ID_LED_RESERVED_F746)
+ *data = ID_LED_DEFAULT_82573;
+ break;
+ default:
+ if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_laa_state_82571 - Get locally administered address state
+ * @hw: pointer to the HW structure
+ *
+ * Retrieve and return the current locally administered address state.
+ **/
+BOOLEAN e1000_get_laa_state_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_get_laa_state_82571");
+
+ if (hw->mac.type != e1000_82571)
+ return FALSE;
+
+ return hw->dev_spec._82571.laa_is_present;
+}
+
+/**
+ * e1000_set_laa_state_82571 - Set locally administered address state
+ * @hw: pointer to the HW structure
+ * @state: enable/disable locally administered address
+ *
+ * Enable/Disable the current locally administered address state.
+ **/
+void e1000_set_laa_state_82571(struct e1000_hw *hw, BOOLEAN state)
+{
+ DEBUGFUNC("e1000_set_laa_state_82571");
+
+ if (hw->mac.type != e1000_82571)
+ return;
+
+ hw->dev_spec._82571.laa_is_present = state;
+
+ /* If workaround is activated... */
+ if (state)
+ /*
+ * Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed, the actual LAA is in one of the RARs and no
+ * incoming packets directed to this port are dropped.
+ * Eventually the LAA will be in RAR[0] and RAR[14].
+ */
+ e1000_rar_set_generic(hw, hw->mac.addr,
+ hw->mac.rar_entry_count - 1);
+ return;
+}
+
+/**
+ * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Verifies that the EEPROM has completed the update. After updating the
+ * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If
+ * the checksum fix is not implemented, we need to set the bit and update
+ * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect,
+ * we need to return bad checksum.
+ **/
+static INT32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_fix_nvm_checksum_82571");
+
+ if (nvm->type != e1000_nvm_flash_hw)
+ goto out;
+
+ /*
+ * Check bit 4 of word 10h. If it is 0, firmware is done updating
+ * 10h-12h. Checksum may need to be fixed.
+ */
+ ret_val = nvm->ops.read(hw, 0x10, 1, &data);
+ if (ret_val)
+ goto out;
+
+ if (!(data & 0x10)) {
+ /*
+ * Read 0x23 and check bit 15. This bit is a 1
+ * when the checksum has already been fixed. If
+ * the checksum is still wrong and this bit is a
+ * 1, we need to return bad checksum. Otherwise,
+ * we need to set this bit to a 1 and update the
+ * checksum.
+ */
+ ret_val = nvm->ops.read(hw, 0x23, 1, &data);
+ if (ret_val)
+ goto out;
+
+ if (!(data & 0x8000)) {
+ data |= 0x8000;
+ ret_val = nvm->ops.write(hw, 0x23, 1, &data);
+ if (ret_val)
+ goto out;
+ ret_val = nvm->ops.update(hw);
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+
+/**
+ * e1000_read_mac_addr_82571 - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_mac_addr_82571");
+
+ if (hw->mac.type == e1000_82571) {
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_82571 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ struct e1000_mac_info *mac = &hw->mac;
+
+ if (!(phy->ops.check_reset_block))
+ return;
+
+ /* If the management interface is not enabled, then power down */
+ if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+STATIC void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_82571");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_PRC64);
+ E1000_READ_REG(hw, E1000_PRC127);
+ E1000_READ_REG(hw, E1000_PRC255);
+ E1000_READ_REG(hw, E1000_PRC511);
+ E1000_READ_REG(hw, E1000_PRC1023);
+ E1000_READ_REG(hw, E1000_PRC1522);
+ E1000_READ_REG(hw, E1000_PTC64);
+ E1000_READ_REG(hw, E1000_PTC127);
+ E1000_READ_REG(hw, E1000_PTC255);
+ E1000_READ_REG(hw, E1000_PTC511);
+ E1000_READ_REG(hw, E1000_PTC1023);
+ E1000_READ_REG(hw, E1000_PTC1522);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ E1000_READ_REG(hw, E1000_ICRXPTC);
+ E1000_READ_REG(hw, E1000_ICRXATC);
+ E1000_READ_REG(hw, E1000_ICTXPTC);
+ E1000_READ_REG(hw, E1000_ICTXATC);
+ E1000_READ_REG(hw, E1000_ICTXQEC);
+ E1000_READ_REG(hw, E1000_ICTXQMTC);
+ E1000_READ_REG(hw, E1000_ICRXDMTC);
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h
new file mode 100755
index 0000000..987a827
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_82571_H_
+#define _E1000_82571_H_
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_ON2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define AN_RETRY_COUNT 5 /* Autoneg Retry Count value */
+
+#ifndef NO_82574_SUPPORT
+/* Intr Throttling - RW */
+#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n)))
+
+#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAC_MASK_82574 0x01F00000
+
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+
+#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
+
+#define E1000_BASE1000T_STATUS 10
+#define E1000_IDLE_ERROR_COUNT_MASK 0xFF
+#define E1000_RECEIVE_ERROR_COUNTER 21
+#define E1000_RECEIVE_ERROR_MAX 0xFFFF
+BOOLEAN e1000_check_phy_82574(struct e1000_hw *hw);
+#endif /* NO_82574_SUPPORT */
+BOOLEAN e1000_get_laa_state_82571(struct e1000_hw *hw);
+void e1000_set_laa_state_82571(struct e1000_hw *hw, BOOLEAN state);
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c
new file mode 100755
index 0000000..ca1e35b
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c
@@ -0,0 +1,2030 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 82575EB Gigabit Network Connection
+ * 82575EB Gigabit Backplane Connection
+ * 82575GB Gigabit Network Connection
+ * 82576 Gigabit Network Connection
+ * 82576 Quad Port Gigabit Mezzanine Adapter
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_phy_82575(struct e1000_hw *hw);
+STATIC void e1000_release_phy_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_82575(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_check_for_link_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_get_cfg_done_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_get_link_up_info_82575(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+STATIC INT32 e1000_init_hw_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data);
+STATIC INT32 e1000_reset_hw_82575(struct e1000_hw *hw);
+#ifndef NO_82580_SUPPORT
+STATIC INT32 e1000_reset_hw_82580(struct e1000_hw *hw);
+STATIC INT32 e1000_read_phy_reg_82580(struct e1000_hw *hw,
+ UINT32 offset, UINT16 *data);
+STATIC INT32 e1000_write_phy_reg_82580(struct e1000_hw *hw,
+ UINT32 offset, UINT16 data);
+#endif /* NO_82580_SUPPORT */
+STATIC INT32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_setup_copper_link_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_serdes_link_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_valid_led_default_82575(struct e1000_hw *hw, UINT16 *data);
+STATIC INT32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw,
+ UINT32 offset, UINT16 data);
+STATIC void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask);
+static INT32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex);
+static INT32 e1000_get_phy_id_82575(struct e1000_hw *hw);
+STATIC void e1000_release_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask);
+static BOOLEAN e1000_sgmii_active_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_reset_init_script_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_read_mac_addr_82575(struct e1000_hw *hw);
+STATIC void e1000_config_collision_dist_82575(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_82575(struct e1000_hw *hw);
+#ifndef NO_82576_SUPPORT
+STATIC void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw);
+STATIC void e1000_power_up_serdes_link_82575(struct e1000_hw *hw);
+#endif
+STATIC INT32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw);
+#ifndef NO_82580_SUPPORT
+STATIC INT32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw);
+
+static const UINT16 e1000_82580_rxpbs_table[] =
+ { 36, 72, 144, 1, 2, 4, 8, 16,
+ 35, 70, 140 };
+#define E1000_82580_RXPBS_TABLE_SIZE \
+ (sizeof(e1000_82580_rxpbs_table)/sizeof(UINT16))
+
+#endif /* NO_82580_SUPPORT */
+
+/**
+ * e1000_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
+ * @hw: pointer to the HW structure
+ *
+ * Called to determine if the I2C pins are being used for I2C or as an
+ * external MDIO interface since the two options are mutually exclusive.
+ **/
+STATIC BOOLEAN e1000_sgmii_uses_mdio_82575(struct e1000_hw *hw)
+{
+ UINT32 reg = 0;
+ BOOLEAN ext_mdio = FALSE;
+
+ DEBUGFUNC("e1000_sgmii_uses_mdio_82575");
+
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ reg = E1000_READ_REG(hw, E1000_MDIC);
+ ext_mdio = !!(reg & E1000_MDIC_DEST);
+ break;
+#ifndef NO_82580_SUPPORT
+ case e1000_82580:
+ reg = E1000_READ_REG(hw, E1000_MDICNFG);
+ ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);
+ break;
+#endif /* NO_82580_SUPPORT */
+ default:
+ break;
+ }
+ return ext_mdio;
+}
+
+/**
+ * e1000_init_phy_params_82575 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_phy_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 ctrl_ext;
+
+ DEBUGFUNC("e1000_init_phy_params_82575");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ goto out;
+ }
+
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_82575;
+
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+
+ phy->ops.acquire = e1000_acquire_phy_82575;
+ phy->ops.check_reset_block = e1000_check_reset_block_generic;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_82575;
+ phy->ops.release = e1000_release_phy_82575;
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+
+ if (e1000_sgmii_active_82575(hw)) {
+ phy->ops.reset = e1000_phy_hw_reset_sgmii_82575;
+ ctrl_ext |= E1000_CTRL_I2C_ENA;
+ } else {
+ phy->ops.reset = e1000_phy_hw_reset_generic;
+ ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+ }
+
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+#ifndef NO_82580_SUPPORT
+ e1000_reset_mdicnfg_82580(hw);
+
+#endif /* NO_82580_SUPPORT */
+ if (e1000_sgmii_active_82575(hw) && !e1000_sgmii_uses_mdio_82575(hw)) {
+ phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575;
+ phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575;
+#ifndef NO_82580_SUPPORT
+ } else if (hw->mac.type >= e1000_82580) {
+ phy->ops.read_reg = e1000_read_phy_reg_82580;
+ phy->ops.write_reg = e1000_write_phy_reg_82580;
+#endif /* NO_82580_SUPPORT */
+ } else {
+ phy->ops.read_reg = e1000_read_phy_reg_igp;
+ phy->ops.write_reg = e1000_write_phy_reg_igp;
+ }
+
+ /* Set phy->phy_addr and phy->id. */
+ ret_val = e1000_get_phy_id_82575(hw);
+
+ /* Verify phy id and set remaining function pointers */
+ switch (phy->id) {
+ case M88E1111_I_PHY_ID:
+ phy->type = e1000_phy_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ break;
+ case IGP03E1000_E_PHY_ID:
+#ifndef NO_82576_SUPPORT
+ case IGP04E1000_E_PHY_ID:
+#endif /* NO_82576_SUPPORT */
+ phy->type = e1000_phy_igp_3;
+ phy->ops.check_polarity = e1000_check_polarity_igp;
+ phy->ops.get_info = e1000_get_phy_info_igp;
+ phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82575;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
+ break;
+#ifndef NO_82580_SUPPORT
+ case I82580_I_PHY_ID:
+ phy->type = e1000_phy_82580;
+ phy->ops.check_polarity = e1000_check_polarity_82577;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82577;
+ phy->ops.get_cable_length = e1000_get_cable_length_82577;
+ phy->ops.get_info = e1000_get_phy_info_82577;
+ break;
+#endif
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_82575 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_nvm_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT16 size;
+
+ DEBUGFUNC("e1000_init_nvm_params_82575");
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ nvm->type = e1000_nvm_eeprom_spi;
+
+ size = (UINT16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+
+ /*
+ * Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+
+ /* EEPROM access above 16k is unsupported */
+ if (size > 14)
+ size = 14;
+ nvm->word_size = 1 << size;
+
+ /* Function Pointers */
+ nvm->ops.acquire = e1000_acquire_nvm_82575;
+ nvm->ops.read = e1000_read_nvm_eerd;
+ nvm->ops.release = e1000_release_nvm_82575;
+ nvm->ops.update = e1000_update_nvm_checksum_generic;
+ nvm->ops.valid_led_default = e1000_valid_led_default_82575;
+ nvm->ops.validate = e1000_validate_nvm_checksum_generic;
+ nvm->ops.write = e1000_write_nvm_spi;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_mac_params_82575 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_mac_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+ UINT32 ctrl_ext = 0;
+
+ DEBUGFUNC("e1000_init_mac_params_82575");
+
+ /* Set media type */
+ /*
+ * The 82575 uses bits 22:23 for link mode. The mode can be changed
+ * based on the EEPROM. We cannot rely upon device ID. There
+ * is no distinguishable difference between fiber and internal
+ * SerDes mode on the 82575. There can be an external PHY attached
+ * on the SGMII interface. For this, we'll set sgmii_active to TRUE.
+ */
+ hw->phy.media_type = e1000_media_type_copper;
+ dev_spec->sgmii_active = FALSE;
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
+ case E1000_CTRL_EXT_LINK_MODE_SGMII:
+ dev_spec->sgmii_active = TRUE;
+ break;
+#ifndef NO_82580_SUPPORT
+ case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
+#endif
+ case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+#ifndef NO_82576_SUPPORT
+ /* Set uta register count */
+ mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
+#endif
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+#ifndef NO_82576_SUPPORT
+ if (mac->type == e1000_82576)
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
+#endif
+#ifndef NO_82580_SUPPORT
+ if (mac->type == e1000_82580)
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /* ARC supported; valid only if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+ ? TRUE : FALSE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+ /* reset */
+#ifndef NO_82580_SUPPORT
+ if (mac->type >= e1000_82580)
+ mac->ops.reset_hw = e1000_reset_hw_82580;
+ else
+#endif /* NO_82580_SUPPORT */
+ mac->ops.reset_hw = e1000_reset_hw_82575;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_82575;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_generic;
+ /* physical interface link setup */
+ mac->ops.setup_physical_interface =
+ (hw->phy.media_type == e1000_media_type_copper)
+ ? e1000_setup_copper_link_82575
+ : e1000_setup_serdes_link_82575;
+#ifndef NO_82576_SUPPORT
+ /* physical interface shutdown */
+ mac->ops.shutdown_serdes = e1000_shutdown_serdes_link_82575;
+ /* physical interface power up */
+ mac->ops.power_up_serdes = e1000_power_up_serdes_link_82575;
+#endif /* NO_82576_SUPPORT */
+ /* check for link */
+ mac->ops.check_for_link = e1000_check_for_link_82575;
+ /* receive address register setting */
+ mac->ops.rar_set = e1000_rar_set_generic;
+ /* read mac address */
+ mac->ops.read_mac_addr = e1000_read_mac_addr_82575;
+ /* configure collision distance */
+ mac->ops.config_collision_dist = e1000_config_collision_dist_82575;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* writing VFTA */
+ mac->ops.write_vfta = e1000_write_vfta_generic;
+ /* clearing VFTA */
+ mac->ops.clear_vfta = e1000_clear_vfta_generic;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_generic;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_generic;
+ mac->ops.led_off = e1000_led_off_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82575;
+ /* link info */
+ mac->ops.get_link_up_info = e1000_get_link_up_info_82575;
+
+ /* set lan id for port to determine which phy lock to use */
+ hw->mac.ops.set_lan_id(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_function_pointers_82575 - Init func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82575(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_82575");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_82575;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_82575;
+ hw->phy.ops.init_params = e1000_init_phy_params_82575;
+}
+
+/**
+ * e1000_acquire_phy_82575 - Acquire rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * Acquire access rights to the correct PHY.
+ **/
+STATIC INT32 e1000_acquire_phy_82575(struct e1000_hw *hw)
+{
+ UINT16 mask = E1000_SWFW_PHY0_SM;
+
+ DEBUGFUNC("e1000_acquire_phy_82575");
+
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_SWFW_PHY1_SM;
+#ifndef NO_82580_SUPPORT
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_SWFW_PHY2_SM;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_SWFW_PHY3_SM;
+#endif /* NO_82580_SUPPORT */
+
+ return e1000_acquire_swfw_sync_82575(hw, mask);
+}
+
+/**
+ * e1000_release_phy_82575 - Release rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to release access rights to the correct PHY.
+ **/
+STATIC void e1000_release_phy_82575(struct e1000_hw *hw)
+{
+ UINT16 mask = E1000_SWFW_PHY0_SM;
+
+ DEBUGFUNC("e1000_release_phy_82575");
+
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_SWFW_PHY1_SM;
+#ifndef NO_82580_SUPPORT
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_SWFW_PHY2_SM;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_SWFW_PHY3_SM;
+#endif /* NO_82580_SUPPORT */
+
+ e1000_release_swfw_sync_82575(hw, mask);
+}
+
+/**
+ * e1000_read_phy_reg_sgmii_82575 - Read PHY register using sgmii
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the serial gigabit media independent
+ * interface and stores the retrieved information in data.
+ **/
+STATIC INT32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data)
+{
+ INT32 ret_val = -E1000_ERR_PARAM;
+
+ DEBUGFUNC("e1000_read_phy_reg_sgmii_82575");
+
+ if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+ DEBUGOUT1("PHY Address %u is out of range\n", offset);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_phy_reg_i2c(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_sgmii_82575 - Write PHY register using sgmii
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset using the serial gigabit
+ * media independent interface.
+ **/
+STATIC INT32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw, UINT32 offset,
+ UINT16 data)
+{
+ INT32 ret_val = -E1000_ERR_PARAM;
+
+ DEBUGFUNC("e1000_write_phy_reg_sgmii_82575");
+
+ if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+ DEBUGOUT1("PHY Address %d is out of range\n", offset);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_write_phy_reg_i2c(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_id_82575 - Retrieve PHY addr and id
+ * @hw: pointer to the HW structure
+ *
+ * Retrieves the PHY address and ID for both PHY's which do and do not use
+ * sgmi interface.
+ **/
+STATIC INT32 e1000_get_phy_id_82575(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_id;
+ UINT32 ctrl_ext;
+ UINT32 mdic;
+
+ DEBUGFUNC("e1000_get_phy_id_82575");
+
+ /*
+ * For SGMII PHYs, we try the list of possible addresses until
+ * we find one that works. For non-SGMII PHYs
+ * (e.g. integrated copper PHYs), an address of 1 should
+ * work. The result of this function should mean phy->phy_addr
+ * and phy->id are set correctly.
+ */
+ if (!e1000_sgmii_active_82575(hw)) {
+ phy->addr = 1;
+ ret_val = e1000_get_phy_id(hw);
+ goto out;
+ }
+
+ if (e1000_sgmii_uses_mdio_82575(hw)) {
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ mdic = E1000_READ_REG(hw, E1000_MDIC);
+ mdic &= E1000_MDIC_PHY_MASK;
+ phy->addr = mdic >> E1000_MDIC_PHY_SHIFT;
+ break;
+#ifndef NO_82580_SUPPORT
+ case e1000_82580:
+ mdic = E1000_READ_REG(hw, E1000_MDICNFG);
+ mdic &= E1000_MDICNFG_PHY_MASK;
+ phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
+ break;
+#endif /* NO_82580_SUPPORT */
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ break;
+ }
+ ret_val = e1000_get_phy_id(hw);
+ goto out;
+ }
+
+ /* Power on sgmii phy if it is disabled */
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(300);
+
+ /*
+ * The address field in the I2CCMD register is 3 bits and 0 is invalid.
+ * Therefore, we need to test 1-7
+ */
+ for (phy->addr = 1; phy->addr < 8; phy->addr++) {
+ ret_val = e1000_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id);
+ if (ret_val == E1000_SUCCESS) {
+ DEBUGOUT2("Vendor ID 0x%08X read at address %u\n",
+ phy_id,
+ phy->addr);
+ /*
+ * At the time of this writing, The M88 part is
+ * the only supported SGMII PHY product.
+ */
+ if (phy_id == M88_VENDOR)
+ break;
+ } else {
+ DEBUGOUT1("PHY address %u was unreadable\n",
+ phy->addr);
+ }
+ }
+
+ /* A valid PHY type couldn't be found. */
+ if (phy->addr == 8) {
+ phy->addr = 0;
+ ret_val = -E1000_ERR_PHY;
+ } else {
+ ret_val = e1000_get_phy_id(hw);
+ }
+
+ /* restore previous sfp cage power state */
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_hw_reset_sgmii_82575 - Performs a PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Resets the PHY using the serial gigabit media independent interface.
+ **/
+STATIC INT32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_phy_hw_reset_sgmii_82575");
+
+ /*
+ * This isn't a TRUE "hard" reset, but is the only reset
+ * available to us at this time.
+ */
+
+ DEBUGOUT("Soft resetting SGMII attached PHY...\n");
+
+ if (!(hw->phy.ops.write_reg))
+ goto out;
+
+ /*
+ * SFP documentation requires the following to configure the SPF module
+ * to work on SGMII. No further documentation is given.
+ */
+ ret_val = hw->phy.ops.write_reg(hw, 0x1B, 0x8084);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.commit(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d0_lplu_state_82575");
+
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ goto out;
+
+ if (active) {
+ data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else {
+ data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_acquire_nvm_82575 - Request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the necessary semaphores for exclusive access to the EEPROM.
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+STATIC INT32 e1000_acquire_nvm_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_acquire_nvm_82575");
+
+ ret_val = e1000_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_acquire_nvm_generic(hw);
+
+ if (ret_val)
+ e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_82575 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ * then release the semaphores acquired.
+ **/
+STATIC void e1000_release_nvm_82575(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_82575");
+
+ e1000_release_nvm_generic(hw);
+ e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * e1000_acquire_swfw_sync_82575 - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+STATIC INT32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+ UINT32 swmask = mask;
+ UINT32 fwmask = mask << 16;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+ DEBUGFUNC("e1000_acquire_swfw_sync_82575");
+
+ while (i < timeout) {
+ if (e1000_get_hw_semaphore_generic(hw)) {
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask)
+ * or other software thread using resource (swmask)
+ */
+ e1000_put_hw_semaphore_generic(hw);
+ msec_delay_irq(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_swfw_sync_82575 - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+STATIC void e1000_release_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+
+ DEBUGFUNC("e1000_release_swfw_sync_82575");
+
+ while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS);
+ /* Empty */
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+}
+
+/**
+ * e1000_get_cfg_done_82575 - Read config done bit
+ * @hw: pointer to the HW structure
+ *
+ * Read the management control register for the config done bit for
+ * completion status. NOTE: silicon which is EEPROM-less will fail trying
+ * to read the config done bit, so an error is *ONLY* logged and returns
+ * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon
+ * would not be able to be reset or change link.
+ **/
+STATIC INT32 e1000_get_cfg_done_82575(struct e1000_hw *hw)
+{
+ INT32 timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+ DEBUGFUNC("e1000_get_cfg_done_82575");
+
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_NVM_CFG_DONE_PORT_1;
+#ifndef NO_82580_SUPPORT
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_NVM_CFG_DONE_PORT_2;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_NVM_CFG_DONE_PORT_3;
+#endif /* NO_82580_SUPPORT */
+ while (timeout) {
+ if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
+ break;
+ msec_delay(1);
+ timeout--;
+ }
+ if (!timeout)
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+
+ /* If EEPROM is not marked present, init the PHY manually */
+ if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+ (hw->phy.type == e1000_phy_igp_3))
+ e1000_phy_init_script_igp3(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_link_up_info_82575 - Get link speed/duplex info
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * This is a wrapper function, if using the serial gigabit media independent
+ * interface, use PCS to retrieve the link speed and duplex information.
+ * Otherwise, use the generic function to get the link speed and duplex info.
+ **/
+STATIC INT32 e1000_get_link_up_info_82575(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_link_up_info_82575");
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, speed,
+ duplex);
+ else
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed,
+ duplex);
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_link_82575 - Check for link
+ * @hw: pointer to the HW structure
+ *
+ * If sgmii is enabled, then use the pcs register to determine link, otherwise
+ * use the generic interface for determining link.
+ **/
+STATIC INT32 e1000_check_for_link_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 speed, duplex;
+
+ DEBUGFUNC("e1000_check_for_link_82575");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, &speed,
+ &duplex);
+ /*
+ * Use this flag to determine if link needs to be checked or
+ * not. If we have link clear the flag so that we do not
+ * continue to check for link.
+ */
+ hw->mac.get_link_status = !hw->mac.serdes_has_link;
+ } else {
+ ret_val = e1000_check_for_copper_link_generic(hw);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_power_up_serdes_link_82575 - Power up the serdes link after shutdown
+ * @hw: pointer to the HW structure
+ **/
+STATIC void e1000_power_up_serdes_link_82575(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_power_up_serdes_link_82575");
+
+ if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+ !e1000_sgmii_active_82575(hw))
+ return;
+
+ /* Enable PCS to turn on link */
+ reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
+ reg |= E1000_PCS_CFG_PCS_EN;
+ E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
+
+ /* Power up the laser */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_SDP3_DATA;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+ /* flush the write to verify completion */
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+}
+
+/**
+ * e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Using the physical coding sub-layer (PCS), retrieve the current speed and
+ * duplex, then store the values in the pointers provided.
+ **/
+static INT32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 pcs;
+
+ DEBUGFUNC("e1000_get_pcs_speed_and_duplex_82575");
+
+ /* Set up defaults for the return values of this function */
+ mac->serdes_has_link = FALSE;
+ *speed = 0;
+ *duplex = 0;
+
+ /*
+ * Read the PCS Status register for link state. For non-copper mode,
+ * the status register is not accurate. The PCS status register is
+ * used instead.
+ */
+ pcs = E1000_READ_REG(hw, E1000_PCS_LSTAT);
+
+ /*
+ * The link up bit determines when link is up on autoneg. The sync ok
+ * gets set once both sides sync up and agree upon link. Stable link
+ * can be determined by checking for both link up and link sync ok
+ */
+ if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) {
+ mac->serdes_has_link = TRUE;
+
+ /* Detect and store PCS speed */
+ if (pcs & E1000_PCS_LSTS_SPEED_1000) {
+ *speed = SPEED_1000;
+ } else if (pcs & E1000_PCS_LSTS_SPEED_100) {
+ *speed = SPEED_100;
+ } else {
+ *speed = SPEED_10;
+ }
+
+ /* Detect and store PCS duplex */
+ if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) {
+ *duplex = FULL_DUPLEX;
+ } else {
+ *duplex = HALF_DUPLEX;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_shutdown_serdes_link_82575 - Remove link during power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of serdes shut down sfp and PCS on driver unload
+ * when management pass thru is not enabled.
+ **/
+void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_shutdown_serdes_link_82575");
+
+ if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+ !e1000_sgmii_active_82575(hw))
+ return;
+
+ if (!e1000_enable_mng_pass_thru(hw)) {
+ /* Disable PCS to turn off link */
+ reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
+ reg &= ~E1000_PCS_CFG_PCS_EN;
+ E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
+
+ /* shutdown the laser */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg |= E1000_CTRL_EXT_SDP3_DATA;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+ /* flush the write to verify completion */
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+ }
+
+ return;
+}
+
+/**
+ * e1000_reset_hw_82575 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state.
+ **/
+STATIC INT32 e1000_reset_hw_82575(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_82575");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+ }
+
+ /* set the completion timeout for interface */
+ ret_val = e1000_set_pcie_completion_timeout(hw);
+ if (ret_val) {
+ DEBUGOUT("PCI-E Set completion timeout has failed.\n");
+ }
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ DEBUGOUT("Auto Read Done did not complete\n");
+ }
+
+ /* If EEPROM is not present, run manual init scripts */
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+ e1000_reset_init_script_82575(hw);
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_82575 - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation.
+ **/
+STATIC INT32 e1000_init_hw_82575(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ UINT16 i, rar_count = mac->rar_entry_count;
+
+ DEBUGFUNC("e1000_init_hw_82575");
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val) {
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+ }
+
+ /* Disabling VLAN filtering */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ mac->ops.clear_vfta(hw);
+
+ /* Setup the receive address */
+ e1000_init_rx_addrs_generic(hw, rar_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+#ifndef NO_82576_SUPPORT
+ /* Zero out the Unicast HASH table */
+ DEBUGOUT("Zeroing the UTA\n");
+ for (i = 0; i < mac->uta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0);
+
+#endif
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_82575(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_82575 - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Configures the link for auto-neg or forced speed and duplex. Then we check
+ * for link, once link is established calls to configure collision distance
+ * and flow control are called.
+ **/
+STATIC INT32 e1000_setup_copper_link_82575(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_setup_copper_link_82575");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ ret_val = e1000_setup_serdes_link_82575(hw);
+ if (ret_val)
+ goto out;
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (e1000_sgmii_active_82575(hw) && !hw->phy.reset_disable) {
+#else
+ if (e1000_sgmii_active_82575(hw)) {
+#endif
+ /* allow time for SFP cage time to power up phy */
+ msec_delay(300);
+
+ ret_val = hw->phy.ops.reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error resetting the PHY.\n");
+ goto out;
+ }
+ }
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
+ ret_val = e1000_copper_link_setup_m88(hw);
+ break;
+ case e1000_phy_igp_3:
+ ret_val = e1000_copper_link_setup_igp(hw);
+ break;
+#ifndef NO_82580_SUPPORT
+ case e1000_phy_82580:
+ ret_val = e1000_copper_link_setup_82577(hw);
+ break;
+#endif
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_setup_copper_link_generic(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_serdes_link_82575 - Setup link for serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configure the physical coding sub-layer (PCS) link. The PCS link is
+ * used on copper connections where the serialized gigabit media independent
+ * interface (sgmii), or serdes fiber is being used. Configures the link
+ * for auto-negotiation or forces speed/duplex.
+ **/
+STATIC INT32 e1000_setup_serdes_link_82575(struct e1000_hw *hw)
+{
+ UINT32 ctrl_ext, ctrl_reg, reg;
+ BOOLEAN pcs_autoneg;
+
+ DEBUGFUNC("e1000_setup_serdes_link_82575");
+
+ if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+ !e1000_sgmii_active_82575(hw))
+ return E1000_SUCCESS;
+
+ /*
+ * On the 82575, SerDes loopback mode persists until it is
+ * explicitly turned off or a power cycle is performed. A read to
+ * the register does not indicate its status. Therefore, we ensure
+ * loopback mode is disabled during initialization.
+ */
+ E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+
+ /* power on the sfp cage if present */
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+ ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl_reg |= E1000_CTRL_SLU;
+
+ /* set both sw defined pins on 82575/82576*/
+ if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576)
+ ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;
+
+ reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
+
+ /* default pcs_autoneg to the same setting as mac autoneg */
+ pcs_autoneg = hw->mac.autoneg;
+
+ switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
+ case E1000_CTRL_EXT_LINK_MODE_SGMII:
+ /* sgmii mode lets the phy handle forcing speed/duplex */
+ pcs_autoneg = TRUE;
+ /* autoneg time out should be disabled for SGMII mode */
+ reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
+ break;
+#ifndef NO_82580_SUPPORT
+ case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
+ /* disable PCS autoneg and support parallel detect only */
+ pcs_autoneg = FALSE;
+ /* fall through to default case */
+#endif
+ default:
+ /*
+ * non-SGMII modes only supports a speed of 1000/Full for the
+ * link so it is best to just force the MAC and let the pcs
+ * link either autoneg or be forced to 1000/Full
+ */
+ ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
+ E1000_CTRL_FD | E1000_CTRL_FRCDPX;
+
+ /* set speed of 1000/Full if speed/duplex is forced */
+ reg |= E1000_PCS_LCTL_FSV_1000 | E1000_PCS_LCTL_FDV_FULL;
+ break;
+ }
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
+
+ /*
+ * New SerDes mode allows for forcing speed or autonegotiating speed
+ * at 1gb. Autoneg should be default set by most drivers. This is the
+ * mode that will be compatible with older link partners and switches.
+ * However, both are supported by the hardware and some drivers/tools.
+ */
+ reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
+ E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
+
+ /*
+ * We force flow control to prevent the CTRL register values from being
+ * overwritten by the autonegotiated flow control values
+ */
+ reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+
+ if (pcs_autoneg) {
+ /* Set PCS register for autoneg */
+ reg |= E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */
+ E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */
+ DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg);
+ } else {
+ /* Set PCS register for forced link */
+ reg |= E1000_PCS_LCTL_FSD; /* Force Speed */
+ DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg);
+ }
+
+ E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg);
+
+ if (!e1000_sgmii_active_82575(hw))
+ e1000_force_mac_fc_generic(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_valid_led_default_82575 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+STATIC INT32 e1000_valid_led_default_82575(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_82575");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+ switch(hw->phy.media_type) {
+ case e1000_media_type_internal_serdes:
+ *data = ID_LED_DEFAULT_82575_SERDES;
+ break;
+ case e1000_media_type_copper:
+ default:
+ *data = ID_LED_DEFAULT;
+ break;
+ }
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_sgmii_active_82575 - Return sgmii state
+ * @hw: pointer to the HW structure
+ *
+ * 82575 silicon has a serialized gigabit media independent interface (sgmii)
+ * which can be enabled for use in the embedded applications. Simply
+ * return the current state of the sgmii interface.
+ **/
+static BOOLEAN e1000_sgmii_active_82575(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+ return dev_spec->sgmii_active;
+}
+
+/**
+ * e1000_reset_init_script_82575 - Inits HW defaults after reset
+ * @hw: pointer to the HW structure
+ *
+ * Inits recommended HW defaults after a reset when there is no EEPROM
+ * detected. This is only for the 82575.
+ **/
+STATIC INT32 e1000_reset_init_script_82575(struct e1000_hw* hw)
+{
+ DEBUGFUNC("e1000_reset_init_script_82575");
+
+ if (hw->mac.type == e1000_82575) {
+ DEBUGOUT("Running reset init script for 82575\n");
+ /* SerDes configuration via SERDESCTRL */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x00, 0x0C);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x01, 0x78);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x1B, 0x23);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x23, 0x15);
+
+ /* CCM configuration via CCMCTL register */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x14, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x10, 0x00);
+
+ /* PCIe lanes configuration */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x00, 0xEC);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x61, 0xDF);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x34, 0x05);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x2F, 0x81);
+
+ /* PCIe PLL Configuration */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x02, 0x47);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x14, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x10, 0x00);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_read_mac_addr_82575 - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_read_mac_addr_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_mac_addr_82575");
+
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_config_collision_dist_82575 - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup.
+ **/
+STATIC void e1000_config_collision_dist_82575(struct e1000_hw *hw)
+{
+ UINT32 tctl_ext;
+
+ DEBUGFUNC("e1000_config_collision_dist_82575");
+
+ tctl_ext = E1000_READ_REG(hw, E1000_TCTL_EXT);
+
+ tctl_ext &= ~E1000_TCTL_EXT_COLD;
+ tctl_ext |= E1000_COLLISION_DISTANCE << E1000_TCTL_EXT_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, E1000_TCTL_EXT, tctl_ext);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_power_down_phy_copper_82575 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_82575(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+
+ if (!(phy->ops.check_reset_block))
+ return;
+
+ /* If the management interface is not enabled, then power down */
+ if (!(e1000_enable_mng_pass_thru(hw) || phy->ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_82575 - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+STATIC void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_82575");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_PRC64);
+ E1000_READ_REG(hw, E1000_PRC127);
+ E1000_READ_REG(hw, E1000_PRC255);
+ E1000_READ_REG(hw, E1000_PRC511);
+ E1000_READ_REG(hw, E1000_PRC1023);
+ E1000_READ_REG(hw, E1000_PRC1522);
+ E1000_READ_REG(hw, E1000_PTC64);
+ E1000_READ_REG(hw, E1000_PTC127);
+ E1000_READ_REG(hw, E1000_PTC255);
+ E1000_READ_REG(hw, E1000_PTC511);
+ E1000_READ_REG(hw, E1000_PTC1023);
+ E1000_READ_REG(hw, E1000_PTC1522);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ E1000_READ_REG(hw, E1000_ICRXPTC);
+ E1000_READ_REG(hw, E1000_ICRXATC);
+ E1000_READ_REG(hw, E1000_ICTXPTC);
+ E1000_READ_REG(hw, E1000_ICTXATC);
+ E1000_READ_REG(hw, E1000_ICTXQEC);
+ E1000_READ_REG(hw, E1000_ICTXQMTC);
+ E1000_READ_REG(hw, E1000_ICRXDMTC);
+
+ E1000_READ_REG(hw, E1000_CBTMPC);
+ E1000_READ_REG(hw, E1000_HTDPMC);
+ E1000_READ_REG(hw, E1000_CBRMPC);
+ E1000_READ_REG(hw, E1000_RPTHC);
+ E1000_READ_REG(hw, E1000_HGPTC);
+ E1000_READ_REG(hw, E1000_HTCBDPC);
+ E1000_READ_REG(hw, E1000_HGORCL);
+ E1000_READ_REG(hw, E1000_HGORCH);
+ E1000_READ_REG(hw, E1000_HGOTCL);
+ E1000_READ_REG(hw, E1000_HGOTCH);
+ E1000_READ_REG(hw, E1000_LENERRS);
+
+ /* This register should not be read in copper configurations */
+ if ((hw->phy.media_type == e1000_media_type_internal_serdes) ||
+ e1000_sgmii_active_82575(hw))
+ E1000_READ_REG(hw, E1000_SCVPC);
+}
+
+/**
+ * e1000_rx_fifo_flush_82575 - Clean rx fifo after RX enable
+ * @hw: pointer to the HW structure
+ *
+ * After rx enable if managability is enabled then there is likely some
+ * bad data at the start of the fifo and possibly in the DMA fifo. This
+ * function clears the fifos and flushes any packets that came in as rx was
+ * being enabled.
+ **/
+void e1000_rx_fifo_flush_82575(struct e1000_hw *hw)
+{
+ UINT32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
+ int i, ms_wait;
+
+ DEBUGFUNC("e1000_rx_fifo_workaround_82575");
+ if (hw->mac.type != e1000_82575 ||
+ !(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN))
+ return;
+
+ /* Disable all RX queues */
+ for (i = 0; i < 4; i++) {
+ rxdctl[i] = E1000_READ_REG(hw, E1000_RXDCTL(i));
+ E1000_WRITE_REG(hw, E1000_RXDCTL(i),
+ rxdctl[i] & ~E1000_RXDCTL_QUEUE_ENABLE);
+ }
+ /* Poll all queues to verify they have shut down */
+ for (ms_wait = 0; ms_wait < 10; ms_wait++) {
+ msec_delay(1);
+ rx_enabled = 0;
+ for (i = 0; i < 4; i++)
+ rx_enabled |= E1000_READ_REG(hw, E1000_RXDCTL(i));
+ if (!(rx_enabled & E1000_RXDCTL_QUEUE_ENABLE))
+ break;
+ }
+
+ if (ms_wait == 10)
+ DEBUGOUT("Queue disable timed out after 10ms\n");
+
+ /* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
+ * incoming packets are rejected. Set enable and wait 2ms so that
+ * any packet that was coming in as RCTL.EN was set is flushed
+ */
+ rfctl = E1000_READ_REG(hw, E1000_RFCTL);
+ E1000_WRITE_REG(hw, E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF);
+
+ rlpml = E1000_READ_REG(hw, E1000_RLPML);
+ E1000_WRITE_REG(hw, E1000_RLPML, 0);
+
+ rctl = E1000_READ_REG(hw, E1000_RCTL);
+ temp_rctl = rctl & ~(E1000_RCTL_EN | E1000_RCTL_SBP);
+ temp_rctl |= E1000_RCTL_LPE;
+
+ E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl);
+ E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl | E1000_RCTL_EN);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(2);
+
+ /* Enable RX queues that were previously enabled and restore our
+ * previous state
+ */
+ for (i = 0; i < 4; i++)
+ E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl[i]);
+ E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+ E1000_WRITE_FLUSH(hw);
+
+ E1000_WRITE_REG(hw, E1000_RLPML, rlpml);
+ E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
+
+ /* Flush receive errors generated by workaround */
+ E1000_READ_REG(hw, E1000_ROC);
+ E1000_READ_REG(hw, E1000_RNBC);
+ E1000_READ_REG(hw, E1000_MPC);
+}
+
+/**
+ * e1000_set_pcie_completion_timeout - set pci-e completion timeout
+ * @hw: pointer to the HW structure
+ *
+ * The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
+ * however the hardware default for these parts is 500us to 1ms which is less
+ * than the 10ms recommended by the pci-e spec. To address this we need to
+ * increase the value to either 10ms to 200ms for capability version 1 config,
+ * or 16ms to 55ms for version 2.
+ **/
+STATIC INT32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw)
+{
+ UINT32 gcr = E1000_READ_REG(hw, E1000_GCR);
+ INT32 ret_val = E1000_SUCCESS;
+#ifndef NO_PCIE_SUPPORT
+ UINT16 pcie_devctl2;
+#endif
+
+ /* only take action if timeout value is defaulted to 0 */
+ if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
+ goto out;
+
+ /*
+ * if capababilities version is type 1 we can write the
+ * timeout of 10ms to 200ms through the GCR register
+ */
+ if (!(gcr & E1000_GCR_CAP_VER2)) {
+ gcr |= E1000_GCR_CMPL_TMOUT_10ms;
+ goto out;
+ }
+
+#ifndef NO_PCIE_SUPPORT
+ /*
+ * for version 2 capabilities we need to write the config space
+ * directly in order to set the completion timeout value for
+ * 16ms to 55ms
+ */
+ ret_val = e1000_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+ if (ret_val)
+ goto out;
+
+ pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+ ret_val = e1000_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+#endif
+out:
+ /* disable completion timeout resend */
+ gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
+
+ E1000_WRITE_REG(hw, E1000_GCR, gcr);
+ return ret_val;
+}
+
+#ifndef NO_82576_SUPPORT
+
+/**
+ * e1000_vmdq_set_anti_spoofing_pf - enable or disable anti-spoofing
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ * @pf: Physical Function pool - do not set anti-spoofing for the PF
+ *
+ * enables/disables L2 switch anti-spoofing functionality.
+ **/
+void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, BOOLEAN enable, int pf)
+{
+ UINT32 dtxswc;
+
+ switch (hw->mac.type) {
+ case e1000_82576:
+ dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
+ if (enable) {
+ dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ /* The PF can spoof - it has to in order to
+ * support emulation mode NICs */
+ dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
+ } else {
+ dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ }
+ E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ *
+ * enables/disables L2 switch loopback functionality.
+ **/
+void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, BOOLEAN enable)
+{
+ UINT32 dtxswc;
+
+ switch (hw->mac.type) {
+ case e1000_82576:
+ dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
+ if (enable)
+ dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ else
+ dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+ break;
+ default:
+ /* Currently no other hardware supports loopback */
+ break;
+ }
+
+
+}
+
+/**
+ * e1000_vmdq_set_replication_pf - enable or disable vmdq replication
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ *
+ * enables/disables replication of packets across multiple pools.
+ **/
+void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, BOOLEAN enable)
+{
+ UINT32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL);
+
+ if (enable)
+ vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
+ else
+ vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN;
+
+ E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl);
+}
+
+#endif /* NO_82576_SUPPORT */
+#ifndef NO_82580_SUPPORT
+/**
+ * e1000_read_phy_reg_82580 - Read 82580 MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control register in the PHY at offset and stores the
+ * information read to data.
+ **/
+STATIC INT32 e1000_read_phy_reg_82580(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_read_phy_reg_82580");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_phy_reg_mdic(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_82580 - Write 82580 MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ **/
+STATIC INT32 e1000_write_phy_reg_82580(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_write_phy_reg_82580");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_write_phy_reg_mdic(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits
+ * @hw: pointer to the HW structure
+ *
+ * This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
+ * the values found in the EEPROM. This addresses an issue in which these
+ * bits are not restored from EEPROM after reset.
+ **/
+STATIC INT32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 mdicnfg;
+ UINT16 nvm_data;
+
+ DEBUGFUNC("e1000_reset_mdicnfg_82580");
+
+ if (hw->mac.type != e1000_82580)
+ goto out;
+ if (!e1000_sgmii_active_82575(hw))
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
+ NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
+ &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG);
+ if (nvm_data & NVM_WORD24_EXT_MDIO)
+ mdicnfg |= E1000_MDICNFG_EXT_MDIO;
+ if (nvm_data & NVM_WORD24_COM_MDIO)
+ mdicnfg |= E1000_MDICNFG_COM_MDIO;
+ E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_82580 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets function or entire device (all ports, etc.)
+ * to a known state.
+ **/
+STATIC INT32 e1000_reset_hw_82580(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ /* BH SW mailbox bit in SW_FW_SYNC */
+ UINT16 swmbsw_mask = E1000_SW_SYNCH_MB;
+ UINT32 ctrl;
+ BOOLEAN global_device_reset = hw->dev_spec._82575.global_device_reset;
+
+ DEBUGFUNC("e1000_reset_hw_82580");
+
+ hw->dev_spec._82575.global_device_reset = FALSE;
+
+ /* Get current control state. */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ /* Determine whether or not a global dev reset is requested */
+ if (global_device_reset &&
+ e1000_acquire_swfw_sync_82575(hw, swmbsw_mask))
+ global_device_reset = FALSE;
+
+ if (global_device_reset &&
+ !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STAT_DEV_RST_SET))
+ ctrl |= E1000_CTRL_DEV_RST;
+ else
+ ctrl |= E1000_CTRL_RST;
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Add delay to insure DEV_RST has time to complete */
+ if (global_device_reset)
+ msec_delay(5);
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ DEBUGOUT("Auto Read Done did not complete\n");
+ }
+
+ /* If EEPROM is not present, run manual init scripts */
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+ e1000_reset_init_script_82575(hw);
+
+ /* clear global device reset status bit */
+ E1000_WRITE_REG(hw, E1000_STATUS, E1000_STAT_DEV_RST_SET);
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ ret_val = e1000_reset_mdicnfg_82580(hw);
+ if (ret_val)
+ DEBUGOUT("Could not reset MDICNFG based on EEPROM\n");
+
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+ /* Release semaphore */
+ if (global_device_reset)
+ e1000_release_swfw_sync_82575(hw, swmbsw_mask);
+
+ return ret_val;
+}
+
+/**
+ * e1000_rxpbs_adjust_82580 - adjust RXPBS value to reflect actual RX PBA size
+ * @data: data received by reading RXPBS register
+ *
+ * The 82580 uses a table based approach for packet buffer allocation sizes.
+ * This function converts the retrieved value into the correct table value
+ * 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7
+ * 0x0 36 72 144 1 2 4 8 16
+ * 0x8 35 70 140 rsv rsv rsv rsv rsv
+ */
+UINT16 e1000_rxpbs_adjust_82580(UINT32 data)
+{
+ UINT16 ret_val = 0;
+
+ if (data < E1000_82580_RXPBS_TABLE_SIZE)
+ ret_val = e1000_82580_rxpbs_table[data];
+
+ return ret_val;
+}
+#endif /* NO_82580_SUPPORT */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h
new file mode 100755
index 0000000..0471292
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h
@@ -0,0 +1,423 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_82575_H_
+#define _E1000_82575_H_
+
+#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_DEF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_OFF1_ON2))
+/*
+ * Receive Address Register Count
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * These entries are also used for MAC-based filtering.
+ */
+#ifndef NO_82576_SUPPORT
+/*
+ * For 82576, there are an additional set of RARs that begin at an offset
+ * separate from the first set of RARs.
+ */
+#endif
+#define E1000_RAR_ENTRIES_82575 16
+#ifndef NO_82576_SUPPORT
+#define E1000_RAR_ENTRIES_82576 24
+#endif
+#ifndef NO_82580_SUPPORT
+#define E1000_RAR_ENTRIES_82580 24
+#define E1000_SW_SYNCH_MB 0x00000100
+#define E1000_STAT_DEV_RST_SET 0x00100000
+#define E1000_CTRL_DEV_RST 0x20000000
+#endif
+
+
+/* SRRCTL bit definitions */
+#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000
+#ifndef NO_82580_SUPPORT
+#define E1000_SRRCTL_TIMESTAMP 0x40000000
+#endif
+#define E1000_SRRCTL_DROP_EN 0x80000000
+
+#define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F
+#define E1000_SRRCTL_BSIZEHDR_MASK 0x00003F00
+
+#define E1000_TX_HEAD_WB_ENABLE 0x1
+#define E1000_TX_SEQNUM_WB_ENABLE 0x2
+
+#define E1000_MRQC_ENABLE_RSS_4Q 0x00000002
+#define E1000_MRQC_ENABLE_VMDQ 0x00000003
+#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005
+#define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000
+#ifndef NO_82580_SUPPORT
+#define E1000_MRQC_ENABLE_RSS_8Q 0x00000002
+#endif /* Barton Hills HW */
+
+#define E1000_VMRCTL_MIRROR_PORT_SHIFT 8
+#define E1000_VMRCTL_MIRROR_DSTPORT_MASK (7 << E1000_VMRCTL_MIRROR_PORT_SHIFT)
+#define E1000_VMRCTL_POOL_MIRROR_ENABLE (1 << 0)
+#define E1000_VMRCTL_UPLINK_MIRROR_ENABLE (1 << 1)
+#define E1000_VMRCTL_DOWNLINK_MIRROR_ENABLE (1 << 2)
+
+#define E1000_EICR_TX_QUEUE ( \
+ E1000_EICR_TX_QUEUE0 | \
+ E1000_EICR_TX_QUEUE1 | \
+ E1000_EICR_TX_QUEUE2 | \
+ E1000_EICR_TX_QUEUE3)
+
+#define E1000_EICR_RX_QUEUE ( \
+ E1000_EICR_RX_QUEUE0 | \
+ E1000_EICR_RX_QUEUE1 | \
+ E1000_EICR_RX_QUEUE2 | \
+ E1000_EICR_RX_QUEUE3)
+
+#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE
+#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE
+
+#define EIMS_ENABLE_MASK ( \
+ E1000_EIMS_RX_QUEUE | \
+ E1000_EIMS_TX_QUEUE | \
+ E1000_EIMS_TCP_TIMER | \
+ E1000_EIMS_OTHER)
+
+/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
+#define E1000_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */
+#define E1000_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */
+#define E1000_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
+#define E1000_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */
+#define E1000_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */
+#define E1000_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */
+#define E1000_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */
+#define E1000_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */
+#define E1000_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */
+#define E1000_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */
+
+/* Receive Descriptor - Advanced */
+union e1000_adv_rx_desc {
+ struct {
+ UINT64 pkt_addr; /* Packet buffer address */
+ UINT64 hdr_addr; /* Header buffer address */
+ } read;
+ struct {
+ struct {
+ union {
+ UINT32 data;
+ struct {
+ UINT16 pkt_info; /*RSS type, Pkt type*/
+ UINT16 hdr_info; /* Split Header,
+ * header buffer len*/
+ } hs_rss;
+ } lo_dword;
+ union {
+ UINT32 rss; /* RSS Hash */
+ struct {
+ UINT16 ip_id; /* IP id */
+ UINT16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ UINT32 status_error; /* ext status/error */
+ UINT16 length; /* Packet length */
+ UINT16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+#define E1000_RXDADV_RSSTYPE_MASK 0x0000000F
+#define E1000_RXDADV_RSSTYPE_SHIFT 12
+#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
+#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
+#define E1000_RXDADV_SPLITHEADER_EN 0x00001000
+#define E1000_RXDADV_SPH 0x8000
+#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
+#ifndef NO_82580_SUPPORT
+#define E1000_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
+#endif
+#define E1000_RXDADV_ERR_HBO 0x00800000
+
+/* RSS Hash results */
+#define E1000_RXDADV_RSSTYPE_NONE 0x00000000
+#define E1000_RXDADV_RSSTYPE_IPV4_TCP 0x00000001
+#define E1000_RXDADV_RSSTYPE_IPV4 0x00000002
+#define E1000_RXDADV_RSSTYPE_IPV6_TCP 0x00000003
+#define E1000_RXDADV_RSSTYPE_IPV6_EX 0x00000004
+#define E1000_RXDADV_RSSTYPE_IPV6 0x00000005
+#define E1000_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
+#define E1000_RXDADV_RSSTYPE_IPV4_UDP 0x00000007
+#define E1000_RXDADV_RSSTYPE_IPV6_UDP 0x00000008
+#define E1000_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
+
+/* RSS Packet Types as indicated in the receive descriptor */
+#define E1000_RXDADV_PKTTYPE_NONE 0x00000000
+#define E1000_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */
+#define E1000_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPV4 hdr + extensions */
+#define E1000_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPV6 hdr present */
+#define E1000_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPV6 hdr + extensions */
+#define E1000_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */
+#define E1000_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */
+#define E1000_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */
+#define E1000_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */
+
+#ifndef NO_82576_SUPPORT
+#define E1000_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */
+#define E1000_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */
+#define E1000_RXDADV_PKTTYPE_LINKSEC 0x00004000 /* LinkSec Encap */
+#define E1000_RXDADV_PKTTYPE_ETQF 0x00008000 /* PKTTYPE is ETQF index */
+#define E1000_RXDADV_PKTTYPE_ETQF_MASK 0x00000070 /* ETQF has 8 indices */
+#define E1000_RXDADV_PKTTYPE_ETQF_SHIFT 4 /* Right-shift 4 bits */
+
+/* LinkSec results */
+/* Security Processing bit Indication */
+#define E1000_RXDADV_LNKSEC_STATUS_SECP 0x00020000
+#define E1000_RXDADV_LNKSEC_ERROR_BIT_MASK 0x18000000
+#define E1000_RXDADV_LNKSEC_ERROR_NO_SA_MATCH 0x08000000
+#define E1000_RXDADV_LNKSEC_ERROR_REPLAY_ERROR 0x10000000
+#define E1000_RXDADV_LNKSEC_ERROR_BAD_SIG 0x18000000
+
+#define E1000_RXDADV_IPSEC_STATUS_SECP 0x00020000
+#define E1000_RXDADV_IPSEC_ERROR_BIT_MASK 0x18000000
+#define E1000_RXDADV_IPSEC_ERROR_INVALID_PROTOCOL 0x08000000
+#define E1000_RXDADV_IPSEC_ERROR_INVALID_LENGTH 0x10000000
+#define E1000_RXDADV_IPSEC_ERROR_AUTHENTICATION_FAILED 0x18000000
+
+#endif
+/* Transmit Descriptor - Advanced */
+union e1000_adv_tx_desc {
+ struct {
+ UINT64 buffer_addr; /* Address of descriptor's data buf */
+ UINT32 cmd_type_len;
+ UINT32 olinfo_status;
+ } read;
+ struct {
+ UINT64 rsvd; /* Reserved */
+ UINT32 nxtseq_seed;
+ UINT32 status;
+ } wb;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
+#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
+#define E1000_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */
+#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
+#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
+#ifndef NO_82576_SUPPORT
+#define E1000_ADVTXD_MAC_LINKSEC 0x00040000 /* Apply LinkSec on packet */
+#endif /* NO_82576_SUPPORT */
+#define E1000_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
+#define E1000_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */
+#define E1000_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */
+#define E1000_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
+#define E1000_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */
+#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+
+/* Context descriptors */
+struct e1000_adv_tx_context_desc {
+ UINT32 vlan_macip_lens;
+ UINT32 seqnum_seed;
+ UINT32 type_tucmd_mlhl;
+ UINT32 mss_l4len_idx;
+};
+
+#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
+#define E1000_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */
+#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
+#define E1000_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */
+#define E1000_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
+#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */
+#define E1000_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */
+/* IPSec Encrypt Enable for ESP */
+#define E1000_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000
+#define E1000_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */
+#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
+#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
+/* Adv ctxt IPSec SA IDX mask */
+#define E1000_ADVTXD_IPSEC_SA_INDEX_MASK 0x000000FF
+/* Adv ctxt IPSec ESP len mask */
+#define E1000_ADVTXD_IPSEC_ESP_LEN_MASK 0x000000FF
+
+/* Additional Transmit Descriptor Control definitions */
+#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
+#define E1000_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */
+/* Tx Queue Arbitration Priority 0=low, 1=high */
+#define E1000_TXDCTL_PRIORITY 0x08000000
+
+/* Additional Receive Descriptor Control definitions */
+#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */
+#define E1000_RXDCTL_SWFLSH 0x04000000 /* Rx Desc. write-back flushing */
+
+/* Direct Cache Access (DCA) definitions */
+#define E1000_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */
+#define E1000_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */
+
+#define E1000_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */
+#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
+
+#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
+#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
+#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
+
+#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
+#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
+
+#ifndef NO_82576_SUPPORT
+#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */
+#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */
+#define E1000_DCA_TXCTRL_CPUID_SHIFT_82576 24 /* Tx CPUID */
+#define E1000_DCA_RXCTRL_CPUID_SHIFT_82576 24 /* Rx CPUID */
+
+/* Additional interrupt register bit definitions */
+#define E1000_ICR_LSECPNS 0x00000020 /* PN threshold - server */
+#define E1000_IMS_LSECPNS E1000_ICR_LSECPNS /* PN threshold - server */
+#define E1000_ICS_LSECPNS E1000_ICR_LSECPNS /* PN threshold - server */
+
+/* ETQF register bit definitions */
+#define E1000_ETQF_FILTER_ENABLE (1 << 26)
+#define E1000_ETQF_IMM_INT (1 << 29)
+#define E1000_ETQF_1588 (1 << 30)
+#define E1000_ETQF_QUEUE_ENABLE (1 << 31)
+/*
+ * ETQF filter list: one static filter per filter consumer. This is
+ * to avoid filter collisions later. Add new filters
+ * here!!
+ *
+ * Current filters:
+ * EAPOL 802.1x (0x888e): Filter 0
+ */
+#define E1000_ETQF_FILTER_EAPOL 0
+
+#define E1000_FTQF_VF_BP 0x00008000
+#define E1000_FTQF_1588_TIME_STAMP 0x08000000
+#define E1000_FTQF_MASK 0xF0000000
+#define E1000_FTQF_MASK_PROTO_BP 0x10000000
+#define E1000_FTQF_MASK_SOURCE_ADDR_BP 0x20000000
+#define E1000_FTQF_MASK_DEST_ADDR_BP 0x40000000
+#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000
+#endif /* NO_82576_SUPPORT */
+
+#ifndef NO_82576_SUPPORT
+#define E1000_NVM_APME_82575 0x0400
+#define MAX_NUM_VFS 8
+
+#define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */
+#define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */
+#define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */
+#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
+#define E1000_DTXSWC_LLE_SHIFT 16
+#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31) /* global VF LB enable */
+
+/* Easy defines for setting default pool, would normally be left a zero */
+#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
+#define E1000_VT_CTL_DEFAULT_POOL_MASK (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT)
+
+/* Other useful VMD_CTL register defines */
+#define E1000_VT_CTL_IGNORE_MAC (1 << 28)
+#define E1000_VT_CTL_DISABLE_DEF_POOL (1 << 29)
+#define E1000_VT_CTL_VM_REPL_EN (1 << 30)
+
+/* Per VM Offload register setup */
+#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
+#define E1000_VMOLR_LPE 0x00010000 /* Accept Long packet */
+#define E1000_VMOLR_RSSE 0x00020000 /* Enable RSS */
+#define E1000_VMOLR_AUPE 0x01000000 /* Accept untagged packets */
+#define E1000_VMOLR_ROMPE 0x02000000 /* Accept overflow multicast */
+#define E1000_VMOLR_ROPE 0x04000000 /* Accept overflow unicast */
+#define E1000_VMOLR_BAM 0x08000000 /* Accept Broadcast packets */
+#define E1000_VMOLR_MPME 0x10000000 /* Multicast promiscuous mode */
+#define E1000_VMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
+#define E1000_VMOLR_STRCRC 0x80000000 /* CRC stripping enable */
+
+
+#define E1000_VLVF_ARRAY_SIZE 32
+#define E1000_VLVF_VLANID_MASK 0x00000FFF
+#define E1000_VLVF_POOLSEL_SHIFT 12
+#define E1000_VLVF_POOLSEL_MASK (0xFF << E1000_VLVF_POOLSEL_SHIFT)
+#define E1000_VLVF_LVLAN 0x00100000
+#define E1000_VLVF_VLANID_ENABLE 0x80000000
+
+#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
+#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */
+
+#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+
+#define E1000_IOVCTL 0x05BBC
+#define E1000_IOVCTL_REUSE_VFQ 0x00000001
+
+#define E1000_RPLOLR_STRVLAN 0x40000000
+#define E1000_RPLOLR_STRCRC 0x80000000
+
+#define E1000_TCTL_EXT_COLD 0x000FFC00
+#define E1000_TCTL_EXT_COLD_SHIFT 10
+
+#define E1000_DTXCTL_8023LL 0x0004
+#define E1000_DTXCTL_VLAN_ADDED 0x0008
+#define E1000_DTXCTL_OOS_ENABLE 0x0010
+#define E1000_DTXCTL_MDP_EN 0x0020
+#define E1000_DTXCTL_SPOOF_INT 0x0040
+
+#define ALL_QUEUES 0xFFFF
+
+/* RX packet buffer size defines */
+#ifndef NO_82576_SUPPORT
+#define E1000_RXPBS_SIZE_MASK_82576 0x0000007F
+#endif
+void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, BOOLEAN enable);
+void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, BOOLEAN enable, int pf);
+void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, BOOLEAN enable);
+#endif /* NO_82576_SUPPORT */
+#ifndef NO_82580_SUPPORT
+UINT16 e1000_rxpbs_adjust_82580(UINT32 data);
+#endif
+#endif /* _E1000_82575_H_ */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c
new file mode 100755
index 0000000..029cbbc
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c
@@ -0,0 +1,1248 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+/**
+ * e1000_init_mac_params - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * This function initializes the function pointers for the MAC
+ * set of functions. Called by drivers or by e1000_setup_init_funcs.
+ **/
+INT32 e1000_init_mac_params(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ if (hw->mac.ops.init_params) {
+ ret_val = hw->mac.ops.init_params(hw);
+ if (ret_val) {
+ DEBUGOUT("MAC Initialization Error\n");
+ goto out;
+ }
+ } else {
+ DEBUGOUT("mac.init_mac_params was NULL\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * This function initializes the function pointers for the NVM
+ * set of functions. Called by drivers or by e1000_setup_init_funcs.
+ **/
+INT32 e1000_init_nvm_params(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ if (hw->nvm.ops.init_params) {
+ ret_val = hw->nvm.ops.init_params(hw);
+ if (ret_val) {
+ DEBUGOUT("NVM Initialization Error\n");
+ goto out;
+ }
+ } else {
+ DEBUGOUT("nvm.init_nvm_params was NULL\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_phy_params - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * This function initializes the function pointers for the PHY
+ * set of functions. Called by drivers or by e1000_setup_init_funcs.
+ **/
+INT32 e1000_init_phy_params(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ if (hw->phy.ops.init_params) {
+ ret_val = hw->phy.ops.init_params(hw);
+ if (ret_val) {
+ DEBUGOUT("PHY Initialization Error\n");
+ goto out;
+ }
+ } else {
+ DEBUGOUT("phy.init_phy_params was NULL\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+
+out:
+ return ret_val;
+}
+
+
+/**
+ * e1000_set_mac_type - Sets MAC type
+ * @hw: pointer to the HW structure
+ *
+ * This function sets the mac type of the adapter based on the
+ * device ID stored in the hw structure.
+ * MUST BE FIRST FUNCTION CALLED (explicitly or through
+ * e1000_setup_init_funcs()).
+ **/
+INT32 e1000_set_mac_type(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_set_mac_type");
+
+ switch (hw->device_id) {
+#ifndef NO_82571_SUPPORT
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571PT_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+ mac->type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI:
+ case E1000_DEV_ID_82572EI_COPPER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82572EI_SERDES:
+ mac->type = e1000_82572;
+ break;
+ case E1000_DEV_ID_82573E:
+ case E1000_DEV_ID_82573E_IAMT:
+ case E1000_DEV_ID_82573L:
+ mac->type = e1000_82573;
+ break;
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_82574_SUPPORT
+ case E1000_DEV_ID_82574L:
+ case E1000_DEV_ID_82574LA:
+ mac->type = e1000_82574;
+ break;
+ case E1000_DEV_ID_82583V:
+ mac->type = e1000_82583;
+ break;
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_80003ES2LAN_SUPPORT
+ case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
+ mac->type = e1000_80003es2lan;
+ break;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case E1000_DEV_ID_ICH8_IFE:
+ case E1000_DEV_ID_ICH8_IFE_GT:
+ case E1000_DEV_ID_ICH8_IFE_G:
+ case E1000_DEV_ID_ICH8_IGP_M:
+ case E1000_DEV_ID_ICH8_IGP_M_AMT:
+ case E1000_DEV_ID_ICH8_IGP_AMT:
+ case E1000_DEV_ID_ICH8_IGP_C:
+ mac->type = e1000_ich8lan;
+ break;
+ case E1000_DEV_ID_ICH9_IFE:
+ case E1000_DEV_ID_ICH9_IFE_GT:
+ case E1000_DEV_ID_ICH9_IFE_G:
+ case E1000_DEV_ID_ICH9_IGP_M:
+ case E1000_DEV_ID_ICH9_IGP_M_AMT:
+ case E1000_DEV_ID_ICH9_IGP_M_V:
+ case E1000_DEV_ID_ICH9_IGP_AMT:
+ case E1000_DEV_ID_ICH9_BM:
+ case E1000_DEV_ID_ICH9_IGP_C:
+ case E1000_DEV_ID_ICH10_R_BM_LM:
+ case E1000_DEV_ID_ICH10_R_BM_LF:
+ case E1000_DEV_ID_ICH10_R_BM_V:
+ mac->type = e1000_ich9lan;
+ break;
+ case E1000_DEV_ID_PCH_D_HV_DM:
+ case E1000_DEV_ID_PCH_D_HV_DC:
+ case E1000_DEV_ID_PCH_M_HV_LM:
+ case E1000_DEV_ID_PCH_M_HV_LC:
+ case E1000_DEV_ID_PCH_LV_LM:
+ case E1000_DEV_ID_PCH_LV_V:
+ mac->type = e1000_pchlan;
+ break;
+ case E1000_DEV_ID_PCH2_LV_LM:
+ case E1000_DEV_ID_PCH2_LV_V:
+ mac->type = e1000_pch2lan;
+ break;
+#endif /*NO_ICH8LAN_SUPPORT */
+#ifndef NO_82575_SUPPORT
+ case E1000_DEV_ID_82575EB_COPPER:
+ case E1000_DEV_ID_82575EB_FIBER_SERDES:
+ case E1000_DEV_ID_82575GB_QUAD_COPPER:
+ mac->type = e1000_82575;
+ break;
+#ifndef NO_82576_SUPPORT
+ case E1000_DEV_ID_82576:
+ case E1000_DEV_ID_82576_FIBER:
+ case E1000_DEV_ID_82576_SERDES:
+ case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
+ case E1000_DEV_ID_82576_NS:
+ case E1000_DEV_ID_82576_NS_SERDES:
+ case E1000_DEV_ID_82576_SERDES_QUAD:
+ mac->type = e1000_82576;
+ break;
+#ifndef NO_82580_SUPPORT
+ case E1000_DEV_ID_82580_COPPER:
+ case E1000_DEV_ID_82580_FIBER:
+ case E1000_DEV_ID_82580_SERDES:
+ case E1000_DEV_ID_82580_SGMII:
+ case E1000_DEV_ID_82580_COPPER_DUAL:
+ case E1000_DEV_ID_82580_QUAD_FIBER:
+ mac->type = e1000_82580;
+ break;
+#endif /* NO_82580_SUPPORT */
+#endif /* NO_82576_SUPPORT */
+#endif /* NO_82575_SUPPORT */
+ default:
+ /* Should never have loaded on this device */
+ ret_val = -E1000_ERR_MAC_INIT;
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_setup_init_funcs - Initializes function pointers
+ * @hw: pointer to the HW structure
+ * @init_device: TRUE will initialize the rest of the function pointers
+ * getting the device ready for use. FALSE will only set
+ * MAC type and the function pointers for the other init
+ * functions. Passing FALSE will not generate any hardware
+ * reads or writes.
+ *
+ * This function must be called by a driver in order to use the rest
+ * of the 'shared' code files. Called by drivers only.
+ **/
+INT32 e1000_setup_init_funcs(struct e1000_hw *hw, BOOLEAN init_device)
+{
+ INT32 ret_val;
+
+ /* Can't do much good without knowing the MAC type. */
+ ret_val = e1000_set_mac_type(hw);
+ if (ret_val) {
+ DEBUGOUT("ERROR: MAC type could not be set properly.\n");
+ goto out;
+ }
+
+ if (!hw->hw_addr) {
+ DEBUGOUT("ERROR: Registers not mapped\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ /*
+ * Init function pointers to generic implementations. We do this first
+ * allowing a driver module to override it afterward.
+ */
+ e1000_init_mac_ops_generic(hw);
+#ifndef NO_NULL_OPS_SUPPORT
+ e1000_init_phy_ops_generic(hw);
+#endif /* NO_NULL_OPS_SUPPORT */
+ e1000_init_nvm_ops_generic(hw);
+
+ /*
+ * Set up the init function pointers. These are functions within the
+ * adapter family file that sets up function pointers for the rest of
+ * the functions in that family.
+ */
+ switch (hw->mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ e1000_init_function_pointers_82571(hw);
+ break;
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+ e1000_init_function_pointers_80003es2lan(hw);
+ break;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ e1000_init_function_pointers_ich8lan(hw);
+ break;
+#endif
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+#ifndef NO_82576_SUPPORT
+ case e1000_82576:
+#endif
+#ifndef NO_82580_SUPPORT
+ case e1000_82580:
+#endif
+ e1000_init_function_pointers_82575(hw);
+ break;
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82576_SUPPORT
+#endif /* NO_82576_SUPPORT */
+ default:
+ DEBUGOUT("Hardware not supported\n");
+ ret_val = -E1000_ERR_CONFIG;
+ break;
+ }
+
+ /*
+ * Initialize the rest of the function pointers. These require some
+ * register reads/writes in some cases.
+ */
+ if (!(ret_val) && init_device) {
+ ret_val = e1000_init_mac_params(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_init_nvm_params(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_init_phy_params(hw);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_bus_info - Obtain bus information for adapter
+ * @hw: pointer to the HW structure
+ *
+ * This will obtain information about the HW bus for which the
+ * adapter is attached and stores it in the hw structure. This is a
+ * function pointer entry point called by drivers.
+ **/
+INT32 e1000_get_bus_info(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.get_bus_info)
+ return hw->mac.ops.get_bus_info(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_clear_vfta - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * This clears the VLAN filter table on the adapter. This is a function
+ * pointer entry point called by drivers.
+ **/
+void e1000_clear_vfta(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.clear_vfta)
+ hw->mac.ops.clear_vfta(hw);
+}
+
+/**
+ * e1000_write_vfta - Write value to VLAN filter table
+ * @hw: pointer to the HW structure
+ * @offset: the 32-bit offset in which to write the value to.
+ * @value: the 32-bit value to write at location offset.
+ *
+ * This writes a 32-bit value to a 32-bit offset in the VLAN filter
+ * table. This is a function pointer entry point called by drivers.
+ **/
+void e1000_write_vfta(struct e1000_hw *hw, UINT32 offset, UINT32 value)
+{
+ if (hw->mac.ops.write_vfta)
+ hw->mac.ops.write_vfta(hw, offset, value);
+}
+
+/**
+ * e1000_update_mc_addr_list - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ *
+ * Updates the Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000_update_mc_addr_list(struct e1000_hw *hw, UINT8 *mc_addr_list,
+ UINT32 mc_addr_count)
+{
+ if (hw->mac.ops.update_mc_addr_list)
+ hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
+ mc_addr_count);
+}
+
+/**
+ * e1000_force_mac_fc - Force MAC flow control
+ * @hw: pointer to the HW structure
+ *
+ * Force the MAC's flow control settings. Currently no func pointer exists
+ * and all implementations are handled in the generic version of this
+ * function.
+ **/
+INT32 e1000_force_mac_fc(struct e1000_hw *hw)
+{
+ return e1000_force_mac_fc_generic(hw);
+}
+
+/**
+ * e1000_check_for_link - Check/Store link connection
+ * @hw: pointer to the HW structure
+ *
+ * This checks the link condition of the adapter and stores the
+ * results in the hw->mac structure. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_check_for_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.check_for_link)
+ return hw->mac.ops.check_for_link(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_check_mng_mode - Check management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has manageability enabled.
+ * This is a function pointer entry point called by drivers.
+ **/
+BOOLEAN e1000_check_mng_mode(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.check_mng_mode)
+ return hw->mac.ops.check_mng_mode(hw);
+
+ return FALSE;
+}
+
+/**
+ * e1000_mng_write_dhcp_info - Writes DHCP info to host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface
+ * @length: size of the buffer
+ *
+ * Writes the DHCP information to the host interface.
+ **/
+INT32 e1000_mng_write_dhcp_info(struct e1000_hw *hw, UINT8 *buffer, UINT16 length)
+{
+ return e1000_mng_write_dhcp_info_generic(hw, buffer, length);
+}
+
+/**
+ * e1000_reset_hw - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state. This is a function pointer
+ * entry point called by drivers.
+ **/
+INT32 e1000_reset_hw(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.reset_hw)
+ return hw->mac.ops.reset_hw(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_init_hw - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation. This is a function
+ * pointer entry point called by drivers.
+ **/
+INT32 e1000_init_hw(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.init_hw)
+ return hw->mac.ops.init_hw(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_setup_link - Configures link and flow control
+ * @hw: pointer to the HW structure
+ *
+ * This configures link and flow control settings for the adapter. This
+ * is a function pointer entry point called by drivers. While modules can
+ * also call this, they probably call their own version of this function.
+ **/
+INT32 e1000_setup_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.setup_link)
+ return hw->mac.ops.setup_link(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_get_speed_and_duplex - Returns current speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to a 16-bit value to store the speed
+ * @duplex: pointer to a 16-bit value to store the duplex.
+ *
+ * This returns the speed and duplex of the adapter in the two 'out'
+ * variables passed in. This is a function pointer entry point called
+ * by drivers.
+ **/
+INT32 e1000_get_speed_and_duplex(struct e1000_hw *hw, UINT16 *speed, UINT16 *duplex)
+{
+ if (hw->mac.ops.get_link_up_info)
+ return hw->mac.ops.get_link_up_info(hw, speed, duplex);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_setup_led - Configures SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This prepares the SW controllable LED for use and saves the current state
+ * of the LED so it can be later restored. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_setup_led(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.setup_led)
+ return hw->mac.ops.setup_led(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_cleanup_led - Restores SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This restores the SW controllable LED to the value saved off by
+ * e1000_setup_led. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_cleanup_led(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.cleanup_led)
+ return hw->mac.ops.cleanup_led(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_blink_led - Blink SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This starts the adapter LED blinking. Request the LED to be setup first
+ * and cleaned up after. This is a function pointer entry point called by
+ * drivers.
+ **/
+INT32 e1000_blink_led(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.blink_led)
+ return hw->mac.ops.blink_led(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_id_led_init - store LED configurations in SW
+ * @hw: pointer to the HW structure
+ *
+ * Initializes the LED config in SW. This is a function pointer entry point
+ * called by drivers.
+ **/
+INT32 e1000_id_led_init(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.id_led_init)
+ return hw->mac.ops.id_led_init(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_on - Turn on SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * Turns the SW defined LED on. This is a function pointer entry point
+ * called by drivers.
+ **/
+INT32 e1000_led_on(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.led_on)
+ return hw->mac.ops.led_on(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_off - Turn off SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * Turns the SW defined LED off. This is a function pointer entry point
+ * called by drivers.
+ **/
+INT32 e1000_led_off(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.led_off)
+ return hw->mac.ops.led_off(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_reset_adaptive - Reset adaptive IFS
+ * @hw: pointer to the HW structure
+ *
+ * Resets the adaptive IFS. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+void e1000_reset_adaptive(struct e1000_hw *hw)
+{
+ e1000_reset_adaptive_generic(hw);
+}
+
+/**
+ * e1000_update_adaptive - Update adaptive IFS
+ * @hw: pointer to the HW structure
+ *
+ * Updates adapter IFS. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+void e1000_update_adaptive(struct e1000_hw *hw)
+{
+ e1000_update_adaptive_generic(hw);
+}
+
+/**
+ * e1000_disable_pcie_master - Disable PCI-Express master access
+ * @hw: pointer to the HW structure
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests. Currently no func pointer exists and all implementations are
+ * handled in the generic version of this function.
+ **/
+INT32 e1000_disable_pcie_master(struct e1000_hw *hw)
+{
+ return e1000_disable_pcie_master_generic(hw);
+}
+
+/**
+ * e1000_config_collision_dist - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup.
+ **/
+void e1000_config_collision_dist(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.config_collision_dist)
+ hw->mac.ops.config_collision_dist(hw);
+}
+
+/**
+ * e1000_rar_set - Sets a receive address register
+ * @hw: pointer to the HW structure
+ * @addr: address to set the RAR to
+ * @index: the RAR to set
+ *
+ * Sets a Receive Address Register (RAR) to the specified address.
+ **/
+void e1000_rar_set(struct e1000_hw *hw, UINT8 *addr, UINT32 index)
+{
+ if (hw->mac.ops.rar_set)
+ hw->mac.ops.rar_set(hw, addr, index);
+}
+
+/**
+ * e1000_validate_mdi_setting - Ensures valid MDI/MDIX SW state
+ * @hw: pointer to the HW structure
+ *
+ * Ensures that the MDI/MDIX SW state is valid.
+ **/
+INT32 e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.validate_mdi_setting)
+ return hw->mac.ops.validate_mdi_setting(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_hash_mc_addr - Determines address location in multicast table
+ * @hw: pointer to the HW structure
+ * @mc_addr: Multicast address to hash.
+ *
+ * This hashes an address to determine its location in the multicast
+ * table. Currently no func pointer exists and all implementations
+ * are handled in the generic version of this function.
+ **/
+UINT32 e1000_hash_mc_addr(struct e1000_hw *hw, UINT8 *mc_addr)
+{
+ return e1000_hash_mc_addr_generic(hw, mc_addr);
+}
+
+/**
+ * e1000_enable_tx_pkt_filtering - Enable packet filtering on TX
+ * @hw: pointer to the HW structure
+ *
+ * Enables packet filtering on transmit packets if manageability is enabled
+ * and host interface is enabled.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+BOOLEAN e1000_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+ return e1000_enable_tx_pkt_filtering_generic(hw);
+}
+
+/**
+ * e1000_mng_host_if_write - Writes to the manageability host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface buffer
+ * @length: size of the buffer
+ * @offset: location in the buffer to write to
+ * @sum: sum of the data (not checksum)
+ *
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient
+ * way. Also fills up the sum of the buffer in *buffer parameter.
+ **/
+INT32 e1000_mng_host_if_write(struct e1000_hw * hw, UINT8 *buffer, UINT16 length,
+ UINT16 offset, UINT8 *sum)
+{
+ if (hw->mac.ops.mng_host_if_write)
+ return hw->mac.ops.mng_host_if_write(hw, buffer, length,
+ offset, sum);
+
+ return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ * e1000_mng_write_cmd_header - Writes manageability command header
+ * @hw: pointer to the HW structure
+ * @hdr: pointer to the host interface command header
+ *
+ * Writes the command header after does the checksum calculation.
+ **/
+INT32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr)
+{
+ if (hw->mac.ops.mng_write_cmd_header)
+ return hw->mac.ops.mng_write_cmd_header(hw, hdr);
+
+ return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ * e1000_mng_enable_host_if - Checks host interface is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ * This function checks whether the HOST IF is enabled for command operation
+ * and also checks whether the previous command is completed. It busy waits
+ * in case of previous command is not completed.
+ **/
+INT32 e1000_mng_enable_host_if(struct e1000_hw * hw)
+{
+ if (hw->mac.ops.mng_enable_host_if)
+ return hw->mac.ops.mng_enable_host_if(hw);
+
+ return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ * e1000_wait_autoneg - Waits for autonegotiation completion
+ * @hw: pointer to the HW structure
+ *
+ * Waits for autoneg to complete. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+INT32 e1000_wait_autoneg(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.wait_autoneg)
+ return hw->mac.ops.wait_autoneg(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_check_reset_block - Verifies PHY can be reset
+ * @hw: pointer to the HW structure
+ *
+ * Checks if the PHY is in a state that can be reset or if manageability
+ * has it tied up. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_check_reset_block(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.check_reset_block)
+ return hw->phy.ops.check_reset_block(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_read_phy_reg - Reads PHY register
+ * @hw: pointer to the HW structure
+ * @offset: the register to read
+ * @data: the buffer to store the 16-bit read.
+ *
+ * Reads the PHY register and returns the value in data.
+ * This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_read_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ if (hw->phy.ops.read_reg)
+ return hw->phy.ops.read_reg(hw, offset, data);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_write_phy_reg - Writes PHY register
+ * @hw: pointer to the HW structure
+ * @offset: the register to write
+ * @data: the value to write.
+ *
+ * Writes the PHY register at offset with the value in data.
+ * This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_write_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ if (hw->phy.ops.write_reg)
+ return hw->phy.ops.write_reg(hw, offset, data);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_release_phy - Generic release PHY
+ * @hw: pointer to the HW structure
+ *
+ * Return if silicon family does not require a semaphore when accessing the
+ * PHY.
+ **/
+void e1000_release_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.release)
+ hw->phy.ops.release(hw);
+}
+
+/**
+ * e1000_acquire_phy - Generic acquire PHY
+ * @hw: pointer to the HW structure
+ *
+ * Return success if silicon family does not require a semaphore when
+ * accessing the PHY.
+ **/
+INT32 e1000_acquire_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.acquire)
+ return hw->phy.ops.acquire(hw);
+
+ return E1000_SUCCESS;
+}
+
+#ifndef NO_80003ES2LAN_SUPPORT
+/**
+ * e1000_cfg_on_link_up - Configure PHY upon link up
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_cfg_on_link_up(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.cfg_on_link_up)
+ return hw->phy.ops.cfg_on_link_up(hw);
+
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_80003ES2LAN_SUPPORT */
+/**
+ * e1000_read_kmrn_reg - Reads register using Kumeran interface
+ * @hw: pointer to the HW structure
+ * @offset: the register to read
+ * @data: the location to store the 16-bit value read.
+ *
+ * Reads a register out of the Kumeran interface. Currently no func pointer
+ * exists and all implementations are handled in the generic version of
+ * this function.
+ **/
+INT32 e1000_read_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return e1000_read_kmrn_reg_generic(hw, offset, data);
+}
+
+/**
+ * e1000_write_kmrn_reg - Writes register using Kumeran interface
+ * @hw: pointer to the HW structure
+ * @offset: the register to write
+ * @data: the value to write.
+ *
+ * Writes a register to the Kumeran interface. Currently no func pointer
+ * exists and all implementations are handled in the generic version of
+ * this function.
+ **/
+INT32 e1000_write_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return e1000_write_kmrn_reg_generic(hw, offset, data);
+}
+
+/**
+ * e1000_get_cable_length - Retrieves cable length estimation
+ * @hw: pointer to the HW structure
+ *
+ * This function estimates the cable length and stores them in
+ * hw->phy.min_length and hw->phy.max_length. This is a function pointer
+ * entry point called by drivers.
+ **/
+INT32 e1000_get_cable_length(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.get_cable_length)
+ return hw->phy.ops.get_cable_length(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_phy_info - Retrieves PHY information from registers
+ * @hw: pointer to the HW structure
+ *
+ * This function gets some information from various PHY registers and
+ * populates hw->phy values with it. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_get_phy_info(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.get_info)
+ return hw->phy.ops.get_info(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_phy_hw_reset - Hard PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Performs a hard PHY reset. This is a function pointer entry point called
+ * by drivers.
+ **/
+INT32 e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.reset)
+ return hw->phy.ops.reset(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_phy_commit - Soft PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Performs a soft PHY reset on those that apply. This is a function pointer
+ * entry point called by drivers.
+ **/
+INT32 e1000_phy_commit(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.commit)
+ return hw->phy.ops.commit(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_d0_lplu_state - Sets low power link up state for D0
+ * @hw: pointer to the HW structure
+ * @active: BOOLEANean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D0
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D0
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_set_d0_lplu_state(struct e1000_hw *hw, BOOLEAN active)
+{
+ if (hw->phy.ops.set_d0_lplu_state)
+ return hw->phy.ops.set_d0_lplu_state(hw, active);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_d3_lplu_state - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: BOOLEANean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_set_d3_lplu_state(struct e1000_hw *hw, BOOLEAN active)
+{
+ if (hw->phy.ops.set_d3_lplu_state)
+ return hw->phy.ops.set_d3_lplu_state(hw, active);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_read_mac_addr - Reads MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the MAC address out of the adapter and stores it in the HW structure.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_mac_addr(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.read_mac_addr)
+ return hw->mac.ops.read_mac_addr(hw);
+
+ return e1000_read_mac_addr_generic(hw);
+}
+
+/**
+ * e1000_read_pba_string - Read device part number string
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_pba_string(struct e1000_hw *hw, UINT8 *pba_num, UINT32 pba_num_size)
+{
+ return e1000_read_pba_string_generic(hw, pba_num, pba_num_size);
+}
+
+/**
+ * e1000_read_pba_length - Read device part number string length
+ * @hw: pointer to the HW structure
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number length from the EEPROM and
+ * stores the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_pba_length(struct e1000_hw *hw, UINT32 *pba_num_size)
+{
+ return e1000_read_pba_length_generic(hw, pba_num_size);
+}
+
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+/**
+ * e1000_read_pba_num - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_pba_num(struct e1000_hw *hw, UINT32 *pba_num)
+{
+ return e1000_read_pba_num_generic(hw, pba_num);
+}
+
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+/**
+ * e1000_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
+ * @hw: pointer to the HW structure
+ *
+ * Validates the NVM checksum is correct. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
+{
+ if (hw->nvm.ops.validate)
+ return hw->nvm.ops.validate(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_update_nvm_checksum - Updates NVM (EEPROM) checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the NVM checksum. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+INT32 e1000_update_nvm_checksum(struct e1000_hw *hw)
+{
+ if (hw->nvm.ops.update)
+ return hw->nvm.ops.update(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_reload_nvm - Reloads EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ * extended control register.
+ **/
+void e1000_reload_nvm(struct e1000_hw *hw)
+{
+ if (hw->nvm.ops.reload)
+ hw->nvm.ops.reload(hw);
+}
+
+/**
+ * e1000_read_nvm - Reads NVM (EEPROM)
+ * @hw: pointer to the HW structure
+ * @offset: the word offset to read
+ * @words: number of 16-bit words to read
+ * @data: pointer to the properly sized buffer for the data.
+ *
+ * Reads 16-bit chunks of data from the NVM (EEPROM). This is a function
+ * pointer entry point called by drivers.
+ **/
+INT32 e1000_read_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ if (hw->nvm.ops.read)
+ return hw->nvm.ops.read(hw, offset, words, data);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_write_nvm - Writes to NVM (EEPROM)
+ * @hw: pointer to the HW structure
+ * @offset: the word offset to read
+ * @words: number of 16-bit words to write
+ * @data: pointer to the properly sized buffer for the data.
+ *
+ * Writes 16-bit chunks of data to the NVM (EEPROM). This is a function
+ * pointer entry point called by drivers.
+ **/
+INT32 e1000_write_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ if (hw->nvm.ops.write)
+ return hw->nvm.ops.write(hw, offset, words, data);
+
+ return E1000_SUCCESS;
+}
+
+#ifndef NO_82575_SUPPORT
+/**
+ * e1000_write_8bit_ctrl_reg - Writes 8bit Control register
+ * @hw: pointer to the HW structure
+ * @reg: 32bit register offset
+ * @offset: the register to write
+ * @data: the value to write.
+ *
+ * Writes the PHY register at offset with the value in data.
+ * This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_write_8bit_ctrl_reg(struct e1000_hw *hw, UINT32 reg, UINT32 offset,
+ UINT8 data)
+{
+ return e1000_write_8bit_ctrl_reg_generic(hw, reg, offset, data);
+}
+
+#endif /* NO_82575_SUPPORT */
+/**
+ * e1000_power_up_phy - Restores link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void e1000_power_up_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.power_up)
+ hw->phy.ops.power_up(hw);
+
+ e1000_setup_link(hw);
+}
+
+/**
+ * e1000_power_down_phy - Power down PHY
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void e1000_power_down_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.power_down)
+ hw->phy.ops.power_down(hw);
+}
+
+#ifndef NO_82576_SUPPORT
+/**
+ * e1000_power_up_fiber_serdes_link - Power up serdes link
+ * @hw: pointer to the HW structure
+ *
+ * Power on the optics and PCS.
+ **/
+void e1000_power_up_fiber_serdes_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.power_up_serdes)
+ hw->mac.ops.power_up_serdes(hw);
+}
+
+/**
+ * e1000_shutdown_fiber_serdes_link - Remove link during power down
+ * @hw: pointer to the HW structure
+ *
+ * Shutdown the optics and PCS on driver unload.
+ **/
+void e1000_shutdown_fiber_serdes_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.shutdown_serdes)
+ hw->mac.ops.shutdown_serdes(hw);
+}
+
+#endif /* NO_82576_SUPPORT */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h
new file mode 100755
index 0000000..9695ddb
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h
@@ -0,0 +1,175 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_API_H_
+#define _E1000_API_H_
+
+#include "e1000_hw.h"
+
+#ifndef NO_82571_SUPPORT
+extern void e1000_init_function_pointers_82571(struct e1000_hw *hw);
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+extern void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw);
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+extern void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw);
+#endif
+#ifndef NO_82575_SUPPORT
+extern void e1000_init_function_pointers_82575(struct e1000_hw *hw);
+extern void e1000_rx_fifo_flush_82575(struct e1000_hw *hw);
+#ifndef NO_82576_SUPPORT
+extern void e1000_init_function_pointers_vf(struct e1000_hw *hw);
+extern void e1000_power_up_fiber_serdes_link(struct e1000_hw *hw);
+extern void e1000_shutdown_fiber_serdes_link(struct e1000_hw *hw);
+#endif
+#endif
+
+INT32 e1000_set_mac_type(struct e1000_hw *hw);
+INT32 e1000_setup_init_funcs(struct e1000_hw *hw, BOOLEAN init_device);
+INT32 e1000_init_mac_params(struct e1000_hw *hw);
+INT32 e1000_init_nvm_params(struct e1000_hw *hw);
+INT32 e1000_init_phy_params(struct e1000_hw *hw);
+INT32 e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_clear_vfta(struct e1000_hw *hw);
+void e1000_write_vfta(struct e1000_hw *hw, UINT32 offset, UINT32 value);
+INT32 e1000_force_mac_fc(struct e1000_hw *hw);
+INT32 e1000_check_for_link(struct e1000_hw *hw);
+INT32 e1000_reset_hw(struct e1000_hw *hw);
+INT32 e1000_init_hw(struct e1000_hw *hw);
+INT32 e1000_setup_link(struct e1000_hw *hw);
+INT32 e1000_get_speed_and_duplex(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+INT32 e1000_disable_pcie_master(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+void e1000_rar_set(struct e1000_hw *hw, UINT8 *addr, UINT32 index);
+UINT32 e1000_hash_mc_addr(struct e1000_hw *hw, UINT8 *mc_addr);
+void e1000_update_mc_addr_list(struct e1000_hw *hw,
+ UINT8 *mc_addr_list, UINT32 mc_addr_count);
+INT32 e1000_setup_led(struct e1000_hw *hw);
+INT32 e1000_cleanup_led(struct e1000_hw *hw);
+INT32 e1000_check_reset_block(struct e1000_hw *hw);
+INT32 e1000_blink_led(struct e1000_hw *hw);
+INT32 e1000_led_on(struct e1000_hw *hw);
+INT32 e1000_led_off(struct e1000_hw *hw);
+INT32 e1000_id_led_init(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+INT32 e1000_get_cable_length(struct e1000_hw *hw);
+INT32 e1000_validate_mdi_setting(struct e1000_hw *hw);
+INT32 e1000_read_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#ifndef NO_82575_SUPPORT
+INT32 e1000_write_8bit_ctrl_reg(struct e1000_hw *hw, UINT32 reg,
+ UINT32 offset, UINT8 data);
+#endif
+INT32 e1000_get_phy_info(struct e1000_hw *hw);
+void e1000_release_phy(struct e1000_hw *hw);
+INT32 e1000_acquire_phy(struct e1000_hw *hw);
+#ifndef NO_80003ES2LAN_SUPPORT
+INT32 e1000_cfg_on_link_up(struct e1000_hw *hw);
+#endif
+INT32 e1000_phy_hw_reset(struct e1000_hw *hw);
+INT32 e1000_phy_commit(struct e1000_hw *hw);
+void e1000_power_up_phy(struct e1000_hw *hw);
+void e1000_power_down_phy(struct e1000_hw *hw);
+INT32 e1000_read_mac_addr(struct e1000_hw *hw);
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+INT32 e1000_read_pba_num(struct e1000_hw *hw, UINT32 *part_num);
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+INT32 e1000_read_pba_string(struct e1000_hw *hw, UINT8 *pba_num,
+ UINT32 pba_num_size);
+INT32 e1000_read_pba_length(struct e1000_hw *hw, UINT32 *pba_num_size);
+void e1000_reload_nvm(struct e1000_hw *hw);
+INT32 e1000_update_nvm_checksum(struct e1000_hw *hw);
+INT32 e1000_validate_nvm_checksum(struct e1000_hw *hw);
+INT32 e1000_read_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data);
+INT32 e1000_read_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data);
+INT32 e1000_wait_autoneg(struct e1000_hw *hw);
+INT32 e1000_set_d3_lplu_state(struct e1000_hw *hw, BOOLEAN active);
+INT32 e1000_set_d0_lplu_state(struct e1000_hw *hw, BOOLEAN active);
+BOOLEAN e1000_check_mng_mode(struct e1000_hw *hw);
+BOOLEAN e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
+INT32 e1000_mng_enable_host_if(struct e1000_hw *hw);
+INT32 e1000_mng_host_if_write(struct e1000_hw *hw,
+ UINT8 *buffer, UINT16 length, UINT16 offset, UINT8 *sum);
+INT32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr);
+INT32 e1000_mng_write_dhcp_info(struct e1000_hw * hw,
+ UINT8 *buffer, UINT16 length);
+
+/*
+ * TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ * adapter = a pointer to struct e1000_hw
+ * status = the 8 bit status field of the Rx descriptor with EOP set
+ * error = the 8 bit error field of the Rx descriptor with EOP set
+ * length = the sum of all the length fields of the Rx descriptors that
+ * make up the current frame
+ * last_byte = the last byte of the frame DMAed by the hardware
+ * max_frame_length = the maximum frame length we want to accept.
+ * min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ * ...
+ * if (TBI_ACCEPT) {
+ * accept_frame = TRUE;
+ * e1000_tbi_adjust_stats(adapter, MacAddress);
+ * frame_length--;
+ * } else {
+ * accept_frame = FALSE;
+ * }
+ * ...
+ */
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION 0x0F
+
+#define TBI_ACCEPT(a, status, errors, length, last_byte, min_frame_size, max_frame_size) \
+ (e1000_tbi_sbp_enabled_82543(a) && \
+ (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+ ((last_byte) == CARRIER_EXTENSION) && \
+ (((status) & E1000_RXD_STAT_VP) ? \
+ (((length) > (min_frame_size - VLAN_TAG_SIZE)) && \
+ ((length) <= (max_frame_size + 1))) : \
+ (((length) > min_frame_size) && \
+ ((length) <= (max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h
new file mode 100755
index 0000000..188ae0a
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h
@@ -0,0 +1,1772 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define REQ_RX_DESCRIPTOR_MULTIPLE 8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME 0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_LSCWE 0x00000010 /* Link Status wake up enable */
+#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */
+#define E1000_WUC_SPM 0x80000000 /* Enable SPM */
+#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */
+#define E1000_WUC_FLX6_PHY 0x4000 /* Flexible Filter 6 Enable */
+#define E1000_WUC_FLX7_PHY 0x8000 /* Flexible Filter 7 Enable */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO_PHY 0x00000800 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0_PHY 0x00001000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1_PHY 0x00002000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2_PHY 0x00004000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3_PHY 0x00008000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX4_PHY 0x00000200 /* Flexible Filter 4 Enable */
+#define E1000_WUFC_FLX5_PHY 0x00000400 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
+#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_FLX6 0x00400000 /* Flexible Filter 6 Enable */
+#define E1000_WUFC_FLX7 0x00800000 /* Flexible Filter 7 Enable */
+#define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF /*Mask for all wakeup filters*/
+#define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 /*Mask for 4 flexible filters*/
+#define E1000_WUFC_ALL_FILTERS_PHY_6 0x0000F6FF /*Mask for 6 wakeup filters */
+#define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 /*Mask for 6 flexible filters*/
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_ALL_FILTERS_6 0x003F00FF /* Mask for all 6 wakeup filters*/
+#define E1000_WUFC_ALL_FILTERS_8 0x00FF00FF /* Mask for all 8 wakeup filters*/
+#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /*Mask for the 4 flexible filters */
+#define E1000_WUFC_FLX_FILTERS_6 0x003F0000 /* Mask for 6 flexible filters */
+#define E1000_WUFC_FLX_FILTERS_8 0x00FF0000 /* Mask for 8 flexible filters */
+#ifndef NO_82576_SUPPORT
+/*
+ * For 82576 to utilize Extended filter masks in addition to
+ * existing (filter) masks
+ */
+#define E1000_WUFC_EXT_FLX_FILTERS 0x00300000 /* Ext. FLX filter mask */
+#endif /* NO_82576_SUPPORT */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC E1000_WUFC_LNKC
+#define E1000_WUS_MAG E1000_WUFC_MAG
+#define E1000_WUS_EX E1000_WUFC_EX
+#define E1000_WUS_MC E1000_WUFC_MC
+#define E1000_WUS_BC E1000_WUFC_BC
+#define E1000_WUS_ARP E1000_WUFC_ARP
+#define E1000_WUS_IPV4 E1000_WUFC_IPV4
+#define E1000_WUS_IPV6 E1000_WUFC_IPV6
+#define E1000_WUS_FLX0_PHY E1000_WUFC_FLX0_PHY
+#define E1000_WUS_FLX1_PHY E1000_WUFC_FLX1_PHY
+#define E1000_WUS_FLX2_PHY E1000_WUFC_FLX2_PHY
+#define E1000_WUS_FLX3_PHY E1000_WUFC_FLX3_PHY
+#define E1000_WUS_FLX_FILTERS_PHY_4 E1000_WUFC_FLX_FILTERS_PHY_4
+#define E1000_WUS_FLX0 E1000_WUFC_FLX0
+#define E1000_WUS_FLX1 E1000_WUFC_FLX1
+#define E1000_WUS_FLX2 E1000_WUFC_FLX2
+#define E1000_WUS_FLX3 E1000_WUFC_FLX3
+#define E1000_WUS_FLX4 E1000_WUFC_FLX4
+#define E1000_WUS_FLX5 E1000_WUFC_FLX5
+#define E1000_WUS_FLX6 E1000_WUFC_FLX6
+#define E1000_WUS_FLX7 E1000_WUFC_FLX7
+#define E1000_WUS_FLX4_PHY E1000_WUFC_FLX4_PHY
+#define E1000_WUS_FLX5_PHY E1000_WUFC_FLX5_PHY
+#define E1000_WUS_FLX6_PHY 0x0400
+#define E1000_WUS_FLX7_PHY 0x0800
+#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS
+#define E1000_WUS_FLX_FILTERS_6 E1000_WUFC_FLX_FILTERS_6
+#define E1000_WUS_FLX_FILTERS_8 E1000_WUFC_FLX_FILTERS_8
+#define E1000_WUS_FLX_FILTERS_PHY_6 E1000_WUFC_FLX_FILTERS_PHY_6
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+/* Six Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX_6 6
+/* Eight Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX_8 8
+#ifndef NO_82576_SUPPORT
+/* Two Extended Flexible Filters are supported (82576) */
+#define E1000_EXT_FLEXIBLE_FILTER_COUNT_MAX 2
+#define E1000_FHFT_LENGTH_OFFSET 0xFC /* Length byte in FHFT */
+#define E1000_FHFT_LENGTH_MASK 0x0FF /* Length in lower byte */
+#endif
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6
+#define E1000_FFLT_SIZE_8 E1000_FLEXIBLE_FILTER_COUNT_MAX_8
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */
+/* Reserved (bits 4,5) in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
+#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
+/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* Direction of SDP3 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */
+#ifndef NO_82576_SUPPORT
+/* Physical Func Reset Done Indication */
+#define E1000_CTRL_EXT_PFRSTD 0x00004000
+#endif
+#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#ifndef NO_82580_SUPPORT
+#define E1000_CTRL_EXT_LINK_MODE_82580_MASK 0x01C00000 /*82580 bit 24:22*/
+#define E1000_CTRL_EXT_LINK_MODE_1000BASE_KX 0x00400000
+#endif
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000
+#define E1000_CTRL_EXT_EIAME 0x01000000
+#define E1000_CTRL_EXT_IRCA 0x00000001
+#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+#define E1000_CTRL_EXT_CANC 0x04000000 /* Int delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+#ifndef NO_82576_SUPPORT
+#endif /* NO_82576_SUPPORT */
+/* IAME enable bit (27) was removed in >= 82575 */
+#define E1000_CTRL_EXT_IAME 0x08000000 /* Int acknowledge Auto-mask */
+#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error
+ * detection enabled */
+#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity
+ * error detection enable */
+#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000
+#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
+#define E1000_CTRL_EXT_PHYPDEN 0x00100000
+#define E1000_I2CCMD_REG_ADDR_SHIFT 16
+#define E1000_I2CCMD_REG_ADDR 0x00FF0000
+#define E1000_I2CCMD_PHY_ADDR_SHIFT 24
+#define E1000_I2CCMD_PHY_ADDR 0x07000000
+#define E1000_I2CCMD_OPCODE_READ 0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE 0x00000000
+#define E1000_I2CCMD_RESET 0x10000000
+#define E1000_I2CCMD_READY 0x20000000
+#define E1000_I2CCMD_INTERRUPT_ENA 0x40000000
+#define E1000_I2CCMD_ERROR 0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR 255
+#define E1000_I2CCMD_PHY_TIMEOUT 200
+#ifndef NO_82576_SUPPORT
+#define E1000_IVAR_VALID 0x80
+#define E1000_GPIE_NSICR 0x00000001
+#define E1000_GPIE_MSIX_MODE 0x00000010
+#define E1000_GPIE_EIAME 0x40000000
+#define E1000_GPIE_PBA 0x80000000
+#endif /* NO_82576_SUPPORT */
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
+#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */
+#define E1000_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */
+#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */
+#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
+#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
+#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
+#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
+#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
+#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE 0x01000000
+#define E1000_RXDEXT_STATERR_SE 0x02000000
+#define E1000_RXDEXT_STATERR_SEQ 0x04000000
+#define E1000_RXDEXT_STATERR_CXE 0x10000000
+#define E1000_RXDEXT_STATERR_TCPE 0x20000000
+#define E1000_RXDEXT_STATERR_IPE 0x40000000
+#define E1000_RXDEXT_STATERR_RXE 0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+ E1000_RXD_ERR_CE | \
+ E1000_RXD_ERR_SE | \
+ E1000_RXD_ERR_SEQ | \
+ E1000_RXD_ERR_CXE | \
+ E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+ E1000_RXDEXT_STATERR_CE | \
+ E1000_RXDEXT_STATERR_SE | \
+ E1000_RXDEXT_STATERR_SEQ | \
+ E1000_RXDEXT_STATERR_CXE | \
+ E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_ENABLE_MASK 0x00000007
+#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT 0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_NEIGHBOR_EN 0x00004000
+#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST 0x00200000
+/* Enable IP address filtering */
+#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000
+#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */
+
+#define E1000_MANC2H_PORT_623 0x00000020 /* Port 0x26f */
+#define E1000_MANC2H_PORT_664 0x00000040 /* Port 0x298 */
+#define E1000_MDEF_PORT_623 0x00000800 /* Port 0x26f */
+#define E1000_MDEF_PORT_664 0x00000400 /* Port 0x298 */
+
+/* Receive Control */
+#define E1000_RCTL_RST 0x00000001 /* Software reset */
+#define E1000_RCTL_EN 0x00000002 /* enable */
+#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
+#define E1000_RCTL_UPE 0x00000008 /* unicast promisc enable */
+#define E1000_RCTL_MPE 0x00000010 /* multicast promisc enable */
+#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
+#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
+#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min thresh size */
+#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
+#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
+#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */
+#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
+#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
+#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
+#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
+#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */
+#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
+#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
+#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ * E1000_PSRCTL_BSIZE0_MASK) |
+ * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ * E1000_PSRCTL_BSIZE1_MASK) |
+ * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ * E1000_PSRCTL_BSIZE2_MASK) |
+ * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ * E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256], default=256
+ * value1 = [1024..64512], default=4096
+ * value2 = [0..64512], default=4096
+ * value3 = [0..64512], default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM 0x01
+#define E1000_SWFW_PHY0_SM 0x02
+#define E1000_SWFW_PHY1_SM 0x04
+#define E1000_SWFW_CSR_SM 0x08
+#ifndef NO_82580_SUPPORT
+#define E1000_SWFW_PHY2_SM 0x20
+#define E1000_SWFW_PHY3_SM 0x40
+#endif /* NO_82580_SUPPORT */
+
+/* FACTPS Definitions */
+#define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */
+/* Device Control */
+#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
+#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
+#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
+#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
+#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
+#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
+#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
+ * indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
+ * PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
+ * LINK_0 and LINK_1 pins */
+#define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */
+#define E1000_CTRL_LANPHYPC_VALUE 0x00020000 /* SW value of LANPHYPC */
+#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */
+#ifndef NO_82575_SUPPORT
+#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
+#endif
+#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST 0x04000000 /* Global reset */
+#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
+#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
+#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
+#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */
+
+/*
+ * Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
+
+#define E1000_CONNSW_ENRGSRC 0x4
+#define E1000_PCS_CFG_PCS_EN 8
+#define E1000_PCS_LCTL_FLV_LINK_UP 1
+#define E1000_PCS_LCTL_FSV_10 0
+#define E1000_PCS_LCTL_FSV_100 2
+#define E1000_PCS_LCTL_FSV_1000 4
+#define E1000_PCS_LCTL_FDV_FULL 8
+#define E1000_PCS_LCTL_FSD 0x10
+#define E1000_PCS_LCTL_FORCE_LINK 0x20
+#define E1000_PCS_LCTL_LOW_LINK_LATCH 0x40
+#define E1000_PCS_LCTL_FORCE_FCTRL 0x80
+#define E1000_PCS_LCTL_AN_ENABLE 0x10000
+#define E1000_PCS_LCTL_AN_RESTART 0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000
+#define E1000_PCS_LCTL_AN_SGMII_BYPASS 0x80000
+#define E1000_PCS_LCTL_AN_SGMII_TRIGGER 0x100000
+#define E1000_PCS_LCTL_FAST_LINK_TIMER 0x1000000
+#define E1000_PCS_LCTL_LINK_OK_FIX 0x2000000
+#define E1000_PCS_LCTL_CRS_ON_NI 0x4000000
+#define E1000_ENABLE_SERDES_LOOPBACK 0x0410
+
+#define E1000_PCS_LSTS_LINK_OK 1
+#define E1000_PCS_LSTS_SPEED_10 0
+#define E1000_PCS_LSTS_SPEED_100 2
+#define E1000_PCS_LSTS_SPEED_1000 4
+#define E1000_PCS_LSTS_DUPLEX_FULL 8
+#define E1000_PCS_LSTS_SYNK_OK 0x10
+#define E1000_PCS_LSTS_AN_COMPLETE 0x10000
+#define E1000_PCS_LSTS_AN_PAGE_RX 0x20000
+#define E1000_PCS_LSTS_AN_TIMED_OUT 0x40000
+#define E1000_PCS_LSTS_AN_REMOTE_FAULT 0x80000
+#define E1000_PCS_LSTS_AN_ERROR_RWS 0x100000
+
+/* Device Status */
+#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */
+#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
+#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */
+#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
+#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */
+#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state.
+ * Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
+#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */
+#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */
+#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution
+ * disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8 0x04000000
+#define E1000_STATUS_FUSE_9 0x08000000
+#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */
+
+/* Constants used to interpret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
+
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define PHY_FORCE_TIME 20
+
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL 0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_PHY_LED0_MODE_MASK 0x00000007
+#define E1000_PHY_LED0_IVRT 0x00000008
+#define E1000_PHY_LED0_BLINK 0x00000010
+#define E1000_PHY_LED0_MASK 0x0000001F
+
+#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020
+#define E1000_LEDCTL_LED0_IVRT 0x00000040
+#define E1000_LEDCTL_LED0_BLINK 0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_BLINK_RATE 0x00002000
+#define E1000_LEDCTL_LED1_IVRT 0x00004000
+#define E1000_LEDCTL_LED1_BLINK 0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000
+#define E1000_LEDCTL_LED2_IVRT 0x00400000
+#define E1000_LEDCTL_LED2_BLINK 0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000
+#define E1000_LEDCTL_LED3_IVRT 0x40000000
+#define E1000_LEDCTL_LED3_BLINK 0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000 0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP 0x2
+#define E1000_LEDCTL_MODE_ACTIVITY 0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10 0x5
+#define E1000_LEDCTL_MODE_LINK_100 0x6
+#define E1000_LEDCTL_MODE_LINK_1000 0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE 0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9
+#define E1000_LEDCTL_MODE_COLLISION 0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED 0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE 0xC
+#define E1000_LEDCTL_MODE_PAUSED 0xD
+#define E1000_LEDCTL_MODE_LED_ON 0xE
+#define E1000_LEDCTL_MODE_LED_OFF 0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_SHIFT 8 /* POPTS shift */
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+/* Extended desc bits for Linksec and timesync */
+
+/* Transmit Control */
+#define E1000_TCTL_RST 0x00000001 /* software reset */
+#define E1000_TCTL_EN 0x00000002 /* enable tx */
+#define E1000_TCTL_BCE 0x00000004 /* busy check enable */
+#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
+#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
+#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
+#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */
+#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
+
+/* Transmit Arbitration Count */
+#define E1000_TARC0_ENABLE 0x00000400 /* Enable Tx Queue 0 */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */
+#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
+#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS 0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT 1
+#define E1000_RFCTL_NFSW_DIS 0x00000040
+#define E1000_RFCTL_NFSR_DIS 0x00000080
+#define E1000_RFCTL_NFS_VER_MASK 0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT 8
+#define E1000_RFCTL_IPV6_DIS 0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800
+#define E1000_RFCTL_ACK_DIS 0x00001000
+#define E1000_RFCTL_ACKD_DIS 0x00002000
+#define E1000_RFCTL_IPFRSP_DIS 0x00004000
+#define E1000_RFCTL_EXTEN 0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+#define E1000_RFCTL_LEF 0x00040000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD 15
+#define E1000_CT_SHIFT 4
+#define E1000_COLLISION_DISTANCE 63
+#define E1000_COLD_SHIFT 12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_FIBER 9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK 0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT 10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT 20
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */
+
+#define ETHERNET_FCS_SIZE 4
+#define MAX_JUMBO_FRAME_SIZE 0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008
+#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16
+
+#define E1000_PHY_CTRL_SPD_EN 0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS 0x00050000
+
+/* PBA constants */
+#define E1000_PBA_6K 0x0006 /* 6KB */
+#define E1000_PBA_8K 0x0008 /* 8KB */
+#define E1000_PBA_10K 0x000A /* 10KB */
+#define E1000_PBA_12K 0x000C /* 12KB */
+#define E1000_PBA_14K 0x000E /* 14KB */
+#define E1000_PBA_16K 0x0010 /* 16KB */
+#define E1000_PBA_18K 0x0012
+#define E1000_PBA_20K 0x0014
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_26K 0x001A
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
+#define E1000_PBA_35K 0x0023
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030 /* 48KB */
+#define E1000_PBA_64K 0x0040 /* 64KB */
+
+#define E1000_PBS_16K E1000_PBA_16K
+#define E1000_PBS_24K E1000_PBA_24K
+
+#define IFS_MAX 80
+#define IFS_MIN 40
+#define IFS_RATIO 4
+#define IFS_STEP 10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
+
+#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO 0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB 0x00000100 /* VM MB event */
+#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD 0x00010000
+#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG 0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */
+#ifndef NO_82580_SUPPORT
+#define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */
+#endif
+#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver
+ * should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
+#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
+#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW
+ * bit in the FWSM */
+#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates
+ * an interrupt */
+#define E1000_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
+#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */
+#ifndef NO_82574_SUPPORT
+#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_82580_SUPPORT
+#define E1000_ICR_FER 0x00400000 /* Fatal Error */
+#endif /* NO_82580_SUPPORT */
+
+#ifndef NO_82571_SUPPORT
+/* PBA ECC Register */
+#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */
+#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */
+#define E1000_PBA_ECC_CORR_EN 0x00000001 /* Enable ECC error correction */
+#define E1000_PBA_ECC_STAT_CLR 0x00000002 /* Clear ECC error counter */
+#define E1000_PBA_ECC_INT_EN 0x00000004 /* Enable ICR bit 5 on ECC error */
+#endif /* NO_82571_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+/* Extended Interrupt Cause Read */
+#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */
+#define E1000_EICR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */
+#define E1000_EICR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */
+#define E1000_EICR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */
+#define E1000_EICR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */
+#define E1000_EICR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */
+#define E1000_EICR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */
+#define E1000_EICR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */
+#define E1000_EICR_TCP_TIMER 0x40000000 /* TCP Timer */
+#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */
+/* TCP Timer */
+#define E1000_TCPTIMER_KS 0x00000100 /* KickStart */
+#define E1000_TCPTIMER_COUNT_ENABLE 0x00000200 /* Count Enable */
+#define E1000_TCPTIMER_COUNT_FINISH 0x00000400 /* Count finish */
+#define E1000_TCPTIMER_LOOP 0x00000800 /* Loop */
+
+#endif /* NO_82575_SUPPORT */
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ)
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXT0 = Receiver Timer Interrupt (ring 0)
+ * o TXDW = Transmit Descriptor Written Back
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ * o LSC = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+ E1000_IMS_RXT0 | \
+ E1000_IMS_TXDW | \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ | \
+ E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW E1000_ICR_TXDW /* Tx desc written back */
+#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */
+#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD E1000_ICR_SRPD
+#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */
+#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */
+#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */
+#ifndef NO_82580_SUPPORT
+#define E1000_IMS_DRSTA E1000_ICR_DRSTA /* Device Reset Asserted */
+#endif
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+ * parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+ * parity error */
+#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer
+ * parity error */
+#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity
+ * error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+ * parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+ * parity error */
+#define E1000_IMS_DSW E1000_ICR_DSW
+#define E1000_IMS_PHYINT E1000_ICR_PHYINT
+#define E1000_IMS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_IMS_EPRST E1000_ICR_EPRST
+#ifndef NO_82574_SUPPORT
+#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
+#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
+#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
+#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */
+#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_82580_SUPPORT
+#define E1000_IMS_FER E1000_ICR_FER /* Fatal Error */
+#endif /* NO_82580_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+/* Extended Interrupt Mask Set */
+#define E1000_EIMS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EIMS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EIMS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EIMS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EIMS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EIMS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EIMS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EIMS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EIMS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EIMS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */
+
+#endif /* NO_82575_SUPPORT */
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW E1000_ICR_TXDW /* Tx desc written back */
+#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD E1000_ICR_SRPD
+#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */
+#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */
+#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */
+#ifndef NO_82580_SUPPORT
+#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Aserted */
+#endif
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+ * parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+ * parity error */
+#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer
+ * parity error */
+#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity
+ * error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+ * parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+ * parity error */
+#define E1000_ICS_DSW E1000_ICR_DSW
+#define E1000_ICS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_ICS_PHYINT E1000_ICR_PHYINT
+#define E1000_ICS_EPRST E1000_ICR_EPRST
+
+#ifndef NO_82575_SUPPORT
+/* Extended Interrupt Cause Set */
+#define E1000_EICS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EICS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EICS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EICS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EICS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EICS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EICS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EICS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EICS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EICS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */
+
+#define E1000_EITR_ITR_INT_MASK 0x0000FFFF
+/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
+#define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
+
+#endif /* NO_82575_SUPPORT */
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+/* Enable the counting of descriptors still to be processed. */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE 0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots. However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 15
+#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
+
+/* Error Codes */
+#define E1000_SUCCESS 0
+#define E1000_ERR_NVM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET 9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET 12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_MBX 15
+#define E1000_ERR_INVALID_ARGUMENT 16
+#define E1000_ERR_NO_SPACE 17
+#define E1000_ERR_NVM_PBA_SECTION 18
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT 50
+#define COPPER_LINK_UP_LIMIT 10
+#define PHY_AUTO_NEG_LIMIT 45
+#define PHY_FORCE_LIMIT 20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT 800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT 100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT 10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT 10
+
+/* Flow Control */
+#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */
+#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
+#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */
+#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */
+#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */
+#define E1000_TXCW_NP 0x00008000 /* TXCW next page */
+#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */
+#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */
+#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */
+#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */
+#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */
+#define E1000_RXCW_CC 0x10000000 /* Receive config change */
+#define E1000_RXCW_C 0x20000000 /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */
+
+#define E1000_TSYNCTXCTL_VALID 0x00000001 /* tx timestamp valid */
+#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable tx timestampping */
+
+#define E1000_TSYNCRXCTL_VALID 0x00000001 /* rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL 0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
+#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable rx timestampping */
+
+#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF
+#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01
+#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE 0x02
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE 0x03
+#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE 0x04
+
+#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK 0x00000F00
+#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE 0x0000
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE 0x0100
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE 0x0200
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE 0x0300
+#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE 0x0800
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE 0x0900
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE 0x0A00
+#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE 0x0B00
+#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE 0x0C00
+#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE 0x0D00
+
+#define E1000_TIMINCA_16NS_SHIFT 24
+#ifndef NO_82580_SUPPORT
+/* TUPLE Filtering Configuration */
+#define E1000_TTQF_DISABLE_MASK 0xF0008000 /* TTQF Disable Mask */
+#define E1000_TTQF_QUEUE_ENABLE 0x100 /* TTQF Queue Enable Bit */
+#define E1000_TTQF_PROTOCOL_MASK 0xFF /* TTQF Protocol Mask */
+/* TTQF TCP Bit, shift with E1000_TTQF_PROTOCOL SHIFT */
+#define E1000_TTQF_PROTOCOL_TCP 0x0
+/* TTQF UDP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */
+#define E1000_TTQF_PROTOCOL_UDP 0x1
+/* TTQF SCTP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */
+#define E1000_TTQF_PROTOCOL_SCTP 0x2
+#define E1000_TTQF_PROTOCOL_SHIFT 5 /* TTQF Protocol Shift */
+#define E1000_TTQF_QUEUE_SHIFT 16 /* TTQF Queue Shfit */
+#define E1000_TTQF_RX_QUEUE_MASK 0x70000 /* TTQF Queue Mask */
+#define E1000_TTQF_MASK_ENABLE 0x10000000 /* TTQF Mask Enable Bit */
+#define E1000_IMIR_CLEAR_MASK 0xF001FFFF /* IMIR Reg Clear Mask */
+#define E1000_IMIR_PORT_BYPASS 0x20000 /* IMIR Port Bypass Bit */
+#define E1000_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */
+#define E1000_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */
+
+#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */
+#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */
+#define E1000_MDICNFG_PHY_MASK 0x03E00000
+#define E1000_MDICNFG_PHY_SHIFT 21
+#endif /*Barton Hills HW */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP 0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004
+#define E1000_GCR_TXD_NO_SNOOP 0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020
+#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000
+#define E1000_GCR_CAP_VER2 0x00040000
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \
+ E1000_GCR_RXDSCW_NO_SNOOP | \
+ E1000_GCR_RXDSCR_NO_SNOOP | \
+ E1000_GCR_TXD_NO_SNOOP | \
+ E1000_GCR_TXDSCW_NO_SNOOP | \
+ E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local Tx is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Register */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */
+
+/* NVM Control */
+#define E1000_EECD_SK 0x00000001 /* NVM Clock */
+#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI 0x00000004 /* NVM Data In */
+#define E1000_EECD_DO 0x00000008 /* NVM Data Out */
+#define E1000_EECD_FWE_MASK 0x00000030
+#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES 0x00000100 /* NVM Present */
+#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_NVM_GRANT_ATTEMPTS
+#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT 22
+#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
+
+#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */
+#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */
+#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write regs */
+#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START 1 /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES 2000
+
+/* NVM Word Offsets */
+#define NVM_COMPAT 0x0003
+#define NVM_ID_LED_SETTINGS 0x0004
+#define NVM_VERSION 0x0005
+#define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */
+#define NVM_PHY_CLASS_WORD 0x0007
+#define NVM_INIT_CONTROL1_REG 0x000A
+#define NVM_INIT_CONTROL2_REG 0x000F
+#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define NVM_INIT_CONTROL3_PORT_B 0x0014
+#define NVM_INIT_3GIO_3 0x001A
+#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define NVM_INIT_CONTROL3_PORT_A 0x0024
+#define NVM_CFG 0x0012
+#define NVM_FLASH_VERSION 0x0032
+#define NVM_ALT_MAC_ADDR_PTR 0x0037
+#define NVM_CHECKSUM_REG 0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */
+#ifndef NO_82580_SUPPORT
+#define E1000_NVM_CFG_DONE_PORT_2 0x100000 /* ...for third port */
+#define E1000_NVM_CFG_DONE_PORT_3 0x200000 /* ...for fourth port */
+
+#define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
+
+/* Mask bits for fields in Word 0x24 of the NVM */
+#define NVM_WORD24_COM_MDIO 0x0008 /* MDIO interface shared */
+#define NVM_WORD24_EXT_MDIO 0x0004 /* MDIO accesses routed external */
+#endif /* NO_82580_SUPPORT */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK 0x3000
+#define NVM_WORD0F_PAUSE 0x1000
+#define NVM_WORD0F_ASM_DIR 0x2000
+#define NVM_WORD0F_ANE 0x0800
+#define NVM_WORD0F_SWPDIO_EXT_MASK 0x00F0
+#define NVM_WORD0F_LPLU 0x0001
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK 0x000C
+
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define NVM_COMPAT_LOM 0x0800
+
+/* length of string needed to store PBA number */
+#define E1000_PBANUM_LENGTH 11
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM 0xBABA
+
+#define NVM_MAC_ADDR_OFFSET 0
+#define NVM_PBA_OFFSET_0 8
+#define NVM_PBA_OFFSET_1 9
+#define NVM_PBA_PTR_GUARD 0xFAFA
+#define NVM_RESERVED_WORD 0xFFFF
+#define NVM_PHY_CLASS_A 0x8000
+#define NVM_SERDES_AMPLITUDE_MASK 0x000F
+#define NVM_SIZE_MASK 0x1C00
+#define NVM_SIZE_SHIFT 10
+#define NVM_WORD_SIZE_BASE_SHIFT 6
+#define NVM_SWDPIO_EXT_SHIFT 4
+
+#ifndef NO_MICROWIRE_SUPPORT
+/* NVM Commands - Microwire */
+#define NVM_READ_OPCODE_MICROWIRE 0x6 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_MICROWIRE 0x5 /* NVM write opcode */
+#define NVM_ERASE_OPCODE_MICROWIRE 0x7 /* NVM erase opcode */
+#define NVM_EWEN_OPCODE_MICROWIRE 0x13 /* NVM erase/write enable */
+#define NVM_EWDS_OPCODE_MICROWIRE 0x10 /* NVM erase/write disable */
+
+#endif /* NO_MICROWIRE_SUPPORT */
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */
+#define NVM_WRDI_OPCODE_SPI 0x04 /* NVM reset Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */
+#define NVM_WRSR_OPCODE_SPI 0x01 /* NVM write Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI 0x01
+#define NVM_STATUS_WEN_SPI 0x02
+#define NVM_STATUS_BP0_SPI 0x04
+#define NVM_STATUS_BP1_SPI 0x08
+#define NVM_STATUS_WPEN_SPI 0x80
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2 0x1
+#define ID_LED_DEF1_ON2 0x2
+#define ID_LED_DEF1_OFF2 0x3
+#define ID_LED_ON1_DEF2 0x4
+#define ID_LED_ON1_ON2 0x5
+#define ID_LED_ON1_OFF2 0x6
+#define ID_LED_OFF1_DEF2 0x7
+#define ID_LED_OFF1_ON2 0x8
+#define ID_LED_OFF1_OFF2 0x9
+
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#ifndef NO_PCIX_SUPPORT
+#define PCIX_COMMAND_REGISTER 0xE6
+#define PCIX_STATUS_REGISTER_LO 0xE8
+#define PCIX_STATUS_REGISTER_HI 0xEA
+#endif
+#define PCI_HEADER_TYPE_REGISTER 0x0E
+#define PCIE_LINK_STATUS 0x12
+#define PCIE_DEVICE_CONTROL2 0x28
+
+#ifndef NO_PCIX_SUPPORT
+#define PCIX_COMMAND_MMRBC_MASK 0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT 0x2
+#define PCIX_STATUS_HI_MMRBC_MASK 0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5
+#define PCIX_STATUS_HI_MMRBC_4K 0x3
+#define PCIX_STATUS_HI_MMRBC_2K 0x2
+#define PCIX_STATUS_LO_FUNC_MASK 0x7
+#endif
+#define PCI_HEADER_TYPE_MULTIFUNC 0x80
+#define PCIE_LINK_WIDTH_MASK 0x3F0
+#define PCIE_LINK_WIDTH_SHIFT 4
+#define PCIE_LINK_SPEED_MASK 0x0F
+#define PCIE_LINK_SPEED_2500 0x01
+#define PCIE_LINK_SPEED_5000 0x02
+#define PCIE_DEVICE_CONTROL2_16ms 0x0005
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN 6
+#endif
+
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1011_I_REV_4 0x04
+#define M88E1111_I_PHY_ID 0x01410CC0
+#define GG82563_E_PHY_ID 0x01410CA0
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+#define BME1000_E_PHY_ID 0x01410CB0
+#define BME1000_E_PHY_ID_R2 0x01410CB1
+#define I82577_E_PHY_ID 0x01540050
+#define I82578_E_PHY_ID 0x004DD040
+#define I82579_E_PHY_ID 0x01540090
+#ifndef NO_82580_SUPPORT
+#define I82580_I_PHY_ID 0x015403A0
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_82576_SUPPORT
+#define IGP04E1000_E_PHY_ID 0x02A80391
+#endif
+#define M88_VENDOR 0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
+#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_CLK125_DISABLE 0x0010
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+ * 0=Normal 10BASE-T Rx Threshold
+ */
+#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
+#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Tx */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380
+#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00
+
+#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020
+#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C
+
+/* BME1000 PHY Specific Control Register */
+#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */
+
+/*
+ * Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT 5
+#define GG82563_REG(page, reg) \
+ (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG 30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL \
+ GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS \
+ GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE \
+ GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2 \
+ GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR \
+ GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT \
+ GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2 \
+ GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT \
+ GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL \
+ GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL \
+ GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2 \
+ GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE \
+ GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL \
+ GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET \
+ GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID \
+ GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID \
+ GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL \
+ GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL \
+ GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+ GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL \
+ GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL \
+ GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC \
+ GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS \
+ GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY \
+ GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+ GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE \
+ GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+ GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC \
+ GG82563_REG(194, 26) /* Misc. */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK 0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK 0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE 0x04000000
+#define E1000_MDIC_OP_READ 0x08000000
+#define E1000_MDIC_READY 0x10000000
+#define E1000_MDIC_INT_EN 0x20000000
+#define E1000_MDIC_ERROR 0x40000000
+#define E1000_MDIC_DEST 0x80000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY 0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT 8
+#define E1000_GEN_POLL_TIMEOUT 640
+
+#ifndef NO_82576_SUPPORT
+/* LinkSec register fields */
+#define E1000_LSECTXCAP_SUM_MASK 0x00FF0000
+#define E1000_LSECTXCAP_SUM_SHIFT 16
+#define E1000_LSECRXCAP_SUM_MASK 0x00FF0000
+#define E1000_LSECRXCAP_SUM_SHIFT 16
+
+#define E1000_LSECTXCTRL_EN_MASK 0x00000003
+#define E1000_LSECTXCTRL_DISABLE 0x0
+#define E1000_LSECTXCTRL_AUTH 0x1
+#define E1000_LSECTXCTRL_AUTH_ENCRYPT 0x2
+#define E1000_LSECTXCTRL_AISCI 0x00000020
+#define E1000_LSECTXCTRL_PNTHRSH_MASK 0xFFFFFF00
+#define E1000_LSECTXCTRL_RSV_MASK 0x000000D8
+
+#define E1000_LSECRXCTRL_EN_MASK 0x0000000C
+#define E1000_LSECRXCTRL_EN_SHIFT 2
+#define E1000_LSECRXCTRL_DISABLE 0x0
+#define E1000_LSECRXCTRL_CHECK 0x1
+#define E1000_LSECRXCTRL_STRICT 0x2
+#define E1000_LSECRXCTRL_DROP 0x3
+#define E1000_LSECRXCTRL_PLSH 0x00000040
+#define E1000_LSECRXCTRL_RP 0x00000080
+#define E1000_LSECRXCTRL_RSV_MASK 0xFFFFFF33
+
+#endif /* NO_82576_SUPPORT */
+
+#ifndef NO_82580_SUPPORT
+/* DMA Coalescing register fields */
+#define E1000_DMACR_DMACWT_MASK 0x00003FFF /* DMA Coalescing
+ * Watchdog Timer */
+#define E1000_DMACR_DMACTHR_MASK 0x00FF0000 /* DMA Coalescing Receive
+ * Threshold */
+#define E1000_DMACR_DMACTHR_SHIFT 16
+#define E1000_DMACR_DMAC_LX_MASK 0x30000000 /* Lx when no PCIe
+ * transactions */
+#define E1000_DMACR_DMAC_LX_SHIFT 28
+#define E1000_DMACR_DMAC_EN 0x80000000 /* Enable DMA Coalescing */
+
+#define E1000_DMCTXTH_DMCTTHR_MASK 0x00000FFF /* DMA Coalescing Transmit
+ * Threshold */
+
+#define E1000_DMCTLX_TTLX_MASK 0x00000FFF /* Time to LX request */
+
+#define E1000_DMCRTRH_UTRESH_MASK 0x0007FFFF /* Receive Traffic Rate
+ * Threshold */
+#define E1000_DMCRTRH_LRPRCW 0x80000000 /* Rcv packet rate in
+ * current window */
+
+#define E1000_DMCCNT_CCOUNT_MASK 0x01FFFFFF /* DMA Coal Rcv Traffic
+ * Current Cnt */
+
+#define E1000_FCRTC_RTH_COAL_MASK 0x0003FFF0 /* Flow ctrl Rcv Threshold
+ * High val */
+#define E1000_FCRTC_RTH_COAL_SHIFT 4
+#define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision based
+ on DMA coal */
+#endif
+
+
+#ifndef UNREFERENCED_XPARAMETER
+#define UNREFERENCED_1PARAMETER(_p) (_p)
+#define UNREFERENCED_2PARAMETER(_p, _q) (_p); (_q);
+#define UNREFERENCED_3PARAMETER(_p, _q, _r) (_p); (_q); (_r);
+#define UNREFERENCED_4PARAMETER(_p, _q, _r, _s) (_p); (_q); (_r); (_s);
+#define UNREFERENCED_5PARAMETER(_p, _q, _r, _s, _t) (_p); (_q); (_r); (_s); (_t);
+#endif
+#endif /* _E1000_DEFINES_H_ */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h
new file mode 100755
index 0000000..a0018ab
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h
@@ -0,0 +1,868 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include "e1000_osdep.h"
+#include "e1000_regs.h"
+#include "e1000_defines.h"
+
+struct e1000_hw;
+
+#ifndef NO_82571_SUPPORT
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_82574_SUPPORT
+#define E1000_DEV_ID_82574L 0x10D3
+#define E1000_DEV_ID_82574LA 0x10F6
+#define E1000_DEV_ID_82583V 0x150C
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_80003ES2LAN_SUPPORT
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+#endif /* NO_80003ES2LAN_SUPPORT */
+#ifndef NO_ICH8LAN_SUPPORT
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M 0x104D
+#define E1000_DEV_ID_ICH9_IGP_M 0x10BF
+#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5
+#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB
+#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD
+#define E1000_DEV_ID_ICH9_BM 0x10E5
+#define E1000_DEV_ID_ICH9_IGP_C 0x294C
+#define E1000_DEV_ID_ICH9_IFE 0x10C0
+#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3
+#define E1000_DEV_ID_ICH9_IFE_G 0x10C2
+#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC
+#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD
+#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE
+#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA
+#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB
+#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF
+#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0
+#define E1000_DEV_ID_PCH_LV_LM 0x1506
+#define E1000_DEV_ID_PCH_LV_V 0x1519
+#define E1000_DEV_ID_PCH2_LV_LM 0x1502
+#define E1000_DEV_ID_PCH2_LV_V 0x1503
+#endif /* NO_ICH8LAN_SUPPORT */
+#ifndef NO_82575_SUPPORT
+#ifndef NO_82576_SUPPORT
+#define E1000_DEV_ID_82576 0x10C9
+#define E1000_DEV_ID_82576_FIBER 0x10E6
+#define E1000_DEV_ID_82576_SERDES 0x10E7
+#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
+#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
+#define E1000_DEV_ID_82576_NS 0x150A
+#define E1000_DEV_ID_82576_NS_SERDES 0x1518
+#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
+#endif /* NO_82576_SUPPORT */
+#define E1000_DEV_ID_82575EB_COPPER 0x10A7
+#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
+#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82580_SUPPORT
+#define E1000_DEV_ID_82580_COPPER 0x150E
+#define E1000_DEV_ID_82580_FIBER 0x150F
+#define E1000_DEV_ID_82580_SERDES 0x1510
+#define E1000_DEV_ID_82580_SGMII 0x1511
+#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
+#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527
+#endif /* NO_82580_SUPPORT */
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_0 0
+#define E1000_FUNC_1 1
+#ifndef NO_82580_SUPPORT
+#define E1000_FUNC_2 2
+#define E1000_FUNC_3 3
+#endif /* Barton Hills HW */
+
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3
+#ifndef NO_82580_SUPPORT
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN2 6
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN3 9
+#endif /* Barton Hills HW */
+
+enum e1000_mac_type {
+ e1000_undefined = 0,
+#ifndef NO_82571_SUPPORT
+ e1000_82571,
+ e1000_82572,
+ e1000_82573,
+#ifndef NO_82574_SUPPORT
+ e1000_82574,
+ e1000_82583,
+#endif /* NO_82574_SUPPORT */
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ e1000_80003es2lan,
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ e1000_ich8lan,
+ e1000_ich9lan,
+ e1000_pchlan,
+ e1000_pch2lan,
+#endif
+#ifndef NO_82575_SUPPORT
+ e1000_82575,
+#ifndef NO_82576_SUPPORT
+ e1000_82576,
+#ifndef NO_82580_SUPPORT
+ e1000_82580,
+#endif
+#endif /* NO_82576_SUPPORT */
+#endif /* NO_82575_SUPPORT */
+ e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */
+};
+
+enum e1000_media_type {
+ e1000_media_type_unknown = 0,
+ e1000_media_type_copper = 1,
+ e1000_media_type_fiber = 2,
+ e1000_media_type_internal_serdes = 3,
+ e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+ e1000_nvm_unknown = 0,
+ e1000_nvm_none,
+ e1000_nvm_eeprom_spi,
+#ifndef NO_MICROWIRE_SUPPORT
+ e1000_nvm_eeprom_microwire,
+#endif
+ e1000_nvm_flash_hw,
+ e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+ e1000_nvm_override_none = 0,
+ e1000_nvm_override_spi_small,
+ e1000_nvm_override_spi_large,
+#ifndef NO_MICROWIRE_SUPPORT
+ e1000_nvm_override_microwire_small,
+ e1000_nvm_override_microwire_large
+#endif
+};
+
+enum e1000_phy_type {
+ e1000_phy_unknown = 0,
+ e1000_phy_none,
+ e1000_phy_m88,
+ e1000_phy_igp,
+ e1000_phy_igp_2,
+ e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
+ e1000_phy_bm,
+ e1000_phy_82578,
+ e1000_phy_82577,
+ e1000_phy_82579,
+#ifndef NO_82580_SUPPORT
+ e1000_phy_82580,
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_82576_SUPPORT
+ e1000_phy_vf,
+#endif
+};
+
+enum e1000_bus_type {
+ e1000_bus_type_unknown = 0,
+ e1000_bus_type_pci,
+ e1000_bus_type_pcix,
+ e1000_bus_type_pci_express,
+ e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+ e1000_bus_speed_unknown = 0,
+ e1000_bus_speed_33,
+ e1000_bus_speed_66,
+ e1000_bus_speed_100,
+ e1000_bus_speed_120,
+ e1000_bus_speed_133,
+ e1000_bus_speed_2500,
+ e1000_bus_speed_5000,
+ e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+ e1000_bus_width_unknown = 0,
+ e1000_bus_width_pcie_x1,
+ e1000_bus_width_pcie_x2,
+ e1000_bus_width_pcie_x4 = 4,
+ e1000_bus_width_pcie_x8 = 8,
+ e1000_bus_width_32,
+ e1000_bus_width_64,
+ e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+ e1000_1000t_rx_status_not_ok = 0,
+ e1000_1000t_rx_status_ok,
+ e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity {
+ e1000_rev_polarity_normal = 0,
+ e1000_rev_polarity_reversed,
+ e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+ e1000_fc_none = 0,
+ e1000_fc_rx_pause,
+ e1000_fc_tx_pause,
+ e1000_fc_full,
+ e1000_fc_default = 0xFF
+};
+
+enum e1000_ms_type {
+ e1000_ms_hw_default = 0,
+ e1000_ms_force_master,
+ e1000_ms_force_slave,
+ e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+ e1000_smart_speed_default = 0,
+ e1000_smart_speed_on,
+ e1000_smart_speed_off
+};
+
+enum e1000_serdes_link_state {
+ e1000_serdes_link_down = 0,
+ e1000_serdes_link_autoneg_progress,
+ e1000_serdes_link_autoneg_complete,
+ e1000_serdes_link_forced_up
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+ UINT64 buffer_addr; /* Address of the descriptor's data buffer */
+ UINT16 length; /* Length of data DMAed into data buffer */
+ UINT16 csum; /* Packet checksum */
+ UINT8 status; /* Descriptor status */
+ UINT8 errors; /* Descriptor Errors */
+ UINT16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+ struct {
+ UINT64 buffer_addr;
+ UINT64 reserved;
+ } read;
+ struct {
+ struct {
+ UINT32 mrq; /* Multiple Rx Queues */
+ union {
+ UINT32 rss; /* RSS Hash */
+ struct {
+ UINT16 ip_id; /* IP id */
+ UINT16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ UINT32 status_error; /* ext status/error */
+ UINT16 length;
+ UINT16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+ struct {
+ /* one buffer for protocol header(s), three data buffers */
+ UINT64 buffer_addr[MAX_PS_BUFFERS];
+ } read;
+ struct {
+ struct {
+ UINT32 mrq; /* Multiple Rx Queues */
+ union {
+ UINT32 rss; /* RSS Hash */
+ struct {
+ UINT16 ip_id; /* IP id */
+ UINT16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ UINT32 status_error; /* ext status/error */
+ UINT16 length0; /* length of buffer 0 */
+ UINT16 vlan; /* VLAN tag */
+ } middle;
+ struct {
+ UINT16 header_status;
+ UINT16 length[3]; /* length of buffers 1-3 */
+ } upper;
+ UINT64 reserved;
+ } wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+ UINT64 buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ UINT32 data;
+ struct {
+ UINT16 length; /* Data buffer length */
+ UINT8 cso; /* Checksum offset */
+ UINT8 cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ UINT32 data;
+ struct {
+ UINT8 status; /* Descriptor status */
+ UINT8 css; /* Checksum start */
+ UINT16 special;
+ } fields;
+ } upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+ union {
+ UINT32 ip_config;
+ struct {
+ UINT8 ipcss; /* IP checksum start */
+ UINT8 ipcso; /* IP checksum offset */
+ UINT16 ipcse; /* IP checksum end */
+ } ip_fields;
+ } lower_setup;
+ union {
+ UINT32 tcp_config;
+ struct {
+ UINT8 tucss; /* TCP checksum start */
+ UINT8 tucso; /* TCP checksum offset */
+ UINT16 tucse; /* TCP checksum end */
+ } tcp_fields;
+ } upper_setup;
+ UINT32 cmd_and_length;
+ union {
+ UINT32 data;
+ struct {
+ UINT8 status; /* Descriptor status */
+ UINT8 hdr_len; /* Header length */
+ UINT16 mss; /* Maximum segment size */
+ } fields;
+ } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+ UINT64 buffer_addr; /* Address of the descriptor's buffer address */
+ union {
+ UINT32 data;
+ struct {
+ UINT16 length; /* Data buffer length */
+ UINT8 typ_len_ext;
+ UINT8 cmd;
+ } flags;
+ } lower;
+ union {
+ UINT32 data;
+ struct {
+ UINT8 status; /* Descriptor status */
+ UINT8 popts; /* Packet Options */
+ UINT16 special;
+ } fields;
+ } upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+ UINT64 crcerrs;
+ UINT64 algnerrc;
+ UINT64 symerrs;
+ UINT64 rxerrc;
+ UINT64 mpc;
+ UINT64 scc;
+ UINT64 ecol;
+ UINT64 mcc;
+ UINT64 latecol;
+ UINT64 colc;
+ UINT64 dc;
+ UINT64 tncrs;
+ UINT64 sec;
+ UINT64 cexterr;
+ UINT64 rlec;
+ UINT64 xonrxc;
+ UINT64 xontxc;
+ UINT64 xoffrxc;
+ UINT64 xofftxc;
+ UINT64 fcruc;
+ UINT64 prc64;
+ UINT64 prc127;
+ UINT64 prc255;
+ UINT64 prc511;
+ UINT64 prc1023;
+ UINT64 prc1522;
+ UINT64 gprc;
+ UINT64 bprc;
+ UINT64 mprc;
+ UINT64 gptc;
+ UINT64 gorc;
+ UINT64 gotc;
+ UINT64 rnbc;
+ UINT64 ruc;
+ UINT64 rfc;
+ UINT64 roc;
+ UINT64 rjc;
+ UINT64 mgprc;
+ UINT64 mgpdc;
+ UINT64 mgptc;
+ UINT64 tor;
+ UINT64 tot;
+ UINT64 tpr;
+ UINT64 tpt;
+ UINT64 ptc64;
+ UINT64 ptc127;
+ UINT64 ptc255;
+ UINT64 ptc511;
+ UINT64 ptc1023;
+ UINT64 ptc1522;
+ UINT64 mptc;
+ UINT64 bptc;
+ UINT64 tsctc;
+ UINT64 tsctfc;
+ UINT64 iac;
+ UINT64 icrxptc;
+ UINT64 icrxatc;
+ UINT64 ictxptc;
+ UINT64 ictxatc;
+ UINT64 ictxqec;
+ UINT64 ictxqmtc;
+ UINT64 icrxdmtc;
+ UINT64 icrxoc;
+ UINT64 cbtmpc;
+ UINT64 htdpmc;
+ UINT64 cbrdpc;
+ UINT64 cbrmpc;
+ UINT64 rpthc;
+ UINT64 hgptc;
+ UINT64 htcbdpc;
+ UINT64 hgorc;
+ UINT64 hgotc;
+ UINT64 lenerrs;
+ UINT64 scvpc;
+ UINT64 hrmpc;
+ UINT64 doosync;
+};
+
+#ifndef NO_82576_SUPPORT
+#endif
+
+struct e1000_phy_stats {
+ UINT32 idle_errors;
+ UINT32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+ UINT32 signature;
+ UINT8 status;
+ UINT8 reserved0;
+ UINT16 vlan_id;
+ UINT32 reserved1;
+ UINT16 reserved2;
+ UINT8 reserved3;
+ UINT8 checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+ UINT8 command_id;
+ UINT8 command_length;
+ UINT8 command_options;
+ UINT8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH 252
+struct e1000_host_command_info {
+ struct e1000_host_command_header command_header;
+ UINT8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+ UINT8 command_id;
+ UINT8 checksum;
+ UINT16 reserved1;
+ UINT16 reserved2;
+ UINT16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+ struct e1000_host_mng_command_header command_header;
+ UINT8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+#include "e1000_manage.h"
+
+struct e1000_mac_operations {
+ /* Function pointers for the MAC. */
+ INT32 (*init_params)(struct e1000_hw *);
+ INT32 (*id_led_init)(struct e1000_hw *);
+ INT32 (*blink_led)(struct e1000_hw *);
+ INT32 (*check_for_link)(struct e1000_hw *);
+ BOOLEAN (*check_mng_mode)(struct e1000_hw *hw);
+ INT32 (*cleanup_led)(struct e1000_hw *);
+ void (*clear_hw_cntrs)(struct e1000_hw *);
+ void (*clear_vfta)(struct e1000_hw *);
+ INT32 (*get_bus_info)(struct e1000_hw *);
+ void (*set_lan_id)(struct e1000_hw *);
+ INT32 (*get_link_up_info)(struct e1000_hw *, UINT16 *, UINT16 *);
+ INT32 (*led_on)(struct e1000_hw *);
+ INT32 (*led_off)(struct e1000_hw *);
+ void (*update_mc_addr_list)(struct e1000_hw *, UINT8 *, UINT32);
+ INT32 (*reset_hw)(struct e1000_hw *);
+ INT32 (*init_hw)(struct e1000_hw *);
+#ifndef NO_82576_SUPPORT
+ void (*shutdown_serdes)(struct e1000_hw *);
+ void (*power_up_serdes)(struct e1000_hw *);
+#endif /* NO_82576_SUPPORT */
+ INT32 (*setup_link)(struct e1000_hw *);
+ INT32 (*setup_physical_interface)(struct e1000_hw *);
+ INT32 (*setup_led)(struct e1000_hw *);
+ void (*write_vfta)(struct e1000_hw *, UINT32, UINT32);
+ void (*config_collision_dist)(struct e1000_hw *);
+ void (*rar_set)(struct e1000_hw *, UINT8*, UINT32);
+ INT32 (*read_mac_addr)(struct e1000_hw *);
+ INT32 (*validate_mdi_setting)(struct e1000_hw *);
+ INT32 (*mng_host_if_write)(struct e1000_hw *, UINT8*, UINT16, UINT16, UINT8*);
+ INT32 (*mng_write_cmd_header)(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header*);
+ INT32 (*mng_enable_host_if)(struct e1000_hw *);
+ INT32 (*wait_autoneg)(struct e1000_hw *);
+};
+
+struct e1000_phy_operations {
+ INT32 (*init_params)(struct e1000_hw *);
+ INT32 (*acquire)(struct e1000_hw *);
+#ifndef NO_80003ES2LAN_SUPPORT
+ INT32 (*cfg_on_link_up)(struct e1000_hw *);
+#endif
+ INT32 (*check_polarity)(struct e1000_hw *);
+ INT32 (*check_reset_block)(struct e1000_hw *);
+ INT32 (*commit)(struct e1000_hw *);
+ INT32 (*force_speed_duplex)(struct e1000_hw *);
+ INT32 (*get_cfg_done)(struct e1000_hw *hw);
+ INT32 (*get_cable_length)(struct e1000_hw *);
+ INT32 (*get_info)(struct e1000_hw *);
+ INT32 (*read_reg)(struct e1000_hw *, UINT32, UINT16 *);
+ INT32 (*read_reg_locked)(struct e1000_hw *, UINT32, UINT16 *);
+ void (*release)(struct e1000_hw *);
+ INT32 (*reset)(struct e1000_hw *);
+ INT32 (*set_d0_lplu_state)(struct e1000_hw *, BOOLEAN);
+ INT32 (*set_d3_lplu_state)(struct e1000_hw *, BOOLEAN);
+ INT32 (*write_reg)(struct e1000_hw *, UINT32, UINT16);
+ INT32 (*write_reg_locked)(struct e1000_hw *, UINT32, UINT16);
+ void (*power_up)(struct e1000_hw *);
+ void (*power_down)(struct e1000_hw *);
+};
+
+struct e1000_nvm_operations {
+ INT32 (*init_params)(struct e1000_hw *);
+ INT32 (*acquire)(struct e1000_hw *);
+ INT32 (*read)(struct e1000_hw *, UINT16, UINT16, UINT16 *);
+ void (*release)(struct e1000_hw *);
+ void (*reload)(struct e1000_hw *);
+ INT32 (*update)(struct e1000_hw *);
+ INT32 (*valid_led_default)(struct e1000_hw *, UINT16 *);
+ INT32 (*validate)(struct e1000_hw *);
+ INT32 (*write)(struct e1000_hw *, UINT16, UINT16, UINT16 *);
+};
+
+struct e1000_mac_info {
+ struct e1000_mac_operations ops;
+ UINT8 addr[6];
+ UINT8 perm_addr[6];
+
+ enum e1000_mac_type type;
+
+ UINT32 collision_delta;
+ UINT32 ledctl_default;
+ UINT32 ledctl_mode1;
+ UINT32 ledctl_mode2;
+ UINT32 mc_filter_type;
+ UINT32 tx_packet_delta;
+ UINT32 txcw;
+
+ UINT16 current_ifs_val;
+ UINT16 ifs_max_val;
+ UINT16 ifs_min_val;
+ UINT16 ifs_ratio;
+ UINT16 ifs_step_size;
+ UINT16 mta_reg_count;
+#ifndef NO_82576_SUPPORT
+ UINT16 uta_reg_count;
+#endif
+
+ /* Maximum size of the MTA register table in all supported adapters */
+ #define MAX_MTA_REG 128
+ UINT32 mta_shadow[MAX_MTA_REG];
+ UINT16 rar_entry_count;
+
+ UINT8 forced_speed_duplex;
+
+ BOOLEAN adaptive_ifs;
+ BOOLEAN has_fwsm;
+ BOOLEAN arc_subsystem_valid;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ BOOLEAN asf_firmware_present;
+#endif
+ BOOLEAN autoneg;
+ BOOLEAN autoneg_failed;
+ BOOLEAN get_link_status;
+ BOOLEAN in_ifs_mode;
+ enum e1000_serdes_link_state serdes_link_state;
+ BOOLEAN serdes_has_link;
+ BOOLEAN tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+ struct e1000_phy_operations ops;
+ enum e1000_phy_type type;
+
+ enum e1000_1000t_rx_status local_rx;
+ enum e1000_1000t_rx_status remote_rx;
+ enum e1000_ms_type ms_type;
+ enum e1000_ms_type original_ms_type;
+ enum e1000_rev_polarity cable_polarity;
+ enum e1000_smart_speed smart_speed;
+
+ UINT32 addr;
+ UINT32 id;
+ UINT32 reset_delay_us; /* in usec */
+ UINT32 revision;
+
+ enum e1000_media_type media_type;
+
+ UINT16 autoneg_advertised;
+ UINT16 autoneg_mask;
+ UINT16 cable_length;
+ UINT16 max_cable_length;
+ UINT16 min_cable_length;
+
+ UINT8 mdix;
+
+ BOOLEAN disable_polarity_correction;
+ BOOLEAN is_mdix;
+ BOOLEAN polarity_correction;
+#ifndef NO_PHY_RESET_DISABLE
+ BOOLEAN reset_disable;
+#endif
+ BOOLEAN speed_downgraded;
+ BOOLEAN autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+ struct e1000_nvm_operations ops;
+ enum e1000_nvm_type type;
+ enum e1000_nvm_override override;
+
+ UINT32 flash_bank_size;
+ UINT32 flash_base_addr;
+
+ UINT16 word_size;
+ UINT16 delay_usec;
+ UINT16 address_bits;
+ UINT16 opcode_bits;
+ UINT16 page_size;
+};
+
+struct e1000_bus_info {
+ enum e1000_bus_type type;
+ enum e1000_bus_speed speed;
+ enum e1000_bus_width width;
+
+ UINT16 func;
+ UINT16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+ UINT32 high_water; /* Flow control high-water mark */
+ UINT32 low_water; /* Flow control low-water mark */
+ UINT16 pause_time; /* Flow control pause timer */
+ UINT16 refresh_time; /* Flow control refresh timer */
+ BOOLEAN send_xon; /* Flow control send XON */
+ BOOLEAN strict_ieee; /* Strict IEEE mode */
+ enum e1000_fc_mode current_mode; /* FC mode in effect */
+ enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
+};
+
+#ifndef NO_82571_SUPPORT
+struct e1000_dev_spec_82571 {
+ BOOLEAN laa_is_present;
+ UINT32 smb_counter;
+ E1000_MUTEX swflag_mutex;
+};
+
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_80003ES2LAN_SUPPORT
+struct e1000_dev_spec_80003es2lan {
+ BOOLEAN mdic_wa_enable;
+};
+
+#endif /* NO_80003ES2LAN_SUPPORT */
+#ifndef NO_ICH8LAN_SUPPORT
+struct e1000_shadow_ram {
+ UINT16 value;
+ BOOLEAN modified;
+};
+
+#define E1000_SHADOW_RAM_WORDS 2048
+
+struct e1000_dev_spec_ich8lan {
+ BOOLEAN kmrn_lock_loss_workaround_enabled;
+ struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS];
+ E1000_MUTEX nvm_mutex;
+ E1000_MUTEX swflag_mutex;
+ BOOLEAN nvm_k1_enabled;
+ BOOLEAN eee_disable;
+};
+
+#endif /* NO_ICH8LAN_SUPPORT */
+#ifndef NO_82575_SUPPORT
+struct e1000_dev_spec_82575 {
+ BOOLEAN sgmii_active;
+ BOOLEAN global_device_reset;
+};
+
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82576_SUPPORT
+struct e1000_dev_spec_vf {
+ UINT32 vf_number;
+ UINT32 v2p_mailbox;
+};
+
+#endif /* NO_82576_SUPPORT */
+struct e1000_hw {
+ void *back;
+
+ UINT8 *hw_addr;
+ UINT8 *flash_address;
+ unsigned long io_base;
+
+ struct e1000_mac_info mac;
+ struct e1000_fc_info fc;
+ struct e1000_phy_info phy;
+ struct e1000_nvm_info nvm;
+ struct e1000_bus_info bus;
+ struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+ union {
+#ifndef NO_82571_SUPPORT
+ struct e1000_dev_spec_82571 _82571;
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ struct e1000_dev_spec_80003es2lan _80003es2lan;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ struct e1000_dev_spec_ich8lan ich8lan;
+#endif
+#ifndef NO_82575_SUPPORT
+ struct e1000_dev_spec_82575 _82575;
+#endif
+#ifndef NO_82576_SUPPORT
+ struct e1000_dev_spec_vf vf;
+#endif
+ } dev_spec;
+
+ UINT16 device_id;
+ UINT16 subsystem_vendor_id;
+ UINT16 subsystem_device_id;
+ UINT16 vendor_id;
+
+ UINT8 revision_id;
+};
+
+#ifndef NO_82571_SUPPORT
+#include "e1000_82571.h"
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+#include "e1000_80003es2lan.h"
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+#include "e1000_ich8lan.h"
+#endif
+#ifndef NO_82575_SUPPORT
+#include "e1000_82575.h"
+#endif
+
+/* These functions must be implemented by drivers */
+INT32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#ifndef NO_PCIE_SUPPORT
+INT32 e1000_write_pcie_cap_reg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#endif
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+void e1000_read_pci_cfg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#endif
+#ifndef NO_PCIX_SUPPORT
+void e1000_write_pci_cfg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#endif
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c
new file mode 100755
index 0000000..d1bead3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c
@@ -0,0 +1,4070 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 82562G 10/100 Network Connection
+ * 82562G-2 10/100 Network Connection
+ * 82562GT 10/100 Network Connection
+ * 82562GT-2 10/100 Network Connection
+ * 82562V 10/100 Network Connection
+ * 82562V-2 10/100 Network Connection
+ * 82566DC-2 Gigabit Network Connection
+ * 82566DC Gigabit Network Connection
+ * 82566DM-2 Gigabit Network Connection
+ * 82566DM Gigabit Network Connection
+ * 82566MC Gigabit Network Connection
+ * 82566MM Gigabit Network Connection
+ * 82567LM Gigabit Network Connection
+ * 82567LF Gigabit Network Connection
+ * 82567V Gigabit Network Connection
+ * 82567LM-2 Gigabit Network Connection
+ * 82567LF-2 Gigabit Network Connection
+ * 82567V-2 Gigabit Network Connection
+ * 82567LM-4 Gigabit Network Connection
+ * 82577LM Gigabit Network Connection
+ * 82577LC Gigabit Network Connection
+ * 82578DM Gigabit Network Connection
+ * 82578DC Gigabit Network Connection
+ * 82579LM Gigabit Network Connection
+ * 82579V Gigabit Network Connection
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_phy_params_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
+STATIC void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
+STATIC BOOLEAN e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
+STATIC BOOLEAN e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
+STATIC void e1000_rar_set_pch2lan(struct e1000_hw *hw, UINT8 *addr, UINT32 index);
+STATIC INT32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, BOOLEAN active);
+STATIC INT32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
+ UINT16 *data);
+STATIC INT32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_reset_hw_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_hw_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex);
+STATIC INT32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_on_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_off_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, BOOLEAN link);
+STATIC INT32 e1000_setup_led_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_cleanup_led_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_on_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_off_pchlan(struct e1000_hw *hw);
+STATIC void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, UINT32 bank);
+static INT32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, UINT32 timeout);
+static INT32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
+static INT32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 *data);
+static INT32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 *data);
+STATIC INT32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT16 *data);
+static INT32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 byte);
+STATIC INT32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 data);
+static INT32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 data);
+STATIC INT32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
+static INT32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
+STATIC INT32 e1000_k1_workaround_lv(struct e1000_hw *hw);
+STATIC void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, BOOLEAN gate);
+
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+ struct ich8_hsfsts {
+ UINT16 flcdone :1; /* bit 0 Flash Cycle Done */
+ UINT16 flcerr :1; /* bit 1 Flash Cycle Error */
+ UINT16 dael :1; /* bit 2 Direct Access error Log */
+ UINT16 berasesz :2; /* bit 4:3 Sector Erase Size */
+ UINT16 flcinprog :1; /* bit 5 flash cycle in Progress */
+ UINT16 reserved1 :2; /* bit 13:6 Reserved */
+ UINT16 reserved2 :6; /* bit 13:6 Reserved */
+ UINT16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+ UINT16 flockdn :1; /* bit 15 Flash Config Lock-Down */
+ } hsf_status;
+ UINT16 regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+ struct ich8_hsflctl {
+ UINT16 flcgo :1; /* 0 Flash Cycle Go */
+ UINT16 flcycle :2; /* 2:1 Flash Cycle */
+ UINT16 reserved :5; /* 7:3 Reserved */
+ UINT16 fldbcount :2; /* 9:8 Flash Data Byte Count */
+ UINT16 flockdn :6; /* 15:10 Reserved */
+ } hsf_ctrl;
+ UINT16 regval;
+};
+
+/* ICH Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+ struct ich8_flracc {
+ UINT32 grra :8; /* 0:7 GbE region Read Access */
+ UINT32 grwa :8; /* 8:15 GbE region Write Access */
+ UINT32 gmrag :8; /* 23:16 GbE Master Read Access Grant */
+ UINT32 gmwag :8; /* 31:24 GbE Master Write Access Grant */
+ } hsf_flregacc;
+ UINT16 regval;
+};
+
+/**
+ * e1000_init_phy_params_pchlan - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific PHY parameters and function pointers.
+ **/
+STATIC INT32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 ctrl, fwsm;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_init_phy_params_pchlan");
+
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
+
+ phy->ops.acquire = e1000_acquire_swflag_ich8lan;
+ phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
+ phy->ops.read_reg = e1000_read_phy_reg_hv;
+ phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
+ phy->ops.release = e1000_release_swflag_ich8lan;
+ phy->ops.reset = e1000_phy_hw_reset_ich8lan;
+ phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
+ phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
+ phy->ops.write_reg = e1000_write_phy_reg_hv;
+ phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /*
+ * The MAC-PHY interconnect may still be in SMBus mode
+ * after Sx->S0. If the manageability engine (ME) is
+ * disabled, then toggle the LANPHYPC Value bit to force
+ * the interconnect to PCIe mode.
+ */
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+ if (!(fwsm & E1000_ICH_FWSM_FW_VALID)) {
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
+ ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ usec_delay(10);
+ ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ msec_delay(50);
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+ }
+
+ /*
+ * Reset the PHY before any acccess to it. Doing so, ensures that
+ * the PHY is in a known good state before we read/write PHY registers.
+ * The generic reset is sufficient here, because we haven't determined
+ * the PHY type yet.
+ */
+ ret_val = e1000_phy_hw_reset_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
+ msec_delay(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
+ }
+
+ phy->id = e1000_phy_unknown;
+ ret_val = e1000_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
+ /*
+ * In case the PHY needs to be in mdio slow mode (eg. 82577),
+ * set slow mode and try to get the PHY id again.
+ */
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ }
+ phy->type = e1000_get_phy_type_from_id(phy->id);
+
+ switch (phy->type) {
+ case e1000_phy_82577:
+ case e1000_phy_82579:
+ phy->ops.check_polarity = e1000_check_polarity_82577;
+ phy->ops.force_speed_duplex =
+ e1000_phy_force_speed_duplex_82577;
+ phy->ops.get_cable_length = e1000_get_cable_length_82577;
+ phy->ops.get_info = e1000_get_phy_info_82577;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ break;
+ case e1000_phy_82578:
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_phy_params_ich8lan - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific PHY parameters and function pointers.
+ **/
+STATIC INT32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i = 0;
+
+ DEBUGFUNC("e1000_init_phy_params_ich8lan");
+
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
+
+ phy->ops.acquire = e1000_acquire_swflag_ich8lan;
+ phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
+ phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
+ phy->ops.read_reg = e1000_read_phy_reg_igp;
+ phy->ops.release = e1000_release_swflag_ich8lan;
+ phy->ops.reset = e1000_phy_hw_reset_ich8lan;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
+ phy->ops.write_reg = e1000_write_phy_reg_igp;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
+
+ /*
+ * We may need to do this twice - once for IGP and if that fails,
+ * we'll set BM func pointers and try again
+ */
+ ret_val = e1000_determine_phy_address(hw);
+ if (ret_val) {
+ phy->ops.write_reg = e1000_write_phy_reg_bm;
+ phy->ops.read_reg = e1000_read_phy_reg_bm;
+ ret_val = e1000_determine_phy_address(hw);
+ if (ret_val) {
+ DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
+ goto out;
+ }
+ }
+
+ phy->id = 0;
+ while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
+ (i++ < 100)) {
+ msec_delay(1);
+ ret_val = e1000_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Verify phy id */
+ switch (phy->id) {
+ case IGP03E1000_E_PHY_ID:
+ phy->type = e1000_phy_igp_3;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
+ phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
+ phy->ops.get_info = e1000_get_phy_info_igp;
+ phy->ops.check_polarity = e1000_check_polarity_igp;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy->type = e1000_phy_ife;
+ phy->autoneg_mask = E1000_ALL_NOT_GIG;
+ phy->ops.get_info = e1000_get_phy_info_ife;
+ phy->ops.check_polarity = e1000_check_polarity_ife;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
+ break;
+ case BME1000_E_PHY_ID:
+ phy->type = e1000_phy_bm;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->ops.read_reg = e1000_read_phy_reg_bm;
+ phy->ops.write_reg = e1000_write_phy_reg_bm;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific NVM parameters and function
+ * pointers.
+ **/
+STATIC INT32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 gfpreg, sector_base_addr, sector_end_addr;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_init_nvm_params_ich8lan");
+
+ /* Can't read flash registers if the register set isn't mapped. */
+ if (!hw->flash_address) {
+ DEBUGOUT("ERROR: Flash registers not mapped\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ nvm->type = e1000_nvm_flash_sw;
+
+ gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
+
+ /*
+ * sector_X_addr is a "sector"-aligned address (4096 bytes)
+ * Add 1 to sector_end_addr since this sector is included in
+ * the overall size.
+ */
+ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+ sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+
+ /* flash_base_addr is byte-aligned */
+ nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+
+ /*
+ * find total size of the NVM, then cut in half since the total
+ * size represents two separate NVM banks.
+ */
+ nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
+ << FLASH_SECTOR_ADDR_SHIFT;
+ nvm->flash_bank_size /= 2;
+ /* Adjust to word count */
+ nvm->flash_bank_size /= sizeof(UINT16);
+
+ nvm->word_size = E1000_SHADOW_RAM_WORDS;
+
+ /* Clear shadow ram */
+ for (i = 0; i < nvm->word_size; i++) {
+ dev_spec->shadow_ram[i].modified = FALSE;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+ //E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
+ //E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
+
+ /* Function Pointers */
+ nvm->ops.acquire = e1000_acquire_nvm_ich8lan;
+ nvm->ops.release = e1000_release_nvm_ich8lan;
+ nvm->ops.read = e1000_read_nvm_ich8lan;
+ nvm->ops.update = e1000_update_nvm_checksum_ich8lan;
+ nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
+ nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan;
+ nvm->ops.write = e1000_write_nvm_ich8lan;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_mac_params_ich8lan - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific MAC parameters and function
+ * pointers.
+ **/
+STATIC INT32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT16 pci_cfg;
+
+ DEBUGFUNC("e1000_init_mac_params_ich8lan");
+
+ /* Set media type function pointer */
+ hw->phy.media_type = e1000_media_type_copper;
+
+ /* Set mta register count */
+ mac->mta_reg_count = 32;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
+ if (mac->type == e1000_ich8lan)
+ mac->rar_entry_count--;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /* ARC subsystem not supported */
+ mac->arc_subsystem_valid = FALSE;
+ /* Adaptive IFS supported */
+ mac->adaptive_ifs = TRUE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
+ /* function id */
+ mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+ /* reset */
+ mac->ops.reset_hw = e1000_reset_hw_ich8lan;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_ich8lan;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_ich8lan;
+ /* physical interface setup */
+ mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
+ /* check for link */
+ mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
+ /* link info */
+ mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
+
+ /* LED operations */
+ switch (mac->type) {
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_ich8lan;
+ mac->ops.led_off = e1000_led_off_ich8lan;
+ break;
+ case e1000_pch2lan:
+ mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
+ mac->ops.rar_set = e1000_rar_set_pch2lan;
+ /* fall-through */
+ case e1000_pchlan:
+ /* save PCH revision_id */
+ e1000_read_pci_cfg(hw, 0x2, &pci_cfg);
+ hw->revision_id = (UINT8)(pci_cfg &= 0x000F);
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_pchlan;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_pchlan;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_pchlan;
+ mac->ops.led_off = e1000_led_off_pchlan;
+ break;
+ default:
+ break;
+ }
+
+ /* Enable PCS Lock-loss workaround for ICH8 */
+ if (mac->type == e1000_ich8lan)
+ e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
+
+ /* Gate automatic PHY configuration by hardware on managed 82579 */
+ if ((mac->type == e1000_pch2lan) &&
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_eee_pchlan - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ *
+ * Enable/disable EEE based on setting in dev_spec structure. The bits in
+ * the LPI Control register will remain set only if/when link is up.
+ **/
+STATIC INT32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_reg;
+
+ DEBUGFUNC("e1000_set_eee_pchlan");
+
+ if (hw->phy.type != e1000_phy_82579)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg);
+ if (ret_val)
+ goto out;
+
+ if (hw->dev_spec.ich8lan.eee_disable)
+ phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
+ else
+ phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
+
+ ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_copper_link_ich8lan - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed. If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ **/
+static INT32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
+
+ /*
+ * We only want to go out to the PHY registers to see if Auto-Neg
+ * has completed and/or if our link status has changed. The
+ * get_link_status flag is set upon receiving a Link Status
+ * Change or Rx Sequence Error interrupt.
+ */
+ if (!mac->get_link_status) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ /*
+ * First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (hw->mac.type == e1000_pchlan) {
+ ret_val = e1000_k1_gig_workaround_hv(hw, link);
+ if (ret_val)
+ goto out;
+ }
+
+ if (!link)
+ goto out; /* No link detected */
+
+ mac->get_link_status = FALSE;
+
+ if (hw->phy.type == e1000_phy_82578) {
+ ret_val = e1000_link_stall_workaround_hv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ if (hw->mac.type == e1000_pch2lan) {
+ ret_val = e1000_k1_workaround_lv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Check if there was DownShift, must be checked
+ * immediately after link-up
+ */
+ e1000_check_downshift_generic(hw);
+
+ /* Enable/Disable EEE after link up */
+ ret_val = e1000_set_eee_pchlan(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if (!mac->autoneg) {
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ /*
+ * Auto-Neg is enabled. Auto Speed Detection takes care
+ * of MAC speed/duplex configuration. So we only need to
+ * configure Collision Distance in the MAC.
+ */
+ e1000_config_collision_dist_generic(hw);
+
+ /*
+ * Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control
+ * settings because we may have had to re-autoneg with a
+ * different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val)
+ DEBUGOUT("Error configuring flow control\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific function pointers for PHY, MAC, and NVM.
+ **/
+void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_ich8lan");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
+ break;
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * e1000_acquire_nvm_ich8lan - Acquire NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the mutex for performing NVM operations.
+ **/
+STATIC INT32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_acquire_nvm_ich8lan");
+
+ //E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_release_nvm_ich8lan - Release NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Releases the mutex used while performing NVM operations.
+ **/
+STATIC void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_ich8lan");
+
+ //E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
+
+ return;
+}
+
+/**
+ * e1000_acquire_swflag_ich8lan - Acquire software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the software control flag for performing PHY and select
+ * MAC CSR accesses.
+ **/
+STATIC INT32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_acquire_swflag_ich8lan");
+
+ //E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
+
+ while (timeout) {
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
+ break;
+
+ msec_delay_irq(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("SW/FW/HW has locked the resource for too long.\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ timeout = SW_FLAG_TIMEOUT;
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+ while (timeout) {
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ break;
+
+ msec_delay_irq(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Failed to acquire the semaphore.\n");
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+out:
+ /*if (ret_val)
+ E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);*/
+
+ return ret_val;
+}
+
+/**
+ * e1000_release_swflag_ich8lan - Release software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Releases the software control flag for performing PHY and select
+ * MAC CSR accesses.
+ **/
+STATIC void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_release_swflag_ich8lan");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+ //E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
+
+ return;
+}
+
+/**
+ * e1000_check_mng_mode_ich8lan - Checks management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has any manageability enabled.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+STATIC BOOLEAN e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 fwsm;
+
+ DEBUGFUNC("e1000_check_mng_mode_ich8lan");
+
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ * e1000_check_mng_mode_pchlan - Checks management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has iAMT enabled.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+STATIC BOOLEAN e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
+{
+ UINT32 fwsm;
+
+ DEBUGFUNC("e1000_check_mng_mode_pchlan");
+
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ * e1000_rar_set_pch2lan - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr. For 82579, RAR[0] is the base address register that is to
+ * contain the MAC address but RAR[1-6] are reserved for manageability (ME).
+ * Use SHRA[0-3] in place of those reserved for ME.
+ **/
+STATIC void e1000_rar_set_pch2lan(struct e1000_hw *hw, UINT8 *addr, UINT32 index)
+{
+ UINT32 rar_low, rar_high;
+
+ DEBUGFUNC("e1000_rar_set_pch2lan");
+
+ /*
+ * HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((UINT32) addr[0] |
+ ((UINT32) addr[1] << 8) |
+ ((UINT32) addr[2] << 16) | ((UINT32) addr[3] << 24));
+
+ rar_high = ((UINT32) addr[4] | ((UINT32) addr[5] << 8));
+
+ /* If MAC address zero, no need to set the AV bit */
+ if (rar_low || rar_high)
+ rar_high |= E1000_RAH_AV;
+
+ if (index == 0) {
+ E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+ E1000_WRITE_FLUSH(hw);
+ return;
+ }
+
+ if (index < hw->mac.rar_entry_count) {
+ E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
+ E1000_WRITE_FLUSH(hw);
+
+ /* verify the register updates */
+ if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
+ (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
+ return;
+
+ DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
+ (index - 1), E1000_READ_REG(hw, E1000_FWSM));
+ }
+
+ DEBUGOUT1("Failed to write receive address at index %d\n", index);
+}
+
+/**
+ * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Checks if firmware is blocking the reset of the PHY.
+ * This is a function pointer entry point only called by
+ * reset routines.
+ **/
+STATIC INT32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 fwsm;
+
+ DEBUGFUNC("e1000_check_reset_block_ich8lan");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (hw->phy.reset_disable)
+ return E1000_BLK_PHY_RESET;
+
+#endif
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
+ : E1000_BLK_PHY_RESET;
+}
+
+/**
+ * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
+ * @hw: pointer to the HW structure
+ *
+ * Assumes semaphore already acquired.
+ *
+ **/
+STATIC INT32 e1000_write_smbus_addr(struct e1000_hw *hw)
+{
+ UINT16 phy_data;
+ UINT32 strap = E1000_READ_REG(hw, E1000_STRAP);
+ INT32 ret_val = E1000_SUCCESS;
+
+ strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+
+ ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~HV_SMB_ADDR_MASK;
+ phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
+ phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
+ * @hw: pointer to the HW structure
+ *
+ * SW should configure the LCD from the NVM extended configuration region
+ * as a workaround for certain parts.
+ **/
+STATIC INT32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+ DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
+
+ /*
+ * Initialize the PHY from the NVM on ICH platforms. This
+ * is needed due to an issue where the NVM configuration is
+ * not properly autoloaded after power transitions.
+ * Therefore, after each PHY reset, we will load the
+ * configuration data out of the NVM manually.
+ */
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ if (phy->type != e1000_phy_igp_3)
+ return ret_val;
+
+ if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
+ (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+ break;
+ }
+ /* Fall-thru */
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+ break;
+ default:
+ return ret_val;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ data = E1000_READ_REG(hw, E1000_FEXTNVM);
+ if (!(data & sw_cfg_mask))
+ goto out;
+
+ /*
+ * Make sure HW does not configure LCD from PHY
+ * extended configuration before SW configuration
+ */
+ data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+ goto out;
+ }
+
+ cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
+ cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+ cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+ if (!cnf_size)
+ goto out;
+
+ cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+ cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+ if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+ (hw->mac.type == e1000_pchlan)) ||
+ (hw->mac.type == e1000_pch2lan)) {
+ /*
+ * HW configures the SMBus address and LEDs when the
+ * OEM and LCD Write Enable bits are set in the NVM.
+ * When both NVM bits are cleared, SW will configure
+ * them instead.
+ */
+ ret_val = e1000_write_smbus_addr(hw);
+ if (ret_val)
+ goto out;
+
+ data = E1000_READ_REG(hw, E1000_LEDCTL);
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
+ (UINT16)data);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Configure LCD from extended configuration region. */
+
+ /* cnf_base_addr is in DWORD */
+ word_addr = (UINT16)(cnf_base_addr << 1);
+
+ for (i = 0; i < cnf_size; i++) {
+ ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
+ 1, ®_addr);
+ if (ret_val)
+ goto out;
+
+ /* Save off the PHY page for future writes. */
+ if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+ phy_page = reg_data;
+ continue;
+ }
+
+ reg_addr &= PHY_REG_MASK;
+ reg_addr |= phy_page;
+
+ ret_val = phy->ops.write_reg_locked(hw, (UINT32)reg_addr,
+ reg_data);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * e1000_k1_gig_workaround_hv - K1 Si workaround
+ * @hw: pointer to the HW structure
+ * @link: link up BOOLEAN flag
+ *
+ * If K1 is enabled for 1Gbps, the MAC might stall when transitioning
+ * from a lower speed. This workaround disables K1 whenever link is at 1Gig
+ * If link is down, the function will restore the default K1 setting located
+ * in the NVM.
+ **/
+STATIC INT32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, BOOLEAN link)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 status_reg = 0;
+ BOOLEAN k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
+
+ DEBUGFUNC("e1000_k1_gig_workaround_hv");
+
+ if (hw->mac.type != e1000_pchlan)
+ goto out;
+
+ /* Wrap the whole flow with the sw flag */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
+ if (link) {
+ if (hw->phy.type == e1000_phy_82578) {
+ ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
+ &status_reg);
+ if (ret_val)
+ goto release;
+
+ status_reg &= BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK;
+
+ if (status_reg == (BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_1000))
+ k1_enable = FALSE;
+ }
+
+ if (hw->phy.type == e1000_phy_82577) {
+ ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
+ &status_reg);
+ if (ret_val)
+ goto release;
+
+ status_reg &= HV_M_STATUS_LINK_UP |
+ HV_M_STATUS_AUTONEG_COMPLETE |
+ HV_M_STATUS_SPEED_MASK;
+
+ if (status_reg == (HV_M_STATUS_LINK_UP |
+ HV_M_STATUS_AUTONEG_COMPLETE |
+ HV_M_STATUS_SPEED_1000))
+ k1_enable = FALSE;
+ }
+
+ /* Link stall fix for link up */
+ ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+ 0x0100);
+ if (ret_val)
+ goto release;
+
+ } else {
+ /* Link stall fix for link down */
+ ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+ 0x4100);
+ if (ret_val)
+ goto release;
+ }
+
+ ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
+
+release:
+ hw->phy.ops.release(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_configure_k1_ich8lan - Configure K1 power state
+ * @hw: pointer to the HW structure
+ * @enable: K1 state to configure
+ *
+ * Configure the K1 power state based on the provided parameter.
+ * Assumes semaphore already acquired.
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ **/
+INT32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, BOOLEAN k1_enable)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 ctrl_reg = 0;
+ UINT32 ctrl_ext = 0;
+ UINT32 reg = 0;
+ UINT16 kmrn_reg = 0;
+
+ DEBUGFUNC("e1000_configure_k1_ich8lan");
+
+ ret_val = e1000_read_kmrn_reg_locked(hw,
+ E1000_KMRNCTRLSTA_K1_CONFIG,
+ &kmrn_reg);
+ if (ret_val)
+ goto out;
+
+ if (k1_enable)
+ kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
+ else
+ kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
+
+ ret_val = e1000_write_kmrn_reg_locked(hw,
+ E1000_KMRNCTRLSTA_K1_CONFIG,
+ kmrn_reg);
+ if (ret_val)
+ goto out;
+
+ usec_delay(20);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
+
+ reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ reg |= E1000_CTRL_FRCSPD;
+ E1000_WRITE_REG(hw, E1000_CTRL, reg);
+
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
+ usec_delay(20);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ usec_delay(20);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
+ * @hw: pointer to the HW structure
+ * @d0_state: BOOLEANean if entering d0 or d3 device state
+ *
+ * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
+ * collectively called OEM bits. The OEM Write Enable bit and SW Config bit
+ * in NVM determines whether HW should configure LPLU and Gbe Disable.
+ **/
+INT32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, BOOLEAN d0_state)
+{
+ INT32 ret_val = 0;
+ UINT32 mac_reg;
+ UINT16 oem_reg;
+
+ DEBUGFUNC("e1000_oem_bits_config_ich8lan");
+
+ if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
+ return ret_val;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+ goto out;
+ }
+
+ mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
+ if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
+ goto out;
+
+ mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+ ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
+ if (ret_val)
+ goto out;
+
+ oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
+
+ if (d0_state) {
+ if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
+ oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+ if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ } else {
+ if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
+ oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+ if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ }
+ /* Restart auto-neg to activate the bits */
+ if (!hw->phy.ops.check_reset_block(hw))
+ oem_reg |= HV_OEM_BITS_RESTART_AN;
+ ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
+
+out:
+ hw->phy.ops.release(hw);
+
+ return ret_val;
+}
+
+
+/**
+ * e1000_hv_phy_powerdown_workaround_ich8lan - Power down workaround on Sx
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_hv_phy_powerdown_workaround_ich8lan");
+
+ if ((hw->phy.type != e1000_phy_82577) || (hw->revision_id > 2))
+ return E1000_SUCCESS;
+
+ return hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0444);
+}
+
+/**
+ * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
+
+ ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= HV_KMRN_MDIO_SLOW;
+
+ ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ **/
+STATIC INT32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
+
+ if (hw->mac.type != e1000_pchlan)
+ goto out;
+
+ /* Set MDIO slow mode before any other MDIO access */
+ if (hw->phy.type == e1000_phy_82577) {
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Hanksville M Phy init for IEEE. */
+ if ((hw->revision_id == 2) &&
+ (hw->phy.type == e1000_phy_82577) &&
+ ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
+ hw->phy.ops.write_reg(hw, 0x10, 0x8823);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0018);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8824);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0016);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8825);
+ hw->phy.ops.write_reg(hw, 0x11, 0x001A);
+ hw->phy.ops.write_reg(hw, 0x10, 0x888C);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0007);
+ hw->phy.ops.write_reg(hw, 0x10, 0x888D);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0007);
+ hw->phy.ops.write_reg(hw, 0x10, 0x888E);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0007);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8827);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0001);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8835);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0001);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8834);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0001);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8833);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0002);
+ }
+
+ if (((hw->phy.type == e1000_phy_82577) &&
+ ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
+ ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
+ /* Disable generation of early preamble */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
+ if (ret_val)
+ goto out;
+
+ /* Preamble tuning for SSC */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
+ if (ret_val)
+ goto out;
+ }
+
+ if (hw->phy.type == e1000_phy_82578) {
+ if (hw->revision_id < 3) {
+ /* PHY config */
+ ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29,
+ 0x66C0);
+ if (ret_val)
+ goto out;
+
+ /* PHY config */
+ ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E,
+ 0xFFFF);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Return registers to default by doing a soft reset then
+ * writing 0x3140 to the control register.
+ */
+ if (hw->phy.revision < 2) {
+ e1000_phy_sw_reset_generic(hw);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
+ 0x3140);
+ }
+ }
+
+ if ((hw->revision_id == 2) &&
+ (hw->phy.type == e1000_phy_82577) &&
+ ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
+ /*
+ * Workaround for OEM (GbE) not operating after reset -
+ * restart AN (twice)
+ */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Select page 0 */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ hw->phy.addr = 1;
+ ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+ hw->phy.ops.release(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Configure the K1 Si workaround during phy reset assuming there is
+ * link so that it disables K1 if link is in 1Gbps.
+ */
+ ret_val = e1000_k1_gig_workaround_hv(hw, TRUE);
+ if (ret_val)
+ goto out;
+
+ /* Workaround for link disconnects on a busy hub in half duplex */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg_locked(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 17),
+ &phy_data);
+ if (ret_val)
+ goto release;
+ ret_val = hw->phy.ops.write_reg_locked(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 17),
+ phy_data & 0x00FF);
+release:
+ hw->phy.ops.release(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
+ * @hw: pointer to the HW structure
+ **/
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 mac_reg;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
+
+ /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
+ hw->phy.ops.write_reg(hw, BM_RAR_L(i), (UINT16)(mac_reg & 0xFFFF));
+ hw->phy.ops.write_reg(hw, BM_RAR_M(i), (UINT16)((mac_reg >> 16) & 0xFFFF));
+ mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
+ hw->phy.ops.write_reg(hw, BM_RAR_H(i), (UINT16)(mac_reg & 0xFFFF));
+ hw->phy.ops.write_reg(hw, BM_RAR_CTRL(i), (UINT16)((mac_reg >> 16) & 0x8000));
+ }
+}
+
+static UINT32 e1000_calc_rx_da_crc(UINT8 mac[])
+{
+ UINT32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */
+ UINT32 i, j, mask, crc;
+
+ DEBUGFUNC("e1000_calc_rx_da_crc");
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ crc = crc ^ mac[i];
+ for (j = 8; j > 0; j--) {
+ mask = (crc & 1) * (-1);
+ crc = (crc >> 1) ^ (poly & mask);
+ }
+ }
+ return ~crc;
+}
+
+/**
+ * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
+ * with 82579 PHY
+ * @hw: pointer to the HW structure
+ * @enable: flag to enable/disable workaround when enabling/disabling jumbos
+ **/
+INT32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, BOOLEAN enable)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_reg, data;
+ UINT32 mac_reg;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* disable Rx path while enabling/disabling workaround */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | (1 << 14));
+ if (ret_val)
+ goto out;
+
+ if (enable) {
+ /*
+ * Write Rx addresses (rar_entry_count for RAL/H, +4 for
+ * SHRAL/H) and initial CRC values to the MAC
+ */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ UINT8 mac_addr[ETH_ADDR_LEN] = {0};
+ UINT32 addr_high, addr_low;
+
+ addr_high = E1000_READ_REG(hw, E1000_RAH(i));
+ if (!(addr_high & E1000_RAH_AV))
+ continue;
+ addr_low = E1000_READ_REG(hw, E1000_RAL(i));
+ mac_addr[0] = (addr_low & 0xFF);
+ mac_addr[1] = ((addr_low >> 8) & 0xFF);
+ mac_addr[2] = ((addr_low >> 16) & 0xFF);
+ mac_addr[3] = ((addr_low >> 24) & 0xFF);
+ mac_addr[4] = (addr_high & 0xFF);
+ mac_addr[5] = ((addr_high >> 8) & 0xFF);
+
+ E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
+ e1000_calc_rx_da_crc(mac_addr));
+ }
+
+ /* Write Rx addresses to the PHY */
+ e1000_copy_rx_addrs_to_phy_ich8lan(hw);
+
+ /* Enable jumbo frame workaround in the MAC */
+ mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
+ mac_reg &= ~(1 << 14);
+ mac_reg |= (7 << 15);
+ E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
+
+ mac_reg = E1000_READ_REG(hw, E1000_RCTL);
+ mac_reg |= E1000_RCTL_SECRC;
+ E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
+
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data | (1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Enable jumbo frame workaround in the PHY */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ data |= (0x37 << 5);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
+ data &= ~(1 << 13);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x1A << 2);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xFE00);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
+ ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data | (1 << 10));
+ if (ret_val)
+ goto out;
+ } else {
+ /* Write MAC register values back to h/w defaults */
+ mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
+ mac_reg &= ~(0xF << 14);
+ E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
+
+ mac_reg = E1000_READ_REG(hw, E1000_RCTL);
+ mac_reg &= ~E1000_RCTL_SECRC;
+ E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
+
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data & ~(1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Write PHY register values back to h/w defaults */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
+ data |= (1 << 13);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x8 << 2);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
+ ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data & ~(1 << 10));
+ if (ret_val)
+ goto out;
+ }
+
+ /* re-enable Rx path after enabling/disabling workaround */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg & ~(1 << 14));
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ **/
+STATIC INT32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set MDIO slow mode before any other MDIO access */
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_k1_gig_workaround_lv - K1 Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * Workaround to set the K1 beacon duration for 82579 parts
+ **/
+STATIC INT32 e1000_k1_workaround_lv(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 status_reg = 0;
+ UINT32 mac_reg;
+
+ DEBUGFUNC("e1000_k1_workaround_lv");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set K1 beacon duration based on 1Gbps speed or otherwise */
+ ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
+ if (ret_val)
+ goto out;
+
+ if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
+ == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
+ mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
+ mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
+
+ if (status_reg & HV_M_STATUS_SPEED_1000)
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
+ else
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
+
+ E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
+ * @hw: pointer to the HW structure
+ * @gate: BOOLEANean set to TRUE to gate, FALSE to un-gate
+ *
+ * Gate/ungate the automatic PHY configuration via hardware; perform
+ * the configuration via software instead.
+ **/
+STATIC void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, BOOLEAN gate)
+{
+ UINT32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ return;
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+
+ if (gate)
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+ else
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ return;
+}
+
+/**
+ * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 reg;
+
+ DEBUGFUNC("e1000_post_phy_reset_ich8lan");
+
+ if (hw->phy.ops.check_reset_block(hw))
+ goto out;
+
+ /* Perform any necessary post-reset workarounds */
+ switch (hw->mac.type) {
+ case e1000_pchlan:
+ ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_pch2lan:
+ ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ break;
+ default:
+ break;
+ }
+
+ /* Dummy read to clear the phy wakeup bit after lcd reset */
+ if (hw->mac.type >= e1000_pchlan)
+ hw->phy.ops.read_reg(hw, BM_WUC, ®);
+
+ /* Configure the LCD with the extended configuration region in NVM */
+ ret_val = e1000_sw_lcd_config_ich8lan(hw);
+ if (ret_val)
+ goto out;
+
+ /* Configure the LCD with the OEM bits in NVM */
+ ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
+
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+ msec_delay(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Resets the PHY
+ * This is a function pointer entry point called by drivers
+ * or other shared routines.
+ **/
+STATIC INT32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
+
+ /* Gate automatic PHY configuration by hardware on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+
+ ret_val = e1000_phy_hw_reset_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_post_phy_reset_ich8lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_lplu_state_pchlan - Set Low Power Link Up state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU state according to the active flag. For PCH, if OEM write
+ * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
+ * the phy speed. This function will manually set the LPLU bit and restart
+ * auto-neg as hw would do. D3 and D0 LPLU will call the same function
+ * since it configures the same bit.
+ **/
+STATIC INT32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, BOOLEAN active)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 oem_reg;
+
+ DEBUGFUNC("e1000_set_lplu_state_pchlan");
+
+ ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
+ if (ret_val)
+ goto out;
+
+ if (active)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ else
+ oem_reg &= ~HV_OEM_BITS_LPLU;
+
+ oem_reg |= HV_OEM_BITS_RESTART_AN;
+ ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 phy_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
+
+ if (phy->type == e1000_phy_ife)
+ goto out;
+
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+ if (active) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers
+ */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D3 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 phy_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
+
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+ if (!active) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers
+ */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
+ * @hw: pointer to the HW structure
+ * @bank: pointer to the variable that returns the active bank
+ *
+ * Reads signature byte from the NVM using the flash access registers.
+ * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
+ **/
+STATIC INT32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, UINT32 *bank)
+{
+ UINT32 eecd;
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 bank1_offset = nvm->flash_bank_size * sizeof(UINT16);
+ UINT32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+ UINT8 sig_byte = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
+
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
+ E1000_EECD_SEC1VAL_VALID_MASK) {
+ if (eecd & E1000_EECD_SEC1VAL)
+ *bank = 1;
+ else
+ *bank = 0;
+
+ goto out;
+ }
+ DEBUGOUT("Unable to determine valid NVM bank via EEC - "
+ "reading flash signature\n");
+ /* fall-thru */
+ default:
+ /* set bank to 0 in case flash read fails */
+ *bank = 0;
+
+ /* Check bank 0 */
+ ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
+ &sig_byte);
+ if (ret_val)
+ goto out;
+ if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+ E1000_ICH_NVM_SIG_VALUE) {
+ *bank = 0;
+ goto out;
+ }
+
+ /* Check bank 1 */
+ ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
+ bank1_offset,
+ &sig_byte);
+ if (ret_val)
+ goto out;
+ if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+ E1000_ICH_NVM_SIG_VALUE) {
+ *bank = 1;
+ goto out;
+ }
+
+ DEBUGOUT("ERROR: No valid NVM bank present\n");
+ ret_val = -E1000_ERR_NVM;
+ break;
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_nvm_ich8lan - Read word(s) from the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to read.
+ * @words: Size of data to read in words
+ * @data: Pointer to the word(s) to read at offset.
+ *
+ * Reads a word(s) from the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 act_offset;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 bank = 0;
+ UINT16 i, word;
+
+ DEBUGFUNC("e1000_read_nvm_ich8lan");
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ nvm->ops.acquire(hw);
+
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+ bank = 0;
+ }
+
+ act_offset = (bank) ? nvm->flash_bank_size : 0;
+ act_offset += offset;
+
+ ret_val = E1000_SUCCESS;
+ for (i = 0; i < words; i++) {
+ if ((dev_spec->shadow_ram) &&
+ (dev_spec->shadow_ram[offset+i].modified)) {
+ data[i] = dev_spec->shadow_ram[offset+i].value;
+ } else {
+ ret_val = e1000_read_flash_word_ich8lan(hw,
+ act_offset + i,
+ &word);
+ if (ret_val)
+ break;
+ data[i] = word;
+ }
+ }
+
+ nvm->ops.release(hw);
+
+out:
+ if (ret_val)
+ DEBUGOUT1("NVM read error: %d\n", ret_val);
+
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_init_ich8lan - Initialize flash
+ * @hw: pointer to the HW structure
+ *
+ * This function does initial flash setup so that a new read/write/erase cycle
+ * can be started.
+ **/
+static INT32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
+{
+ union ich8_hws_flash_status hsfsts;
+ INT32 ret_val = -E1000_ERR_NVM;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
+
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+
+ /* Check if the flash descriptor is valid */
+ if (hsfsts.hsf_status.fldesvalid == 0) {
+ DEBUGOUT("Flash descriptor invalid. "
+ "SW Sequencing must be used.");
+ goto out;
+ }
+
+ /* Clear FCERR and DAEL in hw status by writing 1 */
+ hsfsts.hsf_status.flcerr = 1;
+ hsfsts.hsf_status.dael = 1;
+
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+
+ /*
+ * Either we should have a hardware SPI cycle in progress
+ * bit to check against, in order to start a new cycle or
+ * FDONE bit should be changed in the hardware so that it
+ * is 1 after hardware reset, which can then be used as an
+ * indication whether a cycle is in progress or has been
+ * completed.
+ */
+
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ /*
+ * There is no cycle running at present,
+ * so we can start a cycle.
+ * Begin by setting Flash Cycle Done.
+ */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+ ret_val = E1000_SUCCESS;
+ } else {
+ /*
+ * Otherwise poll for sometime so the current
+ * cycle has a chance to end before giving up.
+ */
+ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+ usec_delay(1);
+ }
+ if (ret_val == E1000_SUCCESS) {
+ /*
+ * Successful in waiting for previous cycle to timeout,
+ * now set the Flash Cycle Done.
+ */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
+ hsfsts.regval);
+ } else {
+ DEBUGOUT("Flash controller busy, cannot get access");
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
+ * @hw: pointer to the HW structure
+ * @timeout: maximum time to wait for completion
+ *
+ * This function starts a flash cycle and waits for its completion.
+ **/
+static INT32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, UINT32 timeout)
+{
+ union ich8_hws_flash_ctrl hsflctl;
+ union ich8_hws_flash_status hsfsts;
+ INT32 ret_val = -E1000_ERR_NVM;
+ UINT32 i = 0;
+
+ DEBUGFUNC("e1000_flash_cycle_ich8lan");
+
+ /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcgo = 1;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ /* wait till FDONE bit is set to 1 */
+ do {
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcdone == 1)
+ break;
+ usec_delay(1);
+ } while (i++ < timeout);
+
+ if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
+ ret_val = E1000_SUCCESS;
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_word_ich8lan - Read word from flash
+ * @hw: pointer to the HW structure
+ * @offset: offset to data location
+ * @data: pointer to the location for storing the data
+ *
+ * Reads the flash word at offset into data. Offset is converted
+ * to bytes before read.
+ **/
+STATIC INT32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_read_flash_word_ich8lan");
+
+ if (!data) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Must convert offset into bytes. */
+ offset <<= 1;
+
+ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_byte_ich8lan - Read byte from flash
+ * @hw: pointer to the HW structure
+ * @offset: The offset of the byte to read.
+ * @data: Pointer to a byte to store the value read.
+ *
+ * Reads a single byte from the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 *data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 word = 0;
+
+ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
+ if (ret_val)
+ goto out;
+
+ *data = (UINT8)word;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_data_ich8lan - Read byte or word from NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte or word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: Pointer to the word to store the value read.
+ *
+ * Reads a byte or word from the NVM using the flash access registers.
+ **/
+static INT32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 *data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ UINT32 flash_linear_addr;
+ UINT32 flash_data = 0;
+ INT32 ret_val = -E1000_ERR_NVM;
+ UINT8 count = 0;
+
+ DEBUGFUNC("e1000_read_flash_data_ich8lan");
+
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ goto out;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ usec_delay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+ /*
+ * Check if FCERR is set to 1, if set to 1, clear it
+ * and try the whole sequence a few more times, else
+ * read in (shift in) the Flash Data0, the order is
+ * least significant byte first msb to lsb
+ */
+ if (ret_val == E1000_SUCCESS) {
+ flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
+ if (size == 1)
+ *data = (UINT8)(flash_data & 0x000000FF);
+ else if (size == 2)
+ *data = (UINT16)(flash_data & 0x0000FFFF);
+ break;
+ } else {
+ /*
+ * If we've gotten here, then things are probably
+ * completely hosed, but if the error condition is
+ * detected, it won't hurt to give it another try...
+ * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_ich8lan - Write word(s) to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to write.
+ * @words: Size of data to write in words
+ * @data: Pointer to the word(s) to write at offset.
+ *
+ * Writes a byte or word to the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_write_nvm_ich8lan");
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ nvm->ops.acquire(hw);
+
+ for (i = 0; i < words; i++) {
+ dev_spec->shadow_ram[offset+i].modified = TRUE;
+ dev_spec->shadow_ram[offset+i].value = data[i];
+ }
+
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
+ * @hw: pointer to the HW structure
+ *
+ * The NVM checksum is updated by calling the generic update_nvm_checksum,
+ * which writes the checksum to the shadow ram. The changes in the shadow
+ * ram are then committed to the EEPROM by processing each bank at a time
+ * checking for the modified bit and writing only the pending changes.
+ * After a successful commit, the shadow ram is cleared and is ready for
+ * future writes.
+ **/
+STATIC INT32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 i, act_offset, new_bank_offset, old_bank_offset, bank;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
+
+ ret_val = e1000_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ goto out;
+
+ if (nvm->type != e1000_nvm_flash_sw)
+ goto out;
+
+ nvm->ops.acquire(hw);
+
+ /*
+ * We're writing to the opposite bank so if we're on bank 1,
+ * write to bank 0 etc. We also need to erase the segment that
+ * is going to be written
+ */
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+ bank = 0;
+ }
+
+ if (bank == 0) {
+ new_bank_offset = nvm->flash_bank_size;
+ old_bank_offset = 0;
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
+ if (ret_val)
+ goto release;
+ } else {
+ old_bank_offset = nvm->flash_bank_size;
+ new_bank_offset = 0;
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
+ if (ret_val)
+ goto release;
+ }
+
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ /*
+ * Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM
+ */
+ if (dev_spec->shadow_ram[i].modified) {
+ data = dev_spec->shadow_ram[i].value;
+ } else {
+ ret_val = e1000_read_flash_word_ich8lan(hw, i +
+ old_bank_offset,
+ &data);
+ if (ret_val)
+ break;
+ }
+
+ /*
+ * If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+ * signature is valid. We want to do this after the write
+ * has completed so that we don't mark the segment valid
+ * while the write is still in progress
+ */
+ if (i == E1000_ICH_NVM_SIG_WORD)
+ data |= E1000_ICH_NVM_SIG_MASK;
+
+ /* Convert offset to bytes. */
+ act_offset = (i + new_bank_offset) << 1;
+
+ usec_delay(100);
+ /* Write the bytes to the new bank. */
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset,
+ (UINT8)data);
+ if (ret_val)
+ break;
+
+ usec_delay(100);
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset + 1,
+ (UINT8)(data >> 8));
+ if (ret_val)
+ break;
+ }
+
+ /*
+ * Don't bother writing the segment valid bits if sector
+ * programming failed.
+ */
+ if (ret_val) {
+ DEBUGOUT("Flash commit failed.\n");
+ goto release;
+ }
+
+ /*
+ * Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b
+ */
+ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+ ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+ if (ret_val)
+ goto release;
+
+ data &= 0xBFFF;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset * 2 + 1,
+ (UINT8)(data >> 8));
+ if (ret_val)
+ goto release;
+
+ /*
+ * And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase
+ */
+ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
+ if (ret_val)
+ goto release;
+
+ /* Great! Everything worked, we can now clear the cached entries. */
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ dev_spec->shadow_ram[i].modified = FALSE;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+release:
+ nvm->ops.release(hw);
+
+ /*
+ * Reload the EEPROM, or else modifications will not appear
+ * until after the next adapter reset.
+ */
+ if (!ret_val) {
+ nvm->ops.reload(hw);
+ msec_delay(10);
+ }
+
+out:
+ if (ret_val)
+ DEBUGOUT1("NVM update error: %d\n", ret_val);
+
+ return ret_val;
+}
+
+/**
+ * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
+ * If the bit is 0, that the EEPROM had been modified, but the checksum was not
+ * calculated, in which case we need to calculate the checksum and set bit 6.
+ **/
+STATIC INT32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
+
+ /*
+ * Read 0x19 and check bit 6. If this bit is 0, the checksum
+ * needs to be fixed. This bit is an indication that the NVM
+ * was prepared by OEM software and did not calculate the
+ * checksum...a likely scenario.
+ */
+ ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data);
+ if (ret_val)
+ goto out;
+
+ if ((data & 0x40) == 0) {
+ data |= 0x40;
+ ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->nvm.ops.update(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_validate_nvm_checksum_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_flash_data_ich8lan - Writes bytes to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte/word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: The byte(s) to write to the NVM.
+ *
+ * Writes one/two bytes to the NVM using the flash access registers.
+ **/
+static INT32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ UINT32 flash_linear_addr;
+ UINT32 flash_data = 0;
+ INT32 ret_val = -E1000_ERR_NVM;
+ UINT8 count = 0;
+
+ DEBUGFUNC("e1000_write_ich8_data");
+
+ if (size < 1 || size > 2 || data > size * 0xff ||
+ offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ goto out;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ usec_delay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+ if (size == 1)
+ flash_data = (UINT32)data & 0x00FF;
+ else
+ flash_data = (UINT32)data;
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
+
+ /*
+ * check if FCERR is set to 1 , if set to 1, clear it
+ * and try the whole sequence a few more times else done
+ */
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+ if (ret_val == E1000_SUCCESS)
+ break;
+
+ /*
+ * If we're here, then things are most likely
+ * completely hosed, but if the error condition
+ * is detected, it won't hurt to give it another
+ * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* Repeat for some time before giving up. */
+ continue;
+ if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_flash_byte_ich8lan - Write a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The index of the byte to read.
+ * @data: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 data)
+{
+ UINT16 word = (UINT16)data;
+
+ DEBUGFUNC("e1000_write_flash_byte_ich8lan");
+
+ return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
+}
+
+/**
+ * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset of the byte to write.
+ * @byte: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ * Goes through a retry algorithm before giving up.
+ **/
+static INT32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 byte)
+{
+ INT32 ret_val;
+ UINT16 program_retries;
+
+ DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
+
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (ret_val == E1000_SUCCESS)
+ goto out;
+
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
+ usec_delay(100);
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (ret_val == E1000_SUCCESS)
+ break;
+ }
+ if (program_retries == 100) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
+ * @hw: pointer to the HW structure
+ * @bank: 0 for first bank, 1 for second bank, etc.
+ *
+ * Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
+ * bank N is 4096 * N + flash_reg_addr.
+ **/
+STATIC INT32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, UINT32 bank)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ UINT32 flash_linear_addr;
+ /* bank size is in 16bit words - adjust to bytes */
+ UINT32 flash_bank_size = nvm->flash_bank_size * 2;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 count = 0;
+ INT32 j, iteration, sector_size;
+
+ DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
+
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+
+ /*
+ * Determine HW Sector size: Read BERASE bits of hw flash status
+ * register
+ * 00: The Hw sector is 256 bytes, hence we need to erase 16
+ * consecutive sectors. The start index for the nth Hw sector
+ * can be calculated as = bank * 4096 + n * 256
+ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+ * The start index for the nth Hw sector can be calculated
+ * as = bank * 4096
+ * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
+ * (ich9 only, otherwise error condition)
+ * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
+ */
+ switch (hsfsts.hsf_status.berasesz) {
+ case 0:
+ /* Hw sector size 256 */
+ sector_size = ICH_FLASH_SEG_SIZE_256;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
+ break;
+ case 1:
+ sector_size = ICH_FLASH_SEG_SIZE_4K;
+ iteration = 1;
+ break;
+ case 2:
+ sector_size = ICH_FLASH_SEG_SIZE_8K;
+ iteration = 1;
+ break;
+ case 3:
+ sector_size = ICH_FLASH_SEG_SIZE_64K;
+ iteration = 1;
+ break;
+ default:
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Start with the base address, then add the sector offset. */
+ flash_linear_addr = hw->nvm.flash_base_addr;
+ flash_linear_addr += (bank) ? flash_bank_size : 0;
+
+ for (j = 0; j < iteration ; j++) {
+ do {
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Write a value 11 (block Erase) in Flash
+ * Cycle field in hw flash control
+ */
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
+ hsflctl.regval);
+
+ /*
+ * Write the last 24 bits of an index within the
+ * block into Flash Linear address field in Flash
+ * Address.
+ */
+ flash_linear_addr += (j * sector_size);
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
+ flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+ if (ret_val == E1000_SUCCESS)
+ break;
+
+ /*
+ * Check if FCERR is set to 1. If 1,
+ * clear it and try the whole sequence
+ * a few more times else Done
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* repeat for some time before giving up */
+ continue;
+ else if (hsfsts.hsf_status.flcdone == 0)
+ goto out;
+ } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_valid_led_default_ich8lan - Set the default LED settings
+ * @hw: pointer to the HW structure
+ * @data: Pointer to the LED settings
+ *
+ * Reads the LED default settings from the NVM to data. If the NVM LED
+ * settings is all 0's or F's, set the LED default to a valid LED default
+ * setting.
+ **/
+STATIC INT32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_ich8lan");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT_ICH8LAN;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_id_led_init_pchlan - store LED configurations
+ * @hw: pointer to the HW structure
+ *
+ * PCH does not control LEDs via the LEDCTL register, rather it uses
+ * the PHY LED configuration register.
+ *
+ * PCH also does not have an "always on" or "always off" mode which
+ * complicates the ID feature. Instead of using the "on" mode to indicate
+ * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
+ * use "link_up" mode. The LEDs will still ID on request if there is no
+ * link based on logic in e1000_led_[on|off]_pchlan().
+ **/
+STATIC INT32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ const UINT32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
+ const UINT32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
+ UINT16 data, i, temp, shift;
+
+ DEBUGFUNC("e1000_id_led_init_pchlan");
+
+ /* Get default ID LED modes */
+ ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+ if (ret_val)
+ goto out;
+
+ mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+ mac->ledctl_mode1 = mac->ledctl_default;
+ mac->ledctl_mode2 = mac->ledctl_default;
+
+ for (i = 0; i < 4; i++) {
+ temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
+ shift = (i * 5);
+ switch (temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+ mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode1 |= (ledctl_on << shift);
+ break;
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode1 |= (ledctl_off << shift);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch (temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+ mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode2 |= (ledctl_on << shift);
+ break;
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode2 |= (ledctl_off << shift);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_bus_info_ich8lan - Get/Set the bus type and width
+ * @hw: pointer to the HW structure
+ *
+ * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
+ * register, so the the bus width is hard coded.
+ **/
+STATIC INT32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_bus_info_ich8lan");
+
+ ret_val = e1000_get_bus_info_pcie_generic(hw);
+
+ /*
+ * ICH devices are "PCI Express"-ish. They have
+ * a configuration space, but do not contain
+ * PCI Express Capability registers, so bus width
+ * must be hardcoded.
+ */
+ if (bus->width == e1000_bus_width_unknown)
+ bus->width = e1000_bus_width_pcie_x1;
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_ich8lan - Reset the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Does a full reset of the hardware which includes a reset of the PHY and
+ * MAC.
+ **/
+STATIC INT32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT16 reg;
+ UINT32 ctrl, kab;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_ich8lan");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ /*
+ * Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC
+ * with the global reset.
+ */
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ /* Workaround for ICH8 bit corruption issue in FIFO memory */
+ if (hw->mac.type == e1000_ich8lan) {
+ /* Set Tx and Rx buffer allocation to 8k apiece. */
+ E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
+ /* Set Packet Buffer Size to 16k. */
+ E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
+ }
+
+ if (hw->mac.type == e1000_pchlan) {
+ /* Save the NVM K1 bit setting*/
+ ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®);
+ if (ret_val)
+ return ret_val;
+
+ if (reg & E1000_NVM_K1_ENABLE)
+ dev_spec->nvm_k1_enabled = TRUE;
+ else
+ dev_spec->nvm_k1_enabled = FALSE;
+ }
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ if (!hw->phy.ops.check_reset_block(hw)) {
+ /*
+ * Full-chip reset requires MAC and PHY reset at the same
+ * time to make sure the interface between MAC and the
+ * external PHY is reset.
+ */
+ ctrl |= E1000_CTRL_PHY_RST;
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+ }
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ DEBUGOUT("Issuing a global reset to ich8lan\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
+ msec_delay(20);
+
+ if (!ret_val)
+ e1000_release_swflag_ich8lan(hw);
+
+ if (ctrl & E1000_CTRL_PHY_RST) {
+ ret_val = hw->phy.ops.get_cfg_done(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_post_phy_reset_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * For PCH, this write will make sure that any noise
+ * will be detected as a CRC error and be dropped rather than show up
+ * as a bad packet to the DMA engine.
+ */
+ if (hw->mac.type == e1000_pchlan)
+ E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
+
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ kab = E1000_READ_REG(hw, E1000_KABGTXD);
+ kab |= E1000_KABGTXD_BGSQLBIAS;
+ E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_ich8lan - Initialize the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Prepares the hardware for transmit and receive by doing the following:
+ * - initialize hardware bits
+ * - initialize LED identification
+ * - setup receive address registers
+ * - setup flow control
+ * - setup transmit descriptors
+ * - clear statistics
+ **/
+STATIC INT32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 ctrl_ext, txdctl, snoop;
+ INT32 ret_val;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_init_hw_ich8lan");
+
+ e1000_initialize_hw_bits_ich8lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val)
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+
+ /* Setup the receive address. */
+ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /*
+ * The 82578 Rx buffer will stall if wakeup is enabled in host and
+ * the ME. Reading the BM_WUC register will clear the host wakeup bit.
+ * Reset the phy after disabling host wakeup to reset the Rx buffer.
+ */
+ if (hw->phy.type == e1000_phy_82578) {
+ hw->phy.ops.read_reg(hw, BM_WUC, &i);
+ ret_val = e1000_phy_hw_reset_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy for both queues */
+ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
+ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
+
+ /*
+ * ICH8 has opposite polarity of no_snoop bits.
+ * By default, we should use snoop behavior.
+ */
+ if (mac->type == e1000_ich8lan)
+ snoop = PCIE_ICH8_SNOOP_ALL;
+ else
+ snoop = (UINT32) ~(PCIE_NO_SNOOP_ALL);
+ e1000_set_pcie_no_snoop_generic(hw, snoop);
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_ich8lan(hw);
+
+ return ret_val;
+}
+/**
+ * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
+ * @hw: pointer to the HW structure
+ *
+ * Sets/Clears required hardware bits necessary for correctly setting up the
+ * hardware for transmit and receive.
+ **/
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
+
+ /* Extended Device Control */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg |= (1 << 22);
+ /* Enable PHY low-power state when MAC is at D3 w/o WoL */
+ if (hw->mac.type >= e1000_pchlan)
+ reg |= E1000_CTRL_EXT_PHYPDEN;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+ /* Transmit Descriptor Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TARC(0));
+ if (hw->mac.type == e1000_ich8lan)
+ reg |= (1 << 28) | (1 << 29);
+ reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
+ E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TARC(1));
+ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ reg |= (1 << 24) | (1 << 26) | (1 << 30);
+ E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+
+ /* Device Status */
+ if (hw->mac.type == e1000_ich8lan) {
+ reg = E1000_READ_REG(hw, E1000_STATUS);
+ reg &= ~(1 << 31);
+ E1000_WRITE_REG(hw, E1000_STATUS, reg);
+ }
+
+ /*
+ * work-around descriptor data corruption issue during nfs v2 udp
+ * traffic, just disable the nfs filtering capability
+ */
+ reg = E1000_READ_REG(hw, E1000_RFCTL);
+ reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
+ E1000_WRITE_REG(hw, E1000_RFCTL, reg);
+
+ return;
+}
+
+/**
+ * e1000_setup_link_ich8lan - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+STATIC INT32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_link_ich8lan");
+
+ if (hw->phy.ops.check_reset_block(hw))
+ goto out;
+
+ /*
+ * ICH parts do not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ if (hw->fc.requested_mode == e1000_fc_default)
+ hw->fc.requested_mode = e1000_fc_full;
+
+ /*
+ * Save off the requested flow control mode for use later. Depending
+ * on the link partner's capabilities, we may or may not use this mode.
+ */
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
+ hw->fc.current_mode);
+
+ /* Continue to configure the copper link. */
+ ret_val = hw->mac.ops.setup_physical_interface(hw);
+ if (ret_val)
+ goto out;
+
+ E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+ if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
+ (hw->phy.type == e1000_phy_82577)) {
+ E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
+
+ ret_val = hw->phy.ops.write_reg(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 27),
+ hw->fc.pause_time);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
+ * @hw: pointer to the HW structure
+ *
+ * Configures the kumeran interface to the PHY to wait the appropriate time
+ * when polling the PHY, then call the generic setup_copper_link to finish
+ * configuring the copper link.
+ **/
+STATIC INT32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+ UINT16 reg_data;
+
+ DEBUGFUNC("e1000_setup_copper_link_ich8lan");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /*
+ * Set the mac to wait the maximum time between each iteration
+ * and increase the max iterations when polling the phy;
+ * this fixes erroneous timeouts at 10Mbps.
+ */
+ ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
+ 0xFFFF);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_INBAND_PARAM,
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_INBAND_PARAM,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ switch (hw->phy.type) {
+ case e1000_phy_igp_3:
+ ret_val = e1000_copper_link_setup_igp(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_phy_bm:
+ case e1000_phy_82578:
+ ret_val = e1000_copper_link_setup_m88(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_phy_82577:
+ case e1000_phy_82579:
+ ret_val = e1000_copper_link_setup_82577(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_phy_ife:
+ ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ reg_data &= ~IFE_PMC_AUTO_MDIX;
+
+ switch (hw->phy.mdix) {
+ case 1:
+ reg_data &= ~IFE_PMC_FORCE_MDIX;
+ break;
+ case 2:
+ reg_data |= IFE_PMC_FORCE_MDIX;
+ break;
+ case 0:
+ default:
+ reg_data |= IFE_PMC_AUTO_MDIX;
+ break;
+ }
+ ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
+ reg_data);
+ if (ret_val)
+ goto out;
+ break;
+ default:
+ break;
+ }
+ ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_link_up_info_ich8lan - Get current link speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to store current link speed
+ * @duplex: pointer to store the current link duplex
+ *
+ * Calls the generic get_speed_and_duplex to retrieve the current link
+ * information and then calls the Kumeran lock loss workaround for links at
+ * gigabit speeds.
+ **/
+STATIC INT32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_link_up_info_ich8lan");
+
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
+ if (ret_val)
+ goto out;
+
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3) &&
+ (*speed == SPEED_1000)) {
+ ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
+ * @hw: pointer to the HW structure
+ *
+ * Work-around for 82566 Kumeran PCS lock loss:
+ * On link status change (i.e. PCI reset, speed change) and link is up and
+ * speed is gigabit-
+ * 0) if workaround is optionally disabled do nothing
+ * 1) wait 1ms for Kumeran link to come up
+ * 2) check Kumeran Diagnostic register PCS lock loss bit
+ * 3) if not set the link is locked (all is good), otherwise...
+ * 4) reset the PHY
+ * 5) repeat up to 10 times
+ * Note: this is only called for IGP3 copper when speed is 1gb.
+ **/
+static INT32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 phy_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i, data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
+
+ if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
+ goto out;
+
+ /*
+ * Make sure link is up before proceeding. If not just return.
+ * Attempting this while link is negotiating fouled up link
+ * stability
+ */
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (!link) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ for (i = 0; i < 10; i++) {
+ /* read once to clear */
+ ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ goto out;
+ /* and again to get new status */
+ ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ goto out;
+
+ /* check for PCS lock */
+ if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ /* Issue PHY reset */
+ hw->phy.ops.reset(hw);
+ msec_delay_irq(5);
+ }
+ /* Disable GigE link negotiation */
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+ phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ /*
+ * Call gig speed drop workaround on Gig disable before accessing
+ * any PHY registers
+ */
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* unable to acquire PCS lock */
+ ret_val = -E1000_ERR_PHY;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
+ * @hw: pointer to the HW structure
+ * @state: BOOLEANean value used to set the current Kumeran workaround state
+ *
+ * If ICH8, set the current Kumeran workaround state (enabled - TRUE
+ * /disabled - FALSE).
+ **/
+void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ BOOLEAN state)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+
+ DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
+
+ if (hw->mac.type != e1000_ich8lan) {
+ DEBUGOUT("Workaround applies to ICH8 only.\n");
+ return;
+ }
+
+ dev_spec->kmrn_lock_loss_workaround_enabled = state;
+
+ return;
+}
+
+/**
+ * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
+ * @hw: pointer to the HW structure
+ *
+ * Workaround for 82566 power-down on D3 entry:
+ * 1) disable gigabit link
+ * 2) write VR power-down enable
+ * 3) read it back
+ * Continue if successful, else issue LCD reset and repeat
+ **/
+void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 reg;
+ UINT16 data;
+ UINT8 retry = 0;
+
+ DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
+
+ if (hw->phy.type != e1000_phy_igp_3)
+ goto out;
+
+ /* Try the workaround twice (if needed) */
+ do {
+ /* Disable link */
+ reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
+ reg |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
+
+ /*
+ * Call gig speed drop workaround on Gig disable before
+ * accessing any PHY registers
+ */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* Write VR power-down enable */
+ hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
+ data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
+ data | IGP3_VR_CTRL_MODE_SHUTDOWN);
+
+ /* Read it back and test */
+ hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
+ data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
+ break;
+
+ /* Issue PHY reset and repeat at most one more time */
+ reg = E1000_READ_REG(hw, E1000_CTRL);
+ E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
+ retry++;
+ } while (retry);
+
+out:
+ return;
+}
+
+/**
+ * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ * @hw: pointer to the HW structure
+ *
+ * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ * LPLU, Gig disable, MDIC PHY reset):
+ * 1) Set Kumeran Near-end loopback
+ * 2) Clear Kumeran Near-end loopback
+ * Should only be called for ICH8[m] devices with IGP_3 Phy.
+ **/
+void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 reg_data;
+
+ DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
+
+ if ((hw->mac.type != e1000_ich8lan) ||
+ (hw->phy.type != e1000_phy_igp_3))
+ goto out;
+
+ ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+ if (ret_val)
+ goto out;
+ reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+out:
+ return;
+}
+
+/**
+ * e1000_disable_gig_wol_ich8lan - disable gig during WoL
+ * @hw: pointer to the HW structure
+ *
+ * During S0 to Sx transition, it is possible the link remains at gig
+ * instead of negotiating to a lower speed. Before going to Sx, set
+ * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
+ * to a lower speed.
+ *
+ * Should only be called for applicable parts.
+ **/
+void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 phy_ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_disable_gig_wol_ich8lan");
+
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (hw->mac.type >= e1000_pchlan) {
+ e1000_oem_bits_config_ich8lan(hw, TRUE);
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return;
+ e1000_write_smbus_addr(hw);
+ hw->phy.ops.release(hw);
+ }
+
+ return;
+}
+
+/**
+ * e1000_cleanup_led_ich8lan - Restore the default LED operation
+ * @hw: pointer to the HW structure
+ *
+ * Return the LED back to the default configuration.
+ **/
+STATIC INT32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led_ich8lan");
+
+ if (hw->phy.type == e1000_phy_ife)
+ return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ 0);
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_on_ich8lan - Turn LEDs on
+ * @hw: pointer to the HW structure
+ *
+ * Turn on the LEDs.
+ **/
+STATIC INT32 e1000_led_on_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_led_on_ich8lan");
+
+ if (hw->phy.type == e1000_phy_ife)
+ return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_off_ich8lan - Turn LEDs off
+ * @hw: pointer to the HW structure
+ *
+ * Turn off the LEDs.
+ **/
+STATIC INT32 e1000_led_off_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_led_off_ich8lan");
+
+ if (hw->phy.type == e1000_phy_ife)
+ return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_setup_led_pchlan - Configures SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This prepares the SW controllable LED for use.
+ **/
+STATIC INT32 e1000_setup_led_pchlan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_setup_led_pchlan");
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+ (UINT16)hw->mac.ledctl_mode1);
+}
+
+/**
+ * e1000_cleanup_led_pchlan - Restore the default LED operation
+ * @hw: pointer to the HW structure
+ *
+ * Return the LED back to the default configuration.
+ **/
+STATIC INT32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led_pchlan");
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+ (UINT16)hw->mac.ledctl_default);
+}
+
+/**
+ * e1000_led_on_pchlan - Turn LEDs on
+ * @hw: pointer to the HW structure
+ *
+ * Turn on the LEDs.
+ **/
+STATIC INT32 e1000_led_on_pchlan(struct e1000_hw *hw)
+{
+ UINT16 data = (UINT16)hw->mac.ledctl_mode2;
+ UINT32 i, led;
+
+ DEBUGFUNC("e1000_led_on_pchlan");
+
+ /*
+ * If no link, then turn LED on by setting the invert bit
+ * for each LED that's mode is "link_up" in ledctl_mode2.
+ */
+ if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+ for (i = 0; i < 3; i++) {
+ led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+ if ((led & E1000_PHY_LED0_MODE_MASK) !=
+ E1000_LEDCTL_MODE_LINK_UP)
+ continue;
+ if (led & E1000_PHY_LED0_IVRT)
+ data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+ else
+ data |= (E1000_PHY_LED0_IVRT << (i * 5));
+ }
+ }
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ * e1000_led_off_pchlan - Turn LEDs off
+ * @hw: pointer to the HW structure
+ *
+ * Turn off the LEDs.
+ **/
+STATIC INT32 e1000_led_off_pchlan(struct e1000_hw *hw)
+{
+ UINT16 data = (UINT16)hw->mac.ledctl_mode1;
+ UINT32 i, led;
+
+ DEBUGFUNC("e1000_led_off_pchlan");
+
+ /*
+ * If no link, then turn LED off by clearing the invert bit
+ * for each LED that's mode is "link_up" in ledctl_mode1.
+ */
+ if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+ for (i = 0; i < 3; i++) {
+ led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+ if ((led & E1000_PHY_LED0_MODE_MASK) !=
+ E1000_LEDCTL_MODE_LINK_UP)
+ continue;
+ if (led & E1000_PHY_LED0_IVRT)
+ data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+ else
+ data |= (E1000_PHY_LED0_IVRT << (i * 5));
+ }
+ }
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Read appropriate register for the config done bit for completion status
+ * and configure the PHY through s/w for EEPROM-less parts.
+ *
+ * NOTE: some silicon which is EEPROM-less will fail trying to read the
+ * config done bit, so only an error is logged and continues. If we were
+ * to return with error, EEPROM-less silicon would not be able to be reset
+ * or change link.
+ **/
+STATIC INT32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 bank = 0;
+ UINT32 status;
+
+ DEBUGFUNC("e1000_get_cfg_done_ich8lan");
+
+ e1000_get_cfg_done_generic(hw);
+
+ /* Wait for indication from h/w that it has completed basic config */
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ DEBUGOUT("Auto Read Done did not complete\n");
+ ret_val = E1000_SUCCESS;
+ }
+
+ /* Clear PHY Reset Asserted bit */
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_PHYRA)
+ E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
+ else
+ DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
+
+ /* If EEPROM is not marked present, init the IGP 3 PHY manually */
+ if (hw->mac.type <= e1000_ich9lan) {
+ if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+ (hw->phy.type == e1000_phy_igp_3)) {
+ e1000_phy_init_script_igp3(hw);
+ }
+ } else {
+ if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
+ /* Maybe we should do a basic PHY config */
+ DEBUGOUT("EEPROM not present\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
+{
+ /* If the management interface is not enabled, then power down */
+ if (!(hw->mac.ops.check_mng_mode(hw) ||
+ hw->phy.ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears hardware counters specific to the silicon family and calls
+ * clear_hw_cntrs_generic to clear all general purpose counters.
+ **/
+STATIC void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
+{
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ /* Clear PHY statistics registers */
+ if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
+ (hw->phy.type == e1000_phy_82577)) {
+ hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
+ }
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h
new file mode 100755
index 0000000..e90f400
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h
@@ -0,0 +1,233 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_ICH8LAN_H_
+#define _E1000_ICH8LAN_H_
+
+#define ICH_FLASH_GFPREG 0x0000
+#define ICH_FLASH_HSFSTS 0x0004
+#define ICH_FLASH_HSFCTL 0x0006
+#define ICH_FLASH_FADDR 0x0008
+#define ICH_FLASH_FDATA0 0x0010
+
+/* Requires up to 10 seconds when MNG might be accessing part. */
+#define ICH_FLASH_READ_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT 10
+
+#define ICH_CYCLE_READ 0
+#define ICH_CYCLE_WRITE 2
+#define ICH_CYCLE_ERASE 3
+
+#define FLASH_GFPREG_BASE_MASK 0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT 12
+
+#define ICH_FLASH_SEG_SIZE_256 256
+#define ICH_FLASH_SEG_SIZE_4K 4096
+#define ICH_FLASH_SEG_SIZE_8K 8192
+#define ICH_FLASH_SEG_SIZE_64K 65536
+#define ICH_FLASH_SECTOR_SIZE 4096
+
+#define ICH_FLASH_REG_MAPSIZE 0x00A0
+
+#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
+#define E1000_ICH_FWSM_DISSW 0x10000000 /* FW Disables SW Writes */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID 0x00008000
+
+#define E1000_ICH_MNG_IAMT_MODE 0x2
+
+#define E1000_FWSM_PROXY_MODE 0x00000008 /* FW is in proxy mode */
+
+/* Shared Receive Address Registers */
+#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8))
+#define E1000_SHRAH_AV 0x80000000 /* Addr Valid bit */
+#define E1000_SHRAH_MAV 0x40000000 /* Multicast Addr Valid bit */
+
+#define E1000_H2ME 0x05B50 /* Host to ME */
+#define E1000_H2ME_LSECREQ 0x00000001 /* Linksec Request */
+#define E1000_H2ME_LSECA 0x00000002 /* Linksec Active */
+#define E1000_H2ME_LSECSF 0x00000004 /* Linksec Failed */
+#define E1000_H2ME_LSECD 0x00000008 /* Linksec Disabled */
+#define E1000_H2ME_SLCAPD 0x00000010 /* Start LCAPD */
+#define E1000_H2ME_IPV4_ARP_EN 0x00000020 /* Arp Offload enable bit */
+#define E1000_H2ME_IPV6_NS_EN 0x00000040 /* NS Offload enable bit */
+
+#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_OFF1_ON2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD 0x13
+#define E1000_ICH_NVM_SIG_MASK 0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0
+#define E1000_ICH_NVM_SIG_VALUE 0x80
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
+
+#define E1000_FEXTNVM_SW_CONFIG 1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */
+
+#define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3
+
+#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES 7
+#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+ ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
+#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */
+#define IGP3_PM_CTRL PHY_REG(769, 20) /* Power Management Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200
+#define IGP3_PM_CTRL_FORCE_PWR_DOWN 0x0020
+
+/* PHY Wakeup Registers and defines */
+#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0)
+#define BM_WUC PHY_REG(BM_WUC_PAGE, 1)
+#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
+#define BM_WUS PHY_REG(BM_WUC_PAGE, 3)
+#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+#define BM_IPAV (BM_PHY_REG(BM_WUC_PAGE, 64))
+#define BM_IP4AT_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 82 + ((_i) * 2)))
+#define BM_IP4AT_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 83 + ((_i) * 2)))
+
+#define BM_SHRAL_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 44 + ((_i) * 4)))
+#define BM_SHRAL_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 45 + ((_i) * 4)))
+#define BM_SHRAH_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 46 + ((_i) * 4)))
+#define BM_SHRAH_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 47 + ((_i) * 4)))
+
+#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */
+#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */
+#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */
+#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */
+#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */
+#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */
+#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */
+
+#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */
+#define HV_MUX_DATA_CTRL PHY_REG(776, 16)
+#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400
+#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004
+#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */
+#define HV_SCC_LOWER PHY_REG(778, 17)
+#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */
+#define HV_ECOL_LOWER PHY_REG(778, 19)
+#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */
+#define HV_MCC_LOWER PHY_REG(778, 21)
+#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */
+#define HV_LATECOL_LOWER PHY_REG(778, 24)
+#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */
+#define HV_COLC_LOWER PHY_REG(778, 26)
+#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */
+#define HV_DC_LOWER PHY_REG(778, 28)
+#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */
+#define HV_TNCRS_LOWER PHY_REG(778, 30)
+
+#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */
+
+#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
+#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */
+
+/* SMBus Address Phy Register */
+#define HV_SMB_ADDR PHY_REG(768, 26)
+#define HV_SMB_ADDR_MASK 0x007F
+#define HV_SMB_ADDR_PEC_EN 0x0200
+#define HV_SMB_ADDR_VALID 0x0080
+
+/* Strapping Option Register - RO */
+#define E1000_STRAP 0x0000C
+#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000
+#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */
+#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */
+#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
+
+#define LCD_CFG_PHY_ADDR_BIT 0x0020 /* Phy address bit from LCD Config word */
+
+/* KMRN Mode Control */
+#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
+#define HV_KMRN_MDIO_SLOW 0x0400
+
+/* PHY Power Management Control */
+#define HV_PM_CTRL PHY_REG(770, 17)
+
+#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */
+
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+
+/*
+ * Additional interrupts need to be handled for ICH family:
+ * DSW = The FW changed the status of the DISSW bit in FWSM
+ * PHYINT = The LAN connected device generates an interrupt
+ * EPRST = Manageability reset event
+ */
+#define IMS_ICH_ENABLE_MASK (\
+ E1000_IMS_DSW | \
+ E1000_IMS_PHYINT | \
+ E1000_IMS_EPRST)
+
+/* Receive Address Initial CRC Calculation */
+#define E1000_PCH_RAICC(_n) (0x05F50 + ((_n) * 4))
+
+void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ BOOLEAN state);
+void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw);
+INT32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, BOOLEAN k1_enable);
+INT32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, BOOLEAN d0_config);
+INT32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
+INT32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, BOOLEAN enable);
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c
new file mode 100755
index 0000000..a29288e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c
@@ -0,0 +1,2203 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+#include <Library/BaseMemoryLib.h>
+
+STATIC INT32 e1000_set_default_fc_generic(struct e1000_hw *hw);
+STATIC INT32 e1000_commit_fc_settings_generic(struct e1000_hw *hw);
+STATIC INT32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
+STATIC INT32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
+STATIC void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+
+/**
+ * e1000_init_mac_ops_generic - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Setups up the function pointers to no-op functions
+ **/
+void e1000_init_mac_ops_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ DEBUGFUNC("e1000_init_mac_ops_generic");
+
+ /* General Setup */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.init_params = e1000_null_ops_generic;
+ mac->ops.init_hw = e1000_null_ops_generic;
+ mac->ops.reset_hw = e1000_null_ops_generic;
+ mac->ops.setup_physical_interface = e1000_null_ops_generic;
+ mac->ops.get_bus_info = e1000_null_ops_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie;
+ mac->ops.read_mac_addr = e1000_read_mac_addr_generic;
+ mac->ops.config_collision_dist = e1000_config_collision_dist_generic;
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.clear_hw_cntrs = e1000_null_mac_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+#ifndef NO_NULL_OPS_SUPPORT
+ /* LED */
+ mac->ops.cleanup_led = e1000_null_ops_generic;
+ mac->ops.setup_led = e1000_null_ops_generic;
+ mac->ops.blink_led = e1000_null_ops_generic;
+ mac->ops.led_on = e1000_null_ops_generic;
+ mac->ops.led_off = e1000_null_ops_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ /* LINK */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.setup_link = e1000_null_ops_generic;
+ mac->ops.get_link_up_info = e1000_null_link_info;
+ mac->ops.check_for_link = e1000_null_ops_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.wait_autoneg = e1000_wait_autoneg_generic;
+ /* Management */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.check_mng_mode = e1000_null_mng_mode;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic;
+ mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic;
+ mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic;
+ /* VLAN, MC, etc. */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.update_mc_addr_list = e1000_null_update_mc;
+ mac->ops.clear_vfta = e1000_null_mac_generic;
+ mac->ops.write_vfta = e1000_null_write_vfta;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.rar_set = e1000_rar_set_generic;
+ mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic;
+}
+
+#ifndef NO_NULL_OPS_SUPPORT
+/**
+ * e1000_null_ops_generic - No-op function, returns 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_ops_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_ops_generic");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_mac_generic - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_mac_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_mac_generic");
+ return;
+}
+
+/**
+ * e1000_null_link_info - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_link_info(struct e1000_hw *hw, UINT16 *s, UINT16 *d)
+{
+ DEBUGFUNC("e1000_null_link_info");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_mng_mode - No-op function, return FALSE
+ * @hw: pointer to the HW structure
+ **/
+BOOLEAN e1000_null_mng_mode(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_mng_mode");
+ return FALSE;
+}
+
+/**
+ * e1000_null_update_mc - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_update_mc(struct e1000_hw *hw, UINT8 *h, UINT32 a)
+{
+ DEBUGFUNC("e1000_null_update_mc");
+ return;
+}
+
+/**
+ * e1000_null_write_vfta - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_write_vfta(struct e1000_hw *hw, UINT32 a, UINT32 b)
+{
+ DEBUGFUNC("e1000_null_write_vfta");
+ return;
+}
+
+/**
+ * e1000_null_rar_set - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_rar_set(struct e1000_hw *hw, UINT8 *h, UINT32 a)
+{
+ DEBUGFUNC("e1000_null_rar_set");
+ return;
+}
+
+#endif /* NO_NULL_OPS_SUPPORT */
+#ifndef NO_PCI_SUPPORT
+/**
+ * e1000_get_bus_info_pci_generic - Get PCI(x) bus information
+ * @hw: pointer to the HW structure
+ *
+ * Determines and stores the system bus information for a particular
+ * network interface. The following bus information is determined and stored:
+ * bus speed, bus width, type (PCI/PCIx), and PCI(-x) function.
+ **/
+INT32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_bus_info *bus = &hw->bus;
+ UINT32 status = E1000_READ_REG(hw, E1000_STATUS);
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_get_bus_info_pci_generic");
+
+ /* PCI or PCI-X? */
+ bus->type = (status & E1000_STATUS_PCIX_MODE)
+ ? e1000_bus_type_pcix
+ : e1000_bus_type_pci;
+
+ /* Bus speed */
+ if (bus->type == e1000_bus_type_pci) {
+ bus->speed = (status & E1000_STATUS_PCI66)
+ ? e1000_bus_speed_66
+ : e1000_bus_speed_33;
+ } else {
+ switch (status & E1000_STATUS_PCIX_SPEED) {
+ case E1000_STATUS_PCIX_SPEED_66:
+ bus->speed = e1000_bus_speed_66;
+ break;
+ case E1000_STATUS_PCIX_SPEED_100:
+ bus->speed = e1000_bus_speed_100;
+ break;
+ case E1000_STATUS_PCIX_SPEED_133:
+ bus->speed = e1000_bus_speed_133;
+ break;
+ default:
+ bus->speed = e1000_bus_speed_reserved;
+ break;
+ }
+ }
+
+ /* Bus width */
+ bus->width = (status & E1000_STATUS_BUS64)
+ ? e1000_bus_width_64
+ : e1000_bus_width_32;
+
+ /* Which PCI(-X) function? */
+ mac->ops.set_lan_id(hw);
+
+ return ret_val;
+}
+
+#endif /* NO_PCI_SUPPORT */
+/**
+ * e1000_get_bus_info_pcie_generic - Get PCIe bus information
+ * @hw: pointer to the HW structure
+ *
+ * Determines and stores the system bus information for a particular
+ * network interface. The following bus information is determined and stored:
+ * bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+INT32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_bus_info *bus = &hw->bus;
+ INT32 ret_val;
+ UINT16 pcie_link_status;
+
+ DEBUGFUNC("e1000_get_bus_info_pcie_generic");
+
+ bus->type = e1000_bus_type_pci_express;
+
+ ret_val = e1000_read_pcie_cap_reg(hw,
+ PCIE_LINK_STATUS,
+ &pcie_link_status);
+ if (ret_val) {
+ bus->width = e1000_bus_width_unknown;
+ bus->speed = e1000_bus_speed_unknown;
+ } else {
+ switch (pcie_link_status & PCIE_LINK_SPEED_MASK) {
+ case PCIE_LINK_SPEED_2500:
+ bus->speed = e1000_bus_speed_2500;
+ break;
+ case PCIE_LINK_SPEED_5000:
+ bus->speed = e1000_bus_speed_5000;
+ break;
+ default:
+ bus->speed = e1000_bus_speed_unknown;
+ break;
+ }
+
+ bus->width = (enum e1000_bus_width)((pcie_link_status &
+ PCIE_LINK_WIDTH_MASK) >>
+ PCIE_LINK_WIDTH_SHIFT);
+ }
+
+ mac->ops.set_lan_id(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ * @hw: pointer to the HW structure
+ *
+ * Determines the LAN function id by reading memory-mapped registers
+ * and swaps the port value if requested.
+ **/
+STATIC void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ UINT32 reg;
+
+ /*
+ * The status register reports the correct function number
+ * for the device regardless of function swap state.
+ */
+ reg = E1000_READ_REG(hw, E1000_STATUS);
+ bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+#ifndef NO_PCI_SUPPORT
+/**
+ * e1000_set_lan_id_multi_port_pci - Set LAN id for PCI multiple port devices
+ * @hw: pointer to the HW structure
+ *
+ * Determines the LAN function id by reading PCI config space.
+ **/
+void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ UINT16 pci_header_type;
+ UINT32 status;
+
+ e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
+ if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ bus->func = (status & E1000_STATUS_FUNC_MASK)
+ >> E1000_STATUS_FUNC_SHIFT;
+ } else {
+ bus->func = 0;
+ }
+}
+
+#endif /* NO_PCI_SUPPORT */
+/**
+ * e1000_set_lan_id_single_port - Set LAN id for a single port device
+ * @hw: pointer to the HW structure
+ *
+ * Sets the LAN function id to zero for a single port device.
+ **/
+void e1000_set_lan_id_single_port(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+
+ bus->func = 0;
+}
+
+/**
+ * e1000_clear_vfta_generic - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * Clears the register array which contains the VLAN filter table by
+ * setting all the values to 0.
+ **/
+void e1000_clear_vfta_generic(struct e1000_hw *hw)
+{
+ UINT32 offset;
+
+ DEBUGFUNC("e1000_clear_vfta_generic");
+
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
+ E1000_WRITE_FLUSH(hw);
+ }
+}
+
+/**
+ * e1000_write_vfta_generic - Write value to VLAN filter table
+ * @hw: pointer to the HW structure
+ * @offset: register offset in VLAN filter table
+ * @value: register value written to VLAN filter table
+ *
+ * Writes value at the given offset in the register array which stores
+ * the VLAN filter table.
+ **/
+void e1000_write_vfta_generic(struct e1000_hw *hw, UINT32 offset, UINT32 value)
+{
+ DEBUGFUNC("e1000_write_vfta_generic");
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_init_rx_addrs_generic - Initialize receive address's
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setups the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ **/
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, UINT16 rar_count)
+{
+ UINT32 i;
+ UINT8 mac_addr[ETH_ADDR_LEN] = {0};
+
+ DEBUGFUNC("e1000_init_rx_addrs_generic");
+
+ /* Setup the receive address */
+ DEBUGOUT("Programming MAC Address into RAR[0]\n");
+
+ hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
+ for (i = 1; i < rar_count; i++)
+ hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
+ * e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
+ * @hw: pointer to the HW structure
+ *
+ * Checks the nvm for an alternate MAC address. An alternate MAC address
+ * can be setup by pre-boot software and must be treated like a permanent
+ * address and must override the actual permanent MAC address. If an
+ * alternate MAC address is found it is programmed into RAR0, replacing
+ * the permanent address that was installed into RAR0 by the Si on reset.
+ * This function will return SUCCESS unless it encounters an error while
+ * reading the EEPROM.
+ **/
+INT32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+ UINT32 i;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 offset, nvm_alt_mac_addr_offset, nvm_data;
+ UINT8 alt_mac_addr[ETH_ADDR_LEN];
+
+ DEBUGFUNC("e1000_check_alt_mac_addr_generic");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &nvm_data);
+ if (ret_val)
+ goto out;
+
+ if (!(nvm_data & NVM_COMPAT_LOM))
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+ &nvm_alt_mac_addr_offset);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (nvm_alt_mac_addr_offset == 0xFFFF) {
+ /* There is no Alternate MAC Address */
+ goto out;
+ }
+
+ if (hw->bus.func == E1000_FUNC_1)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+#ifndef NO_82580_SUPPORT
+ if (hw->bus.func == E1000_FUNC_2)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN2;
+
+ if (hw->bus.func == E1000_FUNC_3)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN3;
+#endif /* Barton Hills HW */
+ for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+ offset = nvm_alt_mac_addr_offset + (i >> 1);
+ ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ alt_mac_addr[i] = (UINT8)(nvm_data & 0xFF);
+ alt_mac_addr[i + 1] = (UINT8)(nvm_data >> 8);
+ }
+
+ /* if multicast bit is set, the alternate address will not be used */
+ if (alt_mac_addr[0] & 0x01) {
+ DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
+ goto out;
+ }
+
+ /*
+ * We have a valid alternate MAC address, and we want to treat it the
+ * same as the normal permanent MAC address stored by the HW into the
+ * RAR. Do this by mapping this address into RAR0.
+ */
+ hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_rar_set_generic - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr.
+ **/
+void e1000_rar_set_generic(struct e1000_hw *hw, UINT8 *addr, UINT32 index)
+{
+ UINT32 rar_low, rar_high;
+
+ DEBUGFUNC("e1000_rar_set_generic");
+
+ /*
+ * HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((UINT32) addr[0] |
+ ((UINT32) addr[1] << 8) |
+ ((UINT32) addr[2] << 16) | ((UINT32) addr[3] << 24));
+
+ rar_high = ((UINT32) addr[4] | ((UINT32) addr[5] << 8));
+
+ /* If MAC address zero, no need to set the AV bit */
+ if (rar_low || rar_high)
+ rar_high |= E1000_RAH_AV;
+
+ /*
+ * Some bridges will combine consecutive 32-bit writes into
+ * a single burst write, which will malfunction on some parts.
+ * The flushes avoid this.
+ */
+ E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_update_mc_addr_list_generic - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ *
+ * Updates entire Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+ UINT8 *mc_addr_list, UINT32 mc_addr_count)
+{
+ UINT32 hash_value, hash_bit, hash_reg;
+ int i;
+
+ DEBUGFUNC("e1000_update_mc_addr_list_generic");
+
+ /* clear mta_shadow */
+ SetMem (&hw->mac.mta_shadow, sizeof(hw->mac.mta_shadow), 0);
+
+ /* update mta_shadow from mc_addr_list */
+ for (i = 0; (UINT32) i < mc_addr_count; i++) {
+ hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
+
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+ mc_addr_list += (ETH_ADDR_LEN);
+ }
+
+ /* replace the entire MTA table */
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_hash_mc_addr_generic - Generate a multicast hash value
+ * @hw: pointer to the HW structure
+ * @mc_addr: pointer to a multicast address
+ *
+ * Generates a multicast address hash value which is used to determine
+ * the multicast filter table array address and new table value.
+ **/
+UINT32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, UINT8 *mc_addr)
+{
+ UINT32 hash_value, hash_mask;
+ UINT8 bit_shift = 0;
+
+ DEBUGFUNC("e1000_hash_mc_addr_generic");
+
+ /* Register count multiplied by bits per register */
+ hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+ /*
+ * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+ * where 0xFF would still fall within the hash mask.
+ */
+ while (hash_mask >> bit_shift != 0xFF)
+ bit_shift++;
+
+ /*
+ * The portion of the address that is used for the hash table
+ * is determined by the mc_filter_type setting.
+ * The algorithm is such that there is a total of 8 bits of shifting.
+ * The bit_shift for a mc_filter_type of 0 represents the number of
+ * left-shifts where the MSB of mc_addr[5] would still fall within
+ * the hash_mask. Case 0 does this exactly. Since there are a total
+ * of 8 bits of shifting, then mc_addr[4] will shift right the
+ * remaining number of bits. Thus 8 - bit_shift. The rest of the
+ * cases are a variation of this algorithm...essentially raising the
+ * number of bits to shift mc_addr[5] left, while still keeping the
+ * 8-bit shifting total.
+ *
+ * For example, given the following Destination MAC Address and an
+ * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+ * we can see that the bit_shift for case 0 is 4. These are the hash
+ * values resulting from each mc_filter_type...
+ * [0] [1] [2] [3] [4] [5]
+ * 01 AA 00 12 34 56
+ * LSB MSB
+ *
+ * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+ * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+ * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+ * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+ */
+ switch (hw->mac.mc_filter_type) {
+ default:
+ case 0:
+ break;
+ case 1:
+ bit_shift += 1;
+ break;
+ case 2:
+ bit_shift += 2;
+ break;
+ case 3:
+ bit_shift += 4;
+ break;
+ }
+
+ hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+ (((UINT16) mc_addr[5]) << bit_shift)));
+
+ return hash_value;
+}
+
+#ifndef NO_PCIX_SUPPORT
+/**
+ * e1000_pcix_mmrbc_workaround_generic - Fix incorrect MMRBC value
+ * @hw: pointer to the HW structure
+ *
+ * In certain situations, a system BIOS may report that the PCIx maximum
+ * memory read byte count (MMRBC) value is higher than than the actual
+ * value. We check the PCIx command register with the current PCIx status
+ * register.
+ **/
+void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw)
+{
+ UINT16 cmd_mmrbc;
+ UINT16 pcix_cmd;
+ UINT16 pcix_stat_hi_word;
+ UINT16 stat_mmrbc;
+
+ DEBUGFUNC("e1000_pcix_mmrbc_workaround_generic");
+
+ /* Workaround for PCI-X issue when BIOS sets MMRBC incorrectly */
+ if (hw->bus.type != e1000_bus_type_pcix)
+ return;
+
+ e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
+ e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
+ cmd_mmrbc = (pcix_cmd & PCIX_COMMAND_MMRBC_MASK) >>
+ PCIX_COMMAND_MMRBC_SHIFT;
+ stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+ PCIX_STATUS_HI_MMRBC_SHIFT;
+ if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+ stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+ if (cmd_mmrbc > stat_mmrbc) {
+ pcix_cmd &= ~PCIX_COMMAND_MMRBC_MASK;
+ pcix_cmd |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+ e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
+ }
+}
+
+#endif /* NO_PCIX_SUPPORT */
+/**
+ * e1000_clear_hw_cntrs_base_generic - Clear base hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_base_generic");
+
+ E1000_READ_REG(hw, E1000_CRCERRS);
+ E1000_READ_REG(hw, E1000_SYMERRS);
+ E1000_READ_REG(hw, E1000_MPC);
+ E1000_READ_REG(hw, E1000_SCC);
+ E1000_READ_REG(hw, E1000_ECOL);
+ E1000_READ_REG(hw, E1000_MCC);
+ E1000_READ_REG(hw, E1000_LATECOL);
+ E1000_READ_REG(hw, E1000_COLC);
+ E1000_READ_REG(hw, E1000_DC);
+ E1000_READ_REG(hw, E1000_SEC);
+ E1000_READ_REG(hw, E1000_RLEC);
+ E1000_READ_REG(hw, E1000_XONRXC);
+ E1000_READ_REG(hw, E1000_XONTXC);
+ E1000_READ_REG(hw, E1000_XOFFRXC);
+ E1000_READ_REG(hw, E1000_XOFFTXC);
+ E1000_READ_REG(hw, E1000_FCRUC);
+ E1000_READ_REG(hw, E1000_GPRC);
+ E1000_READ_REG(hw, E1000_BPRC);
+ E1000_READ_REG(hw, E1000_MPRC);
+ E1000_READ_REG(hw, E1000_GPTC);
+ E1000_READ_REG(hw, E1000_GORCL);
+ E1000_READ_REG(hw, E1000_GORCH);
+ E1000_READ_REG(hw, E1000_GOTCL);
+ E1000_READ_REG(hw, E1000_GOTCH);
+ E1000_READ_REG(hw, E1000_RNBC);
+ E1000_READ_REG(hw, E1000_RUC);
+ E1000_READ_REG(hw, E1000_RFC);
+ E1000_READ_REG(hw, E1000_ROC);
+ E1000_READ_REG(hw, E1000_RJC);
+ E1000_READ_REG(hw, E1000_TORL);
+ E1000_READ_REG(hw, E1000_TORH);
+ E1000_READ_REG(hw, E1000_TOTL);
+ E1000_READ_REG(hw, E1000_TOTH);
+ E1000_READ_REG(hw, E1000_TPR);
+ E1000_READ_REG(hw, E1000_TPT);
+ E1000_READ_REG(hw, E1000_MPTC);
+ E1000_READ_REG(hw, E1000_BPTC);
+}
+
+/**
+ * e1000_check_for_copper_link_generic - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed. If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ **/
+INT32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_check_for_copper_link");
+
+ /*
+ * We only want to go out to the PHY registers to see if Auto-Neg
+ * has completed and/or if our link status has changed. The
+ * get_link_status flag is set upon receiving a Link Status
+ * Change or Rx Sequence Error interrupt.
+ */
+ if (!mac->get_link_status) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ /*
+ * First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ goto out; /* No link detected */
+
+ mac->get_link_status = FALSE;
+
+ /*
+ * Check if there was DownShift, must be checked
+ * immediately after link-up
+ */
+ e1000_check_downshift_generic(hw);
+
+ /*
+ * If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if (!mac->autoneg) {
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ /*
+ * Auto-Neg is enabled. Auto Speed Detection takes care
+ * of MAC speed/duplex configuration. So we only need to
+ * configure Collision Distance in the MAC.
+ */
+ mac->ops.config_collision_dist(hw);
+
+ /*
+ * Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control
+ * settings because we may have had to re-autoneg with a
+ * different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val)
+ DEBUGOUT("Error configuring flow control\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_fiber_link_generic - Check for link (Fiber)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+INT32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 rxcw;
+ UINT32 ctrl;
+ UINT32 status;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_for_fiber_link_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+ /*
+ * If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), the cable is plugged in (we have signal),
+ * and our link partner is not trying to auto-negotiate with us (we
+ * are receiving idles or data), we need to force link up. We also
+ * need to give auto-negotiation time to complete, in case the cable
+ * was just plugged in. The autoneg_failed flag does this.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ goto out;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ goto out;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /*
+ * If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = TRUE;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_serdes_link_generic - Check for link (Serdes)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+INT32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 rxcw;
+ UINT32 ctrl;
+ UINT32 status;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_for_serdes_link_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+ /*
+ * If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), and our link partner is not trying to
+ * auto-negotiate with us (we are receiving idles or data),
+ * we need to force link up. We also need to give auto-negotiation
+ * time to complete.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ goto out;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ goto out;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /*
+ * If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = TRUE;
+ } else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
+ /*
+ * If we force link for non-auto-negotiation switch, check
+ * link status based on MAC synchronization for internal
+ * serdes media type.
+ */
+ /* SYNCH bit and IV bit are sticky. */
+ usec_delay(10);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+ if (rxcw & E1000_RXCW_SYNCH) {
+ if (!(rxcw & E1000_RXCW_IV)) {
+ mac->serdes_has_link = TRUE;
+ DEBUGOUT("SERDES: Link up - forced.\n");
+ }
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - force failed.\n");
+ }
+ }
+
+ if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_LU) {
+ /* SYNCH bit and IV bit are sticky, so reread rxcw. */
+ usec_delay(10);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+ if (rxcw & E1000_RXCW_SYNCH) {
+ if (!(rxcw & E1000_RXCW_IV)) {
+ mac->serdes_has_link = TRUE;
+ DEBUGOUT("SERDES: Link up - autoneg "
+ "completed sucessfully.\n");
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - invalid"
+ "codewords detected in autoneg.\n");
+ }
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - no sync.\n");
+ }
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - autoneg failed\n");
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_link_generic - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+INT32 e1000_setup_link_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_link_generic");
+
+ /*
+ * In the case of the phy reset being blocked, we already have a link.
+ * We do not need to set it up again.
+ */
+ if (e1000_check_reset_block(hw))
+ goto out;
+
+ /*
+ * If requested flow control is set to default, set flow control
+ * based on the EEPROM flow control settings.
+ */
+ if (hw->fc.requested_mode == e1000_fc_default) {
+ ret_val = e1000_set_default_fc_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Save off the requested flow control mode for use later. Depending
+ * on the link partner's capabilities, we may or may not use this mode.
+ */
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
+ hw->fc.current_mode);
+
+ /* Call the necessary media_type subroutine to configure the link. */
+ ret_val = hw->mac.ops.setup_physical_interface(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+ E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+ E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+
+ ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes
+ * links. Upon successful setup, poll for link.
+ **/
+INT32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ /* Take the link out of reset */
+ ctrl &= ~E1000_CTRL_LRST;
+
+ mac->ops.config_collision_dist(hw);
+
+ ret_val = e1000_commit_fc_settings_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Since auto-negotiation is enabled, take the link out of reset (the
+ * link will be in reset, because we previously reset the chip). This
+ * will restart auto-negotiation. If auto-negotiation is successful
+ * then the link-up status bit will be set and the flow control enable
+ * bits (RFCE and TFCE) will be set according to their negotiated value.
+ */
+ DEBUGOUT("Auto-negotiation enabled\n");
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+
+ /*
+ * For these adapters, the SW definable pin 1 is set when the optics
+ * detect a signal. If we have a signal, then poll for a "Link-Up"
+ * indication.
+ */
+ if (hw->phy.media_type == e1000_media_type_internal_serdes ||
+ (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
+ ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+ } else {
+ DEBUGOUT("No signal detected\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_config_collision_dist_generic - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup.
+ **/
+void e1000_config_collision_dist_generic(struct e1000_hw *hw)
+{
+ UINT32 tctl;
+
+ DEBUGFUNC("e1000_config_collision_dist_generic");
+
+ tctl = E1000_READ_REG(hw, E1000_TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_poll_fiber_serdes_link_generic - Poll for link up
+ * @hw: pointer to the HW structure
+ *
+ * Polls for link up by reading the status register, if link fails to come
+ * up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+STATIC INT32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 i, status;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_poll_fiber_serdes_link_generic");
+
+ /*
+ * If we have a signal (the cable is plugged in, or assumed TRUE for
+ * serdes media) then poll for a "Link-Up" indication in the Device
+ * Status Register. Time-out if a link isn't seen in 500 milliseconds
+ * seconds (Auto-negotiation should complete in less than 500
+ * milliseconds even if the other end is doing it in SW).
+ */
+ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+ msec_delay(10);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_LU)
+ break;
+ }
+ if (i == FIBER_LINK_UP_LIMIT) {
+ DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+ mac->autoneg_failed = 1;
+ /*
+ * AutoNeg failed to achieve a link, so we'll call
+ * mac->check_for_link. This routine will force the
+ * link up if we detect a signal. This will allow us to
+ * communicate with non-autonegotiating link partners.
+ */
+ ret_val = mac->ops.check_for_link(hw);
+ if (ret_val) {
+ DEBUGOUT("Error while checking for link\n");
+ goto out;
+ }
+ mac->autoneg_failed = 0;
+ } else {
+ mac->autoneg_failed = 0;
+ DEBUGOUT("Valid Link Found\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_commit_fc_settings_generic - Configure flow control
+ * @hw: pointer to the HW structure
+ *
+ * Write the flow control settings to the Transmit Config Word Register (TXCW)
+ * base on the flow control settings in e1000_mac_info.
+ **/
+STATIC INT32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 txcw;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_commit_fc_settings_generic");
+
+ /*
+ * Check for a software override of the flow control settings, and
+ * setup the device accordingly. If auto-negotiation is enabled, then
+ * software will have to set the "PAUSE" bits to the correct value in
+ * the Transmit Config Word Register (TXCW) and re-start auto-
+ * negotiation. However, if auto-negotiation is disabled, then
+ * software will have to manually configure the two flow control enable
+ * bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames,
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we
+ * do not support receiving pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) are enabled.
+ */
+ switch (hw->fc.current_mode) {
+ case e1000_fc_none:
+ /* Flow control completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /*
+ * Rx Flow control is enabled and Tx Flow control is disabled
+ * by a software over-ride. Since there really isn't a way to
+ * advertise that we are capable of Rx Pause ONLY, we will
+ * advertise that we support both symmetric and asymmetric Rx
+ * PAUSE. Later, we will disable the adapter's ability to send
+ * PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /*
+ * Tx Flow control is enabled, and Rx Flow control is disabled,
+ * by a software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /*
+ * Flow control (both Rx and Tx) is enabled by a software
+ * over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ break;
+ }
+
+ E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+ mac->txcw = txcw;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_fc_watermarks_generic - Set flow control high/low watermarks
+ * @hw: pointer to the HW structure
+ *
+ * Sets the flow control high/low threshold (watermark) registers. If
+ * flow control XON frame transmission is enabled, then set XON frame
+ * transmission as well.
+ **/
+INT32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw)
+{
+ UINT32 fcrtl = 0, fcrth = 0;
+
+ DEBUGFUNC("e1000_set_fc_watermarks_generic");
+
+ /*
+ * Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames is not enabled, then these
+ * registers will be set to 0.
+ */
+ if (hw->fc.current_mode & e1000_fc_tx_pause) {
+ /*
+ * We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
+ */
+ fcrtl = hw->fc.low_water;
+ if (hw->fc.send_xon)
+ fcrtl |= E1000_FCRTL_XONE;
+
+ fcrth = hw->fc.high_water;
+ }
+ E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
+ E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_default_fc_generic - Set flow control default values
+ * @hw: pointer to the HW structure
+ *
+ * Read the EEPROM for the default values for flow control and store the
+ * values.
+ **/
+STATIC INT32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 nvm_data;
+
+ DEBUGFUNC("e1000_set_default_fc_generic");
+
+ /*
+ * Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+ hw->fc.requested_mode = e1000_fc_none;
+ else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+ NVM_WORD0F_ASM_DIR)
+ hw->fc.requested_mode = e1000_fc_tx_pause;
+ else
+ hw->fc.requested_mode = e1000_fc_full;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_force_mac_fc_generic - Force the MAC's flow control settings
+ * @hw: pointer to the HW structure
+ *
+ * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
+ * device control register to reflect the adapter settings. TFCE and RFCE
+ * need to be explicitly set by software when a copper PHY is used because
+ * autonegotiation is managed by the PHY rather than the MAC. Software must
+ * also configure these bits when link is forced on a fiber connection.
+ **/
+INT32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_force_mac_fc_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ /*
+ * Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "hw->fc.current_mode" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+ DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
+
+ switch (hw->fc.current_mode) {
+ case e1000_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case e1000_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case e1000_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case e1000_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_config_fc_after_link_up_generic - Configures flow control after link
+ * @hw: pointer to the HW structure
+ *
+ * Checks the status of auto-negotiation after link up to ensure that the
+ * speed and duplex were not forced. If the link needed to be forced, then
+ * flow control needs to be forced also. If auto-negotiation is enabled
+ * and did not fail, then we configure flow control based on our link
+ * partner.
+ **/
+INT32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+ UINT16 speed, duplex;
+
+ DEBUGFUNC("e1000_config_fc_after_link_up_generic");
+
+ /*
+ * Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if (mac->autoneg_failed) {
+ if (hw->phy.media_type == e1000_media_type_fiber ||
+ hw->phy.media_type == e1000_media_type_internal_serdes)
+ ret_val = e1000_force_mac_fc_generic(hw);
+ } else {
+ if (hw->phy.media_type == e1000_media_type_copper)
+ ret_val = e1000_force_mac_fc_generic(hw);
+ }
+
+ if (ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ goto out;
+ }
+
+ /*
+ * Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+ /*
+ * Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ goto out;
+
+ if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+ DEBUGOUT("Copper PHY and Auto Neg "
+ "has not completed.\n");
+ goto out;
+ }
+
+ /*
+ * The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement
+ * Register (Address 4) and the Auto_Negotiation Base
+ * Page Ability Register (Address 5) to determine how
+ * flow control was negotiated.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
+ &mii_nway_adv_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
+ &mii_nway_lp_ability_reg);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ * Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | E1000_fc_full
+ *
+ */
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /*
+ * Now we need to check if the user selected Rx ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise Rx
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if (hw->fc.requested_mode == e1000_fc_full) {
+ hw->fc.current_mode = e1000_fc_full;
+ DEBUGOUT("Flow Control = FULL.\r\n");
+ } else {
+ hw->fc.current_mode = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = "
+ "Rx PAUSE frames only.\r\n");
+ }
+ }
+ /*
+ * For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ */
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = e1000_fc_tx_pause;
+ DEBUGOUT("Flow Control = Tx PAUSE frames only.\r\n");
+ }
+ /*
+ * For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ */
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = Rx PAUSE frames only.\r\n");
+ } else {
+ /*
+ * Per the IEEE spec, at this point flow control
+ * should be disabled.
+ */
+ hw->fc.current_mode = e1000_fc_none;
+ DEBUGOUT("Flow Control = NONE.\r\n");
+ }
+
+ /*
+ * Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+ if (ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ goto out;
+ }
+
+ if (duplex == HALF_DUPLEX)
+ hw->fc.current_mode = e1000_fc_none;
+
+ /*
+ * Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000_force_mac_fc_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Read the status register for the current speed/duplex and store the current
+ * speed and duplex for copper connections.
+ **/
+INT32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ UINT32 status;
+
+ DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic");
+
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ DEBUGOUT("1000 Mbs, ");
+ } else if (status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ DEBUGOUT("100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ DEBUGOUT("10 Mbs, ");
+ }
+
+ if (status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ DEBUGOUT("Half Duplex\n");
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Sets the speed and duplex to gigabit full duplex (the only possible option)
+ * for fiber/serdes links.
+ **/
+INT32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex)
+{
+ DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
+
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_hw_semaphore_generic - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+INT32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 timeout = hw->nvm.word_size + 1;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_generic");
+
+ /* Get the SW semaphore */
+ while (i < timeout) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ usec_delay(50);
+ i++;
+ }
+
+ if (i == timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ usec_delay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_generic(hw);
+ DEBUGOUT("Driver can't access the NVM\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_generic - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_generic");
+
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ * e1000_get_auto_rd_done_generic - Check for auto read completion
+ * @hw: pointer to the HW structure
+ *
+ * Check EEPROM for Auto Read done bit.
+ **/
+INT32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
+{
+ INT32 i = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_get_auto_rd_done_generic");
+
+ while (i < AUTO_READ_DONE_TIMEOUT) {
+ if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
+ break;
+ msec_delay(1);
+ i++;
+ }
+
+ if (i == AUTO_READ_DONE_TIMEOUT) {
+ DEBUGOUT("Auto read by HW from NVM has not completed.\n");
+ ret_val = -E1000_ERR_RESET;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_valid_led_default_generic - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+INT32 e1000_valid_led_default_generic(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_generic");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_id_led_init_generic -
+ * @hw: pointer to the HW structure
+ *
+ **/
+INT32 e1000_id_led_init_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ const UINT32 ledctl_mask = 0x000000FF;
+ const UINT32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+ const UINT32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+ UINT16 data, i, temp;
+ const UINT16 led_mask = 0x0F;
+
+ DEBUGFUNC("e1000_id_led_init_generic");
+
+ ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+ if (ret_val)
+ goto out;
+
+ mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+ mac->ledctl_mode1 = mac->ledctl_default;
+ mac->ledctl_mode2 = mac->ledctl_default;
+
+ for (i = 0; i < 4; i++) {
+ temp = (data >> (i << 2)) & led_mask;
+ switch (temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch (temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_led_generic - Configures SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This prepares the SW controllable LED for use and saves the current state
+ * of the LED so it can be later restored.
+ **/
+INT32 e1000_setup_led_generic(struct e1000_hw *hw)
+{
+ UINT32 ledctl;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_led_generic");
+
+ if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ if (hw->phy.media_type == e1000_media_type_fiber) {
+ ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+ hw->mac.ledctl_default = ledctl;
+ /* Turn off LED0 */
+ ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+ E1000_LEDCTL_LED0_BLINK |
+ E1000_LEDCTL_LED0_MODE_MASK);
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+ E1000_LEDCTL_LED0_MODE_SHIFT);
+ E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+ } else if (hw->phy.media_type == e1000_media_type_copper) {
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cleanup_led_generic - Set LED config to default operation
+ * @hw: pointer to the HW structure
+ *
+ * Remove the current LED configuration and set the LED configuration
+ * to the default value, saved from the EEPROM.
+ **/
+INT32 e1000_cleanup_led_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led_generic");
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_blink_led_generic - Blink LED
+ * @hw: pointer to the HW structure
+ *
+ * Blink the LEDs which are set to be on.
+ **/
+INT32 e1000_blink_led_generic(struct e1000_hw *hw)
+{
+ UINT32 ledctl_blink = 0;
+ UINT32 i;
+
+ DEBUGFUNC("e1000_blink_led_generic");
+
+ if (hw->phy.media_type == e1000_media_type_fiber) {
+ /* always blink LED0 for PCI-E fiber */
+ ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+ } else {
+ /*
+ * set the blink bit for each LED that's "on" (0x0E)
+ * in ledctl_mode2
+ */
+ ledctl_blink = hw->mac.ledctl_mode2;
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+ (i * 8));
+ }
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_on_generic - Turn LED on
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED on.
+ **/
+INT32 e1000_led_on_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_led_on_generic");
+
+ switch (hw->phy.media_type) {
+ case e1000_media_type_fiber:
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+ break;
+ default:
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_off_generic - Turn LED off
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED off.
+ **/
+INT32 e1000_led_off_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_led_off_generic");
+
+ switch (hw->phy.media_type) {
+ case e1000_media_type_fiber:
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+ break;
+ default:
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities
+ * @hw: pointer to the HW structure
+ * @no_snoop: bitmap of snoop events
+ *
+ * Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, UINT32 no_snoop)
+{
+ UINT32 gcr;
+
+ DEBUGFUNC("e1000_set_pcie_no_snoop_generic");
+
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+ if (hw->bus.type != e1000_bus_type_pci_express)
+ goto out;
+
+#endif
+ if (no_snoop) {
+ gcr = E1000_READ_REG(hw, E1000_GCR);
+ gcr &= ~(PCIE_NO_SNOOP_ALL);
+ gcr |= no_snoop;
+ E1000_WRITE_REG(hw, E1000_GCR, gcr);
+ }
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+out:
+#endif
+ return;
+}
+
+/**
+ * e1000_disable_pcie_master_generic - Disables PCI-express master access
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_SUCCESS if successful, else returns -10
+ * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ * the master requests to be disabled.
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests.
+ **/
+INT32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 timeout = MASTER_DISABLE_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_disable_pcie_master_generic");
+
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+ if (hw->bus.type != e1000_bus_type_pci_express)
+ goto out;
+
+#endif
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ while (timeout) {
+ if (!(E1000_READ_REG(hw, E1000_STATUS) &
+ E1000_STATUS_GIO_MASTER_ENABLE))
+ break;
+ usec_delay(100);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Master requests are pending.\n");
+ ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+ }
+
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+out:
+#endif
+ return ret_val;
+}
+
+/**
+ * e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing
+ * @hw: pointer to the HW structure
+ *
+ * Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000_reset_adaptive_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ DEBUGFUNC("e1000_reset_adaptive_generic");
+
+ if (!mac->adaptive_ifs) {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ goto out;
+ }
+
+ 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;
+ E1000_WRITE_REG(hw, E1000_AIT, 0);
+out:
+ return;
+}
+
+/**
+ * e1000_update_adaptive_generic - 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 e1000_update_adaptive_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ DEBUGFUNC("e1000_update_adaptive_generic");
+
+ if (!mac->adaptive_ifs) {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ goto out;
+ }
+
+ 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;
+ E1000_WRITE_REG(hw, 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;
+ E1000_WRITE_REG(hw, E1000_AIT, 0);
+ }
+ }
+out:
+ return;
+}
+
+/**
+ * e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings
+ * @hw: pointer to the HW structure
+ *
+ * Verify that when not using auto-negotiation that MDI/MDIx is correctly
+ * set, which is forced to MDI mode only.
+ **/
+STATIC INT32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_validate_mdi_setting_generic");
+
+ if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+ DEBUGOUT("Invalid MDI setting detected\n");
+ hw->phy.mdix = 1;
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+#ifndef NO_82575_SUPPORT
+
+/**
+ * e1000_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register
+ * @hw: pointer to the HW structure
+ * @reg: 32bit register offset such as E1000_SCTL
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes an address/data control type register. There are several of these
+ * and they all have the format address << 8 | data and bit 31 is polled for
+ * completion.
+ **/
+INT32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, UINT32 reg,
+ UINT32 offset, UINT8 data)
+{
+ UINT32 i, regvalue = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_8bit_ctrl_reg_generic");
+
+ /* Set up the address and data */
+ regvalue = ((UINT32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
+ E1000_WRITE_REG(hw, reg, regvalue);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+ usec_delay(5);
+ regvalue = E1000_READ_REG(hw, reg);
+ if (regvalue & E1000_GEN_CTL_READY)
+ break;
+ }
+ if (!(regvalue & E1000_GEN_CTL_READY)) {
+ DEBUGOUT1("Reg %08x did not indicate ready\n", reg);
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+#endif /* NO_82575_SUPPORT */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h
new file mode 100755
index 0000000..db43611
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h
@@ -0,0 +1,102 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_MAC_H_
+#define _E1000_MAC_H_
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+void e1000_init_mac_ops_generic(struct e1000_hw *hw);
+#ifndef NO_NULL_OPS_SUPPORT
+void e1000_null_mac_generic(struct e1000_hw *hw);
+INT32 e1000_null_ops_generic(struct e1000_hw *hw);
+INT32 e1000_null_link_info(struct e1000_hw *hw, UINT16 *s, UINT16 *d);
+BOOLEAN e1000_null_mng_mode(struct e1000_hw *hw);
+void e1000_null_update_mc(struct e1000_hw *hw, UINT8 *h, UINT32 a);
+void e1000_null_write_vfta(struct e1000_hw *hw, UINT32 a, UINT32 b);
+void e1000_null_rar_set(struct e1000_hw *hw, UINT8 *h, UINT32 a);
+#endif /* NO_NULL_OPS_SUPPORT */
+INT32 e1000_blink_led_generic(struct e1000_hw *hw);
+INT32 e1000_check_for_copper_link_generic(struct e1000_hw *hw);
+INT32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw);
+INT32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw);
+INT32 e1000_cleanup_led_generic(struct e1000_hw *hw);
+INT32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw);
+INT32 e1000_disable_pcie_master_generic(struct e1000_hw *hw);
+INT32 e1000_force_mac_fc_generic(struct e1000_hw *hw);
+INT32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw);
+#ifndef NO_PCI_SUPPORT
+INT32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw);
+#endif
+INT32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw);
+void e1000_set_lan_id_single_port(struct e1000_hw *hw);
+#ifndef NO_PCI_SUPPORT
+void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw);
+#endif
+INT32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
+INT32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+INT32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex);
+INT32 e1000_id_led_init_generic(struct e1000_hw *hw);
+INT32 e1000_led_on_generic(struct e1000_hw *hw);
+INT32 e1000_led_off_generic(struct e1000_hw *hw);
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+ UINT8 *mc_addr_list, UINT32 mc_addr_count);
+INT32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw);
+INT32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
+INT32 e1000_setup_led_generic(struct e1000_hw *hw);
+INT32 e1000_setup_link_generic(struct e1000_hw *hw);
+#ifndef NO_82575_SUPPORT
+INT32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, UINT32 reg,
+ UINT32 offset, UINT8 data);
+#endif
+
+UINT32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, UINT8 *mc_addr);
+
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
+void e1000_clear_vfta_generic(struct e1000_hw *hw);
+void e1000_config_collision_dist_generic(struct e1000_hw *hw);
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, UINT16 rar_count);
+void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw);
+void e1000_rar_set_generic(struct e1000_hw *hw, UINT8 *addr, UINT32 index);
+INT32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void e1000_reset_adaptive_generic(struct e1000_hw *hw);
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, UINT32 no_snoop);
+void e1000_update_adaptive_generic(struct e1000_hw *hw);
+void e1000_write_vfta_generic(struct e1000_hw *hw, UINT32 offset, UINT32 value);
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c
new file mode 100755
index 0000000..8e6f787
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c
@@ -0,0 +1,409 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+STATIC UINT8 e1000_calculate_checksum(UINT8 *buffer, UINT32 length);
+
+/**
+ * e1000_calculate_checksum - Calculate checksum for buffer
+ * @buffer: pointer to EEPROM
+ * @length: size of EEPROM to calculate a checksum for
+ *
+ * Calculates the checksum for some buffer on a specified length. The
+ * checksum calculated is returned.
+ **/
+STATIC UINT8 e1000_calculate_checksum(UINT8 *buffer, UINT32 length)
+{
+ UINT32 i;
+ UINT8 sum = 0;
+
+ DEBUGFUNC("e1000_calculate_checksum");
+
+ if (!buffer)
+ return 0;
+
+ for (i = 0; i < length; i++)
+ sum += buffer[i];
+
+ return (UINT8) (0 - sum);
+}
+
+/**
+ * e1000_mng_enable_host_if_generic - Checks host interface is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ * This function checks whether the HOST IF is enabled for command operation
+ * and also checks whether the previous command is completed. It busy waits
+ * in case of previous command is not completed.
+ **/
+INT32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
+{
+ UINT32 hicr;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT8 i;
+
+ DEBUGFUNC("e1000_mng_enable_host_if_generic");
+
+ if (!(hw->mac.arc_subsystem_valid)) {
+ DEBUGOUT("ARC subsystem not valid.\n");
+ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+ goto out;
+ }
+
+ /* Check that the host interface is enabled. */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ if ((hicr & E1000_HICR_EN) == 0) {
+ DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+ goto out;
+ }
+ /* check the previous command is completed */
+ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+ msec_delay_irq(1);
+ }
+
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+ DEBUGOUT("Previous command timeout failed .\n");
+ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_mng_mode_generic - Generic check management mode
+ * @hw: pointer to the HW structure
+ *
+ * Reads the firmware semaphore register and returns TRUE (>0) if
+ * manageability is enabled, else FALSE (0).
+ **/
+BOOLEAN e1000_check_mng_mode_generic(struct e1000_hw *hw)
+{
+ UINT32 fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ DEBUGFUNC("e1000_check_mng_mode_generic");
+
+
+ return (fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+}
+
+/**
+ * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on Tx
+ * @hw: pointer to the HW structure
+ *
+ * Enables packet filtering on transmit packets if manageability is enabled
+ * and host interface is enabled.
+ **/
+BOOLEAN e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
+{
+ struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+ UINT32 *buffer = (UINT32 *)&hw->mng_cookie;
+ UINT32 offset;
+ INT32 ret_val, hdr_csum, csum;
+ UINT8 i, len;
+
+ DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
+
+ hw->mac.tx_pkt_filtering = TRUE;
+
+ /* No manageability, no filtering */
+ if (!hw->mac.ops.check_mng_mode(hw)) {
+ hw->mac.tx_pkt_filtering = FALSE;
+ goto out;
+ }
+
+ /*
+ * If we can't read from the host interface for whatever
+ * reason, disable filtering.
+ */
+ ret_val = hw->mac.ops.mng_enable_host_if(hw);
+ if (ret_val != E1000_SUCCESS) {
+ hw->mac.tx_pkt_filtering = FALSE;
+ goto out;
+ }
+
+ /* Read in the header. Length and offset are in dwords. */
+ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+ offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+ for (i = 0; i < len; i++)
+ *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
+ offset + i);
+ hdr_csum = hdr->checksum;
+ hdr->checksum = 0;
+ csum = e1000_calculate_checksum((UINT8 *)hdr,
+ E1000_MNG_DHCP_COOKIE_LENGTH);
+ /*
+ * If either the checksums or signature don't match, then
+ * the cookie area isn't considered valid, in which case we
+ * take the safe route of assuming Tx filtering is enabled.
+ */
+ if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
+ hw->mac.tx_pkt_filtering = TRUE;
+ goto out;
+ }
+
+ /* Cookie area is valid, make the final check for filtering. */
+ if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
+ hw->mac.tx_pkt_filtering = FALSE;
+ goto out;
+ }
+
+out:
+ return hw->mac.tx_pkt_filtering;
+}
+
+/**
+ * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface
+ * @length: size of the buffer
+ *
+ * Writes the DHCP information to the host interface.
+ **/
+INT32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, UINT8 *buffer,
+ UINT16 length)
+{
+ struct e1000_host_mng_command_header hdr;
+ INT32 ret_val;
+ UINT32 hicr;
+
+ DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
+
+ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+ hdr.command_length = length;
+ hdr.reserved1 = 0;
+ hdr.reserved2 = 0;
+ hdr.checksum = 0;
+
+ /* Enable the host interface */
+ ret_val = hw->mac.ops.mng_enable_host_if(hw);
+ if (ret_val)
+ goto out;
+
+ /* Populate the host interface with the contents of "buffer". */
+ ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
+ sizeof(hdr), &(hdr.checksum));
+ if (ret_val)
+ goto out;
+
+ /* Write the manageability command header */
+ ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
+ if (ret_val)
+ goto out;
+
+ /* Tell the ARC a new command is pending. */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_mng_write_cmd_header_generic - Writes manageability command header
+ * @hw: pointer to the HW structure
+ * @hdr: pointer to the host interface command header
+ *
+ * Writes the command header after does the checksum calculation.
+ **/
+INT32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr)
+{
+ UINT16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+ DEBUGFUNC("e1000_mng_write_cmd_header_generic");
+
+ /* Write the whole command header structure with new checksum. */
+
+ hdr->checksum = e1000_calculate_checksum((UINT8 *)hdr, length);
+
+ length >>= 2;
+ /* Write the relevant command block into the ram area. */
+ for (i = 0; i < length; i++) {
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
+ *((UINT32 *) hdr + i));
+ E1000_WRITE_FLUSH(hw);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_mng_host_if_write_generic - Write to the manageability host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface buffer
+ * @length: size of the buffer
+ * @offset: location in the buffer to write to
+ * @sum: sum of the data (not checksum)
+ *
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient
+ * way. Also fills up the sum of the buffer in *buffer parameter.
+ **/
+INT32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, UINT8 *buffer,
+ UINT16 length, UINT16 offset, UINT8 *sum)
+{
+ UINT8 *tmp;
+ UINT8 *bufptr = buffer;
+ UINT32 data = 0;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 remaining, i, j, prev_bytes;
+
+ DEBUGFUNC("e1000_mng_host_if_write_generic");
+
+ /* sum = only sum of the data and it is not checksum */
+
+ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+ ret_val = -E1000_ERR_PARAM;
+ goto out;
+ }
+
+ tmp = (UINT8 *)&data;
+ prev_bytes = offset & 0x3;
+ offset >>= 2;
+
+ if (prev_bytes) {
+ data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
+ for (j = prev_bytes; j < sizeof(UINT32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
+ length -= j - prev_bytes;
+ offset++;
+ }
+
+ remaining = length & 0x3;
+ length -= remaining;
+
+ /* Calculate length in DWORDs */
+ length >>= 2;
+
+ /*
+ * The device driver writes the relevant command block into the
+ * ram area.
+ */
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < sizeof(UINT32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
+ data);
+ }
+ if (remaining) {
+ for (j = 0; j < sizeof(UINT32); j++) {
+ if (j < remaining)
+ *(tmp + j) = *bufptr++;
+ else
+ *(tmp + j) = 0;
+
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_enable_mng_pass_thru - 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.
+ **/
+BOOLEAN e1000_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+ UINT32 manc;
+ UINT32 fwsm, factps;
+ BOOLEAN ret_val = FALSE;
+
+ DEBUGFUNC("e1000_enable_mng_pass_thru");
+
+#ifndef NO_ASF_FIRMWARE_CHECK
+ if (!hw->mac.asf_firmware_present)
+ goto out;
+#endif
+
+ manc = E1000_READ_REG(hw, E1000_MANC);
+
+ if (!(manc & E1000_MANC_RCV_TCO_EN))
+ goto out;
+
+ if (hw->mac.has_fwsm) {
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+ factps = E1000_READ_REG(hw, E1000_FACTPS);
+
+ if (!(factps & E1000_FACTPS_MNGCG) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+ ret_val = TRUE;
+ goto out;
+ }
+#ifndef NO_82574_SUPPORT
+ } else if ((hw->mac.type == e1000_82574) ||
+ (hw->mac.type == e1000_82583)) {
+ UINT16 data;
+
+ factps = E1000_READ_REG(hw, E1000_FACTPS);
+ e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+
+ if (!(factps & E1000_FACTPS_MNGCG) &&
+ ((data & E1000_NVM_INIT_CTRL2_MNGM) ==
+ (e1000_mng_mode_pt << 13))) {
+ ret_val = TRUE;
+ goto out;
+ }
+#endif /* NO_82574_SUPPORT */
+ } else if ((manc & E1000_MANC_SMBUS_EN) &&
+ !(manc & E1000_MANC_ASF_EN)) {
+ ret_val = TRUE;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h
new file mode 100755
index 0000000..09e6867
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h
@@ -0,0 +1,87 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_MANAGE_H_
+#define _E1000_MANAGE_H_
+
+BOOLEAN e1000_check_mng_mode_generic(struct e1000_hw *hw);
+BOOLEAN e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
+INT32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
+INT32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, UINT8 *buffer,
+ UINT16 length, UINT16 offset, UINT8 *sum);
+INT32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr);
+INT32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
+ UINT8 *buffer, UINT16 length);
+BOOLEAN e1000_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+ e1000_mng_mode_none = 0,
+ e1000_mng_mode_asf,
+ e1000_mng_mode_pt,
+ e1000_mng_mode_ipmi,
+ e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG 0x20000000
+
+#define E1000_FWSM_MODE_MASK 0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
+
+#define E1000_VFTA_ENTRY_SHIFT 5
+#define E1000_VFTA_ENTRY_MASK 0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */
+
+#define E1000_HICR_EN 0x01 /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C 0x02
+#define E1000_HICR_SV 0x04 /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET 0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE 0x544D4149
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c
new file mode 100755
index 0000000..319e060
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c
@@ -0,0 +1,1063 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+STATIC void e1000_stop_nvm(struct e1000_hw *hw);
+STATIC void e1000_reload_nvm_generic(struct e1000_hw *hw);
+
+/**
+ * e1000_init_nvm_ops_generic - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Setups up the function pointers to no-op functions
+ **/
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ DEBUGFUNC("e1000_init_nvm_ops_generic");
+
+ /* Initialize function pointers */
+#ifndef NO_NULL_OPS_SUPPORT
+ nvm->ops.init_params = e1000_null_ops_generic;
+ nvm->ops.acquire = e1000_null_ops_generic;
+ nvm->ops.read = e1000_null_read_nvm;
+ nvm->ops.release = e1000_null_nvm_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ nvm->ops.reload = e1000_reload_nvm_generic;
+#ifndef NO_NULL_OPS_SUPPORT
+ nvm->ops.update = e1000_null_ops_generic;
+ nvm->ops.valid_led_default = e1000_null_led_default;
+ nvm->ops.validate = e1000_null_ops_generic;
+ nvm->ops.write = e1000_null_write_nvm;
+#endif /* NO_NULL_OPS_SUPPORT */
+}
+
+#ifndef NO_NULL_OPS_SUPPORT
+/**
+ * e1000_null_nvm_read - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_read_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c)
+{
+ DEBUGFUNC("e1000_null_read_nvm");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_nvm_generic - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_nvm_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_nvm_generic");
+ return;
+}
+
+/**
+ * e1000_null_led_default - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_led_default(struct e1000_hw *hw, UINT16 *data)
+{
+ DEBUGFUNC("e1000_null_led_default");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_write_nvm - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_write_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c)
+{
+ DEBUGFUNC("e1000_null_write_nvm");
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_NULL_OPS_SUPPORT */
+/**
+ * e1000_raise_eec_clk - Raise EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000_raise_eec_clk(struct e1000_hw *hw, UINT32 *eecd)
+{
+ *eecd = *eecd | E1000_EECD_SK;
+ E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_lower_eec_clk - Lower EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000_lower_eec_clk(struct e1000_hw *hw, UINT32 *eecd)
+{
+ *eecd = *eecd & ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ * @hw: pointer to the HW structure
+ * @data: data to send to the EEPROM
+ * @count: number of bits to shift out
+ *
+ * We need to shift 'count' bits out to the EEPROM. So, the value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_eec_bits(struct e1000_hw *hw, UINT16 data, UINT16 count)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT32 mask;
+
+ DEBUGFUNC("e1000_shift_out_eec_bits");
+
+ mask = 0x01 << (count - 1);
+#ifndef NO_MICROWIRE_SUPPORT
+ if (nvm->type == e1000_nvm_eeprom_microwire)
+ eecd &= ~E1000_EECD_DO;
+ else
+#endif /* NO_MICROWIRE_SUPPORT */
+ if (nvm->type == e1000_nvm_eeprom_spi)
+ eecd |= E1000_EECD_DO;
+
+ do {
+ eecd &= ~E1000_EECD_DI;
+
+ if (data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(nvm->delay_usec);
+
+ e1000_raise_eec_clk(hw, &eecd);
+ e1000_lower_eec_clk(hw, &eecd);
+
+ mask >>= 1;
+ } while (mask);
+
+ eecd &= ~E1000_EECD_DI;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ * @hw: pointer to the HW structure
+ * @count: number of bits to shift in
+ *
+ * In order to read a register from the EEPROM, we need to shift 'count' bits
+ * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+ * the EEPROM (setting the SK bit), and then reading the value of the data out
+ * "DO" bit. During this "shifting in" process the data in "DI" bit should
+ * always be clear.
+ **/
+static UINT16 e1000_shift_in_eec_bits(struct e1000_hw *hw, UINT16 count)
+{
+ UINT32 eecd;
+ UINT32 i;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_shift_in_eec_bits");
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for (i = 0; i < count; i++) {
+ data <<= 1;
+ e1000_raise_eec_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ eecd &= ~E1000_EECD_DI;
+ if (eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_eec_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/**
+ * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ * @hw: pointer to the HW structure
+ * @ee_reg: EEPROM flag for polling
+ *
+ * Polls the EEPROM status bit for either read or write completion based
+ * upon the value of 'ee_reg'.
+ **/
+INT32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+ UINT32 attempts = 100000;
+ UINT32 i, reg = 0;
+ INT32 ret_val = -E1000_ERR_NVM;
+
+ DEBUGFUNC("e1000_poll_eerd_eewr_done");
+
+ for (i = 0; i < attempts; i++) {
+ if (ee_reg == E1000_NVM_POLL_READ)
+ reg = E1000_READ_REG(hw, E1000_EERD);
+ else
+ reg = E1000_READ_REG(hw, E1000_EEWR);
+
+ if (reg & E1000_NVM_RW_REG_DONE) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+
+ usec_delay(5);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_acquire_nvm_generic - Generic request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+INT32 e1000_acquire_nvm_generic(struct e1000_hw *hw)
+{
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ INT32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_acquire_nvm_generic");
+
+ E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ while (timeout) {
+ if (eecd & E1000_EECD_GNT)
+ break;
+ usec_delay(5);
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ timeout--;
+ }
+
+ if (!timeout) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ DEBUGOUT("Could not acquire NVM grant\n");
+ ret_val = -E1000_ERR_NVM;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_standby_nvm - Return EEPROM to standby state
+ * @hw: pointer to the HW structure
+ *
+ * Return the EEPROM to a standby state.
+ **/
+static void e1000_standby_nvm(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ DEBUGFUNC("e1000_standby_nvm");
+
+#ifndef NO_MICROWIRE_SUPPORT
+ if (nvm->type == e1000_nvm_eeprom_microwire) {
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+
+ e1000_raise_eec_clk(hw, &eecd);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+
+ e1000_lower_eec_clk(hw, &eecd);
+ } else
+#endif /* NO_MICROWIRE_SUPPORT */
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+ }
+}
+
+/**
+ * e1000_stop_nvm - Terminate EEPROM command
+ * @hw: pointer to the HW structure
+ *
+ * Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+STATIC void e1000_stop_nvm(struct e1000_hw *hw)
+{
+ UINT32 eecd;
+
+ DEBUGFUNC("e1000_stop_nvm");
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+ /* Pull CS high */
+ eecd |= E1000_EECD_CS;
+ e1000_lower_eec_clk(hw, &eecd);
+#ifndef NO_MICROWIRE_SUPPORT
+ } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ e1000_raise_eec_clk(hw, &eecd);
+ e1000_lower_eec_clk(hw, &eecd);
+#endif /* NO_MICROWIRE_SUPPORT */
+ }
+}
+
+/**
+ * e1000_release_nvm_generic - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000_release_nvm_generic(struct e1000_hw *hw)
+{
+ UINT32 eecd;
+
+ DEBUGFUNC("e1000_release_nvm_generic");
+
+ e1000_stop_nvm(hw);
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ * @hw: pointer to the HW structure
+ *
+ * Setups the EEPROM for reading and writing.
+ **/
+static INT32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 timeout = 0;
+ UINT8 spi_stat_reg;
+
+ DEBUGFUNC("e1000_ready_nvm_eeprom");
+
+#ifndef NO_MICROWIRE_SUPPORT
+ if (nvm->type == e1000_nvm_eeprom_microwire) {
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ } else
+#endif /* NO_MICROWIRE_SUPPORT */
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ usec_delay(1);
+ timeout = NVM_MAX_RETRY_SPI;
+
+ /*
+ * Read "Status Register" repeatedly until the LSB is cleared.
+ * The EEPROM will signal that the command has been completed
+ * by clearing bit 0 of the internal status register. If it's
+ * not cleared within 'timeout', then error out.
+ */
+ while (timeout) {
+ e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+ hw->nvm.opcode_bits);
+ spi_stat_reg = (UINT8)e1000_shift_in_eec_bits(hw, 8);
+ if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+ break;
+
+ usec_delay(5);
+ e1000_standby_nvm(hw);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("SPI NVM Status error\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_MICROWIRE_SUPPORT
+/**
+ * e1000_read_nvm_microwire - Reads EEPROM's using microwire
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM.
+ **/
+INT32 e1000_read_nvm_microwire(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 i = 0;
+ INT32 ret_val;
+ UINT8 read_opcode = NVM_READ_OPCODE_MICROWIRE;
+
+ DEBUGFUNC("e1000_read_nvm_microwire");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ ret_val = nvm->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val)
+ goto release;
+
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (UINT16)(offset + i),
+ nvm->address_bits);
+
+ /*
+ * Read the data. For microwire, each word requires the
+ * overhead of setup and tear-down.
+ */
+ data[i] = e1000_shift_in_eec_bits(hw, 16);
+ e1000_standby_nvm(hw);
+ }
+
+release:
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+#endif /* NO_MICROWIRE_SUPPORT */
+/**
+ * e1000_read_nvm_eerd - Reads EEPROM using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+INT32 e1000_read_nvm_eerd(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 i, eerd = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_nvm_eerd");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * too many words for the offset, and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+ E1000_NVM_RW_REG_START;
+
+ E1000_WRITE_REG(hw, E1000_EERD, eerd);
+ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+ if (ret_val)
+ break;
+
+ data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
+ E1000_NVM_RW_REG_DATA);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_spi - Write to EEPROM using SPI
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * Writes data to EEPROM at offset using SPI interface.
+ *
+ * If e1000_update_nvm_checksum is not called after this function , the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+INT32 e1000_write_nvm_spi(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ INT32 ret_val;
+ UINT16 widx = 0;
+
+ DEBUGFUNC("e1000_write_nvm_spi");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ ret_val = nvm->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ while (widx < words) {
+ UINT8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val)
+ goto release;
+
+ e1000_standby_nvm(hw);
+
+ /* Send the WRITE ENABLE command (8 bit opcode) */
+ e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+ nvm->opcode_bits);
+
+ e1000_standby_nvm(hw);
+
+ /*
+ * Some SPI eeproms use the 8th address bit embedded in the
+ * opcode
+ */
+ if ((nvm->address_bits == 8) && (offset >= 128))
+ write_opcode |= NVM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+ e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (UINT16)((offset + widx) * 2),
+ nvm->address_bits);
+
+ /* Loop to allow for up to whole page write of eeprom */
+ while (widx < words) {
+ UINT16 word_out = data[widx];
+ word_out = (word_out >> 8) | (word_out << 8);
+ e1000_shift_out_eec_bits(hw, word_out, 16);
+ widx++;
+
+ if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+ e1000_standby_nvm(hw);
+ break;
+ }
+ }
+ }
+
+ msec_delay(10);
+release:
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_MICROWIRE_SUPPORT
+/**
+ * e1000_write_nvm_microwire - Writes EEPROM using microwire
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * Writes data to EEPROM at offset using microwire interface.
+ *
+ * If e1000_update_nvm_checksum is not called after this function , the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+INT32 e1000_write_nvm_microwire(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ INT32 ret_val;
+ UINT32 eecd;
+ UINT16 words_written = 0;
+ UINT16 widx = 0;
+
+ DEBUGFUNC("e1000_write_nvm_microwire");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ ret_val = nvm->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val)
+ goto release;
+
+ e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE,
+ (UINT16)(nvm->opcode_bits + 2));
+
+ e1000_shift_out_eec_bits(hw, 0, (UINT16)(nvm->address_bits - 2));
+
+ e1000_standby_nvm(hw);
+
+ while (words_written < words) {
+ e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE,
+ nvm->opcode_bits);
+
+ e1000_shift_out_eec_bits(hw, (UINT16)(offset + words_written),
+ nvm->address_bits);
+
+ e1000_shift_out_eec_bits(hw, data[words_written], 16);
+
+ e1000_standby_nvm(hw);
+
+ for (widx = 0; widx < 200; widx++) {
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ if (eecd & E1000_EECD_DO)
+ break;
+ usec_delay(50);
+ }
+
+ if (widx == 200) {
+ DEBUGOUT("NVM Write did not complete\n");
+ ret_val = -E1000_ERR_NVM;
+ goto release;
+ }
+
+ e1000_standby_nvm(hw);
+
+ words_written++;
+ }
+
+ e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE,
+ (UINT16)(nvm->opcode_bits + 2));
+
+ e1000_shift_out_eec_bits(hw, 0, (UINT16)(nvm->address_bits - 2));
+
+release:
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+#endif /* NO_MICROWIRE_SUPPORT */
+/**
+ * e1000_read_pba_string_generic - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ **/
+INT32 e1000_read_pba_string_generic(struct e1000_hw *hw, UINT8 *pba_num,
+ UINT32 pba_num_size)
+{
+ INT32 ret_val;
+ UINT16 nvm_data;
+ UINT16 pba_ptr;
+ UINT16 offset;
+ UINT16 length;
+
+ DEBUGFUNC("e1000_read_pba_string_generic");
+
+ if (pba_num == NULL) {
+ DEBUGOUT("PBA string buffer was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ /*
+ * if nvm_data is not ptr guard the PBA must be in legacy format which
+ * means pba_ptr is actually our second data word for the PBA number
+ * and we can decode it into an ascii string
+ */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ DEBUGOUT("NVM PBA number is not stored as string\n");
+
+ /* we will need 11 characters to store the PBA */
+ if (pba_num_size < 11) {
+ DEBUGOUT("PBA string buffer too small\n");
+ return E1000_ERR_NO_SPACE;
+ }
+
+ /* extract hex string from data and pba_ptr */
+ pba_num[0] = (nvm_data >> 12) & 0xF;
+ pba_num[1] = (nvm_data >> 8) & 0xF;
+ pba_num[2] = (nvm_data >> 4) & 0xF;
+ pba_num[3] = nvm_data & 0xF;
+ pba_num[4] = (pba_ptr >> 12) & 0xF;
+ pba_num[5] = (pba_ptr >> 8) & 0xF;
+ pba_num[6] = '-';
+ pba_num[7] = 0;
+ pba_num[8] = (pba_ptr >> 4) & 0xF;
+ pba_num[9] = pba_ptr & 0xF;
+
+ /* put a null character on the end of our string */
+ pba_num[10] = '\0';
+
+ /* switch all the data but the '-' to hex char */
+ for (offset = 0; offset < 10; offset++) {
+ if (pba_num[offset] < 0xA)
+ pba_num[offset] += '0';
+ else if (pba_num[offset] < 0x10)
+ pba_num[offset] += 'A' - 0xA;
+ }
+
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ DEBUGOUT("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+ /* check if pba_num buffer is big enough */
+ if (pba_num_size < (((UINT32)length * 2) - 1)) {
+ DEBUGOUT("PBA string buffer too small\n");
+ ret_val = E1000_ERR_NO_SPACE;
+ goto out;
+ }
+
+ /* trim pba length from start of string */
+ pba_ptr++;
+ length--;
+
+ for (offset = 0; offset < length; offset++) {
+ ret_val = hw->nvm.ops.read(hw, pba_ptr + offset, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+ pba_num[offset * 2] = (UINT8)(nvm_data >> 8);
+ pba_num[(offset * 2) + 1] = (UINT8)(nvm_data & 0xFF);
+ }
+ pba_num[offset * 2] = '\0';
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_pba_length_generic - Read device part number length
+ * @hw: pointer to the HW structure
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number length from the EEPROM and
+ * stores the value in pba_num_size.
+ **/
+INT32 e1000_read_pba_length_generic(struct e1000_hw *hw, UINT32 *pba_num_size)
+{
+ INT32 ret_val;
+ UINT16 nvm_data;
+ UINT16 pba_ptr;
+ UINT16 length;
+
+ DEBUGFUNC("e1000_read_pba_length_generic");
+
+ if (pba_num_size == NULL) {
+ DEBUGOUT("PBA buffer size was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ /* if data is not ptr guard the PBA must be in legacy format */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ *pba_num_size = 11;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ DEBUGOUT("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+
+ /*
+ * Convert from length in UINT16 values to UINT8 chars, add 1 for NULL,
+ * and subtract 2 because length field is included in length.
+ */
+ *pba_num_size = ((UINT32)length * 2) - 1;
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+/**
+ * e1000_read_pba_num_generic - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ **/
+INT32 e1000_read_pba_num_generic(struct e1000_hw *hw, UINT32 *pba_num)
+{
+ INT32 ret_val;
+ UINT16 nvm_data;
+
+ DEBUGFUNC("e1000_read_pba_num_generic");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ } else if (nvm_data == NVM_PBA_PTR_GUARD) {
+ DEBUGOUT("NVM Not Supported\n");
+ ret_val = E1000_NOT_IMPLEMENTED;
+ goto out;
+ }
+ *pba_num = (UINT32)(nvm_data << 16);
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+ *pba_num |= nvm_data;
+
+out:
+ return ret_val;
+}
+
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+/**
+ * e1000_read_mac_addr_generic - Read device MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the device MAC address from the EEPROM and stores the value.
+ * Since devices with two ports use the same EEPROM, we increment the
+ * last bit in the MAC address for the second port.
+ **/
+INT32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
+{
+ UINT32 rar_high;
+ UINT32 rar_low;
+ UINT16 i;
+
+ rar_high = E1000_READ_REG(hw, E1000_RAH(0));
+ rar_low = E1000_READ_REG(hw, E1000_RAL(0));
+
+ for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i] = (UINT8)(rar_low >> (i*8));
+
+ for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i+4] = (UINT8)(rar_high >> (i*8));
+
+ for (i = 0; i < ETH_ADDR_LEN; i++)
+ hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_validate_nvm_checksum_generic - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+INT32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 checksum = 0;
+ UINT16 i, nvm_data;
+
+ DEBUGFUNC("e1000_validate_nvm_checksum_generic");
+
+ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+
+ if (checksum != (UINT16) NVM_SUM) {
+ DEBUGOUT("NVM Checksum Invalid\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_generic - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+INT32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 checksum = 0;
+ UINT16 i, nvm_data;
+
+ DEBUGFUNC("e1000_update_nvm_checksum");
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error while updating checksum.\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (UINT16) NVM_SUM - checksum;
+ ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
+ if (ret_val)
+ DEBUGOUT("NVM Write Error while updating checksum.\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reload_nvm_generic - Reloads EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ * extended control register.
+ **/
+STATIC void e1000_reload_nvm_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl_ext;
+
+ DEBUGFUNC("e1000_reload_nvm_generic");
+
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h
new file mode 100755
index 0000000..56f497b
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h
@@ -0,0 +1,75 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_NVM_H_
+#define _E1000_NVM_H_
+
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw);
+#ifndef NO_NULL_OPS_SUPPORT
+INT32 e1000_null_read_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c);
+void e1000_null_nvm_generic(struct e1000_hw *hw);
+INT32 e1000_null_led_default(struct e1000_hw *hw, UINT16 *data);
+INT32 e1000_null_write_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c);
+#endif /* NO_NULL_OPS_SUPPORT */
+INT32 e1000_acquire_nvm_generic(struct e1000_hw *hw);
+
+INT32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+INT32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+INT32 e1000_read_pba_num_generic(struct e1000_hw *hw, UINT32 *pba_num);
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+INT32 e1000_read_pba_string_generic(struct e1000_hw *hw, UINT8 *pba_num,
+ UINT32 pba_num_size);
+INT32 e1000_read_pba_length_generic(struct e1000_hw *hw, UINT32 *pba_num_size);
+#ifndef NO_MICROWIRE_SUPPORT
+INT32 e1000_read_nvm_microwire(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+#endif
+INT32 e1000_read_nvm_eerd(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data);
+INT32 e1000_valid_led_default_generic(struct e1000_hw *hw, UINT16 *data);
+INT32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw);
+INT32 e1000_write_nvm_eewr(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+#ifndef NO_MICROWIRE_SUPPORT
+INT32 e1000_write_nvm_microwire(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+#endif
+INT32 e1000_write_nvm_spi(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data);
+INT32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw);
+void e1000_release_nvm_generic(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE 0xDB00
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c
new file mode 100755
index 0000000..b81eab2
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c
@@ -0,0 +1,693 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+
+INT32
+e1000_read_pcie_cap_reg(
+ struct e1000_hw *hw,
+ UINT32 reg,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ Reads from the PCI capabality region.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ reg - The register offset within the cap region.
+ value - The value at the register offset.
+
+Returns:
+ Error code
+
+--*/
+{
+ // Start at the first cap pointer of PCI space
+ UINT16 next_ptr_offset = PCI_CAP_PTR;
+ UINT16 next_ptr_value = 0;
+
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Keep only the first byte of the returned value
+ next_ptr_value &= 0xFF;
+ // Traverse the capabilities linked regions until the end
+ while (next_ptr_value != PCI_CAP_PTR_ENDPOINT)
+ {
+ next_ptr_offset = next_ptr_value;
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Check if we found the requested capabilities region
+ if ((next_ptr_value & 0xFF) != PCI_EX_CAP_ID)
+ {
+ // Jump to the next capabilities region
+ next_ptr_value &= 0xFF00;
+ next_ptr_value = next_ptr_value >> 8;
+ next_ptr_value &= 0xFF;
+ }
+ else
+ {
+ // Read the value from the request offset
+ e1000_read_pci_cfg(hw, next_ptr_offset + reg, &next_ptr_value);
+ *value = next_ptr_value;
+ return E1000_SUCCESS;
+ }
+ }
+ // The requested region was not found in PCI space
+ DEBUGPRINT(IO, ("Cap ID 0x10 was not found in PCI space.\n"));
+ return E1000_ERR_CONFIG;
+}
+
+#ifndef NO_PCIE_SUPPORT
+INT32
+e1000_write_pcie_cap_reg(
+ struct e1000_hw *hw,
+ UINT32 reg,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ Writes into the PCI capabality region.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ reg - The register offset within the cap region.
+ value - The value at the register offset.
+
+Returns:
+ Error code
+
+--*/
+{
+ // Start at the first cap pointer of PCI space
+ UINT16 next_ptr_offset = PCI_CAP_PTR;
+ UINT16 next_ptr_value = 0;
+
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Keep only the first byte of the returned value
+ next_ptr_value &= 0xFF;
+ // Traverse the capabilities linked regions until the end
+ while (next_ptr_value != PCI_CAP_PTR_ENDPOINT)
+ {
+ next_ptr_offset = next_ptr_value;
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Check if we found the requested capabilities region
+ if ((next_ptr_value & 0xFF) != PCI_EX_CAP_ID)
+ {
+ // Jump to the next capabilities region
+ next_ptr_value &= 0xFF00;
+ next_ptr_value = next_ptr_value >> 8;
+ next_ptr_value &= 0xFF;
+ }
+ else
+ {
+ // Write the value from the request offset
+ e1000_write_pci_cfg(hw, next_ptr_offset + reg, value);
+ return E1000_SUCCESS;
+ }
+ }
+ // The requested region was not found in PCI space
+ DEBUGPRINT(IO, ("Cap ID 0x10 was not found in PCI space.\n"));
+ return E1000_ERR_CONFIG;
+}
+#endif
+
+VOID
+e1000_write_reg_io(
+ struct e1000_hw *hw,
+ UINT32 offset,
+ UINT32 value
+ )
+/*++
+
+Routine Description:
+ Writes a value to one of the devices registers using port I/O (as opposed to
+ memory mapped I/O). Only 82544 and newer devices support port I/O.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ offset - The register offset to write.
+ value - The value to write to the register.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+
+ DEBUGPRINT(IO, ("e1000_write_reg_io\n"));
+ DEBUGPRINT(IO, ("IO bAR INDEX = %d\n", Adapter->IoBarIndex));
+ DEBUGWAIT(IO);
+
+ MemoryFence ();
+ Adapter->PciIo->Io.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ Adapter->IoBarIndex,
+ 0, // IO location offset
+ 1,
+ (VOID *) (&offset)
+ );
+ MemoryFence ();
+ Adapter->PciIo->Io.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ Adapter->IoBarIndex,
+ 4, // IO data offset
+ 1,
+ (VOID *) (&value)
+ );
+ MemoryFence ();
+ return;
+}
+
+VOID
+e1000_read_pci_cfg (
+ struct e1000_hw *hw,
+ UINT32 port,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ This function calls the EFI PCI IO protocol to read a value from the device's PCI
+ register space.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ Port - Which register to read from.
+ value - Returns the value read from the PCI register.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Pci.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ port,
+ 1,
+ (VOID *) value
+ );
+ MemoryFence ();
+ return ;
+}
+
+VOID
+e1000_write_pci_cfg (
+ struct e1000_hw *hw,
+ UINT32 port,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ This function calls the EFI PCI IO protocol to write a value to the device's PCI
+ register space.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ Port - Which register to write to.
+ value - Value to write to the PCI register.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Pci.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ port,
+ 1,
+ (VOID *) value
+ );
+ MemoryFence ();
+
+ return ;
+}
+
+VOID
+DelayInMicroseconds (
+ IN GIG_DRIVER_DATA *Adapter,
+ UINTN MicroSeconds
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+ MicroSeconds - Time to delay in Microseconds.
+
+Returns:
+
+--*/
+{
+ if (Adapter->Delay != NULL) {
+ (*Adapter->Delay) (Adapter->Unique_ID, MicroSeconds);
+ } else {
+ gBS->Stall(MicroSeconds);
+ }
+}
+
+VOID
+uSecDelay (
+ struct e1000_hw *hw,
+ UINTN usecs
+ )
+/*++
+
+Routine Description:
+ Delay a specified number of microseconds.
+
+Arguments:
+ hw - Pointer to hardware instance.
+ usecs - Number of microseconds to delay
+
+--*/
+{
+ DelayInMicroseconds(hw->back, usecs);
+}
+
+UINT32
+e1000_InDword (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+{
+ UINT32 Results;
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Mem.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ Port,
+ 1,
+ (VOID *) (&Results)
+ );
+ MemoryFence ();
+ return Results;
+}
+
+VOID
+e1000_OutDword (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+{
+ UINT32 Value;
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+ Value = Data;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Mem.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ Port,
+ 1,
+ (VOID *) (&Value)
+ );
+
+ MemoryFence ();
+ return ;
+}
+
+UINT32
+e1000_FlashRead (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+{
+ UINT32 Results;
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Mem.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Results)
+ );
+ MemoryFence ();
+ return Results;
+}
+
+
+UINT16
+e1000_FlashRead16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+{
+ UINT16 Results;
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Mem.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Results)
+ );
+ MemoryFence ();
+ return Results;
+}
+
+
+VOID
+e1000_FlashWrite (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+{
+ UINT32 Value;
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+ Value = Data;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Mem.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Value)
+ );
+
+ MemoryFence ();
+ return ;
+}
+
+VOID
+e1000_FlashWrite16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT16 Data
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+{
+ GIG_DRIVER_DATA *GigAdapter;
+
+ GigAdapter = hw->back;
+
+ MemoryFence ();
+
+ GigAdapter->PciIo->Mem.Write (
+ GigAdapter->PciIo,
+ EfiPciIoWidthUint16,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Data)
+ );
+
+ MemoryFence ();
+ return ;
+}
+
+VOID
+e1000_PciFlush (
+ IN struct e1000_hw *hw
+ )
+/*++
+
+Routine Description:
+ Flushes a PCI write transaction to system memory.
+
+Arguments:
+ hw - Pointer to hardware structure.
+
+Returns:
+ none
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Flush (Adapter->PciIo);
+
+ MemoryFence ();
+
+ return ;
+}
+
+VOID
+e1000_pci_set_mwi (
+ struct e1000_hw *hw
+ )
+/*++
+
+Routine Description:
+ Sets the memory write and invalidate bit in the device's PCI command register.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ UINT32 CommandReg;
+
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Pci.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+
+ CommandReg |= PCI_COMMAND_MWI;
+
+ Adapter->PciIo->Pci.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+ MemoryFence ();
+
+ return ;
+}
+
+VOID
+e1000_pci_clear_mwi (
+ struct e1000_hw *hw
+ )
+/*++
+
+Routine Description:
+ Clears the memory write and invalidate bit in the device's PCI command register.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ UINT32 CommandReg;
+
+ Adapter = hw->back;
+
+ Adapter->PciIo->Pci.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+
+ CommandReg &= ~PCI_COMMAND_MWI;
+
+ Adapter->PciIo->Pci.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+
+ return ;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h
new file mode 100755
index 0000000..39cda7e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h
@@ -0,0 +1,180 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_OSDEP_H_
+#define _E1000_OSDEP_H_
+
+#ifndef EFI_SPECIFICATION_VERSION
+#define EFI_SPECIFICATION_VERSION 0x00020000
+#endif
+
+#ifndef TIANO_RELEASE_VERSION
+#define TIANO_RELEASE_VERSION 0x00080005
+#endif
+
+struct e1000_hw;
+
+UINT32
+e1000_InDword (
+ struct e1000_hw *hw,
+ UINT32 Port
+ );
+
+VOID
+e1000_OutDword (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ );
+
+UINT32
+e1000_FlashRead (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ );
+
+UINT16
+e1000_FlashRead16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ );
+
+VOID
+e1000_FlashWrite (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ );
+
+VOID
+e1000_FlashWrite16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT16 Data
+ );
+
+VOID
+e1000_PciFlush (
+ struct e1000_hw *hw
+ );
+
+VOID
+uSecDelay (
+ struct e1000_hw *hw,
+ UINTN usecs
+ );
+
+VOID
+e1000_write_reg_io(
+ struct e1000_hw *hw,
+ UINT32 offset,
+ UINT32 value
+ );
+
+
+#define usec_delay(x) uSecDelay(hw, x)
+#define msec_delay(x) uSecDelay(hw, x*1000)
+#define msec_delay_irq(x) uSecDelay(hw, x*1000)
+#define memset(Buffer, Value, BufferLength) SetMem (Buffer, BufferLength, Value)
+
+#define CMD_MEM_WRT_INVALIDATE EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE
+
+typedef BOOLEAN BOOLEANean_t;
+
+
+#if (0)
+#define DEBUGFUNC(F)
+#define DEBUGOUT(s) Aprint(s);
+#define DEBUGOUT1(s,a) Aprint(s,a);
+#define DEBUGOUT2(s,a,b) Aprint(s,a,b);
+#define DEBUGOUT3(s,a,b,c) Aprint(s,a,b,c);
+#define DEBUGOUT7(s,a,b,c,d,e,f,g) Aprint(s,a,b,c,d,e,f,g);
+#else
+#define DEBUGFUNC(F)
+#define DEBUGOUT(s)
+#define DEBUGOUT1(s,a)
+#define DEBUGOUT2(s,a,b)
+#define DEBUGOUT3(s,a,b,c)
+#define DEBUGOUT7(s,a,b,c,d,e,f,g)
+#endif
+
+
+#define E1000_WRITE_REG(a, reg, value) \
+ e1000_OutDword(a, (UINT32)(reg), value)
+
+#define E1000_READ_REG(a, reg) \
+ e1000_InDword(a, (UINT32)(reg)) \
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+ e1000_OutDword(a, (UINT32)(reg + ((offset) << 2)), value)
+
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) \
+ e1000_OutDword(a, (UINT32)(reg + ((offset) << 2)), value) \
+
+#define E1000_WRITE_REG_ARRAY_DWORD(a, reg, offset, value) \
+ e1000_OutDword(a, (UINT32)(reg + ((offset) << 2)), value) \
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
+ e1000_InDword(a, (UINT32)(reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) \
+ e1000_InDword(a, (UINT32)(reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_DWORD(a, reg, offset) \
+ e1000_InDword(a, (UINT32)(reg + ((offset) << 2)))
+
+#define E1000_WRITE_FLUSH(a) e1000_PciFlush(a);
+
+#define E1000_WRITE_REG_IO(a, reg, value) \
+ e1000_write_reg_io(a, (UINT32) (reg), value)
+
+#define E1000_READ_FLASH_REG(a, reg) \
+ e1000_FlashRead(a, (UINT32)(reg))
+
+#define E1000_WRITE_FLASH_REG(a, reg, data) \
+ e1000_FlashWrite(a, (UINT32)(reg), data)
+
+#define E1000_READ_FLASH_REG16(a, reg) \
+ e1000_FlashRead16(a, (UINT32)(reg))
+
+#define E1000_WRITE_FLASH_REG16(a, reg, data) \
+ e1000_FlashWrite16(a, (UINT32)(reg), data)
+
+#define E1000_MUTEX UINT8
+#define E1000_MUTEX_INIT(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_DESTROY(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_LOCK(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_TRYLOCK(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_UNLOCK(mutex) UNREFERENCED_1PARAMETER(mutex)
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c
new file mode 100755
index 0000000..272fc3c
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c
@@ -0,0 +1,3579 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_copper_link_autoneg(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
+static UINT32 e1000_get_phy_addr_for_bm_page(UINT32 page, UINT32 reg);
+STATIC INT32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read);
+STATIC UINT32 e1000_get_phy_addr_for_hv_page(UINT32 page);
+STATIC INT32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read);
+
+/* Cable length tables */
+static const UINT16 e1000_m88_cable_length_table[] =
+ { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_m88_cable_length_table) / \
+ sizeof(e1000_m88_cable_length_table[0]))
+
+static const UINT16 e1000_igp_2_cable_length_table[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+ 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+ 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+ 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+ 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+ 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+ 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+ 104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_igp_2_cable_length_table) / \
+ sizeof(e1000_igp_2_cable_length_table[0]))
+
+#ifndef NO_NULL_OPS_SUPPORT
+/**
+ * e1000_init_phy_ops_generic - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Setups up the function pointers to no-op functions
+ **/
+void e1000_init_phy_ops_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ DEBUGFUNC("e1000_init_phy_ops_generic");
+
+ /* Initialize function pointers */
+ phy->ops.init_params = e1000_null_ops_generic;
+ phy->ops.acquire = e1000_null_ops_generic;
+ phy->ops.check_polarity = e1000_null_ops_generic;
+ phy->ops.check_reset_block = e1000_null_ops_generic;
+ phy->ops.commit = e1000_null_ops_generic;
+ phy->ops.force_speed_duplex = e1000_null_ops_generic;
+ phy->ops.get_cfg_done = e1000_null_ops_generic;
+ phy->ops.get_cable_length = e1000_null_ops_generic;
+ phy->ops.get_info = e1000_null_ops_generic;
+ phy->ops.read_reg = e1000_null_read_reg;
+ phy->ops.read_reg_locked = e1000_null_read_reg;
+ phy->ops.release = e1000_null_phy_generic;
+ phy->ops.reset = e1000_null_ops_generic;
+ phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
+ phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
+ phy->ops.write_reg = e1000_null_write_reg;
+ phy->ops.write_reg_locked = e1000_null_write_reg;
+ phy->ops.power_up = e1000_null_phy_generic;
+ phy->ops.power_down = e1000_null_phy_generic;
+#ifndef NO_80003ES2LAN_SUPPORT
+ phy->ops.cfg_on_link_up = e1000_null_ops_generic;
+#endif
+}
+
+/**
+ * e1000_null_read_reg - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_read_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ DEBUGFUNC("e1000_null_read_reg");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_phy_generic - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_phy_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_phy_generic");
+ return;
+}
+
+/**
+ * e1000_null_lplu_state - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_lplu_state(struct e1000_hw *hw, BOOLEAN active)
+{
+ DEBUGFUNC("e1000_null_lplu_state");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_write_reg - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_write_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ DEBUGFUNC("e1000_null_write_reg");
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_NULL_OPS_SUPPORT */
+/**
+ * e1000_check_reset_block_generic - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Read the PHY management control register and check whether a PHY reset
+ * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise
+ * return E1000_BLK_PHY_RESET (12).
+ **/
+INT32 e1000_check_reset_block_generic(struct e1000_hw *hw)
+{
+ UINT32 manc;
+
+ DEBUGFUNC("e1000_check_reset_block");
+
+ manc = E1000_READ_REG(hw, E1000_MANC);
+
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_phy_id - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+INT32 e1000_get_phy_id(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_id;
+ UINT16 retry_count = 0;
+
+ DEBUGFUNC("e1000_get_phy_id");
+
+ if (!(phy->ops.read_reg))
+ goto out;
+
+ while (retry_count < 2) {
+ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id = (UINT32)(phy_id << 16);
+ usec_delay(20);
+ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id |= (UINT32)(phy_id & PHY_REVISION_MASK);
+ phy->revision = (UINT32)(phy_id & ~PHY_REVISION_MASK);
+
+ if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
+ goto out;
+
+ retry_count++;
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_reset_dsp_generic - Reset PHY DSP
+ * @hw: pointer to the HW structure
+ *
+ * Reset the digital signal processor.
+ **/
+INT32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_phy_reset_dsp_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.write_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_mdic - Read MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control register in the PHY at offset and stores the
+ * information read to data.
+ **/
+INT32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, mdic = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_phy_reg_mdic");
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /*
+ * Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+ /* Workaround for Si errata */
+ if ((hw->phy.type == e1000_phy_82577) && (hw->revision_id <= 2))
+ msec_delay(10);
+
+ /*
+ * Poll the ready bit to see if the MDI read completed
+ * Increasing the time out as testing showed failures with
+ * the lower time out
+ */
+ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+ usec_delay(50);
+ mdic = E1000_READ_REG(hw, E1000_MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Read did not complete\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+ *data = (UINT16) mdic;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_mdic - Write MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ **/
+INT32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, mdic = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_phy_reg_mdic");
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /*
+ * Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = (((UINT32)data) |
+ (offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+ /* Workaround for Si errata */
+ if ((hw->phy.type == e1000_phy_82577) && (hw->revision_id <= 2))
+ msec_delay(10);
+
+ /*
+ * Poll the ready bit to see if the MDI read completed
+ * Increasing the time out as testing showed failures with
+ * the lower time out
+ */
+ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+ usec_delay(50);
+ mdic = E1000_READ_REG(hw, E1000_MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Write did not complete\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_82575_SUPPORT
+/**
+ * e1000_read_phy_reg_i2c - Read PHY register using i2c
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the i2c interface and stores the
+ * retrieved information in data.
+ **/
+INT32 e1000_read_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, i2ccmd = 0;
+
+ DEBUGFUNC("e1000_read_phy_reg_i2c");
+
+ /*
+ * Set up Op-code, Phy Address, and register address in the I2CCMD
+ * register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ (E1000_I2CCMD_OPCODE_READ));
+
+ E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit to see if the I2C read completed */
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ usec_delay(50);
+ i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+ if (i2ccmd & E1000_I2CCMD_READY)
+ break;
+ }
+ if (!(i2ccmd & E1000_I2CCMD_READY)) {
+ DEBUGOUT("I2CCMD Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (i2ccmd & E1000_I2CCMD_ERROR) {
+ DEBUGOUT("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Need to byte-swap the 16-bit value. */
+ *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_write_phy_reg_i2c - Write PHY register using i2c
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset using the i2c interface.
+ **/
+INT32 e1000_write_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, i2ccmd = 0;
+ UINT16 phy_data_swapped;
+
+ DEBUGFUNC("e1000_write_phy_reg_i2c");
+
+ /* Swap the data bytes for the I2C interface */
+ phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+
+ /*
+ * Set up Op-code, Phy Address, and register address in the I2CCMD
+ * register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ E1000_I2CCMD_OPCODE_WRITE |
+ phy_data_swapped);
+
+ E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit to see if the I2C read completed */
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ usec_delay(50);
+ i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+ if (i2ccmd & E1000_I2CCMD_READY)
+ break;
+ }
+ if (!(i2ccmd & E1000_I2CCMD_READY)) {
+ DEBUGOUT("I2CCMD Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (i2ccmd & E1000_I2CCMD_ERROR) {
+ DEBUGOUT("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_82575_SUPPORT */
+/**
+ * e1000_read_phy_reg_m88 - Read m88 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+INT32 e1000_read_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_phy_reg_m88");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_m88 - Write m88 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_phy_reg_m88");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * __e1000_read_phy_reg_igp - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and stores the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+static INT32 __e1000_read_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 *data,
+ BOOLEAN locked)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("__e1000_read_phy_reg_igp");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (UINT16)offset);
+ if (ret_val)
+ goto release;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+release:
+ if (!locked)
+ hw->phy.ops.release(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_igp - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset and stores the
+ * retrieved information in data.
+ * Release the acquired semaphore before exiting.
+ **/
+INT32 e1000_read_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_igp(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_read_phy_reg_igp_locked - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data. Assumes semaphore already acquired.
+ **/
+INT32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_igp(hw, offset, data, TRUE);
+}
+
+/**
+ * e1000_write_phy_reg_igp - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+static INT32 __e1000_write_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 data,
+ BOOLEAN locked)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_phy_reg_igp");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (UINT16)offset);
+ if (ret_val)
+ goto release;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+release:
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_igp - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_igp(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_write_phy_reg_igp_locked - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset.
+ * Assumes semaphore already acquired.
+ **/
+INT32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_igp(hw, offset, data, TRUE);
+}
+
+/**
+ * __e1000_read_kmrn_reg - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary. Then reads the PHY register at offset
+ * using the kumeran interface. The information retrieved is stored in data.
+ * Release any acquired semaphores before exiting.
+ **/
+static INT32 __e1000_read_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data,
+ BOOLEAN locked)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("__e1000_read_kmrn_reg");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
+ *data = (UINT16)kmrnctrlsta;
+
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_kmrn_reg_generic - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset using the
+ * kumeran interface. The information retrieved is stored in data.
+ * Release the acquired semaphore before exiting.
+ **/
+INT32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_kmrn_reg(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_read_kmrn_reg_locked - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the kumeran interface. The
+ * information retrieved is stored in data.
+ * Assumes semaphore already acquired.
+ **/
+INT32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_kmrn_reg(hw, offset, data, TRUE);
+}
+
+/**
+ * __e1000_write_kmrn_reg - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary. Then write the data to PHY register
+ * at the offset using the kumeran interface. Release any acquired semaphores
+ * before exiting.
+ **/
+static INT32 __e1000_write_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data,
+ BOOLEAN locked)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_kmrn_reg_generic");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | data;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_kmrn_reg_generic - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to the PHY register at the offset
+ * using the kumeran interface. Release the acquired semaphore before exiting.
+ **/
+INT32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_kmrn_reg(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_write_kmrn_reg_locked - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Write the data to PHY register at the offset using the kumeran interface.
+ * Assumes semaphore already acquired.
+ **/
+INT32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_kmrn_reg(hw, offset, data, TRUE);
+}
+
+/**
+ * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up Carrier-sense on Transmit and downshift values.
+ **/
+INT32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_copper_link_setup_82577");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (hw->phy.reset_disable) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+#endif /* NO_PHY_RESET_DISABLE */
+#ifndef NO_82580_SUPPORT
+ if (hw->phy.type == e1000_phy_82580) {
+ ret_val = hw->phy.ops.reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error resetting the PHY.\n");
+ goto out;
+ }
+ }
+
+#endif /* NO_82580_SUPPORT */
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = hw->phy.ops.read_reg(hw, I82577_CFG_REG, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
+
+ /* Enable downshift */
+ phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
+
+ ret_val = hw->phy.ops.write_reg(hw, I82577_CFG_REG, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock
+ * and downshift values are set also.
+ **/
+INT32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_copper_link_setup_m88");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (phy->reset_disable) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+#endif /* NO_PHY_RESET_DISABLE */
+
+ /* Enable CRS on Tx. This must be set for half-duplex operation. */
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ /* For BM PHY this bit is downshift enable */
+ if (phy->type == e1000_phy_bm)
+ phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /*
+ * Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (phy->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if (phy->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+ /* Enable downshift on BM (disabled by default) */
+ if (phy->type == e1000_phy_bm)
+ phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
+
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+#ifndef NO_82574_SUPPORT
+ if ((phy->type == e1000_phy_m88) &&
+ (phy->revision < E1000_REVISION_4) &&
+ (phy->id != BME1000_E_PHY_ID_R2)) {
+#else
+ if ((phy->type == e1000_phy_m88) && (phy->revision < E1000_REVISION_4)) {
+#endif /* NO_82574_SUPPORT */
+ /*
+ * Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((phy->revision == E1000_REVISION_2) &&
+ (phy->id == M88E1111_I_PHY_ID)) {
+ /* 82573L PHY - set the downshift counter to 5x. */
+ phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ }
+ ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val)
+ goto out;
+ }
+
+#ifndef NO_82574_SUPPORT
+ if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
+ /* Set PHY page 0, register 29 to 0x0003 */
+ ret_val = phy->ops.write_reg(hw, 29, 0x0003);
+ if (ret_val)
+ goto out;
+
+ /* Set PHY page 0, register 30 to 0x0000 */
+ ret_val = phy->ops.write_reg(hw, 30, 0x0000);
+ if (ret_val)
+ goto out;
+ }
+
+#endif /* NO_82574_SUPPORT */
+ /* Commit the changes. */
+ ret_val = phy->ops.commit(hw);
+ if (ret_val) {
+ DEBUGOUT("Error committing the PHY changes\n");
+ goto out;
+ }
+
+ if (phy->type == e1000_phy_82578) {
+ ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ /* 82578 PHY - set the downshift count to 1x. */
+ phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
+ phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
+ ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_setup_igp - Setup igp PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ * igp PHY's.
+ **/
+INT32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_copper_link_setup_igp");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (phy->reset_disable) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+#endif /* NO_PHY_RESET_DISABLE */
+
+ ret_val = hw->phy.ops.reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error resetting the PHY.\n");
+ goto out;
+ }
+
+ /*
+ * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+ * timeout issues when LFS is enabled.
+ */
+ msec_delay(100);
+
+ /* disable lplu d0 during driver init */
+ if (hw->phy.ops.set_d0_lplu_state) {
+ ret_val = hw->phy.ops.set_d0_lplu_state(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D0\n");
+ goto out;
+ }
+ }
+ /* Configure mdi-mdix settings */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+ switch (phy->mdix) {
+ case 1:
+ data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 2:
+ data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 0:
+ default:
+ data |= IGP01E1000_PSCR_AUTO_MDIX;
+ break;
+ }
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
+ if (ret_val)
+ goto out;
+
+ /* set auto-master slave resolution settings */
+ if (hw->mac.autoneg) {
+ /*
+ * when autonegotiation advertisement is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default.
+ */
+ if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Set auto Master/Slave resolution process */
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~CR_1000T_MS_ENABLE;
+ ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ /* load defaults for future use */
+ phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+ ((data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) :
+ e1000_ms_auto;
+
+ switch (phy->ms_type) {
+ case e1000_ms_force_master:
+ data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ data |= CR_1000T_MS_ENABLE;
+ data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ data &= ~CR_1000T_MS_ENABLE;
+ default:
+ break;
+ }
+ ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Performs initial bounds checking on autoneg advertisement parameter, then
+ * configure to advertise the full capability. Setup the PHY to autoneg
+ * and restart the negotiation process between the link partner. If
+ * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+STATIC INT32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_ctrl;
+
+ DEBUGFUNC("e1000_copper_link_autoneg");
+
+ /*
+ * Perform some bounds checking on the autoneg advertisement
+ * parameter.
+ */
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /*
+ * If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if (phy->autoneg_advertised == 0)
+ phy->autoneg_advertised = phy->autoneg_mask;
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ goto out;
+ }
+ DEBUGOUT("Restarting Auto-Neg\n");
+
+ /*
+ * Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if (phy->autoneg_wait_to_complete) {
+ ret_val = hw->mac.ops.wait_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error while waiting for "
+ "autoneg to complete\n");
+ goto out;
+ }
+ }
+
+ hw->mac.get_link_status = TRUE;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ * @hw: pointer to the HW structure
+ *
+ * Reads the MII auto-neg advertisement register and/or the 1000T control
+ * register and if the PHY is already setup for auto-negotiation, then
+ * return successful. Otherwise, setup advertisement and flow control to
+ * the appropriate values for the wanted auto-negotiation.
+ **/
+STATIC INT32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 mii_autoneg_adv_reg;
+ UINT16 mii_1000t_ctrl_reg = 0;
+
+ DEBUGFUNC("e1000_phy_setup_autoneg");
+
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if (ret_val)
+ goto out;
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
+ &mii_1000t_ctrl_reg);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /*
+ * First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+ NWAY_AR_100TX_HD_CAPS |
+ NWAY_AR_10T_FD_CAPS |
+ NWAY_AR_10T_HD_CAPS);
+ mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+ DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+ DEBUGOUT("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+ DEBUGOUT("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+ DEBUGOUT("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+ DEBUGOUT("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+ DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+ DEBUGOUT("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /*
+ * Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+ * negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->fc.current_mode) {
+ case e1000_fc_none:
+ /*
+ * Flow control (Rx & Tx) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_rx_pause:
+ /*
+ * Rx Flow control is enabled, and Tx Flow control is
+ * disabled, by a software over-ride.
+ *
+ * Since there really isn't a way to advertise that we are
+ * capable of Rx Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric Rx PAUSE. Later
+ * (in e1000_config_fc_after_link_up) we will disable the
+ * hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_tx_pause:
+ /*
+ * Tx Flow control is enabled, and Rx Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case e1000_fc_full:
+ /*
+ * Flow control (both Rx and Tx) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ ret_val = phy->ops.write_reg(hw,
+ PHY_1000T_CTRL,
+ mii_1000t_ctrl_reg);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_generic - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Calls the appropriate function to configure the link for auto-neg or forced
+ * speed and duplex. Then we check for link, once link is established calls
+ * to configure collision distance and flow control are called. If link is
+ * not established, we return -E1000_ERR_PHY (-2).
+ **/
+INT32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_setup_copper_link_generic");
+
+ if (hw->mac.autoneg) {
+ /*
+ * Setup autoneg and flow control advertisement and perform
+ * autonegotiation.
+ */
+ ret_val = e1000_copper_link_autoneg(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ /*
+ * PHY will be set to 10H, 10F, 100H or 100F
+ * depending on user settings.
+ */
+ DEBUGOUT("Forcing Speed and Duplex\n");
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Forcing Speed and Duplex\n");
+ goto out;
+ }
+ }
+
+ /*
+ * Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ ret_val = e1000_phy_has_link_generic(hw,
+ COPPER_LINK_UP_LIMIT,
+ 10,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (link) {
+ DEBUGOUT("Valid link established!!!\n");
+ e1000_config_collision_dist_generic(hw);
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ } else {
+ DEBUGOUT("Unable to establish link!!!\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Waits for link and returns
+ * successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+INT32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("IGP PSCR: %X\n", phy_data);
+
+ usec_delay(1);
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ DEBUGOUT("Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Resets the PHY to commit the
+ * changes. If time expires while waiting for link up, we reset the DSP.
+ * After reset, TX_CLK and CRS on Tx must be set. Return successful upon
+ * successful completion, else return corresponding error code.
+ **/
+INT32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
+
+ /*
+ * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ /* Reset the phy to commit changes. */
+ ret_val = hw->phy.ops.commit(hw);
+ if (ret_val)
+ goto out;
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ if (hw->phy.type != e1000_phy_m88) {
+ DEBUGOUT("Link taking longer than expected.\n");
+ } else {
+ /*
+ * We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = phy->ops.write_reg(hw,
+ M88E1000_PHY_PAGE_SELECT,
+ 0x001d);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_phy_reset_dsp_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+ }
+
+ if (hw->phy.type != e1000_phy_m88)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Resetting the phy means we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock from
+ * the reset value of 2.5MHz.
+ */
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
+ * @hw: pointer to the HW structure
+ *
+ * Forces the speed and duplex settings of the PHY.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+INT32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
+ if (ret_val)
+ goto out;
+
+ /* Disable MDI-X support for 10/100 */
+ ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IFE_PMC_AUTO_MDIX;
+ data &= ~IFE_PMC_FORCE_MDIX;
+
+ ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("IFE PMC: %X\n", data);
+
+ usec_delay(1);
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ DEBUGOUT("Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ * @hw: pointer to the HW structure
+ * @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ * Forces speed and duplex on the PHY by doing the following: disable flow
+ * control, force speed/duplex on the MAC, disable auto speed detection,
+ * disable auto-negotiation, configure duplex, configure speed, configure
+ * the collision distance, write configuration to CTRL register. The
+ * caller must write to the PHY_CONTROL register for these settings to
+ * take affect.
+ **/
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, UINT16 *phy_ctrl)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
+
+ /* Turn off flow control when forcing speed/duplex */
+ hw->fc.current_mode = e1000_fc_none;
+
+ /* Force speed/duplex on the mac */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~E1000_CTRL_SPD_SEL;
+
+ /* Disable Auto Speed Detection */
+ ctrl &= ~E1000_CTRL_ASDE;
+
+ /* Disable autoneg on the phy */
+ *phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Forcing Full or Half Duplex? */
+ if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+ ctrl &= ~E1000_CTRL_FD;
+ *phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Half Duplex\n");
+ } else {
+ ctrl |= E1000_CTRL_FD;
+ *phy_ctrl |= MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ }
+
+ /* Forcing 10mb or 100mb? */
+ if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+ ctrl |= E1000_CTRL_SPD_100;
+ *phy_ctrl |= MII_CR_SPEED_100;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ DEBUGOUT("Forcing 100mb\n");
+ } else {
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ *phy_ctrl |= MII_CR_SPEED_10;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ DEBUGOUT("Forcing 10mb\n");
+ }
+
+ e1000_config_collision_dist_generic(hw);
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+}
+
+/**
+ * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: BOOLEANean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained.
+ **/
+INT32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d3_lplu_state_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ goto out;
+
+ if (!active) {
+ data &= ~IGP02E1000_PM_D3_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ data |= IGP02E1000_PM_D3_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_downshift_generic - Checks whether a downshift in speed occurred
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * A downshift is detected by querying the PHY link health.
+ **/
+INT32 e1000_check_downshift_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, offset, mask;
+
+ DEBUGFUNC("e1000_check_downshift_generic");
+
+ switch (phy->type) {
+ case e1000_phy_m88:
+ case e1000_phy_gg82563:
+ case e1000_phy_bm:
+ case e1000_phy_82578:
+ offset = M88E1000_PHY_SPEC_STATUS;
+ mask = M88E1000_PSSR_DOWNSHIFT;
+ break;
+ case e1000_phy_igp_2:
+ case e1000_phy_igp_3:
+ offset = IGP01E1000_PHY_LINK_HEALTH;
+ mask = IGP01E1000_PLHR_SS_DOWNGRADE;
+ break;
+ default:
+ /* speed downshift not supported */
+ phy->speed_downgraded = FALSE;
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->speed_downgraded = (phy_data & mask) ? TRUE : FALSE;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_m88 - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY specific status register.
+ **/
+INT32 e1000_check_polarity_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_check_polarity_m88");
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_igp - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY port status register, and the
+ * current speed (since there is no polarity at 100Mbps).
+ **/
+INT32 e1000_check_polarity_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data, offset, mask;
+
+ DEBUGFUNC("e1000_check_polarity_igp");
+
+ /*
+ * Polarity is determined based on the speed of
+ * our connection.
+ */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ offset = IGP01E1000_PHY_PCS_INIT_REG;
+ mask = IGP01E1000_PHY_POLARITY_MASK;
+ } else {
+ /*
+ * This really only applies to 10Mbps since
+ * there is no polarity for 100Mbps (always 0).
+ */
+ offset = IGP01E1000_PHY_PORT_STATUS;
+ mask = IGP01E1000_PSSR_POLARITY_REVERSED;
+ }
+
+ ret_val = phy->ops.read_reg(hw, offset, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_ife - Check cable polarity for IFE PHY
+ * @hw: pointer to the HW structure
+ *
+ * Polarity is determined on the polarity reversal feature being enabled.
+ **/
+INT32 e1000_check_polarity_ife(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, offset, mask;
+
+ DEBUGFUNC("e1000_check_polarity_ife");
+
+ /*
+ * Polarity is determined based on the reversal feature being enabled.
+ */
+ if (phy->polarity_correction) {
+ offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+ mask = IFE_PESC_POLARITY_REVERSED;
+ } else {
+ offset = IFE_PHY_SPECIAL_CONTROL;
+ mask = IFE_PSC_FORCE_POLARITY;
+ }
+
+ ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->cable_polarity = (phy_data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_wait_autoneg_generic - Wait for auto-neg completion
+ * @hw: pointer to the HW structure
+ *
+ * Waits for auto-negotiation to complete or for the auto-negotiation time
+ * limit to expire, which ever happens first.
+ **/
+INT32 e1000_wait_autoneg_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i, phy_status;
+
+ DEBUGFUNC("e1000_wait_autoneg_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ return E1000_SUCCESS;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+ for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_AUTONEG_COMPLETE)
+ break;
+ msec_delay(100);
+ }
+
+ /*
+ * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+ * has completed.
+ */
+ return ret_val;
+}
+
+/**
+ * e1000_phy_has_link_generic - Polls PHY for link
+ * @hw: pointer to the HW structure
+ * @iterations: number of times to poll for link
+ * @usec_interval: delay between polling attempts
+ * @success: pointer to whether polling was successful or not
+ *
+ * Polls the PHY status register for link, 'iterations' number of times.
+ **/
+INT32 e1000_phy_has_link_generic(struct e1000_hw *hw, UINT32 iterations,
+ UINT32 usec_interval, BOOLEAN *success)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i, phy_status;
+
+ DEBUGFUNC("e1000_phy_has_link_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ return E1000_SUCCESS;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ for (i = 0; i < iterations; i++) {
+ /*
+ * Some PHYs require the PHY_STATUS register to be read
+ * twice due to the link bit being sticky. No harm doing
+ * it across the board.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ /*
+ * If the first read fails, another entity may have
+ * ownership of the resources, wait and try again to
+ * see if they have relinquished the resources yet.
+ */
+ usec_delay(usec_interval);
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_LINK_STATUS)
+ break;
+ if (usec_interval >= 1000)
+ msec_delay_irq(usec_interval/1000);
+ else
+ usec_delay(usec_interval);
+ }
+
+ *success = (i < iterations) ? TRUE : FALSE;
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_m88 - Determine cable length for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY specific status register to retrieve the cable length
+ * information. The cable length is determined by averaging the minimum and
+ * maximum values to get the "average" cable length. The m88 PHY has four
+ * possible cable length values, which are:
+ * Register Value Cable Length
+ * 0 < 50 meters
+ * 1 50 - 80 meters
+ * 2 80 - 110 meters
+ * 3 110 - 140 meters
+ * 4 > 140 meters
+ **/
+INT32 e1000_get_cable_length_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, index;
+
+ DEBUGFUNC("e1000_get_cable_length_m88");
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ phy->min_cable_length = e1000_m88_cable_length_table[index];
+ phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ * @hw: pointer to the HW structure
+ *
+ * The automatic gain control (agc) normalizes the amplitude of the
+ * received signal, adjusting for the attenuation produced by the
+ * cable. By reading the AGC registers, which represent the
+ * combination of coarse and fine gain value, the value can be put
+ * into a lookup table to obtain the approximate cable length
+ * for each channel.
+ **/
+INT32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data, i, agc_value = 0;
+ UINT16 cur_agc_index, max_agc_index = 0;
+ UINT16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+ UINT16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+ {IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D};
+
+ DEBUGFUNC("e1000_get_cable_length_igp_2");
+
+ /* Read the AGC registers for all channels */
+ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Getting bits 15:9, which represent the combination of
+ * coarse and fine gain values. The result is a number
+ * that can be put into the lookup table to obtain the
+ * approximate cable length.
+ */
+ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
+
+ /* Array index bound check. */
+ if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+ (cur_agc_index == 0)) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc_index] >
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ min_agc_index = cur_agc_index;
+ if (e1000_igp_2_cable_length_table[max_agc_index] <
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ max_agc_index = cur_agc_index;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+ }
+
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+ e1000_igp_2_cable_length_table[max_agc_index]);
+ agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+ /* Calculate cable length with the error range of +/- 10 meters. */
+ phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_m88 - Retrieve PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Valid for only copper links. Read the PHY status register (sticky read)
+ * to verify that link is up. Read the PHY special control register to
+ * determine the polarity and 10base-T extended distance. Read the PHY
+ * special status register to determine MDI/MDIx and current speed. If
+ * speed is 1000, then determine cable length, local and remote receiver.
+ **/
+INT32 e1000_get_phy_info_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_m88");
+
+ if (phy->media_type != e1000_media_type_copper) {
+ DEBUGOUT("Phy info is only valid for copper media\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+ ? TRUE : FALSE;
+
+ ret_val = e1000_check_polarity_m88(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? TRUE : FALSE;
+
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+ ret_val = hw->phy.ops.get_cable_length(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ /* Set values to "undefined" */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_igp - Retrieve igp PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up. If link is up, then
+ * set/determine 10base-T extended distance and polarity correction. Read
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ **/
+INT32 e1000_get_phy_info_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_igp");
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ phy->polarity_correction = TRUE;
+
+ ret_val = e1000_check_polarity_igp(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? TRUE : FALSE;
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ ret_val = phy->ops.get_cable_length(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_ife - Retrieves various IFE PHY states
+ * @hw: pointer to the HW structure
+ *
+ * Populates "phy" structure with various feature states.
+ **/
+INT32 e1000_get_phy_info_ife(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_ife");
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+ if (ret_val)
+ goto out;
+ phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
+ ? FALSE : TRUE;
+
+ if (phy->polarity_correction) {
+ ret_val = e1000_check_polarity_ife(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ /* Polarity is forced */
+ phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+ }
+
+ ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? TRUE : FALSE;
+
+ /* The following parameters are undefined for 10/100 operation. */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_sw_reset_generic - PHY software reset
+ * @hw: pointer to the HW structure
+ *
+ * Does a software reset of the PHY by reading the PHY control register and
+ * setting/write the control register reset bit to the PHY.
+ **/
+INT32 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_ctrl;
+
+ DEBUGFUNC("e1000_phy_sw_reset_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ phy_ctrl |= MII_CR_RESET;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ usec_delay(1);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_hw_reset_generic - PHY hardware reset
+ * @hw: pointer to the HW structure
+ *
+ * Verify the reset block is not blocking us from resetting. Acquire
+ * semaphore (if necessary) and read/set/write the device control reset
+ * bit in the PHY. Wait the appropriate delay time for the device to
+ * reset and release the semaphore (if necessary).
+ **/
+INT32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_phy_hw_reset_generic");
+
+ ret_val = phy->ops.check_reset_block(hw);
+ if (ret_val) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ ret_val = phy->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(phy->reset_delay_us);
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(150);
+
+ phy->ops.release(hw);
+
+ ret_val = phy->ops.get_cfg_done(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cfg_done_generic - Generic configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Generic function to wait 10 milli-seconds for configuration to complete
+ * and return success.
+ **/
+INT32 e1000_get_cfg_done_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_get_cfg_done_generic");
+
+ msec_delay_irq(10);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_phy_init_script_igp3 - Inits the IGP3 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+INT32 e1000_phy_init_script_igp3(struct e1000_hw *hw)
+{
+ DEBUGOUT("Running IGP 3 PHY init script\n");
+
+ /* PHY init IGP 3 */
+ /* Enable rise/fall, 10-mode work in class-A */
+ hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
+ /* Remove all caps from Replica path filter */
+ hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
+ /* Bias trimming for ADC, AFE and Driver (Default) */
+ hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
+ /* Increase Hybrid poly bias */
+ hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
+ /* Add 4% to Tx amplitude in Gig mode */
+ hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
+ /* Disable trimming (TTT) */
+ hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
+ /* Poly DC correction to 94.6% + 2% for all channels */
+ hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
+ /* ABS DC correction to 95.9% */
+ hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
+ /* BG temp curve trim */
+ hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
+ /* Increasing ADC OPAMP stage 1 currents to max */
+ hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
+ /* Force 1000 ( required for enabling PHY regs configuration) */
+ hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
+ /* Set upd_freq to 6 */
+ hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
+ /* Disable NPDFE */
+ hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
+ /* Disable adaptive fixed FFE (Default) */
+ hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
+ /* Enable FFE hysteresis */
+ hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
+ /* Fixed FFE for short cable lengths */
+ hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
+ /* Fixed FFE for medium cable lengths */
+ hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
+ /* Fixed FFE for long cable lengths */
+ hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
+ /* Enable Adaptive Clip Threshold */
+ hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
+ /* AHT reset limit to 1 */
+ hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
+ /* Set AHT master delay to 127 msec */
+ hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
+ /* Set scan bits for AHT */
+ hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
+ /* Set AHT Preset bits */
+ hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
+ /* Change integ_factor of channel A to 3 */
+ hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
+ /* Change prop_factor of channels BCD to 8 */
+ hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
+ /* Change cg_icount + enable integbp for channels BCD */
+ hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
+ /*
+ * Change cg_icount + enable integbp + change prop_factor_master
+ * to 8 for channel A
+ */
+ hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
+ /* Disable AHT in Slave mode on channel A */
+ hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
+ /*
+ * Enable LPLU and disable AN to 1000 in non-D0a states,
+ * Enable SPD+B2B
+ */
+ hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
+ /* Enable restart AN on an1000_dis change */
+ hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
+ /* Enable wh_fifo read clock in 10/100 modes */
+ hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
+ /* Restart AN, Speed selection is 1000 */
+ hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_phy_type_from_id - Get PHY type from id
+ * @phy_id: phy_id read from the phy
+ *
+ * Returns the phy type from the id.
+ **/
+enum e1000_phy_type e1000_get_phy_type_from_id(UINT32 phy_id)
+{
+ enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+ switch (phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1000_E_PHY_ID:
+ case M88E1111_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+ phy_type = e1000_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+ phy_type = e1000_phy_igp_2;
+ break;
+ case GG82563_E_PHY_ID:
+ phy_type = e1000_phy_gg82563;
+ break;
+ case IGP03E1000_E_PHY_ID:
+ phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy_type = e1000_phy_ife;
+ break;
+ case BME1000_E_PHY_ID:
+ case BME1000_E_PHY_ID_R2:
+ phy_type = e1000_phy_bm;
+ break;
+ case I82578_E_PHY_ID:
+ phy_type = e1000_phy_82578;
+ break;
+ case I82577_E_PHY_ID:
+ phy_type = e1000_phy_82577;
+ break;
+ case I82579_E_PHY_ID:
+ phy_type = e1000_phy_82579;
+ break;
+#ifndef NO_82580_SUPPORT
+ case I82580_I_PHY_ID:
+ phy_type = e1000_phy_82580;
+ break;
+#endif /* NO_82580_SUPPORT */
+ default:
+ phy_type = e1000_phy_unknown;
+ break;
+ }
+ return phy_type;
+}
+
+/**
+ * e1000_determine_phy_address - Determines PHY address.
+ * @hw: pointer to the HW structure
+ *
+ * This uses a trial and error method to loop through possible PHY
+ * addresses. It tests each by reading the PHY ID registers and
+ * checking for a match.
+ **/
+INT32 e1000_determine_phy_address(struct e1000_hw *hw)
+{
+ INT32 ret_val = -E1000_ERR_PHY_TYPE;
+ UINT32 phy_addr = 0;
+ UINT32 i;
+ enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+ hw->phy.id = phy_type;
+
+ for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
+ hw->phy.addr = phy_addr;
+ i = 0;
+
+ do {
+ e1000_get_phy_id(hw);
+ phy_type = e1000_get_phy_type_from_id(hw->phy.id);
+
+ /*
+ * If phy_type is valid, break - we found our
+ * PHY address
+ */
+ if (phy_type != e1000_phy_unknown) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+ msec_delay(1);
+ i++;
+ } while (i < 10);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_addr_for_bm_page - Retrieve PHY page address
+ * @page: page to access
+ *
+ * Returns the phy address for the page requested.
+ **/
+static UINT32 e1000_get_phy_addr_for_bm_page(UINT32 page, UINT32 reg)
+{
+ UINT32 phy_addr = 2;
+
+ if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))
+ phy_addr = 1;
+
+ return phy_addr;
+}
+
+/**
+ * e1000_write_phy_reg_bm - Write BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+ UINT32 page_select = 0;
+ UINT32 page = offset >> IGP_PAGE_SHIFT;
+ UINT32 page_shift = 0;
+
+ DEBUGFUNC("e1000_write_phy_reg_bm");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+ FALSE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /*
+ * Page select is register 31 for phy address 1 and 22 for
+ * phy address 2 and 3. Page select is shifted only for
+ * phy address 1.
+ */
+ if (hw->phy.addr == 1) {
+ page_shift = IGP_PAGE_SHIFT;
+ page_select = IGP01E1000_PHY_PAGE_SELECT;
+ } else {
+ page_shift = 0;
+ page_select = BM_PHY_PAGE_SELECT;
+ }
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select,
+ (page << page_shift));
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_bm - Read BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+INT32 e1000_read_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+ UINT32 page_select = 0;
+ UINT32 page = offset >> IGP_PAGE_SHIFT;
+ UINT32 page_shift = 0;
+
+ DEBUGFUNC("e1000_read_phy_reg_bm");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+ TRUE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /*
+ * Page select is register 31 for phy address 1 and 22 for
+ * phy address 2 and 3. Page select is shifted only for
+ * phy address 1.
+ */
+ if (hw->phy.addr == 1) {
+ page_shift = IGP_PAGE_SHIFT;
+ page_select = IGP01E1000_PHY_PAGE_SELECT;
+ } else {
+ page_shift = 0;
+ page_select = BM_PHY_PAGE_SELECT;
+ }
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select,
+ (page << page_shift));
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+#ifndef NO_82574_SUPPORT
+/**
+ * e1000_read_phy_reg_bm2 - Read BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+INT32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+ UINT16 page = (UINT16)(offset >> IGP_PAGE_SHIFT);
+
+ DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+ TRUE);
+ goto out;
+ }
+
+ hw->phy.addr = 1;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+ page);
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_bm2 - Write BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+ UINT16 page = (UINT16)(offset >> IGP_PAGE_SHIFT);
+
+ DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+ FALSE);
+ goto out;
+ }
+
+ hw->phy.addr = 1;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+ page);
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+#endif /* NO_82574_SUPPORT */
+/**
+ * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read or written
+ * @data: pointer to the data to read or write
+ * @read: determines if operation is read or write
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting. Note that procedure to read the wakeup
+ * registers are different. It works as such:
+ * 1) Set page 769, register 17, bit 2 = 1
+ * 2) Set page to 800 for host (801 if we were manageability)
+ * 3) Write the address using the address opcode (0x11)
+ * 4) Read or write the data using the data opcode (0x12)
+ * 5) Restore 769_17.2 to its original value
+ *
+ * Assumes semaphore already acquired.
+ **/
+STATIC INT32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read)
+{
+ INT32 ret_val;
+ UINT16 reg = BM_PHY_REG_NUM(offset);
+ UINT16 phy_reg = 0;
+
+ DEBUGFUNC("e1000_access_phy_wakeup_reg_bm");
+
+ /* Gig must be disabled for MDIO accesses to page 800 */
+ if ((hw->mac.type == e1000_pchlan) &&
+ (!(E1000_READ_REG(hw, E1000_PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
+ DEBUGOUT("Attempting to access page 800 while gig enabled.\n");
+
+ /* All operations in this function are phy address 1 */
+ hw->phy.addr = 1;
+
+ /* Set page 769 */
+ e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+ ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
+ if (ret_val) {
+ DEBUGOUT("Could not read PHY page 769\n");
+ goto out;
+ }
+
+ /* First clear bit 4 to avoid a power state change */
+ phy_reg &= ~(BM_WUC_HOST_WU_BIT);
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+ if (ret_val) {
+ DEBUGOUT("Could not clear PHY page 769 bit 4\n");
+ goto out;
+ }
+
+ /* Write bit 2 = 1, and clear bit 4 to 769_17 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
+ phy_reg | BM_WUC_ENABLE_BIT);
+ if (ret_val) {
+ DEBUGOUT("Could not write PHY page 769 bit 2\n");
+ goto out;
+ }
+
+ /* Select page 800 */
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_PAGE << IGP_PAGE_SHIFT));
+
+ /* Write the page 800 offset value using opcode 0x11 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
+ if (ret_val) {
+ DEBUGOUT("Could not write address opcode to page 800\n");
+ goto out;
+ }
+
+ if (read) {
+ /* Read the page 800 value using opcode 0x12 */
+ ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+ data);
+ } else {
+ /* Write the page 800 value using opcode 0x12 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+ *data);
+ }
+
+ if (ret_val) {
+ DEBUGOUT("Could not access data value from page 800\n");
+ goto out;
+ }
+
+ /*
+ * Restore 769_17.2 to its original value
+ * Set page 769
+ */
+ e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+ /* Clear 769_17.2 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+ if (ret_val) {
+ DEBUGOUT("Could not clear PHY page 769 bit 2\n");
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_up_phy_copper(struct e1000_hw *hw)
+{
+ UINT16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_down_phy_copper(struct e1000_hw *hw)
+{
+ UINT16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+ msec_delay(1);
+}
+
+/**
+ * __e1000_read_phy_reg_hv - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and stores the retrieved information in data. Release any acquired
+ * semaphore before exiting.
+ **/
+static INT32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 *data,
+ BOOLEAN locked)
+{
+ INT32 ret_val;
+ UINT16 page = BM_PHY_REG_PAGE(offset);
+ UINT16 reg = BM_PHY_REG_NUM(offset);
+
+ DEBUGFUNC("__e1000_read_phy_reg_hv");
+
+ if (!locked) {
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+ data, TRUE);
+ goto out;
+ }
+
+ if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+ ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+ data, TRUE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+ if (page == HV_INTC_FC_PAGE_START)
+ page = 0;
+
+ if (reg > MAX_PHY_MULTI_PAGE_REG) {
+ UINT32 phy_addr = hw->phy.addr;
+
+ hw->phy.addr = 1;
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (page << IGP_PAGE_SHIFT));
+ hw->phy.addr = phy_addr;
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+ data);
+out:
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_hv - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset and stores
+ * the retrieved information in data. Release the acquired semaphore
+ * before exiting.
+ **/
+INT32 e1000_read_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_hv(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_read_phy_reg_hv_locked - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data. Assumes semaphore already acquired.
+ **/
+INT32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_hv(hw, offset, data, TRUE);
+}
+
+/**
+ * __e1000_write_phy_reg_hv - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+static INT32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 data,
+ BOOLEAN locked)
+{
+ INT32 ret_val;
+ UINT16 page = BM_PHY_REG_PAGE(offset);
+ UINT16 reg = BM_PHY_REG_NUM(offset);
+
+ DEBUGFUNC("__e1000_write_phy_reg_hv");
+
+ if (!locked) {
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+ &data, FALSE);
+ goto out;
+ }
+
+ if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+ ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+ &data, FALSE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+ if (page == HV_INTC_FC_PAGE_START)
+ page = 0;
+
+ /*
+ * Workaround MDIO accesses being disabled after entering IEEE Power
+ * Down (whenever bit 11 of the PHY Control register is set)
+ */
+ if ((hw->phy.type == e1000_phy_82578) &&
+ (hw->phy.revision >= 1) &&
+ (hw->phy.addr == 2) &&
+ ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
+ (data & (1 << 11))) {
+ UINT16 data2 = 0x7EFF;
+ ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
+ &data2, FALSE);
+ if (ret_val)
+ goto out;
+ }
+
+ if (reg > MAX_PHY_MULTI_PAGE_REG) {
+ UINT32 phy_addr = hw->phy.addr;
+
+ hw->phy.addr = 1;
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (page << IGP_PAGE_SHIFT));
+ hw->phy.addr = phy_addr;
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+ data);
+
+out:
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_hv - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to PHY register at the offset.
+ * Release the acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_hv(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_write_phy_reg_hv_locked - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset. Assumes semaphore
+ * already acquired.
+ **/
+INT32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_hv(hw, offset, data, TRUE);
+}
+
+/**
+ * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
+ * @page: page to be accessed
+ **/
+STATIC UINT32 e1000_get_phy_addr_for_hv_page(UINT32 page)
+{
+ UINT32 phy_addr = 2;
+
+ if (page >= HV_INTC_FC_PAGE_START)
+ phy_addr = 1;
+
+ return phy_addr;
+}
+
+/**
+ * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read or written
+ * @data: pointer to the data to be read or written
+ * @read: determines if operation is read or written
+ *
+ * Reads the PHY register at offset and stores the retreived information
+ * in data. Assumes semaphore already acquired. Note that the procedure
+ * to read these regs uses the address port and data port to read/write.
+ **/
+STATIC INT32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read)
+{
+ INT32 ret_val;
+ UINT32 addr_reg = 0;
+ UINT32 data_reg = 0;
+
+ DEBUGFUNC("e1000_access_phy_debug_regs_hv");
+
+ /* This takes care of the difference with desktop vs mobile phy */
+ addr_reg = (hw->phy.type == e1000_phy_82578) ?
+ I82578_ADDR_REG : I82577_ADDR_REG;
+ data_reg = addr_reg + 1;
+
+ /* All operations in this function are phy address 2 */
+ hw->phy.addr = 2;
+
+ /* masking with 0x3F to remove the page from offset */
+ ret_val = e1000_write_phy_reg_mdic(hw, addr_reg, (UINT16)offset & 0x3F);
+ if (ret_val) {
+ DEBUGOUT("Could not write PHY the HV address register\n");
+ goto out;
+ }
+
+ /* Read or write the data value next */
+ if (read)
+ ret_val = e1000_read_phy_reg_mdic(hw, data_reg, data);
+ else
+ ret_val = e1000_write_phy_reg_mdic(hw, data_reg, *data);
+
+ if (ret_val) {
+ DEBUGOUT("Could not read data value from HV data register\n");
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_link_stall_workaround_hv - Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * This function works around a Si bug where the link partner can get
+ * a link up indication before the PHY does. If small packets are sent
+ * by the link partner they can be placed in the packet buffer without
+ * being properly accounted for by the PHY and will stall preventing
+ * further packets from being received. The workaround is to clear the
+ * packet buffer after the PHY detects link up.
+ **/
+INT32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_link_stall_workaround_hv");
+
+ if (hw->phy.type != e1000_phy_82578)
+ goto out;
+
+ /* Do not apply workaround if in PHY loopback bit 14 set */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &data);
+ if (data & PHY_CONTROL_LB)
+ goto out;
+
+ /* check if link is up and at 1Gbps */
+ ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ data &= BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK;
+
+ if (data != (BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_1000))
+ goto out;
+
+ msec_delay(200);
+
+ /* flush the packets in the fifo buffer */
+ ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC |
+ HV_MUX_DATA_CTRL_FORCE_SPEED);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_82577 - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY specific status register.
+ **/
+INT32 e1000_check_polarity_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_check_polarity_82577");
+
+ ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex.
+ **/
+INT32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_82577");
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ usec_delay(1);
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on 82577 phy\n");
+
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ DEBUGOUT("Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_82577 - Retrieve I82577 PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up. If link is up, then
+ * set/determine 10base-T extended distance and polarity correction. Read
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ **/
+INT32 e1000_get_phy_info_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_82577");
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ phy->polarity_correction = TRUE;
+
+ ret_val = e1000_check_polarity_82577(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? TRUE : FALSE;
+
+ if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
+ I82577_PHY_STATUS2_SPEED_1000MBPS) {
+ ret_val = hw->phy.ops.get_cable_length(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Reads the diagnostic status register and verifies result is valid before
+ * placing it in the phy_cable_length field.
+ **/
+INT32 e1000_get_cable_length_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, length;
+
+ DEBUGFUNC("e1000_get_cable_length_82577");
+
+ ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
+ I82577_DSTATUS_CABLE_LENGTH_SHIFT;
+
+ if (length == E1000_CABLE_LENGTH_UNDEFINED)
+ ret_val = -E1000_ERR_PHY;
+
+ phy->cable_length = length;
+
+out:
+ return ret_val;
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h
new file mode 100755
index 0000000..ec4661d
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h
@@ -0,0 +1,268 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_PHY_H_
+#define _E1000_PHY_H_
+
+void e1000_init_phy_ops_generic(struct e1000_hw *hw);
+#ifndef NO_NULL_OPS_SUPPORT
+INT32 e1000_null_read_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+void e1000_null_phy_generic(struct e1000_hw *hw);
+INT32 e1000_null_lplu_state(struct e1000_hw *hw, BOOLEAN active);
+INT32 e1000_null_write_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#endif /* NO_NULL_OPS_SUPPORT */
+INT32 e1000_check_downshift_generic(struct e1000_hw *hw);
+INT32 e1000_check_polarity_m88(struct e1000_hw *hw);
+INT32 e1000_check_polarity_igp(struct e1000_hw *hw);
+INT32 e1000_check_polarity_ife(struct e1000_hw *hw);
+INT32 e1000_check_reset_block_generic(struct e1000_hw *hw);
+INT32 e1000_copper_link_setup_igp(struct e1000_hw *hw);
+INT32 e1000_copper_link_setup_m88(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
+INT32 e1000_get_cable_length_m88(struct e1000_hw *hw);
+INT32 e1000_get_cable_length_igp_2(struct e1000_hw *hw);
+INT32 e1000_get_cfg_done_generic(struct e1000_hw *hw);
+INT32 e1000_get_phy_id(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_igp(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_m88(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_ife(struct e1000_hw *hw);
+INT32 e1000_phy_sw_reset_generic(struct e1000_hw *hw);
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, UINT16 *phy_ctrl);
+INT32 e1000_phy_hw_reset_generic(struct e1000_hw *hw);
+INT32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw);
+INT32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, BOOLEAN active);
+INT32 e1000_setup_copper_link_generic(struct e1000_hw *hw);
+INT32 e1000_wait_autoneg_generic(struct e1000_hw *hw);
+INT32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_phy_reset_dsp(struct e1000_hw *hw);
+INT32 e1000_phy_has_link_generic(struct e1000_hw *hw, UINT32 iterations,
+ UINT32 usec_interval, BOOLEAN *success);
+INT32 e1000_phy_init_script_igp3(struct e1000_hw *hw);
+enum e1000_phy_type e1000_get_phy_type_from_id(UINT32 phy_id);
+INT32 e1000_determine_phy_address(struct e1000_hw *hw);
+INT32 e1000_write_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_read_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+#ifndef NO_82574_SUPPORT
+INT32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#endif /* NO_82574_SUPPORT */
+void e1000_power_up_phy_copper(struct e1000_hw *hw);
+void e1000_power_down_phy_copper(struct e1000_hw *hw);
+INT32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#ifndef NO_82575_SUPPORT
+INT32 e1000_read_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#endif /* *NO_82575_SUPPORT */
+INT32 e1000_read_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
+INT32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
+INT32 e1000_check_polarity_82577(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_82577(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
+INT32 e1000_get_cable_length_82577(struct e1000_hw *hw);
+
+#define E1000_MAX_PHY_ADDR 4
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
+#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality */
+#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */
+#define IGP_PAGE_SHIFT 5
+#define PHY_REG_MASK 0x1F
+
+/* BM/HV Specific Registers */
+#define BM_PORT_CTRL_PAGE 769
+#define BM_PCIE_PAGE 770
+#define BM_WUC_PAGE 800
+#define BM_WUC_ADDRESS_OPCODE 0x11
+#define BM_WUC_DATA_OPCODE 0x12
+#define BM_WUC_ENABLE_PAGE BM_PORT_CTRL_PAGE
+#define BM_WUC_ENABLE_REG 17
+#define BM_WUC_ENABLE_BIT (1 << 2)
+#define BM_WUC_HOST_WU_BIT (1 << 4)
+
+#define PHY_UPPER_SHIFT 21
+#define BM_PHY_REG(page, reg) \
+ (((reg) & MAX_PHY_REG_ADDRESS) |\
+ (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+ (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+#define BM_PHY_REG_PAGE(offset) \
+ ((UINT16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define BM_PHY_REG_NUM(offset) \
+ ((UINT16)(((offset) & MAX_PHY_REG_ADDRESS) |\
+ (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+ ~MAX_PHY_REG_ADDRESS)))
+
+#define HV_INTC_FC_PAGE_START 768
+#define I82578_ADDR_REG 29
+#define I82577_ADDR_REG 16
+#define I82577_CFG_REG 22
+#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15)
+#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */
+#define I82577_CTRL_REG 23
+
+/* 82577 specific PHY registers */
+#define I82577_PHY_CTRL_2 18
+#define I82577_PHY_LBK_CTRL 19
+#define I82577_PHY_STATUS_2 26
+#define I82577_PHY_DIAG_STATUS 31
+
+/* I82577 PHY Status 2 */
+#define I82577_PHY_STATUS2_REV_POLARITY 0x0400
+#define I82577_PHY_STATUS2_MDIX 0x0800
+#define I82577_PHY_STATUS2_SPEED_MASK 0x0300
+#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
+#define I82577_PHY_STATUS2_SPEED_100MBPS 0x0100
+
+/* I82577 PHY Control 2 */
+#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400
+#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200
+
+/* I82577 PHY Diagnostics Status */
+#define I82577_DSTATUS_CABLE_LENGTH 0x03FC
+#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
+
+/* BM PHY Copper Specific Control 1 */
+#define BM_CS_CTRL1 16
+#define BM_CS_CTRL1_ENERGY_DETECT 0x0300 /* Enable Energy Detect */
+
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS 17
+#define BM_CS_STATUS_ENERGY_DETECT 0x0010 /* Energy Detect Status */
+#define BM_CS_STATUS_LINK_UP 0x0400
+#define BM_CS_STATUS_RESOLVED 0x0800
+#define BM_CS_STATUS_SPEED_MASK 0xC000
+#define BM_CS_STATUS_SPEED_1000 0x8000
+
+/* 82577 Mobile Phy Status Register */
+#define HV_M_STATUS 26
+#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000
+#define HV_M_STATUS_SPEED_MASK 0x0300
+#define HV_M_STATUS_SPEED_1000 0x0200
+#define HV_M_STATUS_LINK_UP 0x0040
+
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK 0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP01E1000_GMII_FLEX_SPD 0x0010
+#define IGP01E1000_GMII_SPD 0x0020 /* Enable SPD */
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX 0x0800
+#define IGP01E1000_PSSR_SPEED_MASK 0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK 0x7F
+#define IGP02E1000_AGC_RANGE 15
+
+#define IGP03E1000_PHY_MISC_CTRL 0x1B
+#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Manually Set Duplex */
+
+#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET 0x1 /* Kumeran Control */
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
+#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
+#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002
+#define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED 0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010
+#define IFE_PSC_FORCE_POLARITY 0x0020
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE 0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h
new file mode 100755
index 0000000..880905b
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h
@@ -0,0 +1,576 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_REGS_H_
+#define _E1000_REGS_H_
+
+#define E1000_CTRL 0x00000 /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS 0x00008 /* Device Status - RO */
+#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
+#define E1000_EERD 0x00014 /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
+#define E1000_FLA 0x0001C /* Flash Access - RW */
+#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#ifndef NO_82580_SUPPORT
+#define E1000_MDICNFG 0x00E04 /* MDI Config - RW */
+#define E1000_REGISTER_SET_SIZE 0x20000 /* CSR Size */
+#define E1000_EEPROM_INIT_CTRL_WORD_2 0x0F /* EEPROM Init Ctrl Word 2 */
+#define E1000_BARCTRL 0x5BBC /* BAR ctrl reg */
+#define E1000_BARCTRL_FLSIZE 0x0700 /* BAR ctrl Flsize */
+#define E1000_BARCTRL_CSRSIZE 0x2000 /* BAR ctrl CSR size */
+#endif
+#define E1000_SCTL 0x00024 /* SerDes Control - RW */
+#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
+#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
+#define E1000_FEXT 0x0002C /* Future Extended - RW */
+#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
+#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */
+#define E1000_FCT 0x00030 /* Flow Control Type - RW */
+#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
+#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
+#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
+#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
+#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
+#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
+#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
+#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
+#ifndef NO_82574_SUPPORT
+#define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */
+#endif /* NO_82574_SUPPORT */
+#define E1000_SVCR 0x000F0
+#define E1000_SVT 0x000F4
+#define E1000_RCTL 0x00100 /* Rx Control - RW */
+#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */
+#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */
+#ifndef NO_82571_SUPPORT
+#define E1000_PBA_ECC 0x01100 /* PBA ECC Register */
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_82575_SUPPORT
+#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
+#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82576_SUPPORT
+#define E1000_GPIE 0x01514 /* General Purpose Interrupt Enable - RW */
+#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */
+#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
+#endif /* NO_82576_SUPPORT */
+#define E1000_TCTL 0x00400 /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */
+#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */
+#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */
+#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
+#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
+#define E1000_PBS 0x01008 /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
+#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT 0x01028 /* FLASH Timer Register */
+#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL 0x01030 /* FLASH control register */
+#define E1000_FLSWDATA 0x01034 /* FLASH data register */
+#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
+#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
+#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */
+#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */
+#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */
+#ifndef NO_82575_SUPPORT
+#define E1000_TCPTIMER 0x0104C /* TCP Timer - RW */
+#endif
+#ifndef NO_82576_SUPPORT
+#define E1000_VPDDIAG 0x01060 /* VPD Diagnostic - RO */
+#define E1000_ICR_V2 0x01500 /* Interrupt Cause - new location - RC */
+#define E1000_ICS_V2 0x01504 /* Interrupt Cause Set - new location - WO */
+#define E1000_IMS_V2 0x01508 /* Interrupt Mask Set/Read - new location - RW */
+#define E1000_IMC_V2 0x0150C /* Interrupt Mask Clear - new location - WO */
+#define E1000_IAM_V2 0x01510 /* Interrupt Ack Auto Mask - new location - RW */
+#endif
+#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
+#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
+#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n)))
+#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */
+#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */
+#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */
+#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */
+#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */
+#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */
+#ifndef NO_82576_SUPPORT
+#define E1000_PBDIAG 0x02458 /* Packet Buffer Diagnostic - RW */
+#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
+#endif
+#ifndef NO_82580_SUPPORT
+#define E1000_IRPBS 0x02404 /* Same as RXPBS, renamed for newer adapters - RW */
+#endif
+#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */
+#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+ (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+ (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+ (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
+ (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+ (0x0C010 + ((_n) * 0x40)))
+#define E1000_RXCTL(_n) ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
+ (0x0C014 + ((_n) * 0x40)))
+#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n)
+#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+ (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+ (0x0C028 + ((_n) * 0x40)))
+#define E1000_RQDPC(_n) ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \
+ (0x0C030 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+ (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+ (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+ (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+ (0x0E010 + ((_n) * 0x40)))
+#define E1000_TXCTL(_n) ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
+ (0x0E014 + ((_n) * 0x40)))
+#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
+#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+ (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+ (0x0E028 + ((_n) * 0x40)))
+#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
+ (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
+ (0x0E03C + ((_n) * 0x40)))
+#define E1000_TARC(_n) (0x03840 + ((_n) * 0x100))
+#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */
+#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */
+#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
+#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
+#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+ (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+ (0x054E4 + ((_i - 16) * 8)))
+#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8))
+#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8))
+#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4))
+#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
+#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8))
+#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8))
+#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8))
+#ifndef NO_82576_SUPPORT
+#define E1000_PBSLAC 0x03100 /* Packet Buffer Slave Access Control */
+#define E1000_PBSLAD(_n) (0x03110 + (0x4 * (_n))) /* Packet Buffer DWORD (_n) */
+#define E1000_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
+#endif
+#ifndef NO_82580_SUPPORT
+#define E1000_ITPBS 0x03404 /* Same as TXPBS, renamed for newer adpaters - RW */
+#endif
+#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */
+#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */
+#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */
+#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */
+#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */
+#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */
+#ifndef NO_82576_SUPPORT
+#define E1000_DTXTCPFLGL 0x0359C /* DMA Tx Control flag low - RW */
+#define E1000_DTXTCPFLGH 0x035A0 /* DMA Tx Control flag high - RW */
+#define E1000_DTXMXSZRQ 0x03540 /* DMA Tx Max Total Allow Size Requests - RW */
+#endif
+#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
+#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
+#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
+#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
+#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
+#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
+#define E1000_COLC 0x04028 /* Collision Count - R/clr */
+#define E1000_DC 0x04030 /* Defer Count - R/clr */
+#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */
+#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */
+#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */
+#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */
+#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */
+#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */
+#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */
+#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */
+#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */
+#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */
+#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */
+#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */
+#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
+#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
+#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset register */
+
+#ifndef NO_82576_SUPPORT
+/* Virtualization statistical counters */
+#define E1000_PFVFGPRC(_n) (0x010010 + (0x100 * (_n)))
+#define E1000_PFVFGPTC(_n) (0x010014 + (0x100 * (_n)))
+#define E1000_PFVFGORC(_n) (0x010018 + (0x100 * (_n)))
+#define E1000_PFVFGOTC(_n) (0x010034 + (0x100 * (_n)))
+#define E1000_PFVFMPRC(_n) (0x010038 + (0x100 * (_n)))
+#define E1000_PFVFGPRLBC(_n) (0x010040 + (0x100 * (_n)))
+#define E1000_PFVFGPTLBC(_n) (0x010044 + (0x100 * (_n)))
+#define E1000_PFVFGORLBC(_n) (0x010048 + (0x100 * (_n)))
+#define E1000_PFVFGOTLBC(_n) (0x010050 + (0x100 * (_n)))
+
+#define E1000_LSECTXUT 0x04300 /* LinkSec Tx Untagged Packet Count - OutPktsUntagged */
+#define E1000_LSECTXPKTE 0x04304 /* LinkSec Encrypted Tx Packets Count - OutPktsEncrypted */
+#define E1000_LSECTXPKTP 0x04308 /* LinkSec Protected Tx Packet Count - OutPktsProtected */
+#define E1000_LSECTXOCTE 0x0430C /* LinkSec Encrypted Tx Octets Count - OutOctetsEncrypted */
+#define E1000_LSECTXOCTP 0x04310 /* LinkSec Protected Tx Octets Count - OutOctetsProtected */
+#define E1000_LSECRXUT 0x04314 /* LinkSec Untagged non-Strict Rx Packet Count - InPktsUntagged/InPktsNoTag */
+#define E1000_LSECRXOCTD 0x0431C /* LinkSec Rx Octets Decrypted Count - InOctetsDecrypted */
+#define E1000_LSECRXOCTV 0x04320 /* LinkSec Rx Octets Validated - InOctetsValidated */
+#define E1000_LSECRXBAD 0x04324 /* LinkSec Rx Bad Tag - InPktsBadTag */
+#define E1000_LSECRXNOSCI 0x04328 /* LinkSec Rx Packet No SCI Count - InPktsNoSci */
+#define E1000_LSECRXUNSCI 0x0432C /* LinkSec Rx Packet Unknown SCI Count - InPktsUnknownSci */
+#define E1000_LSECRXUNCH 0x04330 /* LinkSec Rx Unchecked Packets Count - InPktsUnchecked */
+#define E1000_LSECRXDELAY 0x04340 /* LinkSec Rx Delayed Packet Count - InPktsDelayed */
+#define E1000_LSECRXLATE 0x04350 /* LinkSec Rx Late Packets Count - InPktsLate */
+#define E1000_LSECRXOK(_n) (0x04360 + (0x04 * (_n))) /* LinkSec Rx Packet OK Count - InPktsOk */
+#define E1000_LSECRXINV(_n) (0x04380 + (0x04 * (_n))) /* LinkSec Rx Invalid Count - InPktsInvalid */
+#define E1000_LSECRXNV(_n) (0x043A0 + (0x04 * (_n))) /* LinkSec Rx Not Valid Count - InPktsNotValid */
+#define E1000_LSECRXUNSA 0x043C0 /* LinkSec Rx Unused SA Count - InPktsUnusedSa */
+#define E1000_LSECRXNUSA 0x043D0 /* LinkSec Rx Not Using SA Count - InPktsNotUsingSa */
+#define E1000_LSECTXCAP 0x0B000 /* LinkSec Tx Capabilities Register - RO */
+#define E1000_LSECRXCAP 0x0B300 /* LinkSec Rx Capabilities Register - RO */
+#define E1000_LSECTXCTRL 0x0B004 /* LinkSec Tx Control - RW */
+#define E1000_LSECRXCTRL 0x0B304 /* LinkSec Rx Control - RW */
+#define E1000_LSECTXSCL 0x0B008 /* LinkSec Tx SCI Low - RW */
+#define E1000_LSECTXSCH 0x0B00C /* LinkSec Tx SCI High - RW */
+#define E1000_LSECTXSA 0x0B010 /* LinkSec Tx SA0 - RW */
+#define E1000_LSECTXPN0 0x0B018 /* LinkSec Tx SA PN 0 - RW */
+#define E1000_LSECTXPN1 0x0B01C /* LinkSec Tx SA PN 1 - RW */
+#define E1000_LSECRXSCL 0x0B3D0 /* LinkSec Rx SCI Low - RW */
+#define E1000_LSECRXSCH 0x0B3E0 /* LinkSec Rx SCI High - RW */
+#define E1000_LSECTXKEY0(_n) (0x0B020 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 0 - WO */
+#define E1000_LSECTXKEY1(_n) (0x0B030 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 1 - WO */
+#define E1000_LSECRXSA(_n) (0x0B310 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
+#define E1000_LSECRXPN(_n) (0x0B330 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
+/*
+ * LinkSec Rx Keys - where _n is the SA no. and _m the 4 dwords of the 128 bit
+ * key - RW.
+ */
+#define E1000_LSECRXKEY(_n, _m) (0x0B350 + (0x10 * (_n)) + (0x04 * (_m)))
+
+#define E1000_SSVPC 0x041A0 /* Switch Security Violation Packet Count */
+#define E1000_IPSCTRL 0xB430 /* IpSec Control Register */
+#define E1000_IPSRXCMD 0x0B408 /* IPSec Rx Command Register - RW */
+#define E1000_IPSRXIDX 0x0B400 /* IPSec Rx Index - RW */
+#define E1000_IPSRXIPADDR(_n) (0x0B420+ (0x04 * (_n))) /* IPSec Rx IPv4/v6 Address - RW */
+#define E1000_IPSRXKEY(_n) (0x0B410 + (0x04 * (_n))) /* IPSec Rx 128-bit Key - RW */
+#define E1000_IPSRXSALT 0x0B404 /* IPSec Rx Salt - RW */
+#define E1000_IPSRXSPI 0x0B40C /* IPSec Rx SPI - RW */
+#define E1000_IPSTXKEY(_n) (0x0B460 + (0x04 * (_n))) /* IPSec Tx 128-bit Key - RW */
+#define E1000_IPSTXSALT 0x0B454 /* IPSec Tx Salt - RW */
+#define E1000_IPSTXIDX 0x0B450 /* IPSec Tx SA IDX - RW */
+#endif /* NO_82576_SUPPORT */
+#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */
+#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */
+#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */
+#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */
+#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */
+#define E1000_RPTHC 0x04104 /* Rx Packets To Host */
+#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */
+#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */
+#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */
+#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */
+#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS 0x04138 /* Length Errors Count */
+#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */
+#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */
+#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */
+#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */
+#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */
+#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */
+#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
+#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
+#define E1000_RA 0x05400 /* Receive Address - RW Array */
+#ifndef NO_82576_SUPPORT
+#define E1000_RA2 0x054E0 /* 2nd half of receive address array - RW Array */
+#endif
+#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
+#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */
+#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */
+#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */
+#define E1000_WUC 0x05800 /* Wakeup Control - RW */
+#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
+#define E1000_WUS 0x05810 /* Wakeup Status - RO */
+#define E1000_MANC 0x05820 /* Management Control - RW */
+#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
+#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
+#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
+#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
+#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */
+#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF 0x08800 /* Host Interface */
+#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
+#ifndef NO_82576_SUPPORT
+#define E1000_FHFT(_n) (0x09000 + (_n * 0x100)) /* Flexible Host Filter Table */
+#define E1000_FHFT_EXT(_n) (0x09A00 + (_n * 0x100)) /* Ext Flexible Host Filter Table */
+
+#endif /* NO_82576_SUPPORT */
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA 0x0003C /* PHY address - RW */
+#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */
+#define E1000_MDEF(_n) (0x05890 + (4 * (_n))) /* Mngmt Decision Filters */
+#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL 0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
+#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */
+#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM 0x05B50 /* SW Semaphore */
+#define E1000_FWSM 0x05B54 /* FW Semaphore */
+#define E1000_SWSM2 0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */
+#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */
+#ifndef NO_82580_SUPPORT
+#define E1000_UFUSE 0x05B78 /* UFUSE - RO */
+#endif
+#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
+#define E1000_HICR 0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
+#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
+#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
+ * (_i) - RW */
+#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
+ * low reg - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
+ * upper reg - RW */
+#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
+ * message reg - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
+ * vector ctrl reg - RW */
+#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */
+#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
+#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */
+#ifndef NO_82576_SUPPORT
+/* VT Registers */
+#define E1000_SWPBS 0x03004 /* Switch Packet Buffer Size - RW */
+#define E1000_MBVFICR 0x00C80 /* Mailbox VF Cause - RWC */
+#define E1000_MBVFIMR 0x00C84 /* Mailbox VF int Mask - RW */
+#define E1000_VFLRE 0x00C88 /* VF Register Events - RWC */
+#define E1000_VFRE 0x00C8C /* VF Receive Enables */
+#define E1000_VFTE 0x00C90 /* VF Transmit Enables */
+#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */
+#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_WVBR 0x03554 /* VM Wrong Behavior - RWS */
+#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
+#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
+#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
+#define E1000_VMRCTL 0X05D80 /* Virtual Mirror Rule Control */
+/* These act per VF so an array friendly macro is used */
+#define E1000_V2PMAILBOX(_n) (0x00C40 + (4 * (_n)))
+#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n)))
+#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
+#define E1000_VFVMBMEM(_n) (0x00800 + (_n))
+#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n)))
+#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
+ * Filter - RW */
+#define E1000_VMVIR(_n) (0x03700 + (4 * (_n)))
+#endif /* NO_82576_SUPPORT */
+/* Time Sync */
+#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
+#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
+#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
+#define E1000_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */
+#define E1000_RXSTMPH 0x0B628 /* Rx timestamp High - RO */
+#define E1000_RXSATRL 0x0B62C /* Rx timestamp attribute low - RO */
+#define E1000_RXSATRH 0x0B630 /* Rx timestamp attribute high - RO */
+#define E1000_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
+#define E1000_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
+#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */
+#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */
+#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
+#ifndef NO_82580_SUPPORT
+#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
+#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_82576_SUPPORT
+
+/* Filtering Registers */
+#define E1000_SAQF(_n) (0x05980 + (4 * (_n))) /* Source Address Queue Fltr */
+#define E1000_DAQF(_n) (0x059A0 + (4 * (_n))) /* Dest Address Queue Fltr */
+#define E1000_SPQF(_n) (0x059C0 + (4 * (_n))) /* Source Port Queue Fltr */
+#define E1000_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
+#define E1000_TTQF(_n) (0x059E0 + (4 * (_n))) /* 2-tuple Queue Fltr */
+#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
+#define E1000_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
+
+#define E1000_RTTDCS 0x3600 /* Reedtown Tx Desc plane control and status */
+#define E1000_RTTPCS 0x3474 /* Reedtown Tx Packet Plane control and status */
+#define E1000_RTRPCS 0x2474 /* Rx packet plane control and status */
+#define E1000_RTRUP2TC 0x05AC4 /* Rx User Priority to Traffic Class */
+#define E1000_RTTUP2TC 0x0418 /* Transmit User Priority to Traffic Class */
+#define E1000_RTTDTCRC(_n) (0x3610 + ((_n) * 4)) /* Tx Desc plane TC Rate-scheduler config */
+#define E1000_RTTPTCRC(_n) (0x3480 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Config */
+#define E1000_RTRPTCRC(_n) (0x2480 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Config */
+#define E1000_RTTDTCRS(_n) (0x3630 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler Status */
+#define E1000_RTTDTCRM(_n) (0x3650 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler MMW */
+#define E1000_RTTPTCRS(_n) (0x34A0 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Status */
+#define E1000_RTTPTCRM(_n) (0x34C0 + ((_n) * 4)) /* Tx Packet plane TC Rate-scheduler MMW */
+#define E1000_RTRPTCRS(_n) (0x24A0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Status */
+#define E1000_RTRPTCRM(_n) (0x24C0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler MMW */
+#define E1000_RTTDVMRM(_n) (0x3670 + ((_n) * 4)) /* Tx Desc plane VM Rate-Scheduler MMW*/
+#define E1000_RTTBCNRM(_n) (0x3690 + ((_n) * 4)) /* Tx BCN Rate-Scheduler MMW */
+#define E1000_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select */
+#define E1000_RTTDVMRC 0x3608 /* Tx Desc Plane VM Rate-Scheduler Config */
+#define E1000_RTTDVMRS 0x360C /* Tx Desc Plane VM Rate-Scheduler Status */
+#define E1000_RTTBCNRC 0x36B0 /* Tx BCN Rate-Scheduler Config */
+#define E1000_RTTBCNRS 0x36B4 /* Tx BCN Rate-Scheduler Status */
+#define E1000_RTTBCNCR 0xB200 /* Tx BCN Control Register */
+#define E1000_RTTBCNTG 0x35A4 /* Tx BCN Tagging */
+#define E1000_RTTBCNCP 0xB208 /* Tx BCN Congestion point */
+#define E1000_RTRBCNCR 0xB20C /* Rx BCN Control Register */
+#define E1000_RTTBCNRD 0x36B8 /* Tx BCN Rate Drift */
+#define E1000_PFCTOP 0x1080 /* Priority Flow Control Type and Opcode */
+#define E1000_RTTBCNIDX 0xB204 /* Tx BCN Congestion Point */
+#define E1000_RTTBCNACH 0x0B214 /* Tx BCN Control High */
+#define E1000_RTTBCNACL 0x0B210 /* Tx BCN Control Low */
+#endif /* NO_82576_SUPPORT */
+
+#ifndef NO_82580_SUPPORT
+/* DMA Coalescing registers */
+#define E1000_DMACR 0x02508 /* Control Register */
+#define E1000_DMCTXTH 0x03550 /* Transmit Threshold */
+#define E1000_DMCTLX 0x02514 /* Time to Lx Request */
+#define E1000_DMCRTRH 0x05DD0 /* Receive Packet Rate Threshold */
+#define E1000_DMCCNT 0x05DD4 /* Current RX Count */
+#define E1000_FCRTC 0x02170 /* Flow Control Rx high watermark */
+#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
+
+/* PCIe Parity Status Register */
+#define E1000_PCIEERRSTS 0x05BA8
+#endif
+
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf
new file mode 100755
index 0000000..5311e82
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf
@@ -0,0 +1,97 @@
+#/*++
+#
+# Copyright (c) 2008, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+# Module Name:
+#
+# gig_82575_edk1.inf
+#
+# Abstract:
+#
+# Component description file for the Intel gigabit ethernet driver. This make file
+# includes only support from 82575 controllers to reduce driver size.
+#
+#--*/
+
+[defines]
+BASE_NAME = GigUndi
+FILE_GUID = BB801A52-C90F-4EDE-91B2-82520888CBC3
+COMPONENT_TYPE = RT_DRIVER
+
+[sources.common]
+ inventorystrings.uni
+ inventory.vfr
+ brand.h
+ clp.h
+ clp.c
+ componentname.c
+ decode.c
+ driverconfiguration.c
+ driverdiagnostics.c
+ e1000.h
+ e1000.c
+ e1000_80003es2lan.h
+ e1000_82571.h
+ e1000_82575.h
+ e1000_82575.c
+ e1000_api.h
+ e1000_api.c
+ e1000_defines.h
+ e1000_hw.h
+ e1000_ich8lan.h
+ e1000_mac.h
+ e1000_mac.c
+ e1000_manage.h
+ e1000_manage.c
+ e1000_nvm.h
+ e1000_nvm.c
+ e1000_osdep.h
+ e1000_osdep.c
+ e1000_phy.h
+ e1000_phy.c
+ e1000_regs.h
+ FirmwareManagement.h
+ FirmwareManagement.c
+ hii.h
+ hii.c
+ ieee_define.h
+ init.c
+ nvdatastruc.h
+ startstop.h
+ startstop.c
+ vlan.h
+ vlan.c
+
+[includes.common]
+ $(EDK_SOURCE)\Foundation
+ $(EDK_SOURCE)\Foundation\Include
+ $(EDK_SOURCE)\Foundation\Include\$(ARCH)
+ $(EDK_SOURCE)\Foundation\Include\IndustryStandard
+ $(EDK_SOURCE)\Foundation\Efi\Include
+ $(EDK_SOURCE)\Foundation\Efi
+ $(EDK_SOURCE)\Foundation\Framework
+ $(EDK_SOURCE)\Foundation\Framework\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\UefiEfiIfrSupportLib
+ $(DEST_DIR)
+ .
+
+[libraries.common]
+ EfiDriverLib
+ PrintLib
+ UefiEfiIfrSupportLib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT=InitializeGigUNDIDriver
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_82571_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_80003ES2LAN_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_ICH8LAN_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_BRANDING_SUPPORT
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf
new file mode 100755
index 0000000..aebb475
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf
@@ -0,0 +1,98 @@
+#/*++
+#
+# Copyright (c) 2008, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+# Module Name:
+#
+# gig_ich_edk1.inf
+#
+# Abstract:
+#
+# Component description file for the Intel gigabit ethernet driver. This make file
+# includes only support from ICH8 and ICH9 controllers to reduce driver size.
+#
+#--*/
+
+[defines]
+BASE_NAME = GigUndi
+FILE_GUID = BB801A52-C90F-4EDE-91B2-82520888CBC3
+COMPONENT_TYPE = RT_DRIVER
+
+[sources.common]
+ inventorystrings.uni
+ inventory.vfr
+ brand.h
+ clp.h
+ clp.c
+ componentname.c
+ decode.c
+ driverconfiguration.c
+ driverdiagnostics.c
+ e1000.h
+ e1000.c
+ e1000_80003es2lan.h
+ e1000_82571.h
+ e1000_82575.h
+ e1000_api.h
+ e1000_api.c
+ e1000_defines.h
+ e1000_hw.h
+ e1000_ich8lan.h
+ e1000_ich8lan.c
+ e1000_mac.h
+ e1000_mac.c
+ e1000_manage.h
+ e1000_manage.c
+ e1000_nvm.h
+ e1000_nvm.c
+ e1000_osdep.h
+ e1000_osdep.c
+ e1000_phy.h
+ e1000_phy.c
+ e1000_regs.h
+ FirmwareManagement.h
+ FirmwareManagement.c
+ hii.h
+ hii.c
+ ieee_define.h
+ init.c
+ nvdatastruc.h
+ startstop.h
+ startstop.c
+ vlan.h
+ vlan.c
+
+[includes.common]
+ $(EDK_SOURCE)\Foundation
+ $(EDK_SOURCE)\Foundation\Include
+ $(EDK_SOURCE)\Foundation\Include\$(ARCH)
+ $(EDK_SOURCE)\Foundation\Include\IndustryStandard
+ $(EDK_SOURCE)\Foundation\Efi\Include
+ $(EDK_SOURCE)\Foundation\Efi
+ $(EDK_SOURCE)\Foundation\Framework
+ $(EDK_SOURCE)\Foundation\Framework\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\UefiEfiIfrSupportLib
+ $(DEST_DIR)
+ .
+
+[libraries.common]
+ EfiDriverLib
+ PrintLib
+ UefiEfiIfrSupportLib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT=InitializeGigUNDIDriver
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_80003ES2LAN_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_82571_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_82575_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_BRANDING_SUPPORT
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c
new file mode 100755
index 0000000..b9b941e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c
@@ -0,0 +1,1973 @@
+/*++
+Copyright (c) 2004-2010, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ Hii.c
+
+Abstract:
+
+ This is an example of how a driver might export data to the HII protocol to be
+ later utilized by the Setup Protocol
+
+--*/
+
+#include "e1000.h"
+#include "hii.h"
+
+EFI_GUID mHiiFormGuid = E1000_HII_FORM_GUID;
+EFI_GUID mE1000DataGuid = E1000_HII_DATA_GUID;
+
+#if 0
+STRING_TOKEN (STR_TERMINATION_STRING);
+#endif
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+CHAR16 VariableName[] = L"GigNVData";
+
+UINT32 gGuidInstance = 0;
+
+EFI_STATUS
+GigUndiComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+VOID
+SetWakeOnLan (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINT8 Enable
+ );
+
+VOID
+GetWakeOnLanStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+VOID
+GetWakeOnLanSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+BOOLEAN
+GetFlashEnableStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+);
+
+EFI_STATUS
+GetFlashEnableSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+);
+
+EFI_STATUS
+SetFlashEnable (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ BOOLEAN Enable
+);
+
+
+
+VOID
+e1000_MemCopy (
+ IN UINT8* Dest,
+ IN UINT8* Source,
+ IN UINT32 Count
+ );
+
+UINTN
+GetLanSpeedStatus(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+ UINTN Active;
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // For media other than copper we do not support speed settings
+ //
+
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type != e1000_media_type_copper)
+ return LINK_SPEED_AUTO_NEG;
+
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ }
+
+ e1000_read_nvm(hw, SetupOffset, 1, &SetupWord);
+
+ //
+ // Save the original setup word value so we can tell if the user changed it
+ //
+ GigUndiPrivateData->NicInfo.BackupSetupWord = SetupWord;
+
+ //
+ // If the boot agent EEPROM signature is not set properly then we will initialize
+ // the words to default values and assume a default autonegotiation setting
+ //
+ e1000_read_nvm(hw, ConfigOffset, 1, &CustomConfigWord);
+
+
+ if ((CustomConfigWord & SIG_MASK) != SIG) {
+ CustomConfigWord = SIG;
+ SetupWord = DISPLAY_SETUP_MESSAGE;
+ Active = LINK_SPEED_AUTO_NEG;
+ } else {
+ //
+ // The signature bits are set so get the speed duplex settings
+ // Mask of the speed and duplex setting bits so that we can determine
+ // what the settings are
+ //
+ switch (SetupWord & (FSP_MASK | FDP_FULL_DUPLEX_BIT))
+ {
+ case (FDP_FULL_DUPLEX_BIT | FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ Active = LINK_SPEED_100FULL;
+ break;
+ case (FDP_FULL_DUPLEX_BIT | FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ Active = LINK_SPEED_10FULL;
+ break;
+ case (FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ Active = LINK_SPEED_100HALF;
+ break;
+ case (FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ Active = LINK_SPEED_10HALF;
+ break;
+ default:
+ hw->mac.autoneg = 1;
+ Active = LINK_SPEED_AUTO_NEG;
+ }
+ }
+
+ GigUndiPrivateData->NicInfo.SetupWord = SetupWord;
+ GigUndiPrivateData->NicInfo.CustomConfigWord = CustomConfigWord;
+
+ return Active;
+}
+
+VOID
+SetLanSpeed(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ UINT8 LanSpeed
+)
+{
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+ UINT8 ReceiveStarted;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // Configure offsets depending on function number
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ }
+
+ SetupWord = GigUndiPrivateData->NicInfo.SetupWord;
+ CustomConfigWord = GigUndiPrivateData->NicInfo.CustomConfigWord;
+
+ switch (LanSpeed)
+ {
+ case LINK_SPEED_AUTO_NEG:
+ //
+ // Speed mask has already been cleared
+ //
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FSP_AUTONEG);
+ hw->mac.autoneg = 1;
+ break;
+ case LINK_SPEED_100FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_100MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ break;
+ case LINK_SPEED_100HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_100MBS;
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ break;
+ case LINK_SPEED_10FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_10MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ break;
+ case LINK_SPEED_10HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_10MBS;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ hw->mac.autoneg = 0;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Only write the EEPROM if the speed/duplex value has changed
+ //
+ if (SetupWord != GigUndiPrivateData->NicInfo.BackupSetupWord) {
+ if (e1000_write_nvm (hw, ConfigOffset, 1, &CustomConfigWord) == E1000_SUCCESS) {
+ if (e1000_write_nvm (hw, SetupOffset, 1, &SetupWord) == E1000_SUCCESS) {
+ //
+ // Success
+ //
+ e1000_update_nvm_checksum (hw);
+ GigUndiPrivateData->NicInfo.BackupSetupWord = SetupWord;
+ }
+ }
+ //
+ // After speed/duplex setting completes we need to perform a full reset of the adapter.
+ // If the adapter was initialized on entry then force a full reset of the adapter.
+ // Also reenable the receive unit if it was enabled before we started the PHY loopback test.
+ //
+
+ ReceiveStarted = GigUndiPrivateData->NicInfo.ReceiveStarted;
+
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (GigUndiPrivateData->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigUndiPrivateData->NicInfo);
+ DEBUGPRINT(HII, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(HII, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigUndiPrivateData->NicInfo);
+ }
+ }
+ DEBUGPRINT(HII, ("ADAPTER RESET COMPLETE\n"));
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+/*++
+
+ Routine Description:
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Request - A null-terminated Unicode string in <ConfigRequest> format.
+ Progress - On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ Results - A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ Returns:
+ EFI_SUCCESS - The Results is filled with the requested values.
+ EFI_OUT_OF_RESOURCES - Not enough memory to store the results.
+ EFI_INVALID_PARAMETER - Request is NULL, illegal syntax, or unknown name.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+
+ DEBUGPRINT(HII, ("ExtractConfig\n"));
+ GigUndiPrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mE1000DataGuid,
+ NULL,
+ &BufferSize,
+ &GigUndiPrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("GetVariable failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ // Get Wake on LAN settings
+
+ GetWakeOnLanSupport(GigUndiPrivateData);
+ GetWakeOnLanStatus(GigUndiPrivateData);
+
+ DEBUGPRINT(HII, ("GetWakeOnLan %d\n", GigUndiPrivateData->Configuration.WolEnable));
+
+ // Get Option ROM Enable status
+
+ GigUndiPrivateData->Configuration.OptionRomEnable = GetFlashEnableStatus(GigUndiPrivateData);
+
+ DEBUGPRINT(HII, ("GetFlashEnable %d\n", GigUndiPrivateData->Configuration.OptionRomEnable));
+
+ //
+ // Get link speed settings
+ //
+ GigUndiPrivateData->Configuration.LinkSpeed = GetLanSpeedStatus(GigUndiPrivateData);
+
+ DEBUGPRINT(HII, ("GetLinkSpeed %d\n", GigUndiPrivateData->Configuration.LinkSpeed));
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = GigUndiPrivateData->HiiConfigRouting->BlockToConfig (
+ GigUndiPrivateData->HiiConfigRouting,
+ Request,
+ (UINT8 *) &GigUndiPrivateData->Configuration,
+ sizeof(GIG_DRIVER_CONFIGURATION),
+ Results,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("BlockToConfig failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ DEBUGWAIT(HII);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Configuration - A null-terminated Unicode string in <ConfigResp> format.
+ Progress - A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ Returns:
+ EFI_SUCCESS - The Results is processed successfully.
+ EFI_INVALID_PARAMETER - Configuration is NULL.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+
+ DEBUGPRINT(HII, ("RouteConfig\n"));
+ GigUndiPrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mE1000DataGuid,
+ NULL,
+ &BufferSize,
+ &GigUndiPrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("GetVariable failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = GigUndiPrivateData->HiiConfigRouting->ConfigToBlock (
+ GigUndiPrivateData->HiiConfigRouting,
+ Configuration,
+ (UINT8 *) &GigUndiPrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("ConfigToBlock returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+ DEBUGPRINT(HII, ("Set WakeOnLan %d\n", GigUndiPrivateData->Configuration.WolEnable));
+
+ SetFlashEnable (
+ GigUndiPrivateData,
+ GigUndiPrivateData->Configuration.OptionRomEnable
+ );
+
+ SetWakeOnLan (
+ GigUndiPrivateData,
+ GigUndiPrivateData->Configuration.WolEnable
+ );
+
+ SetLanSpeed(
+ GigUndiPrivateData,
+ GigUndiPrivateData->Configuration.LinkSpeed
+ );
+
+ //
+ // Store Buffer Storage back to EFI variable
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &mE1000DataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (GIG_DRIVER_CONFIGURATION),
+ &GigUndiPrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("SetVariable failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ DEBUGWAIT(HII);
+ return Status;
+}
+
+EFI_STATUS
+GetFlashEnableInformation (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ UINT32 *EepromWord,
+ UINT16 *EepromBitMask
+ )
+/*++
+
+ Routine Description:
+ This initializes eeprom addresss and bit mask for flash enable/disable operations.
+
+ Arguments:
+
+ Returns:
+ EFI_SUCCESS - The Results is processed successfully.
+ EFI_UNSUPPORTED - flash enable/disable operations not supported on current port.
+
+--*/
+{
+ UINT16 SetupWord;
+ UINT32 Result;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // Check for LOM
+ //
+ Result = e1000_read_nvm(hw, COMPATIBILITY_WORD, 1, &SetupWord);
+
+ if (Result != E1000_SUCCESS) return EFI_DEVICE_ERROR;
+
+ if (SetupWord & COMPATABILITY_LOM_BIT) {
+ DEBUGPRINT(HII, ("LOM - unsupported\n"));
+ DEBUGWAIT(HII);
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(HII, ("\n\nGetFlashEnableInformation\n"));
+ DEBUGPRINT(HII, ("Device ID: %x\n", GigUndiPrivateData->NicInfo.hw.device_id));
+ DEBUGPRINT(HII, ("Function: %x\n", GigUndiPrivateData->NicInfo.Function));
+ DEBUGWAIT(HII);
+
+ switch (GigUndiPrivateData->NicInfo.hw.mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ case e1000_82572:
+ if (GigUndiPrivateData->NicInfo.Function == 0x1)
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3_LANB;
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT;
+ }
+ else
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3;
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT;
+ }
+ break;
+ case e1000_82574:
+ /* Read word containing NVM type bit out of NVM */
+ Result = e1000_read_nvm(hw, E1000_FLASH_SIZE_WORD_HARTW, 1, &SetupWord);
+
+ if (Result != E1000_SUCCESS) return EFI_DEVICE_ERROR;
+
+ if ((GigUndiPrivateData->NicInfo.hw.device_id != E1000_DEV_ID_82574L &&
+ GigUndiPrivateData->NicInfo.hw.device_id != E1000_DEV_ID_82574LA) ||
+ ((SetupWord & E1000_NVM_TYPE_BIT_HARTW) != E1000_NVM_TYPE_BIT_HARTW))
+ {
+ return EFI_UNSUPPORTED;
+ }
+ *EepromWord = E1000_HARTW_FLASH_LAN_ADDRESS;
+ *EepromBitMask = E1000_HARTW_EXP_ROM_DISABLE;
+ break;
+ case e1000_82583:
+ break;
+#endif
+ case e1000_82573:
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+#endif
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ return EFI_UNSUPPORTED;
+ break;
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+ case e1000_82576:
+
+ if (GigUndiPrivateData->NicInfo.hw.subsystem_vendor_id == 0x1734) // FSC
+ {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function == 0x01)
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3_LANB;
+ }
+ else
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3;
+ }
+
+ if ((GigUndiPrivateData->NicInfo.hw.revision_id == 0) &&
+ (GigUndiPrivateData->NicInfo.hw.device_id != E1000_DEV_ID_82576))
+ {
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT;
+ }
+ else
+ {
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT_ZOAR;
+ }
+
+ break;
+#endif /* NO_82575_SUPPORT */
+ case e1000_82580:
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT_ZOAR;
+
+ switch(GigUndiPrivateData->NicInfo.Function)
+ {
+ case 0x1:
+ *EepromWord = (LAN1_BASE_ADDRESS_82580 + E1000_INIT_CONTROL_WORD3);
+ break;
+
+ case 0x2:
+ *EepromWord = (LAN2_BASE_ADDRESS_82580 + E1000_INIT_CONTROL_WORD3);
+ break;
+
+ case 0x3:
+ *EepromWord = (LAN3_BASE_ADDRESS_82580 + E1000_INIT_CONTROL_WORD3);
+ break;
+
+ default: //0x0
+ *EepromWord = E1000_INIT_CONTROL_WORD3;
+ break;
+ }
+
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+ DEBUGPRINT(HII, ("EEPROM Word: %x\n", *EepromWord));
+ DEBUGPRINT(HII, ("EepromBitMask: %x\n", *EepromBitMask));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetFlashEnableSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+ UINT32 EepromWord;
+ UINT16 EepromBitMask;
+
+ return GetFlashEnableInformation(GigUndiPrivateData, &EepromWord, &EepromBitMask);
+}
+
+BOOLEAN
+GetFlashEnableStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+ UINT32 EepromWord;
+ UINT16 EepromBitMask;
+
+ UINT16 ReadWord;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ DEBUGPRINT(HII, ("GetFlashEnableStatus\n"));
+
+ if (GetFlashEnableInformation(GigUndiPrivateData, &EepromWord, &EepromBitMask) != EFI_SUCCESS) {
+ return FALSE;
+ }
+
+ e1000_read_nvm(hw, EepromWord, 1, &ReadWord);
+
+ DEBUGPRINT(HII, ("EEPROM Word: %x\n", EepromWord));
+ DEBUGPRINT(HII, ("EepromBitMask: %x\n", EepromBitMask));
+ DEBUGPRINT(HII, ("ReadWord: %x\n", ReadWord));
+
+ if (ReadWord & EepromBitMask){
+ return FALSE; // Flash disabled
+ } else {
+ return TRUE; // Flash enabled
+ }
+}
+
+EFI_STATUS
+SetFlashEnable (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ BOOLEAN Enable
+)
+{
+ UINT32 EepromWord;
+ UINT16 EepromBitMask;
+
+ UINT16 ConfWord, ConfWordTmp;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ GetFlashEnableInformation(GigUndiPrivateData, &EepromWord, &EepromBitMask);
+
+ e1000_read_nvm(hw, EepromWord, 1, &ConfWord);
+
+ if (Enable){
+ ConfWordTmp = ConfWord & ~EepromBitMask;
+ } else {
+ ConfWordTmp = ConfWord | EepromBitMask;
+ }
+
+ if (ConfWordTmp != ConfWord) {
+ if (e1000_write_nvm (hw, EepromWord, 1, &ConfWordTmp) == E1000_SUCCESS)
+ return EFI_SUCCESS;
+ else return EFI_DEVICE_ERROR;
+ }
+ else return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+HiiOpenProtocol(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize the Hii Database handle to NULL so we can check later
+ // to see whether it was installed.
+ //
+ GigUndiPrivateData->HiiDatabase = NULL;
+ GigUndiPrivateData->HiiString = NULL;
+ GigUndiPrivateData->FormBrowser2 = NULL;
+ GigUndiPrivateData->HiiConfigRouting = NULL;
+
+ DEBUGPRINT(HII, ("Locate HII Protocol\n"));
+ //
+ // Locate Hii Database protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->HiiDatabase
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Locate HiiString protocol
+ //
+ DEBUGPRINT(HII, ("Locate HII String Protocol\n"));
+ Status = gBS->LocateProtocol (
+ &gEfiHiiStringProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->HiiString
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII String protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Locate Formbrowser2 protocol
+ //
+ DEBUGPRINT(HII, ("Locate HII Form Browser Protocol\n"));
+ Status = gBS->LocateProtocol (
+ &gEfiFormBrowser2ProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->FormBrowser2
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII form browser protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ DEBUGPRINT(HII, ("Locate HII ConfigRouting Protocol\n"));
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->HiiConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII ConfigRouting protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ DEBUGWAIT(HII);
+ return Status;
+}
+
+VOID
+SetMacIdString (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ OUT CHAR16 *String
+ )
+{
+ switch (GigUndiPrivateData->NicInfo.hw.mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ UnicodeSPrint(String, 80, L"Intel 82571");
+ break;
+ case e1000_82572:
+ UnicodeSPrint(String, 80, L"Intel 82572");
+ break;
+ case e1000_82573:
+ UnicodeSPrint(String, 80, L"Intel 82573");
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ UnicodeSPrint(String, 80, L"Intel 82574");
+ break;
+ case e1000_82583:
+ UnicodeSPrint(String, 80, L"Intel 82583V");
+ break;
+#endif
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+ UnicodeSPrint(String, 80, L"Intel 80003ES2LAN");
+ break;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich8lan:
+ UnicodeSPrint(String, 80, L"Intel ICH8");
+ break;
+ case e1000_ich9lan:
+ UnicodeSPrint(String, 80, L"Intel ICH9");
+ break;
+ case e1000_pchlan:
+ UnicodeSPrint(String, 80, L"Intel PCH");
+ break;
+#endif
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+ UnicodeSPrint(String, 80, L"Intel 82575");
+ break;
+ case e1000_82576:
+ UnicodeSPrint(String, 80, L"Intel 82576");
+ break;
+#endif /* NO_82575_SUPPORT */
+ case e1000_82580:
+ UnicodeSPrint(String, 80, L"Intel 82580");
+ break;
+
+ default:
+ UnicodeSPrint(String, 80, L"unknown");
+ break;
+ }
+}
+
+
+VOID
+SetWakeOnLan (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINT8 Enable
+ )
+{
+ UINT16 Reg;
+ UINT16 Offset;
+
+ DEBUGPRINT(HII, ("SetWakeOnLan\n"));
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ DEBUGPRINT(HII, ("WOL not supported on this port\n"));
+ return;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function == 0) {
+ Offset = E1000_INIT_CONTROL_WORD3;
+ } else {
+ Offset = E1000_INIT_CONTROL_WORD3_LANB;
+ }
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+ if (Enable == WOL_ENABLE) {
+ Reg |= E1000_APM_ENABLE_BIT;
+ } else {
+ Reg &= ~E1000_APM_ENABLE_BIT;
+ }
+ e1000_write_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+
+ Offset = E1000_INIT_CONTROL_WORD2;
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+ if (Enable == WOL_ENABLE) {
+ Reg |= E1000_APM_PME_ENABLE_BIT;
+ } else {
+ Reg &= ~E1000_APM_PME_ENABLE_BIT;
+ }
+ e1000_write_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+
+ e1000_update_nvm_checksum(&GigUndiPrivateData->NicInfo.hw);
+
+ return;
+}
+
+VOID
+GetWakeOnLanSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumHandles = 0;
+ EFI_HANDLE *HandleBuf;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Seg, Bus, Device, Function;
+ UINT16 DeviceId;
+ UINTN i = 0;
+ BOOLEAN LomBit;
+
+ UINT16 SetupWord;
+ UINT32 Result;
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ LomBit = FALSE; // Default LomBit to FALSE
+
+ DEBUGPRINT(HII, ("GetWakeOnLanSupport\n"));
+ DEBUGWAIT(HII);
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Check for LOM
+ //
+ Result = e1000_read_nvm(hw, COMPATIBILITY_WORD, 1, &SetupWord);
+
+ if (Result == E1000_SUCCESS){
+ if (SetupWord & COMPATABILITY_LOM_BIT){
+ LomBit = TRUE;
+ }
+ }
+
+ GigUndiPrivateData->Configuration.WolEnable = WOL_DISABLE;
+
+ //
+ // Check for WOL special cases.
+ //
+ switch (GigUndiPrivateData->NicInfo.hw.device_id) {
+ case E1000_DEV_ID_82571EB_COPPER:
+ if (GigUndiPrivateData->NicInfo.hw.subsystem_device_id != 0x135E) {
+ break;
+ }
+ case E1000_DEV_ID_82576: // WOL supported on each port of 82576 LOM device
+ DEBUGPRINT(HII, ("WOL supported on LOM device with ID: %X with subdevice ID: %X\n",
+ GigUndiPrivateData->NicInfo.hw.device_id, GigUndiPrivateData->NicInfo.hw.subsystem_device_id));
+ DEBUGWAIT(HII);
+ if (LomBit == FALSE) break;
+ case E1000_DEV_ID_82576_SERDES_QUAD:
+ DEBUGPRINT(HII, ("WOL supported on this device ID: %X with subdevice ID: %X\n",
+ GigUndiPrivateData->NicInfo.hw.device_id, GigUndiPrivateData->NicInfo.hw.subsystem_device_id));
+ DEBUGWAIT(HII);
+ return;
+ case E1000_DEV_ID_82575GB_QUAD_COPPER:
+ GigUndiPrivateData->Configuration.WolEnable = WOL_NA;
+ DEBUGPRINT(HII, ("WOL not supported on this device ID: %X\n", GigUndiPrivateData->NicInfo.hw.device_id));
+ DEBUGWAIT(HII);
+ return;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function != 0) {
+ GigUndiPrivateData->Configuration.WolEnable = WOL_NA;
+ DEBUGPRINT(HII, ("WOL not supported on non-primary port!\n"));
+ DEBUGWAIT(HII);
+ return;
+ }
+
+ //
+ // Check for quad-port device WOL support
+ //
+ if (GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571EB_QUAD_COPPER ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571EB_QUAD_COPPER_LP ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571EB_QUAD_FIBER ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82576_QUAD_COPPER ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82576_QUAD_COPPER_ET2 ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571PT_QUAD_COPPER
+ ) {
+
+ DEBUGPRINT(HII, ("Quad port card detected, device ID: %x\n", GigUndiPrivateData->NicInfo.hw.device_id));
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuf
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LocateHandleBuffer returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return;
+ }
+
+ for (i = 0; i < NumHandles; i++) {
+ Status = gBS->OpenProtocol (
+ HandleBuf[i],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ GigUndiPrivateData->ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns status %r for handle[%d] %X\n", Status, i, HandleBuf[i]));
+ continue;
+ }
+
+ PciIo->GetLocation (
+ PciIo,
+ &Seg,
+ &Bus,
+ &Device,
+ &Function
+ );
+
+ //
+ // Only PCI function 0 on the first device supports WOL. On PCIe
+ // cards each device will be on its own secondary bus as device 0.
+ // If we can read device 0 at the next lower bus number and it's
+ // the same ID, then we are looking at the second device on the
+ // card and WOL is not supported. Otherwise it must be the PCIe
+ // switch and therefore this is the first device.
+ //
+ if (Bus == (GigUndiPrivateData->NicInfo.Bus - 1)) {
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 2,
+ 1,
+ &DeviceId
+ );
+ DEBUGPRINT(HII, ("GetWakeOnLanSupport: Read device ID %X on Bus %d\n", DeviceId, Bus));
+ if (DeviceId == GigUndiPrivateData->NicInfo.hw.device_id) {
+ DEBUGPRINT(HII, ("WOL not supported on non-primary port!\n"));
+ GigUndiPrivateData->Configuration.WolEnable = WOL_NA;
+ }
+
+ Status = gBS->CloseProtocol(
+ HandleBuf[i],
+ &gEfiPciIoProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ GigUndiPrivateData->ControllerHandle
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CloseProtocol returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ break;
+ }
+
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ DEBUGPRINT(HII, ("WOL not supported on this port!\n"));
+ } else {
+ DEBUGPRINT(HII, ("WOL supported on this port!\n"));
+ }
+
+ DEBUGWAIT(HII);
+}
+
+VOID
+GetWakeOnLanStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+{
+ UINT16 Reg;
+ UINT16 Offset;
+
+ DEBUGPRINT(HII, ("GetWakeOnLanStatus\n"));
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ DEBUGPRINT(HII, ("WOL not supported on this port\n"));
+ return;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function == 0) {
+ Offset = E1000_INIT_CONTROL_WORD3;
+ DEBUGPRINT(HII, ("Port A WoL status\n"));
+ } else {
+ Offset = E1000_INIT_CONTROL_WORD3_LANB;
+ DEBUGPRINT(HII, ("Port B WoL status\n"));
+ }
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+ if ((Reg & E1000_APM_ENABLE_BIT) == E1000_APM_ENABLE_BIT) {
+ GigUndiPrivateData->Configuration.WolEnable = WOL_ENABLE;
+ DEBUGPRINT(HII, ("WOL is enabled on this port\n"));
+ } else {
+ GigUndiPrivateData->Configuration.WolEnable = WOL_DISABLE;
+ DEBUGPRINT(HII, ("WOL is disabled on this port\n"));
+ }
+
+}
+
+EFI_STATUS
+SetMenuStrings(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ CHAR8 *Lang
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *BrandString;
+ CHAR16 String[HII_STRING_LEN];
+ CHAR16 SubString[HII_STRING_LEN];
+ CHAR8 MacAddr[6];
+ UINTN i, Size;
+ CHAR8 PBAString8[MAX_PBA_STR_LENGTH];
+ CHAR16 PBAString[MAX_PBA_STR_LENGTH];
+
+
+ BrandString = GigUndiPrivateData->Brand;
+
+ //
+ // Branding strings are not localized, use the English branding
+ // string.
+ //
+ UnicodeSPrint(SubString, 85, L"%s", BrandString);
+ UnicodeSPrint(String, 0, L"%s - %02x:%02x:%02x:%02x:%02x:%02x",
+ SubString,
+ GigUndiPrivateData->NicInfo.hw.mac.addr[0],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[1],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[2],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[3],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[4],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[5]);
+
+ Status = HiiSetString (
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_INV_FORM_SET_TITLE),
+ String,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set Factory Default MAC address
+ //
+ DEBUGPRINT(HII, ("Setting MAC address\n"));
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, 0, 3, (UINT16*) MacAddr);
+
+ DEBUGPRINT(HII, ("Adjusting MAC address for PCI function %d\n", (CHAR8) GigUndiPrivateData->NicInfo.Function));
+ MacAddr[5] ^= (CHAR8) GigUndiPrivateData->NicInfo.Function;
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_MAC_ADDR_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("1:GetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ UnicodeSPrint(String, 0, SubString, MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]);
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_MAC_ADDR_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("1:SetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set Alternate MAC address
+ //
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ALT_MAC_ADDR_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("2:GetString error: %r, Size = %d\n", Status, Size));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ UnicodeSPrint(String, 0, SubString,
+ GigUndiPrivateData->NicInfo.hw.mac.addr[0],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[1],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[2],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[3],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[4],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[5]);
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ALT_MAC_ADDR_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("1:SetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set PCI Bus/Device/Function
+ //
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_PCI_BUS_DEV_FUNC_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ UnicodeSPrint(String, 0, SubString,
+ GigUndiPrivateData->NicInfo.Bus,
+ GigUndiPrivateData->NicInfo.Device,
+ GigUndiPrivateData->NicInfo.Function
+ );
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_PCI_BUS_DEV_FUNC_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("4:SetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+
+ //
+ // Set UEFI Driver Branding String
+ //
+ GigUndiComponentNameGetDriverName ( NULL, "eng", &BrandString);
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_EFI_DRIVER_VER_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ UnicodeSPrint(String, 0, SubString, BrandString);
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_EFI_DRIVER_VER_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("4:IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set MAC ID String, not localized, use English string.
+ //
+ SetMacIdString(GigUndiPrivateData, String);
+ Status = HiiSetString (
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_CONTROLER_ID_TEXT),
+ String,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("6:IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set PBA number
+ //
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ADAPTER_PBA_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+
+ if (e1000_read_pba_string(
+ &GigUndiPrivateData->NicInfo.hw,
+ (UINT8*)PBAString8,
+ MAX_PBA_STR_LENGTH) == E1000_SUCCESS) {
+
+ //
+ // Convert CHAR8 to CHAR16 for use with UnicodeSPrint
+ //
+ i = 0;
+ while((PBAString8[i] != '\0') && (i < MAX_PBA_STR_LENGTH)) {
+ PBAString[i] = (CHAR16)PBAString8[i];
+ i++;
+ }
+ PBAString[i] = '\0';
+
+ UnicodeSPrint(String, 0, SubString, PBAString);
+ }
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ADAPTER_PBA_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("4:IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AddDynamicContents(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+/*++
+
+ Routine Description:
+ This function adds some OneOfOpcodes to port configuration form. These Opcodes are dynamically configured
+ depending of current adapter and port capabilities.
+
+ Arguments:
+ GigUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if opcodes were added correctly, otherwise EFI error code
+ is returned.
+
+--*/
+{
+#if 0 //TODO: Port Me
+ EFI_STATUS Status;
+ UINTN CapCnt;
+ IFR_OPTION *IfrOptionList;
+
+ UINT8 QuestionFlags;
+
+ //
+ // Initialize the container for dynamic opcodes.
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ //
+ // Allocate space for creation of Option List
+ //
+ IfrOptionList = AllocatePool (5 * sizeof (IFR_OPTION));
+ if (IfrOptionList == NULL){
+ DEBUGPRINT(CRITICAL, ("Allocate memory for IfrOptionList, out of resource.\n"));
+ DEBUGWAIT(CRITICAL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Create Flash Enable/Disable options
+ //
+
+ if (GetFlashEnableSupport (GigUndiPrivateData) == EFI_SUCCESS) {
+ IfrOptionList[0].Flags = 0;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_DISABLED_TEXT);
+ IfrOptionList[0].Value.UINT8 = OROM_DISABLE;
+ IfrOptionList[1].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_ENABLED_TEXT);
+ IfrOptionList[1].Value.UINT8 = OROM_ENABLE;
+
+ CapCnt = 2;
+
+ QuestionFlags = EFI_IFR_FLAG_RESET_REQUIRED;
+ } else {
+ IfrOptionList[0].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_NA_TEXT);
+ IfrOptionList[0].Value.UINT8 = OROM_DISABLE;
+
+ CapCnt = 1;
+
+ QuestionFlags = EFI_IFR_FLAG_READ_ONLY;
+ }
+
+ //
+ // Create OneOfOpcode
+ //
+ Status = HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ 0x8001, // Question ID
+ 0x1234, // Variable ID
+ 0, // Offset for Enable OROM field
+ STRING_TOKEN (STR_OPTION_ROM_EN_PROMPT), // Prompt Token
+ STRING_TOKEN (STR_OPTION_ROM_EN_HELP), // Help Token
+ QuestionFlags,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ CapCnt, // Number of Options
+ NULL
+ );
+
+ //
+ // Create link speed options depending on link capabilities of adapter
+ //
+
+ CapCnt=0;
+
+ IfrOptionList[0].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_AUTONEG_TEXT);
+ IfrOptionList[0].Value.UINT8 = LINK_SPEED_AUTO_NEG;
+ CapCnt++;
+
+ QuestionFlags = EFI_IFR_FLAG_READ_ONLY;
+
+ // Other options are only available for copper media type
+
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type == e1000_media_type_copper) {
+
+ IfrOptionList[1].Flags = 0;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_10HALF_TEXT);
+ IfrOptionList[1].Value.UINT8 = LINK_SPEED_10HALF;
+ IfrOptionList[2].Flags = 0;
+ IfrOptionList[2].StringToken = STRING_TOKEN (STR_10FULL_TEXT);
+ IfrOptionList[2].Value.UINT8 = LINK_SPEED_10FULL;
+ IfrOptionList[3].Flags = 0;
+ IfrOptionList[3].StringToken = STRING_TOKEN (STR_100HALF_TEXT);
+ IfrOptionList[3].Value.UINT8 = LINK_SPEED_100HALF;
+ IfrOptionList[4].Flags = 0;
+ IfrOptionList[4].StringToken = STRING_TOKEN (STR_100FULL_TEXT);
+ IfrOptionList[4].Value.UINT8 = LINK_SPEED_100FULL;
+ CapCnt+=4;
+
+ QuestionFlags = 0;
+
+ }
+
+ //
+ // Create OneOfOpcode
+ //
+ Status = HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ 0x8001, // Question ID
+ 0x1234, // Variable ID
+ 1, // Offset for LinkSpeed field
+ STRING_TOKEN (STR_LINK_SPEED_PROMPT), // Prompt Token
+ STRING_TOKEN (STR_LINK_SPEED_HELP), // Help Token
+ QuestionFlags,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ CapCnt, // Number of Options
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CreateOneOfOpcode %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Create WOL options depending on port capabilities
+ //
+
+ GetWakeOnLanSupport(GigUndiPrivateData);
+ GetWakeOnLanStatus(GigUndiPrivateData);
+
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ IfrOptionList[0].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_NA_TEXT);
+ IfrOptionList[0].Value.UINT8 = WOL_NA;
+
+ CapCnt = 1;
+
+ QuestionFlags = EFI_IFR_FLAG_READ_ONLY;
+
+ } else {
+ IfrOptionList[0].Flags = 0;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_DISABLED_TEXT);
+ IfrOptionList[0].Value.UINT8 = WOL_DISABLE;
+ IfrOptionList[1].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_ENABLED_TEXT);
+ IfrOptionList[1].Value.UINT8 = WOL_ENABLE;
+
+ CapCnt = 2;
+
+ QuestionFlags = 0;
+
+ }
+
+ //
+ // Create OneOfOpcode
+ //
+ Status = HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ 0x8001, // Question ID
+ 0x1234, // Variable ID
+ 2, // Offset for LegacyBoot field
+ STRING_TOKEN (STR_WOL_TEXT), // Prompt Token
+ STRING_TOKEN (STR_WOL_HELP), // Help Token
+ QuestionFlags,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ CapCnt, // Number of Options
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CreateOneOfOpcode %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+
+ //
+ // Update Form ID 0x1235 with newly created element
+ //
+
+ Status = HiiUpdateForm (
+ GigUndiPrivateData->HiiHandle,
+ &mHiiFormGuid,
+ FORM_2, // Destination form ID
+ TRUE,
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("IfrLibUpdateForm %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ gBS->FreePool (IfrOptionList);
+
+ return Status;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+
+EFI_STATUS
+InventoryPackage(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+#if 0 //TODO: PortMe
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList = NULL;
+ CHAR8 Lang[HII_STRING_LEN];
+ CHAR8 SubLang[HII_STRING_LEN];
+ UINTN Size;
+ UINTN i, j;
+
+ DEBUGPRINT(HII, ("InventoryPackage\n"));
+
+ PackageList = PreparePackageList (
+ 2,
+ &GigUndiPrivateData->HiiFormGuid,
+ GigUndiStrings,
+ inventoryBin
+ );
+ if (PackageList == NULL) {
+ DEBUGPRINT(CRITICAL, ("PreparePackageList, out of resource.\n"));
+ DEBUGWAIT(CRITICAL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUGPRINT(HII, ("Calling NewPackageList: %X %X\n", GigUndiPrivateData->HiiDatabase, PackageList));
+ Status = GigUndiPrivateData->HiiDatabase->NewPackageList (
+ GigUndiPrivateData->HiiDatabase,
+ PackageList,
+ GigUndiPrivateData->ControllerHandle,
+ &GigUndiPrivateData->HiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PackageList);
+ DEBUGPRINT(CRITICAL, ("NewPackageList error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetLanguages (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ Lang,
+ &Size
+ );
+
+ for (i = 0; i < Size; i++) {
+ DEBUGPRINT(HII, ("%c", Lang[i]));
+ }
+ DEBUGPRINT (HII, ("Languages: %a, Size: %d\n", Lang, Size));
+ DEBUGPRINT (HII, ("GetLanguages returns %r\n", Status));
+
+ i = 0;
+ while (i < Size) {
+ j=0;
+ do {
+ if (Lang[i] == ';') {
+ SubLang[j]='\0';
+ i++;
+ j++;
+ break;
+ }else{
+ SubLang[j]=Lang[i];
+ i++;
+ j++;
+ }
+
+ } while (Lang[i] != '\0');
+
+ //
+ //Set strings for all languages except x-UEFI
+ //
+ if (SubLang[0] != 'x') Status = SetMenuStrings(GigUndiPrivateData, SubLang);
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("SetMenuStrings returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ break;
+ }
+
+ // This was the last supported language so we can leave the loop
+ if (Lang[i] == '\0')
+ break;
+ }
+
+ Status = AddDynamicContents(GigUndiPrivateData);
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("AddDynamicContents returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ return Status;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+EFI_STATUS
+EFIAPI
+DriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT(HII, ("DriverCallback\n"));
+ DEBUGWAIT(HII);
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+
+ switch (QuestionId) {
+ case 0x1236:
+ DEBUGPRINT(HII, ("Save key press\n"));
+ DEBUGWAIT(HII);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ break;
+
+ case 0x1237:
+ //
+ // User press "Exit now", request Browser to exit
+ //
+ DEBUGPRINT(HII, ("Exit key press\n"));
+ DEBUGWAIT(HII);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+HiiInit (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Installs the HII user interface screen in the UEFI device manager.
+
+ Arguments:
+ GigUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if HII interface installed correctly, otherwise EFI error code
+ is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_SCREEN_DESCRIPTOR Screen;
+ UINTN BufferSize;
+ BOOLEAN ExtractIfrDefault;
+ UINT8 MacAddr[6];
+
+ DEBUGPRINT(HII, ("HiiInit\n"));
+
+ //
+ // Try to open the HII protocols first. If they are not present in the system
+ // get out.
+ //
+ Status = HiiOpenProtocol(GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("HiiOpenProtocol returns: %x\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Initialize screen dimensions for SendForm().
+ // Remove 3 characters from top and bottom
+ //
+ ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow);
+
+ Screen.TopRow = 3;
+ Screen.BottomRow = Screen.BottomRow - 3;
+
+ e1000_MemCopy ((UINT8 *) (UINTN) &GigUndiPrivateData->HiiFormGuid, (UINT8 *) (UINTN) &mHiiFormGuid, sizeof(EFI_GUID));
+ //
+ // Copy the factory default MAC address into the last 6 bytes of the GUID to ensure the GUID is unique.
+ //
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, 0, 3, (UINT16*) MacAddr);
+ MacAddr[5] ^= (CHAR8) GigUndiPrivateData->NicInfo.Function;
+
+ GigUndiPrivateData->HiiFormGuid.Data4[0] = MacAddr[0];
+ GigUndiPrivateData->HiiFormGuid.Data4[1] = MacAddr[1];
+ GigUndiPrivateData->HiiFormGuid.Data4[2] = MacAddr[2];
+ GigUndiPrivateData->HiiFormGuid.Data4[3] = MacAddr[3];
+ GigUndiPrivateData->HiiFormGuid.Data4[4] = MacAddr[4];
+ GigUndiPrivateData->HiiFormGuid.Data4[5] = MacAddr[5];
+
+
+ GigUndiPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ GigUndiPrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ GigUndiPrivateData->ConfigAccess.Callback = DriverCallback;
+
+ Status = gBS->InstallProtocolInterface (
+ &GigUndiPrivateData->ControllerHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &GigUndiPrivateData->ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InstallProtocolInterface error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = InventoryPackage(GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InventoryPackage returns: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Initialize configuration data
+ //
+ DEBUGPRINT(HII, ("initialize configuration data\n"));
+ ZeroMem (&GigUndiPrivateData->Configuration, sizeof (GIG_DRIVER_CONFIGURATION));
+
+ //
+ // Try to read NV config EFI variable first
+ //
+ ExtractIfrDefault = TRUE;
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mE1000DataGuid,
+ NULL,
+ &BufferSize,
+ &GigUndiPrivateData->Configuration
+ );
+ if (!EFI_ERROR (Status) && (BufferSize == sizeof (GIG_DRIVER_CONFIGURATION))) {
+ DEBUGPRINT(HII, ("E1000 NV variable already created\n"));
+ ExtractIfrDefault = FALSE;
+ }
+
+ if (ExtractIfrDefault) {
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ DEBUGPRINT(HII, ("Creating E1000 variable.\n"));
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+
+ GigUndiPrivateData->Configuration.OptionRomEnable = GetFlashEnableStatus(GigUndiPrivateData);
+ GigUndiPrivateData->Configuration.LinkSpeed = GetLanSpeedStatus(GigUndiPrivateData);
+
+ GetWakeOnLanSupport (GigUndiPrivateData);
+ GetWakeOnLanStatus (GigUndiPrivateData);
+
+ gRT->SetVariable(
+ VariableName,
+ &mE1000DataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (GIG_DRIVER_CONFIGURATION),
+ &GigUndiPrivateData->Configuration
+ );
+ }
+
+
+ DEBUGPRINT(HII, ("HiiInit is complete\n"));
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+HiiUnload (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ HII uninstalls the HII user interface screen in the UEFI device manager.
+
+ Arguments:
+ GigUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if HII interface uninstalled correctly, otherwise EFI error code
+ is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ if (GigUndiPrivateData->HiiDatabase == NULL ||
+ GigUndiPrivateData->HiiString == NULL ||
+ GigUndiPrivateData->FormBrowser2 == NULL ||
+ GigUndiPrivateData->HiiConfigRouting == NULL
+ ) {
+ DEBUGPRINT(HII, ("HII Not initialized, returning.\n"));
+ return EFI_SUCCESS;
+ }
+
+ DEBUGPRINT(HII, ("Calling RemovePackageList: %X\n", GigUndiPrivateData->HiiDatabase));
+ Status = GigUndiPrivateData->HiiDatabase->RemovePackageList (
+ GigUndiPrivateData->HiiDatabase,
+ GigUndiPrivateData->HiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("RemovePackageList error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+
+ Status = gBS->UninstallProtocolInterface (
+ GigUndiPrivateData->ControllerHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &GigUndiPrivateData->ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallProtocolInterface error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ return Status;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h
new file mode 100755
index 0000000..bf582ab
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 2004-2010, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Hii.h
+
+Abstract:
+
+
+Revision History
+
+--*/
+
+#ifndef _HII_H_
+#define _HII_H_
+
+#include "NVDataStruc.h"
+
+//
+// This is the generated header file which includes whatever needs to be exported (strings + IFR)
+//
+#include "LanIntelE1000DxeStrDefs.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of PreparePackageList() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 vfrBin[];
+extern UINT8 inventoryBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of PreparePackageList() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 GigUndiStrings[];
+
+#define SAMPLE_STRING L"This is an error!"
+
+#define DRIVER_SAMPLE_PRIVATE_SIGNATURE SIGNATURE_32 ('D', 'S', 'p', 's')
+
+//
+// EEPROM power management bit definitions
+//
+#define E1000_INIT_CONTROL_WORD1 0x0A
+#define E1000_PME_ENABLE_BIT 0x0008
+
+#define E1000_INIT_CONTROL_WORD2 0x0F
+#define E1000_APM_PME_ENABLE_BIT 0x8000
+
+#define E1000_LEGACY_APM_ENABLE_BIT 0x0004
+#define E1000_LEGACY_FLASH_DISABLE_BIT 0x0100
+
+#define E1000_INIT_CONTROL_WORD3 0x24
+#define E1000_INIT_CONTROL_WORD3_LANB 0x14
+#define E1000_FLASH_DISABLE_BIT 0x0800
+#define E1000_FLASH_DISABLE_BIT_ZOAR 0x0080
+#define E1000_APM_ENABLE_BIT 0x0400
+
+#define E1000_FLASH_SIZE_WORD_HARTW 0xf
+#define E1000_NVM_TYPE_BIT_HARTW 0x1000
+
+#define E1000_HARTW_FLASH_LAN_ADDRESS 0x21
+#define E1000_HARTW_EXP_ROM_DISABLE 0x80 /* bit 7 */
+
+#define LAN1_BASE_ADDRESS_82580 0x80
+#define LAN2_BASE_ADDRESS_82580 0xC0
+#define LAN3_BASE_ADDRESS_82580 0x100
+
+
+#define HII_STRING_LEN 200
+#define MAX_PBA_STR_LENGTH 15 // normally it is 10 chars string
+
+#define DRIVER_SAMPLE_PRIVATE_FROM_THIS(a) CR (a, GIG_UNDI_PRIVATE_DATA, ConfigAccess, GIG_UNDI_DEV_SIGNATURE)
+
+#endif
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h
new file mode 100755
index 0000000..7be86a5
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h
@@ -0,0 +1,33 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c
new file mode 100755
index 0000000..6979034
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c
@@ -0,0 +1,1505 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "clp.h"
+
+
+//
+// Global Variables
+//
+VOID *e1000_pxe_memptr = NULL;
+PXE_SW_UNDI *e1000_pxe_31 = NULL; // 3.1 entry
+GIG_UNDI_PRIVATE_DATA *e1000_UNDI32DeviceList[MAX_NIC_INTERFACES];
+NII_TABLE e1000_UndiData;
+UINT8 ActiveInterfaces = 0;
+EFI_EVENT EventNotifyExitBs;
+EFI_EVENT EventNotifyVirtual;
+
+//
+// external Global Variables
+//
+extern UNDI_CALL_TABLE e1000_api_table[];
+extern EFI_COMPONENT_NAME_PROTOCOL gGigUndiComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gGigUndiComponentName2;
+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gGigUndiSupportedEFIVersion;
+extern EFI_DRIVER_CONFIGURATION_PROTOCOL gGigUndiDriverConfiguration;
+extern EFI_DRIVER_DIAGNOSTICS_PROTOCOL gGigUndiDriverDiagnostics;
+extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gGigUndiDriverDiagnostics2;
+
+extern EFI_GUID gEfiStartStopProtocolGuid;
+
+#define EFI_PRO1000_COM_GUID \
+ { \
+ 0xE3161450, 0xAD0F, 0x11D9, \
+ { \
+ 0x96, 0x69, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 \
+ } \
+ }
+
+EFI_GUID gEfiPro1000ComGuid = EFI_PRO1000_COM_GUID;
+
+//
+// function prototypes
+//
+EFI_STATUS
+EFIAPI
+InitializeGigUNDIDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+VOID
+EFIAPI
+GigUndiNotifyExitBs (
+ EFI_EVENT Event,
+ VOID *Context
+ );
+
+EFI_STATUS
+InitializePxeStruct(VOID);
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+GigAppendMac2DevPath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+VOID
+GigUndiPxeStructInit (
+ PXE_SW_UNDI *PxePtr,
+ UINTN VersionFlag
+ );
+
+VOID
+GigUndiPxeUpdate (
+ IN GIG_DRIVER_DATA *NicPtr,
+ IN PXE_SW_UNDI *PxePtr
+ );
+
+EFI_STATUS
+EFIAPI
+GigUndiUnload (
+ IN EFI_HANDLE ImageHandle
+ );
+
+UINT8
+e1000_ChkSum (
+ IN VOID *Buffer,
+ IN UINT16 Len
+ );
+
+EFI_STATUS
+EFIAPI
+HiiInit (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+EFI_STATUS
+EFIAPI
+HiiUnload (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+EFI_STATUS
+InitFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+
+EFI_STATUS
+UninstallFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+//
+// end function prototypes
+//
+//
+// This is a macro to convert the preprocessor defined version number into a hex value
+// that can be registered with EFI.
+//
+#define VERSION_TO_HEX ((MAJORVERSION << 24) + (MINORVERSION << 16) + (BUILDNUMBER / 10 << 12) + (BUILDNUMBER % 10 << 8))
+
+//
+// UNDI Class Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding = {
+ GigUndiDriverSupported, // Supported
+ GigUndiDriverStart, // Start
+ GigUndiDriverStop, // Stop
+ VERSION_TO_HEX, // Driver Version
+ NULL, // ImageHandle
+ NULL // Driver Binding Handle
+};
+
+EFI_STATUS
+EFIAPI
+InitializeGigUNDIDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+ Register Driver Binding protocol for this driver.
+
+Arguments:
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
+
+Returns:
+ EFI_SUCCESS - Driver loaded.
+ other - Driver not loaded.
+
+--*/
+// GC_TODO: ImageHandle - add argument and description to function comment
+// GC_TODO: SystemTable - add argument and description to function comment
+{
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImageInterface;
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBinding (ImageHandle, SystemTable, &mGigUndiDriverBinding, ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUGPRINT (INIT, ("SystemTable->Hdr.Revision = %x\n", SystemTable->Hdr.Revision));
+
+ DEBUGPRINT (INIT, ("Installing UEFI 1.10/2.10 Driver Diags and Component Name protocols.\n"));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mGigUndiDriverBinding.DriverBindingHandle,
+ &gEfiComponentNameProtocolGuid,
+ &gGigUndiComponentName,
+ &gEfiDriverDiagnosticsProtocolGuid,
+ &gGigUndiDriverDiagnostics,
+ &gEfiComponentName2ProtocolGuid,
+ &gGigUndiComponentName2,
+ &gEfiDriverDiagnostics2ProtocolGuid,
+ &gGigUndiDriverDiagnostics2,
+ &gEfiDriverConfigurationProtocolGuid,
+ &gGigUndiDriverConfiguration,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("InstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+ if (SystemTable->Hdr.Revision >= EFI_2_10_SYSTEM_TABLE_REVISION) {
+ DEBUGPRINT (INIT, ("Installing UEFI 2.1 Supported EFI Version Protocol.\n"));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gGigUndiSupportedEFIVersion,
+ NULL
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("InstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+
+ //
+ // This protocol does not need to be closed because it uses the GET_PROTOCOL attribute
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID *) &LoadedImageInterface,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ return Status;
+ }
+
+ LoadedImageInterface->Unload = GigUndiUnload;
+
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_NOTIFY,
+ GigUndiNotifyExitBs,
+ NULL,
+ &EventNotifyExitBs
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CreateEvent returns %r\n", Status));
+ return Status;
+ }
+
+ Status = InitializePxeStruct();
+
+ return Status;
+}
+
+
+EFI_STATUS
+InitializePxeStruct(VOID)
+/*++
+
+Routine Description:
+ Allocate and initialize both (old and new) the !pxe structures here,
+ there should only be one copy of each of these structure for any number
+ of NICs this undi supports. Also, these structures need to be on a
+ paragraph boundary as per the spec. so, while allocating space for these,
+ make sure that there is space for 2 !pxe structures (old and new) and a
+ 32 bytes padding for alignment adjustment (in case)
+
+Arguments:
+ VOID
+
+Returns:
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData, //EfiRuntimeServicesData,
+ (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),
+ &e1000_pxe_memptr
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("AllocatePool returns %r\n", Status));
+ return Status;
+ }
+
+ ZeroMem (
+ e1000_pxe_memptr,
+ sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32
+ );
+
+ //
+ // check for paragraph alignment here, assuming that the pointer is
+ // already 8 byte aligned.
+ //
+ if (((UINTN) e1000_pxe_memptr & 0x0F) != 0) {
+ e1000_pxe_31 = (PXE_SW_UNDI *) ((UINTN)( (((UINTN)e1000_pxe_memptr) & (0xFFFFFFFFFFFFFFF0)) + 0x10 ));
+ } else {
+ e1000_pxe_31 = (PXE_SW_UNDI *) e1000_pxe_memptr;
+ }
+
+ //
+ // assuming that the sizeof pxe_31 is a 16 byte multiple
+ //
+ //e1000_pxe = (PXE_SW_UNDI*)((UINT8 *)(e1000_pxe_31) + sizeof (PXE_SW_UNDI));
+
+ // GigUndiPxeStructInit (e1000_pxe, 0x30); // 3.0 entry point
+ GigUndiPxeStructInit (e1000_pxe_31, 0x31); // 3.1 entry
+
+ return Status;
+}
+
+VOID
+EFIAPI
+GigUndiNotifyExitBs (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+/*++
+
+Routine Description:
+ When EFI is shuting down the boot services, we need to install a
+ configuration table for UNDI to work at runtime!
+
+Arguments:
+ (Standard Event handler)
+
+Returns:
+ None
+
+--*/
+// GC_TODO: Context - add argument and description to function comment
+{
+ UINT32 i;
+
+ //
+ // Divide Active interfaces by two because it tracks both the controller and
+ // child handle, then shutdown the receive unit in case it did not get done
+ // by the SNP, and release the software semaphore aquired by the shared code
+ //
+ for (i = 0; i < ActiveInterfaces; i++) {
+ if (e1000_UNDI32DeviceList[i]->NicInfo.hw.device_id != 0) {
+ E1000_WRITE_REG (&(e1000_UNDI32DeviceList[i]->NicInfo.hw), E1000_RCTL, 0);
+ E1000_WRITE_REG (&(e1000_UNDI32DeviceList[i]->NicInfo.hw), E1000_SWSM, 0);
+ e1000_PciFlush (&e1000_UNDI32DeviceList[i]->NicInfo.hw);
+ //
+ // Delay for 10ms to allow in progress DMA to complete
+ //
+ gBS->Stall(10000);
+ }
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+GigUndiUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+ Callback to unload the GigUndi from memory.
+
+Arguments:
+ ImageHandle to driver.
+
+Returns:
+ EFI_SUCCESS - This driver was unloaded successfully.
+ EFI_INVALID_PARAMETER - This driver was not unloaded.
+
+--*/
+{
+ EFI_HANDLE *DeviceHandleBuffer;
+ UINTN DeviceHandleCount;
+ UINTN Index;
+
+ EFI_STATUS Status;
+
+ DEBUGPRINT(INIT, ("GigUndiUnload e1000_pxe->IFcnt = %d\n", e1000_pxe_31->IFcnt));
+ DEBUGWAIT (INIT);
+
+ //
+ // Get the list of all the handles in the handle database.
+ // If there is an error getting the list, then the unload operation fails.
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &DeviceHandleCount,
+ &DeviceHandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("LocateHandleBuffer returns %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Disconnect the driver specified by ImageHandle from all the devices in the
+ // handle database.
+ //
+ DEBUGPRINT(INIT, ("Active interfaces = %d\n", ActiveInterfaces));
+ for (Index = 0; Index < DeviceHandleCount; Index++) {
+ Status = gBS->DisconnectController (
+ DeviceHandleBuffer[Index],
+ ImageHandle,
+ NULL
+ );
+ }
+ DEBUGPRINT(INIT, ("Active interfaces = %d\n", ActiveInterfaces));
+
+ //
+ // Free the buffer containing the list of handles from the handle database
+ //
+ if (DeviceHandleBuffer != NULL) {
+ gBS->FreePool (DeviceHandleBuffer);
+ }
+
+ if (ActiveInterfaces == 0) {
+ //
+ // Free PXE structures since they will no longer be needed
+ //
+ Status = gBS->FreePool (e1000_pxe_memptr);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("FreePool returns %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Close both events before unloading
+ //
+ Status = gBS->CloseEvent (EventNotifyExitBs);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("CloseEvent returns %r\n", Status));
+ return Status;
+ }
+
+ DEBUGPRINT (INIT, ("Uninstalling UEFI 1.10/2.10 Driver Diags and Component Name protocols.\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &mGigUndiDriverBinding,
+ &gEfiComponentNameProtocolGuid,
+ &gGigUndiComponentName,
+ &gEfiDriverDiagnosticsProtocolGuid,
+ &gGigUndiDriverDiagnostics,
+ &gEfiComponentName2ProtocolGuid,
+ &gGigUndiComponentName2,
+ &gEfiDriverDiagnostics2ProtocolGuid,
+ &gGigUndiDriverDiagnostics2,
+ &gEfiDriverConfigurationProtocolGuid,
+ &gGigUndiDriverConfiguration,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("UninstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+
+ if (gST->Hdr.Revision >= EFI_2_10_SYSTEM_TABLE_REVISION) {
+ DEBUGPRINT (INIT, ("Uninstalling UEFI 2.1 Supported EFI Version Protocol.\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gGigUndiSupportedEFIVersion,
+ NULL
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("UninstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+
+ } else {
+ DEBUGPRINT(INIT, ("Returning EFI_INVALID_PARAMETER\n"));
+ DEBUGWAIT (INIT);
+ return EFI_INVALID_PARAMETER;
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,
+ and DeviceId matching an Intel PRO/1000 adapter can be supported.
+
+Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to test.
+ RemainingDevicePath - Not used.
+
+Returns:
+ EFI_SUCCESS - This driver supports this device.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PCI_CONFIG_HEADER),
+ &Pci
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.VendorId == INTEL_VENDOR_ID) {
+ if (
+#ifndef NO_82571_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_QUAD_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571PT_QUAD_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_QUAD_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_QUAD_COPPER_LP ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82573E ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82573E_IAMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82573L ||
+#ifndef NO_82574_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82574L ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82574LA ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82583V ||
+#endif
+#endif /* NO_82571_SUPPORT */
+
+#ifndef NO_80003ES2LAN_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_COPPER_DPT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_SERDES_DPT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_COPPER_SPT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_SERDES_SPT ||
+#endif /* NO_80003ES2LAN_SUPPORT */
+
+#ifndef NO_ICH8LAN_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_M_AMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_AMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_C ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IFE ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_M ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_M ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_M_AMT ||//
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_M_V ||//
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_AMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_BM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_C ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH10_R_BM_LM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH10_R_BM_LF ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH10_R_BM_V ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_M_HV_LM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_M_HV_LC ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_D_HV_DM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_D_HV_DC ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH2_LV_LM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH2_LV_V ||
+#endif /* NO_ICH8LAN_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+#ifndef NO_82576_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576 ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_QUAD_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_QUAD_COPPER_ET2 ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_NS ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_NS_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_SERDES_QUAD ||
+#endif /* NO_82576_SUPPORT */
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82575EB_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82575EB_FIBER_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82575GB_QUAD_COPPER ||
+#endif /* NO_82575_SUPPORT */
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_SGMII ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_COPPER_DUAL ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_QUAD_FIBER ||
+ Pci.Hdr.DeviceId == 0xDEAD
+ ) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ Start this driver on Controller by opening PciIo and DevicePath protocol.
+ Initialize PXE structures, create a copy of the Controller Device Path with the
+ NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol
+ on the newly created Device Path.
+
+Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to work with.
+ RemainingDevicePath - Not used, always produce all possible children.
+
+Returns:
+ EFI_SUCCESS - This driver is added to Controller.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PCI_IO_PROTOCOL *PciIoFncs;
+ UINT64 Result = 0;
+ EFI_STATUS Status;
+
+ DEBUGPRINT(INIT, ("GigUndiDriverStart\n"));
+ DEBUGWAIT(INIT);
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (GIG_UNDI_PRIVATE_DATA),
+ (VOID **) &GigUndiPrivateData
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("AllocatePool returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiError;
+ }
+
+ ZeroMem ((UINT8 *) GigUndiPrivateData, sizeof (GIG_UNDI_PRIVATE_DATA));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &GigUndiPrivateData->NicInfo.PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData->NIIProtocol_31.Id = (UINT64) (e1000_pxe_31);
+
+ //
+ // Get the PCI Command options that are supported by this controller.
+ //
+ Status = GigUndiPrivateData->NicInfo.PciIo->Attributes (
+ GigUndiPrivateData->NicInfo.PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Result
+ );
+
+ DEBUGPRINT(INIT, ("Attributes supported %x\n", Result));
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Attributes returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiError;
+ }
+
+ //
+ // Set the PCI Command options to enable device memory mapped IO,
+ // port IO, and bus mastering.
+ //
+ Status = GigUndiPrivateData->NicInfo.PciIo->Attributes (
+ GigUndiPrivateData->NicInfo.PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Result & (EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE),
+ NULL
+ );
+
+ DEBUGPRINT(INIT, ("Attributes enabled %x\n", Result));
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Attributes returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiError;
+ }
+
+ //
+ // the IfNum index for the current interface will be the total number
+ // of interfaces initialized so far
+ //
+ GigUndiPxeUpdate (&GigUndiPrivateData->NicInfo, e1000_pxe_31);
+ //
+ // IFcnt should be equal to the total number of physical ports - 1
+ //
+ DEBUGWAIT(INIT);
+ GigUndiPrivateData->NIIProtocol_31.IfNum = e1000_pxe_31->IFcnt;
+ e1000_UNDI32DeviceList[GigUndiPrivateData->NIIProtocol_31.IfNum] = GigUndiPrivateData;
+
+ ActiveInterfaces++;
+ GigUndiPrivateData->Undi32BaseDevPath = UndiDevicePath;
+
+ //
+ // Initialize the UNDI callback functions to 0 so that the default boot services
+ // callback is used instead of the SNP callback.
+ //
+ GigUndiPrivateData->NicInfo.Delay = (VOID *) 0;
+ GigUndiPrivateData->NicInfo.Virt2Phys = (VOID *) 0;
+ GigUndiPrivateData->NicInfo.Block = (VOID *) 0;
+ GigUndiPrivateData->NicInfo.MapMem = (void *) 0;
+ GigUndiPrivateData->NicInfo.UnMapMem = (void *) 0;
+ GigUndiPrivateData->NicInfo.SyncMem = (void *) 0;
+ GigUndiPrivateData->NicInfo.Unique_ID = (UINT64) &GigUndiPrivateData->NicInfo;
+ GigUndiPrivateData->NicInfo.VersionFlag = 0x31;
+
+ //
+ // Allocate memory for transmit and receive resources.
+ //
+ Status = GigUndiPrivateData->NicInfo.PciIo->AllocateBuffer (
+ GigUndiPrivateData->NicInfo.PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ UNDI_MEM_PAGES (MEMORY_NEEDED),
+ (VOID **) &GigUndiPrivateData->NicInfo.MemoryPtr,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("AllocateBuffer returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+
+ //
+ // Perform the first time initialization of the hardware
+ //
+ Status = e1000_FirstTimeInit (&GigUndiPrivateData->NicInfo);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("e1000_FirstTimeInit returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ Status = ClpEntry (
+ This,
+ Controller,
+ &GigUndiPrivateData->NicInfo
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("ClpEntry returns %r\n", Status));
+ }
+
+ //
+ // Re-read the MAC address after running CLP. This will also set the RAR0 address
+ // if the alternate MAC address is in effect.
+ //
+ if (e1000_read_mac_addr (&GigUndiPrivateData->NicInfo.hw) != E1000_SUCCESS) {
+ DEBUGPRINT(INIT, ("Could not read MAC address\n"));
+ }
+
+ Status = GigAppendMac2DevPath (
+ &GigUndiPrivateData->Undi32DevPath,
+ GigUndiPrivateData->Undi32BaseDevPath,
+ &GigUndiPrivateData->NicInfo
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("GigAppendMac2DevPath returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ //
+ // Figure out the controllers name for the Component Naming protocol
+ // This must be performed after GigAppendMac2DevPath because we need the MAC
+ // address of the controller to name it properly
+ //
+ GetUndiControllerName (GigUndiPrivateData);
+
+ GigUndiPrivateData->Signature = GIG_UNDI_DEV_SIGNATURE;
+
+ GigUndiPrivateData->NIIProtocol_31.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
+ GigUndiPrivateData->NIIProtocol_31.Type = EfiNetworkInterfaceUndi;
+ GigUndiPrivateData->NIIProtocol_31.MajorVer = PXE_ROMID_MAJORVER;
+ GigUndiPrivateData->NIIProtocol_31.MinorVer = PXE_ROMID_MINORVER;
+ GigUndiPrivateData->NIIProtocol_31.ImageSize = 0;
+ GigUndiPrivateData->NIIProtocol_31.ImageAddr = 0;
+ GigUndiPrivateData->NIIProtocol_31.Ipv6Supported = TRUE;
+
+ GigUndiPrivateData->NIIProtocol_31.StringId[0] = 'U';
+ GigUndiPrivateData->NIIProtocol_31.StringId[1] = 'N';
+ GigUndiPrivateData->NIIProtocol_31.StringId[2] = 'D';
+ GigUndiPrivateData->NIIProtocol_31.StringId[3] = 'I';
+
+ GigUndiPrivateData->DeviceHandle = NULL;
+
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+
+ //
+ // The PRO1000 COM protocol is used only by this driver. It is done so that
+ // we can get the NII protocol from either the parent or the child handle. This is convenient
+ // in the Diagnostic protocol because it allows the test to be run when called from either the
+ // parent or child handle which makes it more user friendly.
+ //
+ GigUndiPrivateData->EfiPro1000Com.NIIProtocol_31 = &GigUndiPrivateData->NIIProtocol_31;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ NULL
+ );
+
+ DEBUGPRINT(INIT, ("InstallMultipleProtocolInterfaces returns = %d %r\n", Status, Status));
+ DEBUGWAIT(INIT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InstallMultipleProtocolInterfaces returns Error = %d %r\n", Status, Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ GigUndiPrivateData->DriverStop.StartDriver = StartDriver;
+ GigUndiPrivateData->DriverStop.StopDriver = StopDriver;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &GigUndiPrivateData->DeviceHandle,
+ &gEfiDevicePathProtocolGuid, GigUndiPrivateData->Undi32DevPath,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &GigUndiPrivateData->NIIProtocol_31,
+ &gEfiVlanProtocolGuid, &gGigUndiVlanData,
+ &gEfiStartStopProtocolGuid, &GigUndiPrivateData->DriverStop,
+ NULL
+ );
+ DEBUGPRINT(INIT, ("InstallMultipleProtocolInterfaces returns = %d %r\n", Status, Status));
+ DEBUGWAIT(INIT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InstallMultipleProtocolInterfaces returns Error = %d %r\n", Status, Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ Status = InitFirmwareManagementProtocol (GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("Could not install Firmware Management protocol interfaces. Error = %d %r\n", Status, Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIoFncs,
+ This->DriverBindingHandle,
+ GigUndiPrivateData->DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ }
+
+ //
+ // Save off the controller handle so we can disconnect the driver later
+ //
+ GigUndiPrivateData->ControllerHandle = Controller;
+ DEBUGPRINT(INIT, ("ControllerHandle = %x, DeviceHandle = %x\n",
+ GigUndiPrivateData->ControllerHandle,
+ GigUndiPrivateData->DeviceHandle
+ ));
+
+ //
+ // HII may not install, so we do not want to return any errors
+ //
+ Status = HiiInit(GigUndiPrivateData);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("HiiInit returns %r\n", Status));
+ }
+
+ return EFI_SUCCESS;
+
+UndiErrorDeleteDevicePath:
+ e1000_UNDI32DeviceList[GigUndiPrivateData->NIIProtocol_31.IfNum] = NULL;
+ gBS->FreePool (GigUndiPrivateData->Undi32DevPath);
+ GigUndiPxeUpdate (NULL, e1000_pxe_31);
+ ActiveInterfaces--;
+
+UndiError:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+Routine Description:
+ Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
+ closing the DevicePath and PciIo protocols on Controller.
+
+Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to stop driver on.
+ NumberOfChildren - How many children need to be stopped.
+ ChildHandleBuffer - Child handle buffer to uninstall.
+
+Returns:
+ EFI_SUCCESS - This driver is removed Controller.
+ EFI_DEVICE_ERROR - The driver could not be successfully stopped.
+ other - This driver was not removed from this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
+
+ DEBUGPRINT(INIT, ("Number of children %d\n", NumberOfChildren));
+ //
+ // If we are called with less than one child handle it means that we already sucessfully
+ // uninstalled
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // Decrement the number of interfaces this driver is supporting
+ //
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate"));
+ ActiveInterfaces--;
+ // The below is commmented out because it causes a crash when SNP, MNP, and ARP drivers are loaded
+ // This has not been root caused but it is probably because some driver expects IFcnt not to change
+ // This should be okay because when ifCnt is set when the driver is started it is based on ActiveInterfaces
+ // GigUndiPxeUpdate (NULL, e1000_pxe);
+ // GigUndiPxeUpdate (NULL, e1000_pxe_31);
+
+ DEBUGPRINT(INIT, ("Removing gEfiDevicePathProtocolGuid\n"));
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Close of gEfiDevicePathProtocolGuid failed with %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Close of gEfiPciIoProtocolGuid failed with %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ return Status;
+ }
+
+ if (NumberOfChildren > 1) {
+ DEBUGPRINT(INIT, ("Unexpected number of child handles.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check to see
+ // if the interface has been shutdown. Does not need to be closed because we use the
+ // GET_PROTOCOL attribute to open it.
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[0],
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &NIIProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ return Status;
+ }
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (NIIProtocol);
+ DEBUGPRINT(INIT, ("State = %X\n", GigUndiPrivateData->NicInfo.State));
+ DEBUGWAIT (INIT);
+
+ //
+ // Call shutdown to clear DRV_LOAD bit and stop tx and rx
+ //
+ e1000_Shutdown (&GigUndiPrivateData->NicInfo);
+
+ e1000_ClearRegBits(&GigUndiPrivateData->NicInfo, E1000_CTRL_EXT, E1000_CTRL_EXT_DRV_LOAD);
+
+ Status = HiiUnload(GigUndiPrivateData);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("HiiUnload returns %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Close the bus driver
+ //
+ DEBUGPRINT(INIT, ("Removing gEfiPciIoProtocolGuid\n"));
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[0]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Close of gEfiPciIoProtocolGuid failed with %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ DEBUGPRINT(INIT, ("UninstallFirmwareManagementProtocol\n"));
+ Status = UninstallFirmwareManagementProtocol (GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallFirmwareManagementProtocol returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ DEBUGPRINT(INIT, ("UninstallMultipleProtocolInterfaces\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ GigUndiPrivateData->DeviceHandle,
+ &gEfiStartStopProtocolGuid, &GigUndiPrivateData->DriverStop,
+ &gEfiVlanProtocolGuid, &gGigUndiVlanData,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &GigUndiPrivateData->NIIProtocol_31,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ &gEfiDevicePathProtocolGuid, GigUndiPrivateData->Undi32DevPath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallMultipleProtocolInterfaces returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ //
+ // If we get the ACCESS_DENIED status code usually calling UninstallMultipleProtocolInterfaces a second
+ // time will uninstall the protocols successfully.
+ //
+ if (Status == EFI_ACCESS_DENIED)
+ {
+ DEBUGPRINT(INIT, ("UninstallMultipleProtocolInterfaces\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ GigUndiPrivateData->DeviceHandle,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &GigUndiPrivateData->NIIProtocol_31,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ &gEfiDevicePathProtocolGuid, GigUndiPrivateData->Undi32DevPath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallMultipleProtocolInterfaces returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+ }
+
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallMultipleProtocolInterfaces returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ DEBUGPRINT(INIT, ("FreeUnicodeStringTable"));
+ FreeUnicodeStringTable (GigUndiPrivateData->ControllerNameTable);
+
+ e1000_UNDI32DeviceList[GigUndiPrivateData->NIIProtocol_31.IfNum] = NULL;
+ DEBUGPRINT(INIT, ("FreePool(GigUndiPrivateData->Undi32DevPath)"));
+ Status = gBS->FreePool (GigUndiPrivateData->Undi32DevPath);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("FreePool(GigUndiPrivateData->Undi32DevPath) returns %r\n", Status));
+ }
+
+ Status = GigUndiPrivateData->NicInfo.PciIo->FreeBuffer (
+ GigUndiPrivateData->NicInfo.PciIo,
+ UNDI_MEM_PAGES (MEMORY_NEEDED),
+ (VOID*) (UINTN) GigUndiPrivateData->NicInfo.MemoryPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("PCI IO FreeBuffer returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+
+ DEBUGPRINT(INIT, ("Attributes"));
+ Status = GigUndiPrivateData->NicInfo.PciIo->Attributes (
+ GigUndiPrivateData->NicInfo.PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("PCI IO Attributes returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ Status = gBS->FreePool (GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("FreePool(GigUndiPrivateData) returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ return Status;
+}
+
+VOID
+WaitForEnter (
+ VOID
+ )
+/*++
+
+Routine Description:
+ This is only for debugging, it will pause and wait for the user to press <ENTER>
+ Results AFTER this call are unpredicable. You can only be assured the code up to
+ this call is working.
+
+Arguments:
+ VOID
+
+Returns:
+ none
+
+--*/
+// GC_TODO: VOID - add argument and description to function comment
+{
+ EFI_INPUT_KEY Key;
+
+ DEBUGPRINT(0xFFFF, ("\nPress <Enter> to continue...\n"));
+
+ do {
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ } while (Key.UnicodeChar != 0xD);
+}
+
+EFI_STATUS
+GigAppendMac2DevPath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ )
+/*++
+
+Routine Description:
+ Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space
+ for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)
+ and an added MAC node.
+
+Arguments:
+ DevPtr - Pointer which will point to the newly created device path with the MAC node attached.
+ BaseDevPtr - Pointer to the device path which the UNDI device driver is latching on to.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ EFI_SUCCESS - A MAC address was successfully appended to the Base Device Path.
+ other - Not enough resources available to create new Device Path node.
+
+--*/
+// GC_TODO: GigAdapterInfo - add argument and description to function comment
+{
+ MAC_ADDR_DEVICE_PATH MacAddrNode;
+ EFI_DEVICE_PATH_PROTOCOL *EndNode;
+ UINT16 i;
+ UINT16 TotalPathLen;
+ UINT16 BasePathLen;
+ EFI_STATUS Status;
+ UINT8 *DevicePtr;
+
+ DEBUGPRINT(INIT, ("GigAppendMac2DevPath\n"));
+
+ ZeroMem (
+ (char *) &MacAddrNode,
+ sizeof (MacAddrNode)
+ );
+
+ E1000_COPY_MAC (MacAddrNode.MacAddress.Addr, GigAdapterInfo->hw.mac.perm_addr);
+
+ DEBUGPRINT(INIT, ("\n"));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(INIT, ("%2x ", MacAddrNode.MacAddress.Addr[i]));
+ }
+
+ DEBUGPRINT(INIT, ("\n"));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(INIT, ("%2x ", GigAdapterInfo->hw.mac.perm_addr[i]));
+ }
+
+ DEBUGPRINT(INIT, ("\n"));
+ DEBUGWAIT (INIT);
+
+ MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
+ MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
+ MacAddrNode.Header.Length[0] = sizeof (MacAddrNode);
+ MacAddrNode.Header.Length[1] = 0;
+
+ //
+ // find the size of the base dev path.
+ //
+ EndNode = BaseDevPtr;
+ while (!IsDevicePathEnd (EndNode)) {
+ EndNode = NextDevicePathNode (EndNode);
+ }
+
+ BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));
+
+ //
+ // create space for full dev path
+ //
+ TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData, //EfiRuntimeServicesData,
+ TotalPathLen,
+ (VOID**)&DevicePtr
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ //
+ // copy the base path, mac addr and end_dev_path nodes
+ //
+ *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;
+ CopyMem (DevicePtr, (char *) BaseDevPtr, BasePathLen);
+ DevicePtr += BasePathLen;
+ CopyMem (DevicePtr, (char *) &MacAddrNode, sizeof (MacAddrNode));
+ DevicePtr += sizeof (MacAddrNode);
+ CopyMem (DevicePtr, (char *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
+
+ return EFI_SUCCESS;
+}
+
+VOID
+GigUndiPxeUpdate (
+ IN GIG_DRIVER_DATA *NicPtr,
+ IN PXE_SW_UNDI *PxePtr
+ )
+/*++
+
+Routine Description:
+ When called with a null NicPtr, this routine decrements the number of NICs
+ this UNDI is supporting and removes the NIC_DATA_POINTER from the array.
+ Otherwise, it increments the number of NICs this UNDI is supported and
+ updates the pxe.Fudge to ensure a proper check sum results.
+
+Arguments:
+ NicPtr = contains bus, dev, function etc.
+ PxePtr = Pointer to the PXE structure
+
+Returns:
+ None
+
+--*/
+{
+ if (NicPtr == NULL) {
+ //
+ // IFcnt is equal to the number of NICs this undi supports - 1
+ //
+ if (PxePtr->IFcnt > 0) {
+ PxePtr->IFcnt--;
+ }
+
+ PxePtr->Fudge = (UINT8) (PxePtr->Fudge - e1000_ChkSum ((VOID *) PxePtr, PxePtr->Len));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: ActiveInterfaces = %d\n", ActiveInterfaces));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: PxePtr->IFcnt = %d\n", PxePtr->IFcnt));
+ return ;
+ }
+
+ //
+ // number of NICs this undi supports
+ //
+ PxePtr->IFcnt = ActiveInterfaces;
+ PxePtr->Fudge = (UINT8) (PxePtr->Fudge - e1000_ChkSum ((VOID *) PxePtr, PxePtr->Len));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: ActiveInterfaces = %d\n", ActiveInterfaces));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: PxePtr->IFcnt = %d\n", PxePtr->IFcnt));
+
+ return ;
+}
+
+VOID
+GigUndiPxeStructInit (
+ PXE_SW_UNDI *PxePtr,
+ UINTN VersionFlag
+ )
+/*++
+
+Routine Description:
+ Initialize the !PXE structure
+
+Arguments:
+ PxePtr = Pointer to the PXE structure to initialize
+ VersionFlag = Indicates PXE version 3.0 or 3.1
+
+Returns:
+ EFI_SUCCESS - This driver is added to Controller.
+ other - This driver does not support this device.
+
+--*/
+{
+ //
+ // initialize the !PXE structure
+ //
+ PxePtr->Signature = PXE_ROMID_SIGNATURE;
+ PxePtr->Len = sizeof (PXE_SW_UNDI);
+ PxePtr->Fudge = 0; // cksum
+ PxePtr->IFcnt = 0; // number of NICs this undi supports
+ PxePtr->Rev = PXE_ROMID_REV;
+ PxePtr->MajorVer = PXE_ROMID_MAJORVER;
+ PxePtr->MinorVer = PXE_ROMID_MINORVER;
+ PxePtr->reserved1 = 0;
+
+ PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
+ PXE_ROMID_IMP_FRAG_SUPPORTED |
+ PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
+ PXE_ROMID_IMP_NVDATA_READ_ONLY |
+ PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
+ PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
+ PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
+ PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
+ PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |
+ PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |
+ PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;
+
+ PxePtr->EntryPoint = (UINT64) e1000_UNDI_APIEntry;
+ PxePtr->MinorVer = PXE_ROMID_MINORVER;
+ PxePtr->reserved2[0] = 0;
+ PxePtr->reserved2[1] = 0;
+ PxePtr->reserved2[2] = 0;
+ PxePtr->BusCnt = 1;
+ PxePtr->BusType[0] = PXE_BUSTYPE_PCI;
+
+ // TODO: Check if this is correct.
+ PxePtr->Fudge = (UINT8) (PxePtr->Fudge - e1000_ChkSum ((VOID *) PxePtr, PxePtr->Len));
+
+ //
+ // return the !PXE structure
+ //
+}
+
+UINT8
+e1000_ChkSum (
+ IN VOID *Buffer,
+ IN UINT16 Len
+ )
+/*++
+
+Routine Description:
+ This does an 8 bit check sum of the passed in buffer for Len bytes.
+ This is primarily used to update the check sum in the SW UNDI header.
+
+Arguments:
+ Buffer - Pointer to the passed in buffer to check sum
+ Len - Length of buffer to be check summed in bytes.
+
+Returns:
+ The 8-bit checksum of the array pointed to by buf.
+
+--*/
+{
+ UINT8 Chksum;
+ INT8 *Bp;
+
+ Chksum = 0;
+
+ if ((Bp = Buffer) != NULL) {
+ while (Len--) {
+ Chksum = (UINT8) (Chksum + *Bp++);
+ }
+ }
+
+ return Chksum;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr
new file mode 100755
index 0000000..8846e32
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr
@@ -0,0 +1,138 @@
+// *++
+//
+// Copyright (c) 2007, Intel Corporation
+// All rights reserved. This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// Module Name:
+//
+// Inventory.vfr
+//
+// Abstract:
+//
+// Sample Inventory Data.
+//
+// Revision History:
+//
+// --*/
+
+#include "LanIntelE1000DxeStrDefs.h"
+#include "NVDataStruc.h"
+
+//
+// Formset class used by Device Manager
+//
+#define EFI_NON_DEVICE_CLASS 0x00
+#define EFI_DISK_DEVICE_CLASS 0x01
+#define EFI_VIDEO_DEVICE_CLASS 0x02
+#define EFI_NETWORK_DEVICE_CLASS 0x04
+#define EFI_INPUT_DEVICE_CLASS 0x08
+#define EFI_ON_BOARD_DEVICE_CLASS 0x10
+#define EFI_OTHER_DEVICE_CLASS 0x20
+
+//
+// Formset subclass
+//
+#define EFI_SETUP_APPLICATION_SUBCLASS 0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01
+#define EFI_FRONT_PAGE_SUBCLASS 0x02
+#define EFI_SINGLE_USE_SUBCLASS 0x03
+
+//
+// EFI Variable attributes
+//
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+#define EFI_VARIABLE_READ_ONLY 0x00000008
+
+formset
+ guid = E1000_HII_FORM_GUID,
+ title = STRING_TOKEN(STR_INV_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ class = EFI_NETWORK_DEVICE_CLASS,
+ subclass = EFI_SETUP_APPLICATION_SUBCLASS,
+
+ //
+ // Define a Buffer Storage (EFI_IFR_VARSTORE)
+ //
+ varstore GIG_DRIVER_CONFIGURATION, // This is the data structure type
+ varid = 0x1234, // Optional VarStore ID
+ name = GigNVData, // Define referenced name in vfr
+ guid = E1000_HII_DATA_GUID; // GUID of this buffer storage
+
+ form formid = 1,
+ title = STRING_TOKEN(STR_INV_FORM1_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ goto 0x1235,
+ prompt = STRING_TOKEN(STR_PORT_CONFIG_MENU_REF),
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ subtitle text = STRING_TOKEN(STR_PORT_CONFIGURATION_INFO);
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ text
+ help = STRING_TOKEN(STR_MAC_ADDR_HELP),
+ text = STRING_TOKEN(STR_MAC_ADDR_PROMPT),
+ text = STRING_TOKEN(STR_MAC_ADDR_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_ALT_MAC_ADDR_HELP),
+ text = STRING_TOKEN(STR_ALT_MAC_ADDR_PROMPT),
+ text = STRING_TOKEN(STR_ALT_MAC_ADDR_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_EFI_DRIVER_VER_PROMPT),
+ text = STRING_TOKEN(STR_EFI_DRIVER_VER_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_PCI_BUS_DEV_FUNC_HELP),
+ text = STRING_TOKEN(STR_PCI_BUS_DEV_FUNC_PROMPT),
+ text = STRING_TOKEN(STR_PCI_BUS_DEV_FUNC_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_CONTROLER_ID_HELP),
+ text = STRING_TOKEN(STR_CONTROLER_ID_PROMPT),
+ text = STRING_TOKEN(STR_CONTROLER_ID_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_ADAPTER_PBA_PROMPT),
+ text = STRING_TOKEN(STR_ADAPTER_PBA_TEXT),
+ flags = 0,
+ key = 0;
+
+ endform;
+
+ form formid = FORM_2,
+
+ title = STRING_TOKEN(STR_PORT_CONFIG_MENU);
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ label LABEL_START; // Placeholder for opcodes that are dynamically created during driver initialization
+
+ label LABEL_END;
+
+ endform;
+
+endformset;
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventorystrings.uni b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventorystrings.uni
new file mode 100755
index 0000000000000000000000000000000000000000..7d47c47b38cd4c8118dba136242265287ac85e1b
GIT binary patch
literal 47396
zcmeI5U5s7VRmV>w(PE&y!9!oTOsHx?ZhTTze7HjD#2!0NJ$***@4V~<Tpo%!};Ja?QK
zf5dKUm$VWh4$220qCB)EO89z-5D(NZ6x2czps0N)L8vXUiq)imB4|`3V`Bcly=Hr#
z`?be+Jm(`)***@5(Qx%b?C{(J4c{(G&x*52p(+dGmSNiDe}`33#GKlw48?YQw?OLiqI
z$%*7_vYIR=3(2wMq^{kb%p^ar_YWtj{(dQ`uOIz#a;HAsmo#<NTyk8;{CZWt=XFY-
zF6yYM&x`)^^{OR<!UeKWpEY+jm#hi%YI0hyv&mihY(lkN)TcG!Ulr~JSBGVtPpJ;G
zdOxWv=G^&=B(jn$>q@>mtKT(seNCTGYsy{J(Q#K=|8)=Or&JPmJg)L)bkuaH!QwG-
z$JupMr**ujYp0TFz4E(L4mo%Ndc(Kuu=!G`4Ru_+(PqeDC7I9s?w({k*{$>aEm%5h
z7to(^5}na2cw1$*D16)lnVQtO`<l*?-L#PV-b341>rkV4ePb<3Js#0j?KoRyWo>d+
zS4}&K%&S%=6)^GZ*1v$BzJF3Jywhn2T4D0%_p7co?owH+YWE#&?X#v&rd5|&X-***@a
zyHv_C{kPt8>&^oDtt+#*k^=gP<lbaRQW{Ohl96PuUI&w5o$pg0tf?3BKA}(dCHEu;
zbu{F9=E0<)_aS{wf3XrmuiYnh8qyWxuH+FN!4A9*=$&#YbwKa;xO2|nx10S7=qFVY
z_aAZCYRRO^8*_DN=<|KLKX)5(ILCBGE%^*|6S|gbz-L$O(Y4?_qW6#M8|nzIq4m31
zeTS06H_8d6?~~L<rLo*|w_~|pwF&6M(XjgWtkX9%uOWR|mJaN^F<OKxDV1>mHf1zG
zFU|_TX*1lorn{qei#L8<%Nz|***@_&;$-F?*{irqw#=GizIl~Nxt=f9bQM|-=XGM@
zJ2-Mqcmn=#G^TG(>xwn~+t_ulJM(o4wa+4}OVjUIA4e(6%KO#ic6Y?t?YbvyyReR#
zx*)5%`Uvecpcdj=_+m{QG2njL?N_jU-Su;RwOeO!<(lNiuPE0>_`UjO)***@K$o
zb=}z`SQ9r*CI6+GA8#pZ+<lIe!Pcuj^SWO>+2i{4fZl1%X7W9~@;***@GQOeiAnsMx
zL;6)cxlg^9T3(sEbK&!kS?#EyFX=vAWn-|7=e<fhr#sc9k>H_!3?!fV<***@tbp5
ziH!><V>)d>FTpavreTC?>I{pa*Bu^F`3EJ*J?e9mk0sP}r7XDdB5Mr|JJcs!saOsB
z9WJh$QV*DOlJYeSW!_4Opf==wgf)A`SoEkcH<CliQK5&GhIIrRP3Rpinh-+RIQ)fv
z=`pwV=5VDQ4LD8oR-&=`j^u7<Po^rjp<16z&N!`I(z(?YnZpLAiL?}TXfJ!S=iTa%
z)vfk&Z>|pKR15TO$#LPTc#XaTiz0E;>h_X1d)}=ES&eQl*Y`^7rp4q3LSzhzb!>gz
zEJ;|iS6k&@gDi{mssTNNIv7K*CT}?1oRXA{^UFh@<*iQiG0E1Fucco}***@h
zFU&mq>HKBg&Wl;Z8};`C7ru4=J5RhYlRwHVw{A<eNsIP4rdSqB!5fC4AAY;LC$pIZ
zx@%S#t+R6CctD)VD2GPHczQI$@a1wDW8o={btlDCy+*1vr&U;1j7fRpjWgG1a#{R|
zgr_89Jamp{^vd{;hi}}4l~vQ{?RDZx7%%^N#QDqj0FSp5sUPpU)v}0oh%?yb^!fA$
zX)UQg_U!%tBBuIMn!***@KenTr=FSq{rr)1GEr9BecNs=ju@|vI(rQ}ZI|;H
zu|D_84#i*gUZh!fSa!9H7jm<9+o)q&=1H<OWd<Z`(K4=?&t)@URk7Fxh08pn<6=Ab
ztS%qAog2Ky;q!H?2foVIwrThACHP{U<4dcAJ)3zJ*@*SRbt{qq%yLSczA9$tJpa1I
zIkB~FzBN4N7(-%LQyaW}ZwIu?ZnNjz+9=MA-***@oyfy`*8kpjWgq$=e|1*
zH(nlDc`$!0o!n^mjPcj7cxso}Yf$qTyTw{Z-5l14o3)xy%***@Ym@9OO8fO#iZ-KU
zGg38`%pI9go7EqF53I0LI#9NEIq5WVNoeN8L(Bu<<#@z(huGs~7B2r5jay{9g%Ui>
z>w9m~***@0%dD(2!x`x=rR3V7tJVToY33|!GGaqscg47uSka`jFjkC$s17|*a&wMlW
zGJP(6CH;@|Qt9^A)dP=?2ic{QADjHZ_5Ax{C%fQr&D_xA&2SBIgTu0u+F8TS`{$Yu
zYCh}3nwQv_^m|l3`}B)A)G`0IkMmHKk;nO{%E;r~RAuCGo2bgjJ2`GMtVY~(zl)o6
z<F)=-t=)***@ZkR5{Jhx^y3qG2w{BnQTZWVL)OHq8&|pBTkCgKz~&;FNK9x}ud8~k
zD^_c>_t;?gjy98w_sIM`9-7s+-e!-Pw?fRZy~cITQWEL17$uQ9UnVigve`3c#WBl9
zT!1-Nq_XT}LOV0Z*3HJVPnnI&dYGLuDWcwS?(***@GMh*%&MKy0y_`O4ekSL^o+U=&
zzwv##oSMeDy1hTv67Q#8dEg_5y_NY=`pxuD(tnr#8Z_EloVS&3b6#***@S{MpZ)
z#{T^0&p&@L;KT+k0^?@*c~D%;{G74I#-48f{7i<M=_hmJ90keH%L6A@!OQK%***@f@4
zQ<xGD__+9zytgTxao#M%Ba2&_F|H&Ak!^)V#eb{p^D=%DK_%CL$Q4Xq1+VwJjqCHi
z|K>k7#%;y-***@WI4qs)Vw&BrpWB;py8FBRGtRBp&}GlE-3s<{BcN4A9=Elsj67~T
zRT+7lyQ+-5lj%10b9=K|cYn8kR_kU*nf1ZEFtfsB1DgFp?s(R+dS`gMzos#txWXBY
z_gFgd2!r`@{d%-WW+O|k2=DJ!EIH!9w7B<lyW4gqpLc?<O9m^m9JD<)^@m)|x<x|p
zAHoWZH{A7>RrgNxaF^26vB%Q!qx0!+rH`ja)2wY-OT2emww0OnZLv7tJ2w1O;F&7>
zwxf!q?vroJ8jNwhv-ZNWh*^n2T-P#vS%Wa4p4UGo+Z|YuLH5Q@-NCZ+SqrsOv0Y~6
zLWXb^{***@zkztKkgg{GCav;#mvn6TF-61}<2-0`Wt|NziG0b_N7vy%aGut&NABai
zMc|HGl<l}jHCsoVnblQx^sxGd^%1gtTKh=ec6{8X^nLp4isgRbdM$Y={kn4M?D)Cg
zJ26*8G&OEJdW0W+@XP0SCVzSHeMfdCUl{wp&lJ(_owlL1byoA+^?qaP(P|W9s#f2)
zf2J~fdse#Ac~q6?ZZC9s>qDG_I^`8)nE%)u=b3V`#d)M$Y;guD7h5NXYz0HK`kDPR
zglARaW~?y8hQS(N(NV~ytwL1Pkk*w+>}?k`*hfk&*Rp&c?x6fk%PjMDN$|*K^-ZT8
z<L#Uxu*Z32Xnma_8BB9J#uLv*6T4e8MdFWhkMGOgc4?*`IsCEdB4TiH-toAwS%ycN
z7m7f%8MYzcb<lZ5tlq{?V$FHGzZCK}`ez#=***@tQm=rySJ5<3#>W!>iJH#XuIK*au
zkRV5}UJ>?hoHup}3z_bW93F2GsN!t!T>4k(tLc}OIbfK|_h4>&a`>rZhl<3rl`PQe
zi`)ted{Coc6}*ok)|hPMWfXxSuD#Y8d9z$xSBt?***@Iuo;cCRdnnuGvf9<U~Jx}
zvAWmD-2b?2yGgJE(1dnKVNandjL9BVeH~***@h0KC){***@hU5h?zgGmZxEA|%
z^T^0_G+(X=Y;o=WYwaMwNc_BB^PfA3Yx#?h?p^)lr!G$BkE2u5eSaQS?_nn!IG6w1
zogZs!$Ju$s?|;%;@4Ju1{p<Zfd3a0uUs3cm>=Hn%jlFi*k7%_5BQ+@5Cv8b~W>bIO
zd$6^??P&8J$>I#***@MuW!|5;l|^U0=idwCtP#+@<yxB+)HPuvHUZM6SR{Xp
zarStB<0t1IO8;Ez`(IA~Q)^***@D4j#@Sh#ZLk7j;x?AW3FWz)$bx568(vxVM<@1Hjs
z(#Gu0NY-0gHIZz4^9yUPA1yl_UUjPr%Feel{9#w5x+0DA_tqL<cd+6D9z+wC-JF=!
zpj?(|Bv;q51Y5*Q8!sH|gdC98c4=iJzrRxX^***@xtwOLGF7k;Y^>*+&XvRswj
zWvPgo#JMWFS5lU-n&~&hTwhHeI`u!}Ma=%iZ6NkYGX8q~$saa~L9`hjvwiEx;9yV9
zL(1d8^YQPkSsZX#|2!7<vD>ZQM_vIIPZfM0j|>hXCyL!?J+^YWr<ExKr+CCg_#1Jn
zX4G-^%KD6?$5n-O1Odw{vSXfCjz#&ik^$4h&;Ie)kDq(u6GdR!dOq+z5qq)q&jdF6
zQ?^}F%p6qQgDD0>T!V|j5Fg8n!4My*i@~rNUF^Qc7b^<cFZ!UyX?Bm^vngF1l^sYt
zDZabcu*O64Ps`R?***@c&&iU-gYMkntM`6}`TLM_nqTt!DSMyKzq3aqa=a?keohll
***@FQ09>J}d43-^Iz5Tj;f9PEgpW(_C)!U(q{kfXy<@E2<EAkcc?-g<***@w;?=>$3;P
z^T*Q3K%N84+O*#2cQPDPkDb4X`O}R!YIBx?***@l|***@DYx_wIJtyX@4uZ{@q}#7Nq@
zH-5H{4J1`&r;X=lN0gBg_CY18%ii|bO|22#&G<2+Znj`r78L$3&+{Nx$nQyR_bNa4
z;*hiOSd(WNoLGBUD64L_1>4(sRb#Z@-NxfCcjki~LCNi8Zvw15n~}8rAXsa8!hL5u
z*cXL3?niZNeXJkW+AX^_;5itqz{`J(k9%9Mrr%Hh$?a77r-~B)MfyFrpL0=CjI+(>
zp82Vx*Y4l;<***@FxE(c?{0BLozh?ocTnr$sRrZ!yOVl?PjuZVPvxqNJCb5_-mbPGPP
zCxqeu(ND>j4xe`K&Hkx6GtT!yMwYeAdNFwAE|oN?(S*<2%Vg~|@mOM2L?66#xh~8H
zqv=GR{nNV0j%VJ})?TB5v_kf&VgBCL%%tClXL%aYHPs3!nAD~edp{}p5>>KjST`S+
zRo1qSkd*|?R@<+6UK3|lUbkzkjkwy{Xs)BAlkVwKJ_DfURsj0;#J?q9y*s8QeMdyQ
zrpN(3qIJ|E;umJuYmN)q-^bV7o||H4MZ}llzWShgqOE_l5y;2O(2~|~Z13%EW0E}+
zhu6+k;#LZ~upf7N!?TBKPP****@pW8-<kFxf7?S3y}7JoG=`_p8BWGc#`3GK9YQ3J
zERzsHVE;***@j>dvs3JzAhq4;TK8`&qBY{9YiJE>&lC7S4D!$#e8bxI?%V}W*o=|!
zUf>Pi60{Q9VJ*>KI&0x+1!B}*PMq<)C|1j|Ue<FeeVBG()jcg^8i|dCTq(gvOuE?z
z))r)y!O2!9bdKjzfwgtLh~0@-U!x*gD{f)Dy|#U_nfhJkf|X%5MlE?d-L`OP?7UXw
***@TIY(bTU1k9!YO=XRIap(TVq@<Jw8x%J{g}?+2^J$8)ZwPrEFYSM<w^>BYuM
zx{wa5ocq(?QAzn*S#e8d$HewiKRx{$XSbgkKRP^SJJ)6Hn%lH50pI>`?kBGQ!SQVi
zX8HKI(3|5|8vodsU2@)+*0FqX?9)#***@Xk#CXrwcapR0W<HHY(48Ck?iHSDW##
z_N)JsGlxc!CyNbG1%C={ZhflPn$vN6&IEg_*ppNjgq`uOi02Z-$Ff7hVe1UZg<}*j
zjxi={-r$w|btca8hn%#ii;Z%|qkf0FHL+%Mi!JbOvt)5@`@X!T7t^14@((|ezqH~E
z^Y-t)FjEYUPFC3OG&8H0TRC44^NYH(P1YmY4A+n^***@M>jd`%R(Q7n^=VoC=
zJfgFWeWLO?i(Ngi5a5A+xywI8ny2oDdYhdeb~3j4BV!e8mYefp(Da)2MnSG1Yr2fZ
zt?WtN^gGU#tgs`0($74Zbx*cZJA?8}X|wF{6R^Il{=8nz^bqO>)3)x2?5$3-|MTaP
zIP+%vKi;FSwapL4_!t>5`)O8nt8O5Zo3Xj`uYH`;TkX}***@P9YHmcFDI;j4P?##hAp
zmt>J{JMz|i{&?fe|JMAk%mu5`j{}cS{KNQ_2g<Y(vyp>aIgauFpfVmN<l{ADXYQ4q
znaxGo4D%1Fhw>CG@|1Z#YuOnN?Rd&%!=ll|S*mC>an>jrO`H>oM$>5%=7}K22s}ml
z-h}-@_jK^VW*C9;*ne+YBR2L4Pf9)RvLMRlhJcK5c}E7_bc<D*|M(QQp#n~***@UC
z7T~+Z`6J+Jm!HpZxs_2X``d1IXPiv}Hj~+X<BvDK_Ei2Y8E2JFRM;5#qv~WAka(R8
z8o8CD<3=2_N0!Ha{k7X1Tfs5xXh*!KeETD`c+e4|IiSm0_xbmM{y2t6hs}}WkE~RJ
zYrg1uY>;DU<*n?ux6U=k4pfnAjvc51*W}Y?8*xo<i>6y^6V0u=J$SQYkR1;sXmph=
z8jmgLiSc{&Y#NWWdRC1`)-J<p*fkzq)hwHKTxIf2+15=***@2TCs>0}f8WGgr*@M;yj
zD&G@={#***@kmXVs%Z73NtNxMR{2%O@@dCqT+~***@3)3)~g78YD3*XHs*x
zSzoGGjr`~RbIzoTLJ{{Gk$qIt-3B$wo4?;eyr-^c*^utp{x_hkR`Pc&|A%LYwr279
zINCMMK3UdKQK;kI){rDf=8<JKup1_EpCY9ipV=8xE*LR7%g$O`k2)14yZFpbS^Y3R
zvtzQUB|mrY=>le%I(frO1>M{)P4$@_H^Uh|+TX5S?dSb-2K_u_LG$Ed%fTbNGpy}k
zexauI6GXY;7kk1n*_&te&***@Oi$dU=fH$=m0`***@I%)-(_aCi=^7$(b&H&ZnJ)OtZ;@
zq;}+n!w$xzSvjyz58v~YEV8t+wdYyE#Dy(Wz$C(x4806kVd!OGt9fmg9LpSFe-Q3!
zdCkZu?~yIee}lqm*}zDFYuOdJeI<(R3&iK(wg^8pvCLe{0w7P+_Yto2D_eYa=u~1)
zF0nm+mzCjb5?d)GHzLlmSt*=z*y+KBv{gew<ey!GJTsFcVA%yo(QC`=>P4KBi_G(1
zE#t(r#LFV+k9|@^kBGB6*{LD3)iPSiV|`Eho%BmCTi_e%pXvQ&WvN~m*?wv=o!45M
zOX=UHuj!LBzx~azgUVFBSdmQC*(GvQ$vOoq(XXJXC+3<***@xPz?*YjoO7sSQ}
z*7OZ(kMsTO`KLZFpnXj6=eIUCR3Q_!owdu)GY$M;D-H5z?Tz?qms|aLD0!uT5hTtR
zWW47ukGReE-w%+Lo<E9CYcFe8p*v`DOq+Krr+mB*eePeI$%zar-m0L_yPeJ8{Xs^`
z@--Sv*)=xR(CgjOXL?6<w3}5d`Rmn2+Rb{B{84mjcc(6Gq~DCyA&&0H<lgW7>vu!>
***@qKGt?C7gJaON}OM*7(E#dyY>DC_cvA761#7E$VWS!@)9dR9fbpExu{4sQDDEemi
zjg7i+Dtmq&RnFUxEa}k=bhKM9VD6xIEP8z1%k!%v?U}^***@v~pL-!vO3fBFX9T&3I
zEzH=kqMg+Vwl)-B)#gNM$yfC$^Syot4VyW^m&Yr{*Ui=_Zw-v|z+TOYG7|w_^7UD@
***@Q=w4T?k^=M5}JW>c62VcvveTWtV(X3}X3cCBI^w4bBnJDz^!*TlY|U-8*%
z?zhal6j{SKFR`NFX+1kBAgU!x>9<D?-_N?%{MjPTSnvIHRvUmO9m`_OA6F-fZOmY-
zMCA$8Lt+qi{yCy!d&UFb>{YwB{`JpbwF)p37|P|6A`rxRp$G(Vy)6PkTsMnAuo*36
z?rlsOh|UeV85q{<^wz}wwJ?i{Cn+)35^*4U<HrC-YsL#ct-{Kl&0sE9%d3bu&I(mT
i9A}X#B96086%l7Ku`AYq)@I{{*mDhTmLbqK{{J7+PdK9h
literal 0
HcmV?d00001
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c
new file mode 100755
index 0000000..ad3f565
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c
@@ -0,0 +1,118 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+#include "e1000.h"
+#include "startstop.h"
+
+EFI_GUID gEfiStartStopProtocolGuid = EFI_DRIVER_STOP_PROTOCOL_GUID;
+
+EFI_STATUS
+StopDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+ Issues a call to stop the driver so diagnostic application can access the hardware.
+
+Arguments:
+ This - pointer to the EFI_DRIVER_STOP_PROTOCOL instance.
+
+Returns:
+ EFI_SUCCESS if driver is stopped successfully
+
+--*/
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ GIG_UNDI_PRIVATE_DATA *GigPrivate;
+
+ DEBUGPRINT (DIAG, ("Entering StopDriver\n"));
+ DEBUGWAIT(DIAG);
+
+ GigPrivate = GIG_UNDI_PRIVATE_DATA_FROM_DRIVER_STOP(This);
+
+ GigPrivate->NicInfo.DriverBusy = TRUE;
+
+ return Status;
+}
+
+EFI_STATUS
+StartDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+ Issues a call to start the driver after diagnostic application has completed.
+
+Arguments:
+ This - pointer to the EFI_DRIVER_STOP_PROTOCOL instance.
+
+Returns:
+ EFI_SUCCESS if driver has restarted successfully
+
+--*/
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ GIG_UNDI_PRIVATE_DATA *GigPrivate;
+ BOOLEAN ReceiveStarted;
+
+ DEBUGPRINT (DIAG, ("Entering StartDriver\n"));
+ DEBUGWAIT(DIAG);
+
+ GigPrivate = GIG_UNDI_PRIVATE_DATA_FROM_DRIVER_STOP(This);
+
+ //
+ // Save off the value of ReceiveStarted as it will be reset by XgbeInitialize
+ //
+ ReceiveStarted = GigPrivate->NicInfo.ReceiveStarted;
+
+ GigPrivate->NicInfo.HwInitialized = FALSE;
+ e1000_reset_hw(&GigPrivate->NicInfo.hw);
+ if (GigPrivate->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigPrivate->NicInfo);
+ DEBUGPRINT(DIAG, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(DIAG, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigPrivate->NicInfo);
+ }
+ }
+
+ GigPrivate->NicInfo.DriverBusy = FALSE;
+
+ return Status;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h
new file mode 100755
index 0000000..b107db3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _STARTSTOP_H_
+#define _STARTSTOP_H_
+
+#include "e1000.h"
+
+#define EFI_DRIVER_STOP_PROTOCOL_GUID \
+{ 0x34d59603, 0x1428, 0x4429, { 0xa4, 0x14, 0xe6, 0xb3, \
+0xb5, 0xfd, 0x7d, 0xc1 } }
+
+typedef struct _EFI_DRIVER_STOP_PROTOCOL EFI_DRIVER_STOP_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_STOP_PROTOCOL_STOP_DRIVER) (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_STOP_PROTOCOL_START_DRIVER) (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+typedef struct _EFI_DRIVER_STOP_PROTOCOL {
+ EFI_DRIVER_STOP_PROTOCOL_STOP_DRIVER StopDriver;
+ EFI_DRIVER_STOP_PROTOCOL_START_DRIVER StartDriver;
+} EFI_DRIVER_STOP_PROTOCOL;
+
+EFI_STATUS
+StopDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+EFI_STATUS
+StartDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+
+#endif /* _STARTSTOP_H_ */
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c
new file mode 100755
index 0000000..4053495
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c
@@ -0,0 +1,138 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+extern EFI_GUID gEfiPro1000ComGuid;
+
+EFI_GUID gEfiVlanProtocolGuid = EFI_VLAN_GUID;
+
+EFI_VLAN_PROTOCOL gGigUndiVlanData = {
+ 1,
+ GigUndiSetVlanTag
+};
+
+EFI_STATUS
+GigUndiSetVlanTag (
+ IN EFI_HANDLE ControllerHandle,
+ IN BOOLEAN VlanEnable,
+ IN UINT16 VlanId,
+ IN UINT16 VlanPriority,
+ IN BOOLEAN VlanCfi
+ )
+/*++
+
+Routine Description:
+ Enables or disables 802.3Q VLAN tagging on the specified network interface.
+
+Arguments:
+ ControllerHandle - The handle to the network interface to configure VLAN tagging.
+ VlanEnable - Enable or disable 802.3Q ethernet header and VLAN tag insertion
+ VlanTag - Vlan tag to insert into each 802.3Q packet.
+
+Returns:
+ EFI_SUCCESS on success, appropriate EFI status code on failure
+
+--*/
+{
+ EFI_STATUS Status;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ UINT32 Reg;
+
+ if (VlanId > 0x0FFF) {
+ DEBUGPRINT (VLAN, ("VlanId parameter out of range.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VlanPriority > 7) {
+ DEBUGPRINT (VLAN, ("VlanPriority parameter out of range.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VlanCfi > 1) {
+ DEBUGPRINT (VLAN, ("VlanCfi parameter out of range.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (VLAN, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("2. OpenProtocol returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+ DEBUGPRINT (VLAN, ("Subsystem Vendor ID = %X\n", GigUndiPrivateData->NicInfo.hw.subsystem_vendor_id));
+ DEBUGPRINT (VLAN, ("Vendor ID = %X\n", GigUndiPrivateData->NicInfo.hw.vendor_id));
+ DEBUGPRINT (VLAN, ("Device ID = %X\n", GigUndiPrivateData->NicInfo.hw.device_id));
+
+ Reg = E1000_READ_REG (&GigUndiPrivateData->NicInfo.hw, E1000_CTRL);
+ if (VlanEnable) {
+ GigUndiPrivateData->NicInfo.VlanEnable = TRUE;
+ GigUndiPrivateData->NicInfo.VlanTag = VlanId | (VlanCfi << 12) | (VlanPriority << 13);
+ DEBUGPRINT (VLAN, ("VlanTag = %X\n", GigUndiPrivateData->NicInfo.VlanTag));
+ Reg |= E1000_CTRL_VME;
+ DEBUGPRINT (VLAN, ("VME in CTRL register enabled\n"));
+ } else {
+ GigUndiPrivateData->NicInfo.VlanEnable = FALSE;
+ GigUndiPrivateData->NicInfo.VlanTag = 0;
+ Reg &= ~E1000_CTRL_VME;
+ DEBUGPRINT (VLAN, ("VME in CTRL register disabled\n"));
+ }
+ E1000_WRITE_REG (&GigUndiPrivateData->NicInfo.hw, E1000_CTRL, Reg);
+ DEBUGPRINT (VLAN, ("E1000_CTRL=%X\n", Reg));
+ DEBUGPRINT (VLAN, ("Vlan setting complete.\n"));
+
+ Reg = E1000_READ_REG (&GigUndiPrivateData->NicInfo.hw, E1000_VET);
+ DEBUGPRINT (VLAN, ("E1000_VET=%X\n", Reg));
+
+ return Status;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h
new file mode 100755
index 0000000..b78df64
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+
+#ifndef _VLAN_H
+#define _VLAN_H
+
+#define EFI_VLAN_GUID \
+ { \
+ 0xe1ad94a, 0xdcf4, 0x11db, \
+ { \
+ 0x97, 0x5, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f \
+ } \
+ }
+
+typedef EFI_STATUS
+(EFIAPI *EFI_SET_VLAN_TAG) (
+ IN EFI_HANDLE ControllerHandle,
+ IN BOOLEAN VlanEnable,
+ IN UINT16 VlanId,
+ IN UINT16 VlanPriority,
+ IN BOOLEAN VlanCfi
+ );
+
+typedef struct _EFI_VLAN_PROTOCOL {
+ UINT16 Version;
+ EFI_SET_VLAN_TAG SetVlanTag;
+} EFI_VLAN_PROTOCOL;
+
+extern EFI_GUID gEfiVlanProtocolGuid;
+
+extern EFI_VLAN_PROTOCOL gGigUndiVlanData;
+
+EFI_STATUS
+GigUndiSetVlanTag (
+ IN EFI_HANDLE ControllerHandle,
+ IN BOOLEAN VlanEnable,
+ IN UINT16 VlanId,
+ IN UINT16 VlanPriority,
+ IN BOOLEAN VlanCfi
+ );
+
+#endif
downloaded on from http://tianocore.sourceforge.net/wiki/EDK.
The driver has been ported to EDK2.
It builds but it has not been tested.
Change-Id: If7f81cc53d87c4ef224ced1ba995f1f84a6715bf
Signed-off-by: Olivier Martin <***@arm.com>
---
.../Drivers/LanIntelE1000Dxe/ComponentName.c | 407 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c | 1751 +++++++++
.../Drivers/LanIntelE1000Dxe/DriverConfiguration.c | 666 ++++
.../Drivers/LanIntelE1000Dxe/DriverDiagnostics.c | 1553 ++++++++
.../Drivers/LanIntelE1000Dxe/FirmwareManagement.c | 1126 ++++++
.../Drivers/LanIntelE1000Dxe/FirmwareManagement.h | 216 ++
.../Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf | 99 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h | 68 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h | 159 +
.../LanIntelE1000Dxe/build_instructions.txt | 63 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c | 514 +++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h | 100 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c | 2222 +++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h | 680 ++++
.../Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c | 1561 ++++++++
.../Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h | 103 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c | 2042 ++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h | 66 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c | 2030 ++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h | 423 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c | 1248 ++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h | 175 +
.../Drivers/LanIntelE1000Dxe/e1000_defines.h | 1772 +++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h | 868 +++++
.../Drivers/LanIntelE1000Dxe/e1000_ich8lan.c | 4070 ++++++++++++++++++++
.../Drivers/LanIntelE1000Dxe/e1000_ich8lan.h | 233 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c | 2203 +++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h | 102 +
.../Drivers/LanIntelE1000Dxe/e1000_manage.c | 409 ++
.../Drivers/LanIntelE1000Dxe/e1000_manage.h | 87 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c | 1063 +++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h | 75 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c | 693 ++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h | 180 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c | 3579 +++++++++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h | 268 ++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h | 576 +++
.../Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf | 97 +
.../Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf | 98 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c | 1973 ++++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h | 87 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h | 33 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c | 1505 ++++++++
EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr | 138 +
.../Drivers/LanIntelE1000Dxe/inventorystrings.uni | Bin 0 -> 47396 bytes
EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c | 118 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h | 74 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c | 138 +
EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h | 73 +
49 files changed, 37784 insertions(+)
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventorystrings.uni
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c
create mode 100755 EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c
new file mode 100755
index 0000000..bc47d53
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ComponentName.c
@@ -0,0 +1,407 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "brand.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+//
+// Version and Branding Information
+//
+
+CHAR16 VersionNumber[36];
+
+CHAR16* PrefixString = L"Intel(R) PRO/1000 ";
+CHAR16* PlatformName = L" PCI-E ";
+
+static EFI_UNICODE_STRING_TABLE mGigUndiDriverNameTable[] = {
+ { "eng", VersionNumber},
+ { "en-US", VersionNumber},
+ { NULL, NULL }
+};
+
+#define WILD_CARD 0x0000
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+GigUndiComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+GigUndiComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+
+EFI_COMPONENT_NAME_PROTOCOL gGigUndiComponentName = {
+ GigUndiComponentNameGetDriverName,
+ GigUndiComponentNameGetControllerName,
+ "eng"
+};
+
+EFI_COMPONENT_NAME2_PROTOCOL gGigUndiComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GigUndiComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GigUndiComponentNameGetControllerName,
+ "en-US"
+};
+
+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gGigUndiSupportedEFIVersion = {
+ sizeof(EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL),
+ EFI_2_10_SYSTEM_TABLE_REVISION
+};
+
+VOID
+GetUndiControllerName (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+ Routine Description:
+ Searches through the branding string list for the best possible match for the controller
+ associated with GigUndiPrivateData.
+
+ Arguments:
+ GigUndiPrivateData - Stores the PCI IDs and component name table for the device.
+
+ Returns:
+ VOID
+--*/
+{
+ struct e1000_hw *Nic;
+ CHAR16 *Brand;
+ UINTN i;
+ INTN VendorMatch;
+ INTN DeviceIdMatch;
+ INTN SubVendorMatch;
+ INTN SubSystemMatch;
+
+ i = 0;
+ VendorMatch = -1;
+ DeviceIdMatch = -1;
+ SubVendorMatch = -1;
+ SubSystemMatch = -1;
+ Brand = NULL;
+
+ Nic = &GigUndiPrivateData->NicInfo.hw;
+
+ for (i = 0; branding_table[i].vendor_id != 0xFFFF; i++) {
+ if (Nic->vendor_id == branding_table[i].vendor_id) {
+ if (Nic->device_id == branding_table[i].device_id) {
+ if (Nic->subsystem_vendor_id == branding_table[i].subvendor_id) {
+ if (Nic->subsystem_device_id == branding_table[i].subsystem_id) {
+ //
+ // Found the best possible match
+ //
+ SubSystemMatch = i;
+ break;
+ }
+ else if (branding_table[i].subsystem_id == WILD_CARD) {
+ SubVendorMatch = i;
+ }
+ }
+ else if (branding_table[i].subvendor_id == WILD_CARD) {
+ DeviceIdMatch = i;
+ }
+ }
+ else if (branding_table[i].device_id == WILD_CARD) {
+ //
+ // Worst match: Vendor ID only, everything else wildcard
+ //
+ VendorMatch = i;
+ }
+ }
+ }
+
+ //
+ // Pick the best possible match
+ //
+ do {
+ if (SubSystemMatch != -1) {
+ Brand = branding_table[SubSystemMatch].brand_string;
+ break;
+ }
+ if (SubVendorMatch != -1) {
+ Brand = branding_table[SubVendorMatch].brand_string;
+ break;
+ }
+ if (DeviceIdMatch != -1) {
+ Brand = branding_table[DeviceIdMatch].brand_string;
+ break;
+ }
+ if (VendorMatch != -1) {
+ Brand = branding_table[VendorMatch].brand_string;
+ break;
+ }
+ } while(0);
+
+ if (Brand == NULL) {
+ return;
+ }
+
+ GigUndiPrivateData->Brand = Brand;
+ AddUnicodeString (
+ "en-US",
+ gGigUndiComponentName2.SupportedLanguages,
+ &GigUndiPrivateData->ControllerNameTable,
+ Brand
+ );
+
+ AddUnicodeString (
+ "eng",
+ gGigUndiComponentName.SupportedLanguages,
+ &GigUndiPrivateData->ControllerNameTable,
+ Brand
+ );
+}
+
+
+EFI_STATUS
+GigUndiComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ Language - A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ DriverName - A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ Returns:
+ EFI_SUCCES - The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - DriverName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT(INIT, ("GigUndiComponentNameGetDriverName\n"));
+
+ //
+ // First lets put together the branding string
+ //
+ CopyMem(&VersionNumber[0], PrefixString, 18 * sizeof(CHAR16));
+
+ VersionNumber[18] = '0' + MAJORVERSION;
+ VersionNumber[19] = '.';
+ VersionNumber[20] = '0' + MINORVERSION;
+ VersionNumber[21] = '.';
+ VersionNumber[22] = '0' + BUILDNUMBER/10;
+ VersionNumber[23] = '0' + BUILDNUMBER%10;
+
+ CopyMem(&VersionNumber[24], PlatformName, 7 * sizeof(CHAR16));
+ VersionNumber[31] = '\0';
+
+ if (This == (EFI_COMPONENT_NAME_PROTOCOL *)&gGigUndiComponentName2) {
+ Language = "en-US";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName2.SupportedLanguages,
+ mGigUndiDriverNameTable,
+ DriverName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+ return Status;
+ }
+
+ Language = "eng";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName.SupportedLanguages,
+ mGigUndiDriverNameTable,
+ DriverName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+GigUndiComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ ControllerHandle - The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ ChildHandle - The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ ControllerName - A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language from the point of view of the driver specified
+ by This.
+
+ Returns:
+ EFI_SUCCESS - The Unicode string for the user readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - ControllerName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_STATUS Status;
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ if (ChildHandle == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ else {
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **)&NIIProtocol,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (NIIProtocol);
+
+ if (This == (EFI_COMPONENT_NAME_PROTOCOL *)&gGigUndiComponentName2) {
+ Language = "en-US";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName2.SupportedLanguages,
+ GigUndiPrivateData->ControllerNameTable,
+ ControllerName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+ return Status;
+ }
+
+ Language = "eng";
+ Status = LookupUnicodeString (
+ Language,
+ gGigUndiComponentName.SupportedLanguages,
+ GigUndiPrivateData->ControllerNameTable,
+ ControllerName
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LookupUnicodeString returns %r\n", Status));
+ }
+ return Status;
+ }
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c
new file mode 100755
index 0000000..a860113
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/Decode.c
@@ -0,0 +1,1751 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+//
+// Global variables defined outside this file
+//
+extern PXE_SW_UNDI *e1000_pxe_31;
+extern GIG_UNDI_PRIVATE_DATA *e1000_UNDI32DeviceList[MAX_NIC_INTERFACES];
+
+//
+// Global variables defined in this file
+//
+UNDI_CALL_TABLE e1000_api_table[PXE_OPCODE_LAST_VALID + 1] = {
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ (UINT16) (ANY_STATE),
+ e1000_UNDI_GetState
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ (UINT16) (ANY_STATE),
+ e1000_UNDI_Start
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ MUST_BE_STARTED,
+ e1000_UNDI_Stop
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ sizeof (PXE_DB_GET_INIT_INFO),
+ 0,
+ MUST_BE_STARTED,
+ e1000_UNDI_GetInitInfo
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ sizeof (PXE_DB_GET_CONFIG_INFO),
+ 0,
+ MUST_BE_STARTED,
+ e1000_UNDI_GetConfigInfo
+ },
+ {
+ sizeof (PXE_CPB_INITIALIZE),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_STARTED,
+ e1000_UNDI_Initialize
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Reset
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ 0,
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Shutdown
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Interrupt
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_RecFilter
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_StnAddr
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Statistics
+ },
+ {
+ sizeof (PXE_CPB_MCAST_IP_TO_MAC),
+ sizeof (PXE_DB_MCAST_IP_TO_MAC),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_ip2mac
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_NVData
+ },
+ {
+ PXE_CPBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Status
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_FillHeader
+ },
+ {
+ (UINT16) (DONT_CHECK),
+ PXE_DBSIZE_NOT_USED,
+ (UINT16) (DONT_CHECK),
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Transmit
+ },
+ {
+ sizeof (PXE_CPB_RECEIVE),
+ sizeof (PXE_DB_RECEIVE),
+ 0,
+ MUST_BE_INITIALIZED,
+ e1000_UNDI_Receive
+ }
+};
+
+//
+// External Functions
+//
+extern
+UINTN
+e1000_Reset (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 Opflags
+ );
+
+extern
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+extern
+UINTN
+e1000_SetFilter (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 NewFilter,
+ UINT64 cpb,
+ UINT32 cpbsize
+ );
+
+extern
+int
+e1000_Statistics (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 db,
+ UINT16 dbsize
+ );
+
+extern
+BOOLEAN
+e1000_WaitForAutoNeg (
+ IN GIG_DRIVER_DATA *GigAdapter
+ );
+
+extern
+int
+e1000_SetInterruptState (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+VOID
+e1000_UNDI_GetState (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine determines the operational state of the UNDI. It updates the state flags in the
+ Command Descriptor Block based on information derived from the AdapterInfo instance data.
+
+ To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of
+ the command execution.
+
+ The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command
+ has successfully completed.
+
+ Keep in mind the AdapterInfo->State is the active state of the adapter (based on software
+ interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected
+ to the caller of the UNDI API.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ DEBUGPRINT(DECODE, ("e1000_UNDI_GetState\n"));
+ DEBUGWAIT(DECODE);
+
+ CdbPtr->StatFlags |= GigAdapter->State;
+ CdbPtr->StatFlags |= PXE_STATFLAGS_COMMAND_COMPLETE;
+
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Start (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to change the operational state of the Gigabit UNDI from stopped to started.
+ It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise
+ the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
+ UNDI as having already been started.
+
+ This routine is modified to reflect the undi 1.1 specification changes. The
+ changes in the spec are mainly in the callback routines, the new spec adds
+ 3 more callbacks and a unique id.
+ Since this UNDI supports both old and new undi specifications,
+ The NIC's data structure is filled in with the callback routines (depending
+ on the version) pointed to in the caller's CpbPtr. This seeds the Delay,
+ Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem
+ and Sync_Mem routines and a unique id variable for the new version.
+ This is the function which an external entity (SNP, O/S, etc) would call
+ to provide it's I/O abstraction to the UNDI.
+
+ It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_START_31 *CpbPtr_31;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Start\n"));
+ DEBUGWAIT(DECODE);
+
+ //
+ // check if it is already started.
+ //
+ if (GigAdapter->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_ALREADY_STARTED;
+ return ;
+ }
+
+ if (CdbPtr->CPBsize != sizeof (PXE_CPB_START_30) && CdbPtr->CPBsize != sizeof (PXE_CPB_START_31)) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr);
+
+ GigAdapter->Delay = (bsptr) (UINTN) CpbPtr_31->Delay;
+ GigAdapter->Virt2Phys = (virtphys) (UINTN) CpbPtr_31->Virt2Phys;
+ GigAdapter->Block = (block) (UINTN) CpbPtr_31->Block;
+ GigAdapter->MemIo = (mem_io) (UINTN) CpbPtr_31->Mem_IO;
+ GigAdapter->MapMem = (map_mem) (UINTN) CpbPtr_31->Map_Mem;
+ GigAdapter->UnMapMem = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem;
+ GigAdapter->SyncMem = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem;
+ GigAdapter->Unique_ID = CpbPtr_31->Unique_ID;
+ DEBUGPRINT(DECODE, ("CpbPtr_31->Unique_ID = %x\n", CpbPtr_31->Unique_ID));
+
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STARTED;
+
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Stop (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to change the operational state of the UNDI from started to stopped.
+ It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise
+ the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
+ UNDI as having already not been shut down.
+
+ The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out..
+
+ It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Stop\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
+ return ;
+ }
+
+ GigAdapter->Delay = 0;
+ GigAdapter->Virt2Phys = 0;
+ GigAdapter->Block = 0;
+
+ GigAdapter->MapMem = 0;
+ GigAdapter->UnMapMem = 0;
+ GigAdapter->SyncMem = 0;
+
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STOPPED;
+
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_GetInitInfo (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to retrieve the initialization information that is needed by drivers and
+ applications to initialize the UNDI. This will fill in data in the Data Block structure that is
+ pointed to by the caller's CdbPtr->DBaddr. The fields filled in are as follows:
+
+ MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen,
+ MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack.
+
+ In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection. (APRIORI knowledge)
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_GET_INIT_INFO *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_GetInitInfo\n"));
+ DEBUGWAIT(DECODE);
+
+ DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr);
+
+ DbPtr->MemoryRequired = 0;
+ DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
+ //
+ // First check for FIBER, Links are 1000,0,0,0
+ //
+ if (GigAdapter->hw.phy.media_type == e1000_media_type_copper ) {
+ DbPtr->LinkSpeeds[0] = 10;
+ DbPtr->LinkSpeeds[1] = 100;
+ DbPtr->LinkSpeeds[2] = 1000;
+ DbPtr->LinkSpeeds[3] = 0;
+ } else {
+ DbPtr->LinkSpeeds[0] = 1000;
+ DbPtr->LinkSpeeds[1] = 0;
+ DbPtr->LinkSpeeds[2] = 0;
+ DbPtr->LinkSpeeds[3] = 0;
+ }
+
+ DbPtr->NvCount = MAX_EEPROM_LEN;
+ DbPtr->NvWidth = 4;
+ DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
+ DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER;
+ DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
+
+ DbPtr->TxBufCnt = DEFAULT_TX_DESCRIPTORS;
+ DbPtr->TxBufSize = sizeof (E1000_TRANSMIT_DESCRIPTOR);
+ DbPtr->RxBufCnt = DEFAULT_RX_DESCRIPTORS;
+ DbPtr->RxBufSize = sizeof (E1000_RECEIVE_DESCRIPTOR) + sizeof (LOCAL_RX_BUFFER);
+
+ DbPtr->IFtype = PXE_IFTYPE_ETHERNET;
+ DbPtr->SupportedDuplexModes = PXE_DUPLEX_ENABLE_FULL_SUPPORTED | PXE_DUPLEX_FORCE_FULL_SUPPORTED;
+ DbPtr->SupportedLoopBackModes = 0;
+
+ CdbPtr->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
+ PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
+
+ CdbPtr->StatFlags |= PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_GetConfigInfo (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to retrieve the configuration information about the NIC being controlled by
+ this driver. This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr.
+ The fields filled in are as follows:
+
+ DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci.
+
+ In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_GET_CONFIG_INFO *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_GetConfigInfo\n"));
+ DEBUGWAIT(DECODE);
+
+ DbPtr = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr);
+
+ DbPtr->pci.BusType = PXE_BUSTYPE_PCI;
+ DbPtr->pci.Bus = (UINT16) GigAdapter->Bus;
+ DbPtr->pci.Device = (UINT8) GigAdapter->Device;
+ DbPtr->pci.Function = (UINT8) GigAdapter->Function;
+ DEBUGPRINT(DECODE, (
+ "Bus %x, Device %x, Function %x\n",
+ GigAdapter->Bus,
+ GigAdapter->Device,
+ GigAdapter->Function
+ ));
+
+ CopyMem (DbPtr->pci.Config.Dword, &GigAdapter->PciConfig, MAX_PCI_CONFIG_LEN * sizeof (UINT32));
+
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Initialize (
+ IN PXE_CDB *CdbPtr,
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine resets the network adapter and initializes the Gigabit UNDI using the parameters
+ supplied in the CPB. This command must be issued before the network adapter can be setup to
+ transmit and receive packets.
+
+ Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block
+ of non-swappable memory may need to be allocated. The address of this memory must be passed to
+ UNDI during the Initialize in the CPB. This memory is used primarily for transmit and receive buffers.
+
+ The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with
+ information that was passed in the CPB and the NIC is initialized.
+
+ If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
+ Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of
+ the UNDI is now initialized.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_INITIALIZE *CpbPtr;
+ PXE_DB_INITIALIZE *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Initialize\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Initialize called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
+ (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)
+ ) {
+ DEBUGPRINT(CRITICAL, ("INVALID CDB\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ //
+ // Check if it is already initialized
+ //
+ if (GigAdapter->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ DEBUGPRINT(DECODE, ("ALREADY INITIALIZED\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
+ return ;
+ }
+
+ CpbPtr = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;
+ DbPtr = (PXE_DB_INITIALIZE *) (UINTN) CdbPtr->DBaddr;
+
+ //
+ // Default behaviour is to detect the cable, if the 3rd param is 1,
+ // do not do that
+ //
+ GigAdapter->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);
+ DEBUGPRINT(DECODE, ("CdbPtr->OpFlags = %X\n", CdbPtr->OpFlags));
+ GigAdapter->LinkSpeed = (UINT16) CpbPtr->LinkSpeed;
+
+ GigAdapter->DuplexMode = CpbPtr->DuplexMode;
+ GigAdapter->LoopBack = CpbPtr->LoopBackMode;
+
+ DEBUGPRINT(DECODE, ("CpbPtr->TxBufCnt = %X\n", CpbPtr->TxBufCnt));
+ DEBUGPRINT(DECODE, ("CpbPtr->TxBufSize = %X\n", CpbPtr->TxBufSize));
+ DEBUGPRINT(DECODE, ("CpbPtr->RxBufCnt = %X\n", CpbPtr->RxBufCnt));
+ DEBUGPRINT(DECODE, ("CpbPtr->RxBufSize = %X\n", CpbPtr->RxBufSize));
+
+ if (GigAdapter->CableDetect != 0) {
+ DEBUGPRINT(DECODE, ("Setting wait_autoneg_complete\n"));
+ GigAdapter->hw.phy.autoneg_wait_to_complete = TRUE;
+ } else {
+ GigAdapter->hw.phy.autoneg_wait_to_complete = FALSE;
+ }
+
+ CdbPtr->StatCode = (PXE_STATCODE) e1000_Inititialize (GigAdapter);
+
+ //
+ // We allocate our own memory for transmit and receive so set MemoryUsed to 0.
+ //
+ DbPtr->MemoryUsed = 0;
+ DbPtr->TxBufCnt = DEFAULT_TX_DESCRIPTORS;
+ DbPtr->TxBufSize = sizeof (E1000_TRANSMIT_DESCRIPTOR);
+ DbPtr->RxBufCnt = DEFAULT_RX_DESCRIPTORS;
+ DbPtr->RxBufSize = sizeof (E1000_RECEIVE_DESCRIPTOR) + sizeof (LOCAL_RX_BUFFER);
+
+ if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("e1000_Inititialize failed! Statcode = %X\n", CdbPtr->StatCode));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ } else {
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
+ }
+
+ //
+ // If no link is detected we want to set the driver state back to _GET_STATE_STARTED so
+ // that the SNP will not try to restart the driver.
+ //
+ if (e1000_WaitForAutoNeg (GigAdapter) == TRUE) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ } else {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STARTED;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Reset (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine resets the network adapter and initializes the Gigabit UNDI using the
+ parameters supplied in the CPB. The transmit and receive queues are emptied and any
+ pending interrupts are cleared.
+
+ If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver
+ is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Reset\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Reset called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED &&
+ CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS &&
+ CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS
+ ) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS; //(UINT16) e1000_Reset (GigAdapter, CdbPtr->OpFlags);
+
+ if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ } else {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ }
+}
+
+VOID
+e1000_UNDI_Shutdown (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine resets the network adapter and leaves it in a safe state for another driver to
+ initialize. Any pending transmits or receives are lost. Receive filters and external
+ interrupt enables are disabled. Once the UNDI has been shutdown, it can then be stopped
+ or initialized again.
+
+ If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
+
+ Otherwise, GigAdapter->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing
+ the state of the NIC as being started.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ //
+ // do the shutdown stuff here
+ //
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Shutdown\n"));
+ DEBUGWAIT(DECODE);
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Shutdown called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ CdbPtr->StatCode = (UINT16) e1000_Shutdown (GigAdapter);
+
+ if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ } else {
+ GigAdapter->State = PXE_STATFLAGS_GET_STATE_STARTED;
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Interrupt (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine can be used to read and/or change the current external interrupt enable
+ settings. Disabling an external interrupt enable prevents and external (hardware)
+ interrupt from being signaled by the network device. Internally the interrupt events
+ can still be polled by using the UNDI_GetState command.
+
+ The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on.
+
+Returns:
+ None
+
+--*/
+{
+ UINT8 IntMask;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Interrupt\n"));
+
+ IntMask = (UINT8) (UINTN)
+ (
+ CdbPtr->OpFlags &
+ (
+ PXE_OPFLAGS_INTERRUPT_RECEIVE |
+ PXE_OPFLAGS_INTERRUPT_TRANSMIT |
+ PXE_OPFLAGS_INTERRUPT_COMMAND |
+ PXE_OPFLAGS_INTERRUPT_SOFTWARE
+ )
+ );
+
+ switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) {
+ case PXE_OPFLAGS_INTERRUPT_READ:
+ break;
+
+ case PXE_OPFLAGS_INTERRUPT_ENABLE:
+ if (IntMask == 0) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ GigAdapter->int_mask = IntMask;
+ e1000_SetInterruptState (GigAdapter);
+ break;
+
+ case PXE_OPFLAGS_INTERRUPT_DISABLE:
+ if (IntMask != 0) {
+ GigAdapter->int_mask &= ~(IntMask);
+ e1000_SetInterruptState (GigAdapter);
+ break;
+ }
+
+ //
+ // else fall thru.
+ //
+ default:
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ if ((GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE;
+ }
+
+ if ((GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT;
+ }
+
+ if ((GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_RecFilter (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to read and change receive filters and, if supported, read
+ and change multicast MAC address filter list.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI
+ driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+
+ UINT16 NewFilter;
+ UINT16 OpFlags;
+ PXE_DB_RECEIVE_FILTERS *DbPtr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_RecFilter\n"));
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_RecFilter called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ OpFlags = CdbPtr->OpFlags;
+ NewFilter = (UINT16) (OpFlags & 0x1F);
+
+ switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
+ case PXE_OPFLAGS_RECEIVE_FILTER_READ:
+ //
+ // not expecting a cpb, not expecting any filter bits
+ //
+ if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {
+ goto BadCdb;
+ }
+
+ if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
+ goto JustRead;
+ }
+
+ NewFilter |= GigAdapter->Rx_Filter;
+
+ //
+ // all other flags are ignored except mcast_reset
+ //
+ break;
+
+ case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
+ //
+ // there should be atleast one other filter bit set.
+ //
+ if (NewFilter == 0) {
+ //
+ // nothing to enable
+ //
+ goto BadCdb;
+ }
+
+ if (CdbPtr->CPBsize != 0) {
+ //
+ // this must be a multicast address list!
+ // don't accept the list unless selective_mcast is set
+ // don't accept confusing mcast settings with this
+ //
+ if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
+ ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
+ ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0)
+ ) {
+ goto BadCdb;
+ }
+ }
+
+ //
+ // check selective mcast case enable case
+ //
+ if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
+ ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0)
+ ) {
+ goto BadCdb;
+
+ }
+
+ //
+ // if no cpb, make sure we have an old list
+ //
+ if ((CdbPtr->CPBsize == 0) && (GigAdapter->McastList.Length == 0)) {
+ goto BadCdb;
+ }
+ }
+
+ //
+ // if you want to enable anything, you got to have unicast
+ // and you have what you already enabled!
+ //
+ NewFilter |= (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | GigAdapter->Rx_Filter);
+
+ break;
+
+ case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
+ //
+ // mcast list not expected, i.e. no cpb here!
+ //
+ if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {
+ goto BadCdb; // db with all_multi??
+ }
+
+ NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & GigAdapter->Rx_Filter);
+
+ break;
+
+ default:
+ goto BadCdb;
+ }
+
+ if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {
+ GigAdapter->McastList.Length = 0;
+ NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ }
+
+ e1000_SetFilter (GigAdapter, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);
+
+JustRead:
+ DEBUGPRINT(DECODE, ("Read current filter\n"));
+ //
+ // give the current mcast list
+ //
+ if ((CdbPtr->DBsize != 0) && (GigAdapter->McastList.Length != 0)) {
+ //
+ // copy the mc list to db
+ //
+ UINT16 i;
+ UINT16 copy_len;
+ UINT8 *ptr1;
+ UINT8 *ptr2;
+
+ DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;
+ ptr1 = (UINT8 *) (&DbPtr->MCastList[0]);
+
+ copy_len = (UINT16) (GigAdapter->McastList.Length * PXE_MAC_LENGTH);
+
+ if (copy_len > CdbPtr->DBsize) {
+ copy_len = CdbPtr->DBsize;
+
+ }
+
+ ptr2 = (UINT8 *) (&GigAdapter->McastList.McAddr[0]);
+ for (i = 0; i < copy_len; i++) {
+ ptr1[i] = ptr2[i];
+ }
+ }
+
+ //
+ // give the stat flags here
+ //
+ if (GigAdapter->ReceiveStarted) {
+ CdbPtr->StatFlags |= (GigAdapter->Rx_Filter | PXE_STATFLAGS_COMMAND_COMPLETE);
+ }
+
+ return ;
+
+BadCdb:
+ DEBUGPRINT(CRITICAL, ("ERROR: Bad CDB!\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+}
+
+VOID
+e1000_UNDI_StnAddr (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to get the current station and broadcast MAC addresses, and to change the
+ current station MAC address.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver
+ is layering on.
+
+Returns:
+ None
+
+--*/
+{
+
+ PXE_CPB_STATION_ADDRESS *CpbPtr;
+ PXE_DB_STATION_ADDRESS *DbPtr;
+ UINT16 i;
+
+ DbPtr = NULL;
+ DEBUGPRINT(DECODE, ("e1000_UNDI_StnAddr\n"));
+
+ if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
+ //
+ // configure the permanent address.
+ // change the AdapterInfo->CurrentNodeAddress field.
+ //
+ if (CompareMem (
+ GigAdapter->hw.mac.addr,
+ GigAdapter->hw.mac.perm_addr,
+ PXE_HWADDR_LEN_ETHER
+ ) != 0) {
+ CopyMem (
+ GigAdapter->hw.mac.addr,
+ GigAdapter->hw.mac.perm_addr,
+ PXE_HWADDR_LEN_ETHER
+ );
+ e1000_rar_set (&GigAdapter->hw, GigAdapter->hw.mac.addr, 0);
+ }
+ }
+
+ if (CdbPtr->CPBaddr != (UINT64) 0) {
+ CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);
+ GigAdapter->MacAddrOverride = TRUE;
+
+ //
+ // configure the new address
+ //
+ CopyMem (
+ GigAdapter->hw.mac.addr,
+ CpbPtr->StationAddr,
+ PXE_HWADDR_LEN_ETHER
+ );
+
+ DEBUGPRINT(DECODE, ("Reassigned address:\n"));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(DECODE, ("%2x ", CpbPtr->StationAddr[i]));
+ }
+
+ e1000_rar_set (&GigAdapter->hw, GigAdapter->hw.mac.addr, 0);
+ }
+
+ if (CdbPtr->DBaddr != (UINT64) 0) {
+ DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);
+
+ //
+ // fill it with the new values
+ //
+ ZeroMem (DbPtr->StationAddr, PXE_MAC_LENGTH);
+ ZeroMem (DbPtr->PermanentAddr, PXE_MAC_LENGTH);
+ ZeroMem (DbPtr->BroadcastAddr, PXE_MAC_LENGTH);
+ CopyMem (DbPtr->StationAddr, GigAdapter->hw.mac.addr, PXE_HWADDR_LEN_ETHER);
+ CopyMem (DbPtr->PermanentAddr, GigAdapter->hw.mac.perm_addr, PXE_HWADDR_LEN_ETHER);
+ CopyMem (DbPtr->BroadcastAddr, GigAdapter->BroadcastNodeAddress, PXE_MAC_LENGTH);
+ }
+
+ DEBUGPRINT(DECODE, ("DbPtr->BroadcastAddr ="));
+ for (i = 0; i < PXE_MAC_LENGTH; i++) {
+ DEBUGPRINT(DECODE, (" %x", DbPtr->BroadcastAddr[i]));
+ }
+
+ DEBUGPRINT(DECODE, ("\n"));
+ DEBUGWAIT(DECODE);
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+ return ;
+}
+
+VOID
+e1000_UNDI_Statistics (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to read and clear the NIC traffic statistics. This command is supported only
+ if the !PXE structure's Implementation flags say so.
+
+ Results will be parsed out in the following manner:
+ CdbPtr->DBaddr.Data[0] R Total Frames (Including frames with errors and dropped frames)
+ CdbPtr->DBaddr.Data[1] R Good Frames (All frames copied into receive buffer)
+ CdbPtr->DBaddr.Data[2] R Undersize Frames (Frames below minimum length for media <64 for ethernet)
+ CdbPtr->DBaddr.Data[4] R Dropped Frames (Frames that were dropped because receive buffers were full)
+ CdbPtr->DBaddr.Data[8] R CRC Error Frames (Frames with alignment or CRC errors)
+ CdbPtr->DBaddr.Data[A] T Total Frames (Including frames with errors and dropped frames)
+ CdbPtr->DBaddr.Data[B] T Good Frames (All frames copied into transmit buffer)
+ CdbPtr->DBaddr.Data[C] T Undersize Frames (Frames below minimum length for media <64 for ethernet)
+ CdbPtr->DBaddr.Data[E] T Dropped Frames (Frames that were dropped because of collisions)
+ CdbPtr->DBaddr.Data[14] T Total Collision Frames (Total collisions on this subnet)
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+// GC_TODO: GigAdapter - add argument and description to function comment
+{
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Statistics\n"));
+
+ if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {
+ //
+ // Reset the statistics
+ //
+ CdbPtr->StatCode = (UINT16) e1000_Statistics (GigAdapter, 0, 0);
+ } else {
+ CdbPtr->StatCode = (UINT16) e1000_Statistics (GigAdapter, CdbPtr->DBaddr, CdbPtr->DBsize);
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_ip2mac (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to translate a multicast IP address to a multicast MAC address.
+
+ This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP
+ address being appended to it. Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;
+ PXE_DB_MCAST_IP_TO_MAC *DbPtr;
+ UINT32 IPAddr;
+ UINT8 *TmpPtr;
+
+ CpbPtr = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;
+ DbPtr = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_ip2mac\n"));
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
+ //
+ // for now this is not supported
+ //
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_UNSUPPORTED;
+ return ;
+ }
+
+ //
+ // Take the last 23 bits of IP to generate a multicase IP address.
+ //
+ IPAddr = CpbPtr->IP.IPv4;
+ TmpPtr = (UINT8 *) (&IPAddr);
+
+ DbPtr->MAC[0] = 0x01;
+ DbPtr->MAC[1] = 0x00;
+ DbPtr->MAC[2] = 0x5e;
+ DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);
+ DbPtr->MAC[4] = (UINT8) TmpPtr[2];
+ DbPtr->MAC[5] = (UINT8) TmpPtr[3];
+
+ return ;
+}
+
+VOID
+e1000_UNDI_NVData (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to read and write non-volatile storage on the NIC (if supported). The NVRAM
+ could be EEPROM, FLASH, or battery backed RAM.
+
+ This is an optional function according to the UNDI specification (or will be......)
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_NVDATA *DbPtr;
+ PXE_CPB_NVDATA_BULK *PxeCpbNvdata;
+ UINT32 Result;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_NVData\n"));
+
+ if ((GigAdapter->State != PXE_STATFLAGS_GET_STATE_STARTED) &&
+ (GigAdapter->State != PXE_STATFLAGS_GET_STATE_INITIALIZED)
+ ) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {
+ DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;
+ Result = e1000_read_nvm (&GigAdapter->hw, 0, 256, &DbPtr->Data.Word[0]);
+ } else {
+ //
+ // Begin the write at word 40h so we do not overwrite any vital data
+ // All data from address 00h to address CFh will be ignored
+ //
+ PxeCpbNvdata = (PXE_CPB_NVDATA_BULK *) (UINTN) CdbPtr->CPBaddr;
+ Result = e1000_write_nvm (&GigAdapter->hw, 0x40, 0xBF, &PxeCpbNvdata->Word[0x40]);
+ }
+
+ if (Result == E1000_SUCCESS) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+ } else {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+ }
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Status (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine returns the current interrupt status and/or the transmitted buffer addresses.
+ If the current interrupt status is returned, pending interrupts will be acknowledged by this
+ command. Transmitted buffer addresses that are written to the DB are removed from the transmit
+ buffer queue.
+
+ Normally, this command would be polled with interrupts disabled.
+
+ The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].
+ The interrupt status is returned in CdbPtr->StatFlags.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the Gigabit UNDI
+ driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ PXE_DB_GET_STATUS *DbPtr;
+ UINT16 Status;
+ UINT16 NumEntries;
+ E1000_RECEIVE_DESCRIPTOR *RxPtr;
+#if (DBG_LVL&CRITICAL)
+ UINT32 Rdh;
+ UINT32 Rdt;
+#endif
+ UINT32 Reg;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_Status\n"));
+
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Status called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ //
+ // If the size of the DB is not large enough to store at least one 64 bit
+ // complete transmit buffer address and size of the next available receive
+ // packet we will return an error. Per E.4.16 of the EFI spec the DB should
+ // have enough space for at least 1 completed transmit buffer.
+ //
+ if (CdbPtr->DBsize < (sizeof (UINT64) * 2)) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ DEBUGPRINT(CRITICAL, ("Invalid CDB\n"));
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN;
+ }
+
+ return ;
+ }
+
+ DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;
+
+ //
+ // Fill in size of next available receive packet and
+ // reserved field in caller's DB storage.
+ //
+ RxPtr = &GigAdapter->rx_ring[GigAdapter->cur_rx_ind];
+
+#if (DBG_LVL&CRITICAL)
+ if (RxPtr->buffer_addr != GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind]) {
+ DEBUGPRINT(CRITICAL, ("GetStatus ERROR: Rx buff mismatch on desc %d: expected %X, actual %X\n",
+ GigAdapter->cur_rx_ind,
+ GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind],
+ RxPtr->buffer_addr
+ ));
+ }
+
+ Rdt = E1000_READ_REG (&GigAdapter->hw, E1000_RDT(0));
+ Rdh = E1000_READ_REG (&GigAdapter->hw, E1000_RDH(0));
+ if (Rdt == Rdh) {
+ DEBUGPRINT(CRITICAL, ("GetStatus ERROR: RX Buffers Full!\n"));
+ }
+#endif
+
+ if ((RxPtr->status & (E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD)) != 0) {
+ DEBUGPRINT(DECODE, ("Get Status->We have a Rx Frame at %x\n", GigAdapter->cur_rx_ind));
+ DEBUGPRINT(DECODE, ("Frame length = %X\n", RxPtr->length));
+ DbPtr->RxFrameLen = RxPtr->length;
+ } else {
+ DbPtr->RxFrameLen = 0;
+ }
+
+ //
+ // Fill in the completed transmit buffer addresses so they can be freed by
+ // the calling application or driver
+ //
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
+ //
+ // Calculate the number of entries available in the DB to save the addresses
+ // of completed transmit buffers.
+ //
+ NumEntries = (UINT16) ((CdbPtr->DBsize - sizeof (UINT64)) / sizeof (UINT64));
+ DEBUGPRINT(DECODE, ("CdbPtr->DBsize = %d\n", CdbPtr->DBsize));
+ DEBUGPRINT(DECODE, ("NumEntries in DbPtr = %d\n", NumEntries));
+
+ //
+ // On return NumEntries will be the number of TX buffers written into the DB
+ //
+ NumEntries = e1000_FreeTxBuffers(GigAdapter, NumEntries, DbPtr->TxBuffer);
+ if (NumEntries == 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN;
+ }
+
+ //
+ // The receive buffer size and reserved fields take up the first 64 bits of the DB
+ // The completed transmit buffers take up the rest
+ //
+ CdbPtr->DBsize = (UINT16) (sizeof (UINT64) + NumEntries * sizeof (UINT64));
+ DEBUGPRINT(DECODE, ("Return DBsize = %d\n", CdbPtr->DBsize));
+ }
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
+ Status = (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_ICR);
+ GigAdapter->Int_Status |= Status;
+
+ //
+ // Acknowledge the interrupts.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_IMC, 0xFFFFFFFF);
+
+ //
+ // Report all the outstanding interrupts.
+ //
+ if (GigAdapter->Int_Status &
+ (E1000_ICR_RXT0 | E1000_ICR_RXSEQ | E1000_ICR_RXDMT0 | E1000_ICR_RXO | E1000_ICR_RXCFG)
+ ) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
+ }
+
+ if (GigAdapter->int_mask & (E1000_ICR_TXDW | E1000_ICR_TXQE)) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TRANSMIT;
+ }
+
+ if (GigAdapter->int_mask &
+ (E1000_ICR_GPI_EN0 | E1000_ICR_GPI_EN1 | E1000_ICR_GPI_EN2 | E1000_ICR_GPI_EN3 | E1000_ICR_LSC)
+ ) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;
+ }
+ }
+
+ //
+ // Return current media status
+ //
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
+ Reg = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ if ((Reg & E1000_STATUS_LU) == 0) {
+ CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
+ }
+ }
+
+ CdbPtr->StatFlags |= PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ return ;
+}
+
+VOID
+e1000_UNDI_FillHeader (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to fill media header(s) in transmit packet(s).
+ Copies the MAC address into the media header whether it is dealing
+ with fragmented or non-fragmented packets.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on.
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CPB_FILL_HEADER *Cpb;
+ PXE_CPB_FILL_HEADER_FRAGMENTED *Cpbf;
+ ETHER_HEADER *MacHeader;
+ UINTN i;
+
+ DEBUGPRINT(DECODE, ("e1000_UNDI_FillHeader\n"));
+
+ if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
+ Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;
+
+ //
+ // Assume 1st fragment is big enough for the mac header.
+ //
+ if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
+ //
+ // No buffers given.
+ //
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ MacHeader = (ETHER_HEADER *) (UINTN) Cpbf->FragDesc[0].FragAddr;
+
+ //
+ // We don't swap the protocol bytes.
+ //
+ MacHeader->type = Cpbf->Protocol;
+
+ DEBUGPRINT(DECODE, ("MacHeader->src_addr = "));
+ for (i = 0; i < PXE_HWADDR_LEN_ETHER; i++) {
+ MacHeader->dest_addr[i] = Cpbf->DestAddr[i];
+ MacHeader->src_addr[i] = Cpbf->SrcAddr[i];
+ DEBUGPRINT(DECODE, ("%x ", MacHeader->src_addr[i]));
+ }
+
+ DEBUGPRINT(DECODE, ("\n"));
+ } else {
+ Cpb = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;
+ MacHeader = (ETHER_HEADER *) (UINTN) Cpb->MediaHeader;
+
+ //
+ // We don't swap the protocol bytes.
+ //
+ MacHeader->type = Cpb->Protocol;
+
+ DEBUGPRINT(DECODE, ("MacHeader->src_addr = "));
+ for (i = 0; i < PXE_HWADDR_LEN_ETHER; i++) {
+ MacHeader->dest_addr[i] = Cpb->DestAddr[i];
+ MacHeader->src_addr[i] = Cpb->SrcAddr[i];
+ DEBUGPRINT(DECODE, ("%x ", MacHeader->src_addr[i]));
+ }
+
+ DEBUGPRINT(DECODE, ("\n"));
+ }
+
+ DEBUGWAIT(DECODE);
+ return ;
+}
+
+VOID
+e1000_UNDI_Transmit (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine is used to place a packet into the transmit queue. The data buffers given to
+ this command are to be considered locked and the application or network driver loses
+ ownership of these buffers and must not free or relocate them until the ownership returns.
+
+ When the packets are transmitted, a transmit complete interrupt is generated (if interrupts
+ are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status
+ command.
+
+ Some implementations and adapters support transmitting multiple packets with one transmit
+ command. If this feature is supported, the transmit CPBs can be linked in one transmit
+ command.
+
+ All UNDIs support fragmented frames, now all network devices or protocols do. If a fragmented
+ frame CPB is given to UNDI and the network device does not support fragmented frames
+ (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer
+ before transmitting.
+
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Transmit called when driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ CdbPtr->StatCode = (PXE_STATCODE) e1000_Transmit (GigAdapter, CdbPtr->CPBaddr, CdbPtr->OpFlags);
+
+ CdbPtr->StatCode == PXE_STATCODE_SUCCESS ? (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE) : (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED);
+
+ return ;
+}
+
+VOID
+e1000_UNDI_Receive (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ When the network adapter has received a frame, this command is used to copy the frame
+ into the driver/application storage location. Once a frame has been copied, it is
+ removed from the receive queue.
+
+Arguments:
+ CdbPtr - Pointer to the command descriptor block.
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ if (GigAdapter->DriverBusy == TRUE) {
+ DEBUGPRINT (DECODE, ("ERROR: e1000_UNDI_Receive called while driver busy\n"));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_BUSY;
+ return ;
+ }
+
+ //
+ // Check if RU has started.
+ //
+ if (GigAdapter->ReceiveStarted == FALSE) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;
+ return ;
+ }
+
+ CdbPtr->StatCode = (UINT16) e1000_Receive (GigAdapter, CdbPtr->CPBaddr, CdbPtr->DBaddr);
+
+ CdbPtr->StatCode == PXE_STATCODE_SUCCESS ? (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE) : (CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED);
+
+ return ;
+}
+
+
+VOID
+e1000_UNDI_APIEntry (
+ IN UINT64 cdb
+ )
+/*++
+
+Routine Description:
+ This is the main SW UNDI API entry using the newer nii protocol.
+ The parameter passed in is a 64 bit flat model virtual
+ address of the cdb. We then jump into the common routine for both old and
+ new nii protocol entries.
+
+Arguments:
+ cdb - Pointer to the command descriptor block.
+
+Returns:
+ None
+
+--*/
+{
+ PXE_CDB *CdbPtr;
+ GIG_DRIVER_DATA *GigAdapter;
+ UNDI_CALL_TABLE *tab_ptr;
+
+ if (cdb == (UINT64) 0) {
+ return ;
+ }
+
+ CdbPtr = (PXE_CDB *) (UINTN) cdb;
+
+ if (CdbPtr->IFnum > e1000_pxe_31->IFcnt) {
+ DEBUGPRINT(DECODE, ("Invalid IFnum %d\n", CdbPtr->IFnum));
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+ }
+
+ GigAdapter = &(e1000_UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
+ GigAdapter->VersionFlag = 0x31; // entering from new entry point
+
+ //
+ // Check the OPCODE range.
+ //
+ if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||
+ (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||
+ (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE)
+ ) {
+ DEBUGPRINT(DECODE, ("Invalid StatCode, OpCode, or StatFlags.\n", CdbPtr->IFnum));
+ goto badcdb;
+ }
+
+ if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
+ if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {
+ goto badcdb;
+ }
+ } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {
+ goto badcdb;
+ }
+
+ if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {
+ if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {
+ goto badcdb;
+ }
+ } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {
+ goto badcdb;
+ }
+
+ //
+ // Check if cpbsize and dbsize are as needed.
+ // Check if opflags are as expected.
+ //
+ tab_ptr = &e1000_api_table[CdbPtr->OpCode];
+
+ if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {
+ goto badcdb;
+ }
+
+ if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {
+ goto badcdb;
+ }
+
+ if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {
+ goto badcdb;
+ }
+
+ GigAdapter = &(e1000_UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
+
+ //
+ // Check if UNDI_State is valid for this call.
+ //
+ if (tab_ptr->state != (UINT16) (-1)) {
+ //
+ // Should atleast be started.
+ //
+ if (GigAdapter->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_NOT_STARTED;
+ return ;
+ }
+
+ //
+ // Check if it should be initialized.
+ //
+ if (tab_ptr->state == 2) {
+ if (GigAdapter->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ CdbPtr->StatCode = PXE_STATCODE_NOT_INITIALIZED;
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ return ;
+ }
+ }
+ }
+
+ //
+ // Set the return variable for success case here.
+ //
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
+ CdbPtr->StatCode = PXE_STATCODE_SUCCESS;
+
+ tab_ptr->api_ptr (CdbPtr, GigAdapter);
+ return ;
+
+badcdb:
+ CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
+ CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB;
+ return ;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c
new file mode 100755
index 0000000..70531c1
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverConfiguration.c
@@ -0,0 +1,666 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+extern EFI_GUID gEfiPro1000ComGuid;
+
+EFI_STATUS
+GigUndiDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+EFI_STATUS
+GigUndiDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+EFI_STATUS
+GigUndiDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+EFI_DRIVER_CONFIGURATION_PROTOCOL gGigUndiDriverConfiguration = {
+ GigUndiDriverConfigurationSetOptions,
+ GigUndiDriverConfigurationOptionsValid,
+ GigUndiDriverConfigurationForceDefaults,
+ "eng"
+};
+
+#define MENU_AUTONEG 0
+#define MENU_100_FULL 1
+#define MENU_100_HALF 2
+#define MENU_10_FULL 3
+#define MENU_10_HALF 4
+#define MENU_SAVE 5
+#define MENU_EXIT 6
+
+CHAR16 *ConfigMenu[] = {
+ L"Set adapter to Autonegotiate (recommended)",
+ L"Set adapter to 100Mbps full duplex",
+ L"Set adapter to 100Mbps half duplex",
+ L"Set adapter to 10Mbps full duplex",
+ L"Set adapter to 10Mbps half duplex",
+ L"Save settings to NVRAM",
+ L"Exit (maintain current settings)",
+ NULL
+};
+
+
+VOID
+GigUndiDriverConfigurationDisplayMenu (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+Routine Description:
+
+ Displays the options for the configuration menu to allow the user to change the speed/duplex settings
+
+Arguments:
+
+ hw - adapter to configure
+
+Returns:
+
+ VOID
+
+--*/
+{
+ UINTN Active;
+ UINT16 Selection;
+ UINT16 i;
+ EFI_INPUT_KEY Key;
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+ UINT16 Word0;
+ CHAR16 *SpeedDuplexString = L"";
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ Selection = 0; // Tracks which menu item is highligted
+ i = 0;
+ Active = 0; // Tracks current speed/duplex setting so '*' can be drawn next to it
+
+ //
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ return;
+ }
+
+ e1000_read_nvm(hw, SetupOffset, 1, &SetupWord);
+
+ //
+ // Save the original setup word value so we can tell if the user changed it
+ //
+ Word0 = SetupWord;
+
+ //
+ // If the boot agent EEPROM signature is not set properly then we will initialize
+ // the words to default values and assume a default autonegotiation setting
+ //
+ e1000_read_nvm(hw, ConfigOffset, 1, &CustomConfigWord);
+
+
+ if ((CustomConfigWord & SIG_MASK) != SIG) {
+ CustomConfigWord = SIG;
+ SetupWord = DISPLAY_SETUP_MESSAGE;
+ } else {
+ //
+ // The signature bits are set so get the speed duplex settings
+ // Mask of the speed and duplex setting bits so that we can determine
+ // what the settings are
+ //
+ switch (SetupWord & (FSP_MASK | FDP_FULL_DUPLEX_BIT))
+ {
+ case (FDP_FULL_DUPLEX_BIT | FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ SpeedDuplexString = L"100Mbps full duplex";
+ Active = MENU_100_FULL;
+ break;
+ case (FDP_FULL_DUPLEX_BIT | FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ SpeedDuplexString = L"10Mbps full duplex";
+ Active = MENU_10_FULL;
+ break;
+ case (FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ SpeedDuplexString = L"100Mbps half duplex";
+ Active = MENU_100_HALF;
+ break;
+ case (FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ SpeedDuplexString = L"10Mbps half duplex";
+ Active = MENU_10_HALF;
+ break;
+ default:
+ hw->mac.autoneg = 1;
+ SpeedDuplexString = L"Autonegotiation";
+ Active = MENU_AUTONEG;
+ }
+ }
+
+ while (1) {
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BACKGROUND_BLACK);
+ gST->ConOut->OutputString (gST->ConOut, L"Configure adapter speed and duplex\n\r");
+
+ gST->ConOut->OutputString (gST->ConOut, L"Current setting: ");
+ gST->ConOut->OutputString (gST->ConOut, SpeedDuplexString);
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n");
+
+ //
+ // Print out the menu items with the current selection highlighted
+ //
+ for (i = 0; ConfigMenu[i] != NULL; i++) {
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n ");
+ if (i == Selection) {
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_BLACK | EFI_BACKGROUND_LIGHTGRAY);
+ }
+
+ //
+ // Draw an asterisk next to the current speed/duplex selection
+ //
+ if (i == Active) {
+ gST->ConOut->OutputString(gST->ConOut, L"*");
+ } else {
+ gST->ConOut->OutputString(gST->ConOut, L" ");
+ }
+
+ gST->ConOut->OutputString (gST->ConOut, ConfigMenu[i]);
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+
+ //
+ // Capture the user input
+ //
+ while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) != EFI_SUCCESS);
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+
+ //
+ // Check to see if user made a change to the speed/duplex settings
+ //
+ switch (Selection)
+ {
+ case MENU_AUTONEG:
+ //
+ // Speed mask has already been cleared
+ //
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FSP_AUTONEG);
+ hw->mac.autoneg = 1;
+ Active = Selection;
+ break;
+ case MENU_100_FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_100MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ Active = Selection;
+ break;
+ case MENU_100_HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_100MBS;
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ Active = Selection;
+ break;
+ case MENU_10_FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_10MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ Active = Selection;
+ break;
+ case MENU_10_HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_10MBS;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ hw->mac.autoneg = 0;
+ Active = Selection;
+ break;
+ default:
+ break;
+ }
+ gBS->Stall(1000000);
+
+ if (Selection == MENU_SAVE) {
+ //
+ // Only write the EEPROM if the speed/duplex value has changed
+ //
+ if (SetupWord != Word0) {
+ gST->ConOut->OutputString (gST->ConOut, L"\n\n\rSaving settings...");
+ gBS->Stall(1000000);
+ if (e1000_write_nvm (hw, ConfigOffset, 1, &CustomConfigWord) != E1000_SUCCESS) {
+ gST->ConOut->OutputString (gST->ConOut, L"EEPROM write error\n\r");
+ } else
+ if (e1000_write_nvm (hw, SetupOffset, 1, &SetupWord) != E1000_SUCCESS) {
+ gST->ConOut->OutputString (gST->ConOut, L"EEPROM write error\n\r");
+ } else {
+ //
+ // Success
+ //
+ e1000_update_nvm_checksum (hw);
+ Word0 = SetupWord;
+ gST->ConOut->OutputString (gST->ConOut, L"done\n\r");
+ }
+ gBS->Stall(1000000);
+ } else {
+ gST->ConOut->OutputString (gST->ConOut, L"\n\n\rSettings have not changed\n");
+ gBS->Stall(1000000);
+ }
+ }
+
+ if (Selection == MENU_EXIT) {
+ if (Word0 != SetupWord) {
+ gST->ConOut->OutputString (gST->ConOut, L"\n\n\n\n\n\n\rChanged settings have not been saved. Do you want to exit anyway? (y/n)");
+ do {
+ while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) != EFI_SUCCESS);
+ if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y' || Key.UnicodeChar == 'n' || Key.UnicodeChar == 'N')
+ break;
+ } while (1);
+ }
+ //
+ // Always exit unless the users selects N
+ //
+ if ((Key.UnicodeChar != 'n') && (Key.UnicodeChar != 'N')) {
+ break;
+ }
+ }
+ }
+
+ if (Key.ScanCode == SCAN_UP) {
+ if (Selection > 0) {
+ Selection--;
+ }
+ } else if (Key.ScanCode == SCAN_DOWN) {
+ if (ConfigMenu[Selection + 1] != NULL) {
+ Selection++;
+ }
+ } else if (Key.ScanCode == SCAN_ESC) {
+ break;
+ }
+ } // end while(1)
+
+
+ return;
+}
+
+EFI_STATUS
+GigUndiDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+/*++
+
+Routine Description:
+
+ Callback function for Driver Configuration protocol. Finds the NII adapter handle for
+ Controller handle and then calls the setup menu
+
+Arguments:
+
+ This - Driver configuration protocol instance
+ ControllerHandle - The network driver controller handle
+ ChildHandle - The NII child handle (not used)
+ Language - Always english
+ ActionRequired - Not used
+
+Returns:
+
+ EFI_UNSUPPORTED - Unable to open the driver configuration protocol for ControllerHandle
+ EFI_SUCCESS - Configuration was successful
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ EFI_STATUS Status;
+
+ UINT8 ReceiveStarted;
+
+ GigUndiPrivateData = NULL;
+ *ActionRequired = EfiDriverConfigurationActionNone;
+
+ if (ControllerHandle == NULL) {
+ DEBUGPRINT (CRITICAL, ("ControllerHandle == NULL\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ DEBUGPRINT (CRITICAL, ("OpenProtocol Status != EFI_ALREADY_STARTED %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (CFG, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("OpenProtocol error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+ //
+ // Speed duplex configuration is not supported on fiber or serdes cards.
+ //
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type != e1000_media_type_copper) {
+ DEBUGPRINT (CRITICAL, ("Phy media type not copper\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Remember receiver state, so we can leave it in the same state as it was before settings were made.
+ //
+ ReceiveStarted = GigUndiPrivateData->NicInfo.ReceiveStarted;
+
+ GigUndiDriverConfigurationDisplayMenu (GigUndiPrivateData);
+
+ //
+ // After speed/duplex setting completes we need to perform a full reset of the adapter.
+ // If the adapter was initialized on entry then force a full reset of the adapter.
+ // Also reenable the receive unit if it was enabled before we started the PHY loopback test.
+ //
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (GigUndiPrivateData->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigUndiPrivateData->NicInfo);
+ DEBUGPRINT(DIAG, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(DIAG, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigUndiPrivateData->NicInfo);
+ }
+ }
+ DEBUGPRINT(DIAG, ("ADAPTER RESET COMPLETE\n"));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GigUndiDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Not implemented
+
+Arguments:
+
+ This - GC_TODO: add argument description
+ ControllerHandle - GC_TODO: add argument description
+ ChildHandle - GC_TODO: add argument description
+
+Returns:
+
+ EFI_UNSUPPORTED - GC_TODO: Add description for return value
+
+--*/
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GigUndiDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+/*++
+
+Routine Description:
+
+ Restores the speed/duplex settings to the autonegotiation default value
+
+Arguments:
+
+ This - Driver configuration protocol instance
+ ControllerHandle - The network driver controller handle
+ ChildHandle - The NII child handle (not used)
+ DefaultType - Not used
+ ActionRequired - Not used
+
+Returns:
+
+ EFI_UNSUPPORTED - Unable to open the driver configuration protocol for ControllerHandle
+ EFI_SUCCESS - Configuration was successful
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ EFI_STATUS Status;
+ struct e1000_hw *hw;
+ UINT16 ConfigOffset;
+ UINT16 SetupOffset;
+ UINT16 CustomConfigWord;
+ UINT16 SetupWord;
+
+ GigUndiPrivateData = NULL;
+ *ActionRequired = EfiDriverConfigurationActionNone;
+
+ if (ControllerHandle == NULL) {
+ DEBUGPRINT (CRITICAL, ("ControllerHandle == NULL\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ DEBUGPRINT (CRITICAL, ("OpenProtocol Status != EFI_ALREADY_STARTED %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (CFG, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("OpenProtocol error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+ //
+ // Speed duplex configuration is not supported on fiber or serdes cards.
+ //
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type != e1000_media_type_copper) {
+ DEBUGPRINT (CRITICAL, ("Phy media type not copper\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ e1000_read_nvm (hw, ConfigOffset, 1, &CustomConfigWord);
+ e1000_read_nvm (hw, SetupOffset, 1, &SetupWord);
+
+ //
+ // If the signature word is not set then we will always assume the default values
+ // so do not change anything. If the signature bits are set then set the adapter
+ // back to autonegotiate
+ //
+ if ((CustomConfigWord & SIG_MASK) == SIG) {
+ //
+ // Only write the setup word if the adapter is not already set to autonegotiate
+ //
+ if ((SetupWord & FSP_MASK) != FSP_AUTONEG) {
+ SetupWord = (UINT16) ((SetupWord & ~FSP_MASK) | FSP_AUTONEG);
+ e1000_write_nvm (hw, SetupOffset, 1, &SetupWord);
+ e1000_update_nvm_checksum (hw);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c
new file mode 100755
index 0000000..1d1b9a3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/DriverDiagnostics.c
@@ -0,0 +1,1553 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+extern EFI_GUID gEfiPro1000ComGuid;
+
+
+#define MAX_ETHERNET_SIZE 1518
+#define TEST_PACKET_SIZE 1024
+
+#if (DBG_LVL & DIAG)
+#define PHY_LOOPBACK_ITERATIONS 10
+#else
+#define PHY_LOOPBACK_ITERATIONS 10000
+#endif
+
+#define PHY_PHLBKC 19
+#define PHY_PHCTRL1 23
+#define PHY_PHSTAT 26
+
+EFI_STATUS
+GigUndiDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ );
+
+EFI_STATUS
+GigUndiRunPhyLoopback (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ PXE_CPB_TRANSMIT PxeCpbTransmit
+ );
+
+BOOLEAN
+_SetIntegratedM88PhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ );
+
+BOOLEAN
+_SetNinevehPhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ );
+
+BOOLEAN
+_SetIgpPhyLoopback(
+ IN struct e1000_hw *hw,
+ IN UINT16 Speed
+ );
+
+EFI_DRIVER_DIAGNOSTICS_PROTOCOL gGigUndiDriverDiagnostics = {
+ GigUndiDriverDiagnosticsRunDiagnostics,
+ "eng"
+};
+
+EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gGigUndiDriverDiagnostics2 = {
+ (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) GigUndiDriverDiagnosticsRunDiagnostics,
+ "en-US"
+};
+
+
+#define E1000_RCTL_LBM_MASK (0x000000C0) /* bitmask to retrieve LBM bits */
+
+typedef enum {
+ e1000_lbm_none = 0,
+ e1000_lbm_mac,
+ e1000_lbm_phy_1000,
+ e1000_lbm_phy_100,
+ e1000_lbm_phy_10,
+ e1000_lbm_transceiver,
+ e1000_lbm_count,
+ e1000_lbm_invalid = 0xFF
+} e1000_lbm_type;
+
+UINT8 Packet[MAX_ETHERNET_SIZE];
+
+#pragma pack(1)
+typedef struct {
+ UINT8 DestAddr[6];
+ UINT8 SourceAddr[6];
+ UINT8 Length[2];
+} ETHERNET_HDR;
+#pragma pack()
+
+/***************************************************************************
+**
+** Name: _NalGenericReadPhyRegister16Ex()
+**
+** Description: Writes a 16bit value to the Phy. - allows user to
+** set PHY Page
+**
+** Author: GVR
+**
+** Born on Date: 06/01/2005
+**
+** Arguments: Handle = Handle to this adapter.
+** Page = PHY Page # or device #
+** Offset = The register to read from the PHY. This is a
+** numeric offset value.
+** Value = The value read to return.
+**
+** Returns: NAL_STATUS
+**
+****************************************************************************/
+INT32
+_ReadPhyRegister16Ex(
+ IN struct e1000_hw *hw,
+ IN UINT32 Page,
+ IN UINT32 Offset,
+ OUT UINT16* Value
+ )
+{
+ //
+ // See e1000_hw.c and e1000_hw.h for bit field specifications for PHY page register
+ //
+ Page = (Page & 0x07FF) << 5;
+ Offset = ((Offset & 0x1F) | Page);
+
+ return e1000_read_phy_reg(hw, Offset, Value);
+}
+
+/***************************************************************************
+**
+** Name: _NalGenericWritePhyRegister16Ex()
+**
+** Description: Writes a 16bit value to the Phy. - allows user to
+** set PHY Page
+**
+** Author: GVR
+**
+** Born on Date: 06/01/2005
+**
+** Arguments: Handle = Handle to this adapter.
+** Page = PHY Page #
+** Register = The register to write to the PHY. This is a
+** numeric offset value.
+** Data = The value read to write.
+**
+** Returns: NAL_STATUS
+**
+****************************************************************************/
+INT32
+_WritePhyRegister16Ex(
+ IN struct e1000_hw *hw,
+ IN UINT32 Page,
+ IN UINT32 Offset,
+ IN UINT16 Data
+ )
+{
+ /* see sdk/adapters/module0/e1000_hw.c and e1000_hw.h for bit field
+ * specifications for PHY page register */
+ Page = (Page & 0x07FF) << 5;
+ Offset = ((Offset & 0x1F) | Page);
+
+ return e1000_write_phy_reg(hw, Offset, Data);
+}
+
+
+VOID
+_BuildPacket (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ )
+/*++
+
+Routine Description:
+ Build a packet to transmit in the phy loopback test.
+
+Arguments:
+ GigAdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on so that we can
+ get the MAC address
+Returns:
+ Sets the global array Packet[] with the packet to send out during PHY loopback.
+
+--*/
+{
+ ETHERNET_HDR *EthernetHdr;
+ UINT16 Length;
+ UINT16 i;
+
+ EthernetHdr = NULL;
+ Length = 0;
+ i = 0;
+
+ ZeroMem ((char *) Packet, MAX_ETHERNET_SIZE);
+
+ //
+ // First copy the source and destination addresses
+ //
+ EthernetHdr = (ETHERNET_HDR *) Packet;
+ CopyMem ((char *) &EthernetHdr->SourceAddr, (char *) GigAdapterInfo->hw.mac.addr, ETH_ADDR_LEN);
+ CopyMem ((char *) &EthernetHdr->DestAddr, (char *) GigAdapterInfo->BroadcastNodeAddress, ETH_ADDR_LEN);
+
+ //
+ // Calculate the data segment size and store it in the header big Endian style
+ //
+ Length = TEST_PACKET_SIZE - sizeof (ETHERNET_HDR);
+ EthernetHdr->Length[0] = (UINT8) (Length >> 8);
+ EthernetHdr->Length[1] = (UINT8) Length;
+
+ //
+ // Generate Packet data
+ //
+ for (i = 0; i < Length; i++) {
+ Packet[i + sizeof (ETHERNET_HDR)] = (UINT8) i;
+ }
+}
+
+VOID
+_DisplayBuffersAndDescriptors (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ )
+/*++
+
+Routine Description:
+ Display the buffer and descriptors for debuging the PHY loopback test.
+
+Arguments:
+ GigAdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on so that we can
+ get the MAC address
+Returns:
+ Sets the global array Packet[] with the packet to send out during PHY loopback.
+
+--*/
+{
+ E1000_RECEIVE_DESCRIPTOR *ReceiveDesc;
+ E1000_TRANSMIT_DESCRIPTOR *TransmitDesc;
+ UINT32 j;
+
+ DEBUGPRINT (DIAG, ("Receive Descriptor\n"));
+ DEBUGPRINT(DIAG, ("RCTL=%X ", E1000_READ_REG(&GigAdapterInfo->hw, E1000_RCTL)));
+ DEBUGPRINT(DIAG, ("RDH0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_RDH(0))));
+ DEBUGPRINT(DIAG, ("RDT0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_RDT(0))));
+ DEBUGPRINT(DIAG, ("cur_rx_ind=%X\n", GigAdapterInfo->cur_rx_ind));
+
+ ReceiveDesc = GigAdapterInfo->rx_ring;
+ for (j = 0; j < DEFAULT_RX_DESCRIPTORS; j++) {
+ DEBUGPRINT (DIAG, ("Buff=%x,", ReceiveDesc->buffer_addr));
+ DEBUGPRINT (DIAG, ("Len=%x,", ReceiveDesc->length));
+ DEBUGPRINT (DIAG, ("Stat=%x,", ReceiveDesc->status));
+ DEBUGPRINT (DIAG, ("Csum=%x,", ReceiveDesc->csum));
+ DEBUGPRINT (DIAG, ("Special=%x\n", ReceiveDesc->special));
+ ReceiveDesc++;
+ }
+
+ DEBUGWAIT (DIAG);
+ DEBUGPRINT (DIAG, ("Transmit Descriptor\n"));
+ DEBUGPRINT(DIAG, ("TCTL=%X ", E1000_READ_REG(&GigAdapterInfo->hw, E1000_TCTL)));
+ DEBUGPRINT(DIAG, ("TDH0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_TDH(0))));
+ DEBUGPRINT(DIAG, ("TDT0=%x ", (UINT16) E1000_READ_REG (&GigAdapterInfo->hw, E1000_TDT(0))));
+ DEBUGPRINT(DIAG, ("cur_tx_ind=%X\n", GigAdapterInfo->cur_tx_ind));
+
+ TransmitDesc = GigAdapterInfo->tx_ring;
+ for (j = 0; j < DEFAULT_TX_DESCRIPTORS; j++) {
+ DEBUGPRINT (DIAG, ("Buff=%x,", TransmitDesc->buffer_addr));
+ DEBUGPRINT (DIAG, ("Cmd=%x,", TransmitDesc->lower.flags.cmd));
+ DEBUGPRINT (DIAG, ("Cso=%x,", TransmitDesc->lower.flags.cso));
+ DEBUGPRINT (DIAG, ("Length=%x,", TransmitDesc->lower.flags.length));
+ DEBUGPRINT (DIAG, ("Status= %x,", TransmitDesc->upper.fields.status));
+ DEBUGPRINT (DIAG, ("Special=%x,", TransmitDesc->upper.fields.special));
+ DEBUGPRINT (DIAG, ("Css=%x\n", TransmitDesc->upper.fields.css));
+ TransmitDesc++;
+ }
+
+ DEBUGWAIT (DIAG);
+}
+
+BOOLEAN
+_SetIntegratedM88PhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ )
+/*++
+ Description: This routine is used by diagnostic software to put
+ the 82544, 82540, 82545, and 82546 MAC based network
+ cards and the M88E1000 PHY into loopback mode.
+
+ Loopback speed is determined by the Speed value
+ passed into this routine.
+
+ Valid values are 1000, 100, and 10 Mbps
+
+ Current procedure is to:
+ 1) Disable auto-MDI/MDIX
+ 2) Perform SW phy reset (bit 15 of PHY_CONTROL)
+ 3) Disable autoneg and reset
+ 4) For the specified speed, set the loopback
+ mode for that speed. Also force the MAC
+ to the correct speed and duplex for the
+ specified operation.
+ 5) If this is an 82543, setup the TX_CLK and
+ TX_CRS again.
+ 6) Disable the receiver so a cable disconnect
+ and reconnect will not cause autoneg to
+ begin.
+
+ Arguments: Adapter - Ptr to this card's adapter data structure
+ Speed - desired loopback speed
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+{
+ UINT32 CtrlReg = 0;
+ UINT32 StatusReg = 0;
+ UINT16 PhyReg = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ hw->mac.autoneg = FALSE;
+
+ /*******************************************************************
+ ** Set up desired loopback speed and duplex depending on input
+ ** into this function.
+ *******************************************************************/
+ switch(Speed)
+ {
+ case SPEED_1000:
+ DEBUGPRINT(DIAG, ("Setting M88E1000 PHY into loopback at 1000 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ if (hw->phy.type == e1000_phy_igp)
+ {
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ }
+ else if (hw->phy.type == e1000_phy_m88)
+ {
+ e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8140); /* autoneg off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ }
+ else if (hw->phy.type == e1000_phy_gg82563)
+ {
+ e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CE); /* Force Link Up */
+ e1000_write_phy_reg(hw, GG82563_REG(0, 0), 0x4140); /* bit 14 = IEEE loopback, force 1000, full duplex */
+ }
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ /* For some SerDes we'll need to commit the writes now so that the
+ * status register is updated on link. */
+ if (hw->phy.media_type == e1000_media_type_internal_serdes)
+ {
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ msec_delay(100);
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ }
+
+ if (hw->phy.media_type == e1000_media_type_copper)
+ {
+ /* For Marvel Phy, inverts Loss-Of-Signal */
+ if (hw->phy.type == e1000_phy_m88)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS); /* Invert Loss-Of-Signal */
+ }
+ }
+ else
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ DEBUGPRINT(DIAG, ("Link seems unstable in PHY Loopback setup\n"));
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_100:
+ DEBUGPRINT(DIAG, ("Setting M88E1000 PHY into loopback at 100 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8140); /* autoneg off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8100); /* reset to update autoneg */
+ e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, 0x0c14); /* MAC interface speed to 100Mbps */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0xe100); /* reset to update MAC interface speed */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x6100); /* force 100, set loopback */
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg =E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */
+ E1000_CTRL_SLU | /* Set the Force Link Bit */
+ E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 | /* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_10:
+ DEBUGPRINT(DIAG, ("Setting M88E1000 PHY into loopback at 10 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8140); /* autoneg off */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8100); /* reset to update autoneg */
+ e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, 0x0c04); /* MAC interface speed to 10Mbps */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x8100); /* reset to update MAC interface speed */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4100); /* force 10, set loopback */
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_SLU | /* Set the Force Link Bit */
+ E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_10 | /* Force Speed to 10 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ default:
+ DEBUGPRINT(DIAG, ("Invalid speed value loopback mode \"%d\"\n", Speed));
+ LoopbackModeSet = FALSE;
+ break;
+ }
+
+ e1000_read_phy_reg(hw, PHY_CONTROL, &PhyReg);
+ if (hw->phy.type == e1000_phy_m88)
+ {
+
+ /****************************************************************
+ * Disable the receiver on the PHY so when a cable is plugged
+ * in, the PHY does not begin to autoneg when a cable is
+ * reconnected to the NIC.
+ ***************************************************************/
+ e1000_write_phy_reg(hw, 29, 0x001F);
+ e1000_write_phy_reg(hw, 30, 0x8FFC);
+ e1000_write_phy_reg(hw, 29, 0x001A);
+ e1000_write_phy_reg(hw, 30, 0x8FF0);
+
+ /****************************************************************
+ * This delay is necessary with some nics on some machines after
+ * the PHY receiver is disabled.
+ ***************************************************************/
+ usec_delay(500);
+
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &PhyReg);
+ e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &PhyReg);
+ }
+ //
+ // The following delay is necessary for the PHY loopback mode to take on ESB2 based LOMs
+ //
+ msec_delay(100);
+
+ return LoopbackModeSet;
+}
+
+#ifndef NO_82571_SUPPORT
+VOID
+_SetI82571SerdesLoopback(
+ struct e1000_hw *hw
+ )
+/*++
+ Description: This routine is used to set fiber and serdes based 82571
+ and 82575 adapters into loopback mode.
+
+ Arguments: hw - Ptr to this card's adapter data structure
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+
+{
+ UINT32 CtrlReg = 0;
+ UINT32 TxctlReg = 0;
+ UINT32 StatusReg = 0;
+ BOOLEAN LinkUp = FALSE;
+
+ DEBUGPRINT(DIAG, ("Setting PHY loopback on I82571 fiber/serdes.\n"));
+ /* I82571 transceiver loopback */
+ CtrlReg = E1000_READ_REG (hw, E1000_CTRL);
+ CtrlReg |= E1000_CTRL_SLU;
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+
+ /* Disable autoneg by setting bit 31 of TXCW to zero */
+ TxctlReg = E1000_READ_REG (hw, E1000_TXCW);
+ TxctlReg &= ~(1 << 31);
+ E1000_WRITE_REG (hw, E1000_TXCW, TxctlReg);
+
+ /* Read status register link up */
+ StatusReg = E1000_READ_REG (hw, E1000_STATUS);
+ LinkUp = ((StatusReg & E1000_STATUS_LU) == 0) ? FALSE : TRUE;
+
+ /* Set ILOS if link is not up */
+ if(LinkUp == FALSE)
+ {
+ /* Set bit 7 (Invert Loss) and set link up in bit 6. */
+ CtrlReg = E1000_READ_REG (hw, E1000_CTRL);
+ CtrlReg |= (E1000_CTRL_ILOS);
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ }
+
+ /* Write 0x410 to Serdes control register to enable SerDes analog loopback */
+ E1000_WRITE_REG (hw, E1000_SCTL, 0x0410);
+ msec_delay(10);
+}
+#endif
+
+#ifndef NO_82575_SUPPORT
+VOID
+_SetI82575SerdesLoopback(
+ struct e1000_hw *hw
+ )
+/*++
+ Description: This routine is used to set fiber and serdes based 82571
+ and 82575 adapters into loopback mode.
+
+ Arguments: hw - Ptr to this card's adapter data structure
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+
+{
+ UINT32 CtrlReg = 0;
+ UINT32 CtrlExtReg = 0;
+ UINT32 PcsLctl = 0;
+ UINT32 ConnSwReg = 0;
+
+ DEBUGPRINT(DIAG, ("Setting PHY loopback on I82575 fiber/serdes.\n"));
+
+ /* I82575 transceiver loopback per EAS */
+ /* Write 0x410 to Serdes control register to enable SerDes analog loopback */
+ E1000_WRITE_REG (hw, E1000_SCTL, 0x0410);
+ msec_delay(10);
+
+ CtrlExtReg = E1000_READ_REG (hw, E1000_CTRL_EXT);
+ CtrlExtReg |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
+ E1000_WRITE_REG (hw, E1000_CTRL_EXT, CtrlExtReg);
+ msec_delay(10);
+
+ CtrlReg = E1000_READ_REG (hw, E1000_CTRL);
+ CtrlReg |= E1000_CTRL_SLU | E1000_CTRL_FD;
+ CtrlReg &= ~(E1000_CTRL_RFCE | E1000_CTRL_TFCE | E1000_CTRL_LRST);
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ msec_delay(10);
+
+ PcsLctl = E1000_READ_REG(hw, E1000_PCS_LCTL);
+ PcsLctl |= E1000_PCS_LCTL_FORCE_LINK | E1000_PCS_LCTL_FSD
+ | E1000_PCS_LCTL_FDV_FULL| E1000_PCS_LCTL_FLV_LINK_UP;
+ PcsLctl &= ~E1000_PCS_LCTL_AN_ENABLE;
+ E1000_WRITE_REG (hw, E1000_PCS_LCTL, PcsLctl);
+ msec_delay(10);
+
+ /* Read status register link up */
+ ConnSwReg = E1000_READ_REG (hw, E1000_CONNSW);
+ ConnSwReg &= ~E1000_CONNSW_ENRGSRC;
+ E1000_WRITE_REG (hw, E1000_CONNSW, ConnSwReg);
+ msec_delay(10);
+
+}
+#endif
+
+VOID
+_SetI82580SerdesLoopback(
+ struct e1000_hw *hw
+ )
+/*++
+ Description: This routine is used to set fiber and serdes based 82571
+ and 82575 adapters into loopback mode.
+
+ Arguments: hw - Ptr to this card's adapter data structure
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+
+{
+ UINT32 RctlReg = 0;
+ UINT32 CtrlReg = 0;
+ UINT32 PcsLctl = 0;
+ UINT32 ConnSwReg = 0;
+
+ DEBUGPRINT(DIAG, ("Setting PHY loopback on 82580 fiber/serdes.\n"));
+
+ /* Write 0x410 to Serdes control register to enable SerDes analog loopback */
+ E1000_WRITE_REG (hw, E1000_SCTL, 0x0410);
+
+ /* Configure SerDes to loopback */
+ RctlReg = E1000_READ_REG(hw, E1000_RCTL);
+ RctlReg |= E1000_RCTL_LBM_TCVR;
+ E1000_WRITE_REG(hw, E1000_RCTL, RctlReg);
+
+ /* Move to Force mode */
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg |= E1000_CTRL_SLU | E1000_CTRL_FD;
+ CtrlReg &= ~(E1000_CTRL_RFCE | E1000_CTRL_TFCE);
+ E1000_WRITE_REG(hw, E1000_CTRL, CtrlReg);
+
+ PcsLctl = E1000_READ_REG(hw, E1000_PCS_LCTL);
+ PcsLctl |= E1000_PCS_LCTL_FORCE_LINK | E1000_PCS_LCTL_FSD
+ | E1000_PCS_LCTL_FDV_FULL| E1000_PCS_LCTL_FLV_LINK_UP;
+ PcsLctl &= ~E1000_PCS_LCTL_AN_ENABLE;
+ E1000_WRITE_REG(hw, E1000_PCS_LCTL, PcsLctl);
+
+ ConnSwReg = E1000_READ_REG (hw, E1000_CONNSW);
+ ConnSwReg &= ~E1000_CONNSW_ENRGSRC;
+ E1000_WRITE_REG (hw, E1000_CONNSW, ConnSwReg);
+
+ msec_delay(10); // Need this delay or SerDes loopback will fail.
+}
+
+/**********************************************************************
+** Procedure: _NalI8254xSetBoazmanPhyLoopback
+**
+** Description: This routine is used by diagnostic software to put
+** the Intel Gigabit PHY into loopback mode.
+**
+** Loopback speed is determined by the Speed value
+** passed into this routine.
+**
+** Valid values are 1000, 100, and 10 Mbps
+**
+** Author: MVM
+**
+** Born on Date: 04/02/2007
+**
+** Arguments: Adapter - Ptr to this card's adapter data structure
+** Speed - desired loopback speed
+**
+** Returns: TRUE - Success, FALSE - Failure
+**********************************************************************/
+BOOLEAN
+_SetBoazmanPhyLoopback(
+ IN struct e1000_hw* hw,
+ IN UINT16 Speed
+ )
+{
+ UINT16 PhyValue = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+#ifndef NO_82571_SUPPORT
+#ifndef NO_82574_SUPPORT
+ UINT32 Reg = 0;
+ /* 82574 requires ILOS set */
+ if(hw->mac.type == e1000_82574
+ || hw->mac.type == e1000_82583
+ )
+ {
+ DEBUGPRINT(DIAG, ( "Setting ILOS on 82574.\n"));
+ Reg = E1000_READ_REG(hw, E1000_CTRL);
+ E1000_WRITE_REG(hw, E1000_CTRL, Reg | E1000_CTRL_ILOS);
+ }
+#endif
+#endif
+
+ if(Speed == SPEED_1000)
+ {
+ DEBUGPRINT(DIAG, ( "Setting Boazman PHY into loopback at 1000 Mbps\n"));
+ /* set 21_2.2:0 to the relevant speed (1G ?3b110, 100Mb ?3b101, 10Mb ? 3b100) */
+ _ReadPhyRegister16Ex(hw, 2, 21, &PhyValue);
+ PhyValue = (PhyValue & (~(7))) | 6;
+ }
+ else if(Speed == SPEED_100)
+ {
+ DEBUGPRINT(DIAG, ( "Setting Boazman PHY into loopback at 100 Mbps\n"));
+ /* set 21_2.2:0 to the relevant speed (1G ?3b110, 100Mb ?3b101, 10Mb ? 3b100) */
+ _ReadPhyRegister16Ex(hw, 2, 21, &PhyValue);
+ PhyValue = (PhyValue & (~(7))) | 5;
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ( "Setting Boazman PHY into loopback at 10 Mbps\n"));
+ /* set 21_2.2:0 to the relevant speed (1G ?3b110, 100Mb ?3b101, 10Mb ? 3b100) */
+ _ReadPhyRegister16Ex(hw, 2, 21, &PhyValue);
+ PhyValue = (PhyValue & (~(7))) | 4;
+ }
+
+ _WritePhyRegister16Ex(hw, 2, 21, PhyValue);
+
+ /* assert sw reset (so settings will take effect). */
+ e1000_read_phy_reg(hw, PHY_CONTROL, &PhyValue);
+ e1000_write_phy_reg(hw, PHY_CONTROL, PhyValue | (1 << 15));
+ msec_delay(1);
+
+#ifndef NO_82571_SUPPORT
+#ifndef NO_82574_SUPPORT
+ /* ICH9 and ICH10 version requires all these undocumented writes */
+ if (hw->mac.type != e1000_82574
+ || hw->mac.type != e1000_82583
+ )
+ {
+ /* force duplex to FD: 16_769.3:2=3. */
+ _ReadPhyRegister16Ex(hw, 769, 16, &PhyValue);
+ PhyValue |= (3 << 2);
+ _WritePhyRegister16Ex(hw, 769, 16, PhyValue);
+
+ /* set 16_776.6= state (link up when in force link) */
+ _ReadPhyRegister16Ex(hw, 776, 16, &PhyValue);
+ PhyValue |= (1 << 6);
+ _WritePhyRegister16Ex(hw, 776, 16, PhyValue);
+
+ /* set 16_769.6= state (force link) */
+ _ReadPhyRegister16Ex(hw, 769, 16, &PhyValue);
+ PhyValue |= (1 << 6);
+ _WritePhyRegister16Ex(hw, 769, 16, PhyValue);
+
+ /* Set Early Link Enable - 20_769.10 = 1 */
+ _ReadPhyRegister16Ex(hw, 769, 20, &PhyValue);
+ PhyValue |= (1 << 10);
+ _WritePhyRegister16Ex(hw, 769, 20, PhyValue);
+ }
+#endif
+#endif
+
+ LoopbackModeSet = _SetIgpPhyLoopback(hw, Speed);
+
+ return LoopbackModeSet;
+}
+
+
+BOOLEAN
+_SetNinevehPhyLoopback(
+ struct e1000_hw *hw,
+ IN UINT16 Speed
+ )
+/*++
+ Description: This routine is used by diagnostic software to put
+ the Intel Gigabit PHY into loopback mode.
+
+ Loopback speed is determined by the Speed value
+ passed into this routine.
+
+ Valid values are 1000, 100, and 10 Mbps
+
+ Arguments: Adapter - Ptr to this card's adapter data structure
+ Speed - desired loopback speed
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+{
+ UINT32 StatusReg = 0;
+ UINT32 DelayValue = 10;
+ UINT32 DelayMax = 5000;
+ UINT32 i = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ if(Speed == SPEED_1000)
+ {
+ DEBUGPRINT(DIAG, ("Setting Nineveh PHY into loopback at 1000 Mbps\n"));
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ LoopbackModeSet = TRUE;
+ }
+ else if(Speed == SPEED_100)
+ {
+ DEBUGPRINT(DIAG, ( "Setting Nineveh PHY into loopback at 100 Mbps\n"));
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x6100); /* force 100, set loopback */
+ }
+ else
+ {
+ LoopbackModeSet = _SetIgpPhyLoopback(hw, Speed);
+ }
+
+ /* Poll for link to be stable */
+ for(i = 0; i < DelayMax; i += DelayValue)
+ {
+ msec_delay(DelayValue);
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if(StatusReg & (E1000_STATUS_LU | E1000_STATUS_FD))
+ {
+ DEBUGPRINT(DIAG, ("Nineveh link up indication after %d iterations\n", i));
+ if(Speed == SPEED_1000)
+ {
+ if(StatusReg & E1000_STATUS_SPEED_1000)
+ {
+ DEBUGPRINT(DIAG, ("Nineveh 1gb loopback link detected after %d iterations\n", i));
+ break;
+ }
+ }
+ else if(Speed == SPEED_100)
+ {
+ if(StatusReg & E1000_STATUS_SPEED_100)
+ {
+ DEBUGPRINT(DIAG, ("Nineveh 100mbit loopback link detected after %d iterations\n", i));
+ break;
+ }
+ }
+
+ /* Don't bother reading the status register data for 10mbit. We force this up in
+ * _SetIgpPhyLoopback */
+ else
+ {
+ DEBUGPRINT(DIAG, ("Nineveh 10mbit loopback link detected after %d iterations\n", i));
+ break;
+ }
+ }
+ }
+
+ return LoopbackModeSet;
+}
+
+
+BOOLEAN
+_SetIgpPhyLoopback(
+ IN struct e1000_hw *hw,
+ IN UINT16 Speed
+ )
+/*++
+ Description: This routine is used by diagnostic software to put
+ the Intel Gigabit PHY into loopback mode.
+
+ Loopback speed is determined by the Speed value
+ passed into this routine.
+
+ Valid values are 1000, 100, and 10 Mbps
+
+ Arguments: Adapter - Ptr to this card's adapter data structure
+ Speed - desired loopback speed
+
+ Returns: TRUE - Success, FALSE - Failure
+--*/
+{
+ UINT32 CtrlReg = 0;
+ UINT32 StatusReg = 0;
+ UINT16 PhyReg = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ hw->mac.autoneg = FALSE;
+
+ /*******************************************************************
+ ** Set up desired loopback speed and duplex depending on input
+ ** into this function.
+ *******************************************************************/
+ switch(Speed)
+ {
+ case SPEED_1000:
+ DEBUGPRINT(DIAG, ("Setting IGP01E1000 PHY into loopback at 1000 Mbps\n"));
+
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* force 1000, set loopback */
+ msec_delay(250);
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_100:
+ DEBUGPRINT(DIAG, ("Setting IGP01E1000 PHY into loopback at 100 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x6100); /* force 100, set loopback */
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 | /* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is */
+ /* detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ case SPEED_10:
+ DEBUGPRINT(DIAG, ("Setting IGP01E1000 PHY into loopback at 10 Mbps\n"));
+ /****************************************************************
+ ** Set up the MII control reg to the desired loopback speed.
+ ****************************************************************/
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4100); /* force 10, set loopback */
+ /* For 10mbps loopback we need to assert the "Force link pass" bit in
+ the Port Configuration register */
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &PhyReg);
+ PhyReg |= 0x4000;
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, PhyReg);
+
+ /****************************************************************
+ ** Now set up the MAC to the same speed/duplex as the PHY.
+ ****************************************************************/
+ CtrlReg = E1000_READ_REG(hw, E1000_CTRL);
+ CtrlReg &= ~E1000_CTRL_SPD_SEL; /* Clear the Speed selection bits */
+ CtrlReg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_10 | /* Force Speed to 10 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ {
+ /* Set the ILOS bits on the fiber nic if half duplex link is */
+ /* detected. */
+ StatusReg = E1000_READ_REG(hw, E1000_STATUS);
+ if((StatusReg & E1000_STATUS_FD) == 0)
+ {
+ CtrlReg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); /* Invert Loss-Of-Signal */
+ }
+ }
+
+ E1000_WRITE_REG (hw, E1000_CTRL, CtrlReg);
+ LoopbackModeSet = TRUE;
+ break;
+
+ default:
+ DEBUGPRINT(DIAG, ("Invalid speed value loopback mode \"%d\"\n", Speed));
+ LoopbackModeSet = FALSE;
+ break;
+ }
+
+ usec_delay(500);
+ return LoopbackModeSet;
+}
+
+BOOLEAN
+_SetPhyLoopback82580 (
+ struct e1000_hw *hw
+ )
+{
+ UINT32 Reg;
+ UINT16 PhyReg = 0;
+ BOOLEAN LoopbackModeSet = FALSE;
+
+ DEBUGPRINT(DIAG, ("_SetPhyLoopback82580\n"));
+
+ /* Set Link Mode to Internal */
+ Reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ DEBUGPRINT(DIAG, ("_SetPhyLoopback82580: E1000_CTRL_EXT = 0x%x\n", Reg));
+ Reg = (~E1000_CTRL_EXT_LINK_MODE_MASK) & Reg;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, Reg);
+
+ /* Disable PHY power management in case the cable is unplugged and the PHY is asleep */
+ DEBUGPRINT(DIAG, ("PHPM = %08x\n", E1000_READ_REG(hw, 0x0E14)));
+ Reg = E1000_READ_REG(hw, 0x0E14);
+ Reg &= ~0x0005; /* SPD_EN and LPLU */
+ E1000_WRITE_REG(hw, 0x0E14, Reg);
+
+ /* Set 1000 Mbps loopback mode in PHY */
+ e1000_write_phy_reg(hw, PHY_CONTROL, 0x4140);
+
+ /* Set 1000 Mbps mode in MAC */
+ Reg = E1000_READ_REG(hw, E1000_CTRL);
+ Reg &= ~E1000_CTRL_SPD_SEL; // Clear the Speed selection bits
+ Reg |= (E1000_CTRL_FRCSPD | // Set the Force Speed Bit
+ E1000_CTRL_FRCDPX | // Set the Force Duplex Bit
+ E1000_CTRL_SPD_1000 | // Force Speed to 1000
+ E1000_CTRL_FD); // Force Duplex to FULL
+ E1000_WRITE_REG (hw, E1000_CTRL, Reg);
+
+
+ /* Enable PHY loopback mode */
+ e1000_read_phy_reg(hw, PHY_PHLBKC, &PhyReg);
+ DEBUGPRINT(DIAG, ("PHY_PHLBKC = %04x\n", PhyReg));
+ PhyReg = 0x8001; /* MII and Force Link Status */
+ e1000_write_phy_reg(hw, PHY_PHLBKC, PhyReg);
+
+ e1000_read_phy_reg(hw, PHY_PHCTRL1, &PhyReg);
+ DEBUGPRINT(DIAG, ("PHY_PHCTRL1 = %04x\n", PhyReg));
+ PhyReg |= 0x2000; /* LNK_EN */
+ e1000_write_phy_reg(hw, PHY_PHCTRL1, PhyReg);
+
+ msec_delay(500);
+
+ LoopbackModeSet = TRUE;
+ return LoopbackModeSet;
+}
+
+BOOLEAN
+e1000_set_phy_loopback (
+ struct e1000_hw *hw,
+ UINT16 speed
+ )
+/*++
+
+Routine Description:
+
+ Set the PHY into loopback mode. This routine integrates any errata workarounds that might exist.
+
+Arguments:
+
+ hw - Pointer to the shared code adapter structure
+ speed - Select speed to perform loopback test
+
+Returns:
+ True if PHY has been configured for loopback mode
+ False otherwise
+
+--*/
+{
+ BOOLEANean_t status;
+
+ DEBUGPRINT(DIAG, ("e1000_set_phy_loopback\n"));
+
+ switch (hw->mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82573:
+ DEBUGPRINT(DIAG, ("Enabling M88E1000 loopback mode.\n"));
+ status = _SetIntegratedM88PhyLoopback (hw, speed);
+ break;
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+ DEBUGPRINT(DIAG, ("Enabling M88E1000 loopback mode.\n"));
+ status = _SetIntegratedM88PhyLoopback (hw, speed);
+ break;
+#endif
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ case e1000_82572:
+ /* I82571 sets a special loopback mode through the SERDES register. This is only for Fiber
+ * adapters and is used because MAC and PHY loopback are broken on these adapters */
+ if(hw->phy.media_type != e1000_media_type_copper)
+ {
+ _SetI82571SerdesLoopback(hw);
+ status = TRUE;
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ("I82571: Enabling IGP01E100 loopback mode.\n"));
+ status = _SetIgpPhyLoopback (hw, speed);
+ }
+ break;
+#endif
+
+#ifndef NO_82571_SUPPORT
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ DEBUGPRINT(DIAG, ("Enabling Boazman for 82574, 82583 loopback mode.\n"));
+ status = _SetBoazmanPhyLoopback(hw, speed);
+ break;
+#endif
+#endif
+
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich9lan:
+ DEBUGPRINT(DIAG, ("Enabling Boazman for ICH9 loopback mode.\n"));
+ status = _SetBoazmanPhyLoopback(hw, speed);
+ break;
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ DEBUGPRINT(DIAG, ("Enabling Hanksville for PCH loopback mode.\n"));
+ status = _SetBoazmanPhyLoopback(hw, speed);
+ break;
+#endif
+
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+ if(hw->phy.media_type != e1000_media_type_copper)
+ {
+ _SetI82575SerdesLoopback(hw);
+ status = TRUE;
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ("Enabling 82575, 82576 loopback\n"));
+ status = _SetNinevehPhyLoopback (hw, speed);
+ }
+ break;
+#endif
+#ifndef NO_82576_SUPPORT
+ case e1000_82576:
+#endif
+ case e1000_82580:
+ if(hw->phy.media_type == e1000_media_type_copper && hw->dev_spec._82575.sgmii_active == FALSE)
+ {
+ DEBUGPRINT(DIAG, ("Enabling 82580 loopback for copper\n"));
+ status = _SetPhyLoopback82580(hw);
+ }
+ else
+ {
+ DEBUGPRINT(DIAG, ("Enabling 82580 loopback for SerDes/SGMII/1000BASE-KX\n"));
+ _SetI82580SerdesLoopback(hw);
+ status = TRUE;
+ }
+ break;
+
+ default:
+ DEBUGPRINT(DIAG, ("Unknown MAC type.\n"));
+ DEBUGWAIT(DIAG);
+ status = FALSE;
+ break;
+ }
+
+
+ return status;
+}
+
+EFI_STATUS
+GigUndiRunPhyLoopback (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ PXE_CPB_TRANSMIT PxeCpbTransmit
+ )
+/*++
+
+Routine Description:
+ Run the PHY loopback test for N iterations. This routine transmits a packet, waits a bit, and then
+ checks to see if it was received. If any of the packets are not received then it will be interpreted as
+ a failure.
+
+Arguments:
+ GigAdapterInfo - Pointer to the NIC data structure the PHY loopback test will be run on.
+ PxeCpbTransmit - Pointer to the packet to transmit.
+
+Returns:
+ EFI_SUCCESS - All packets were received successfully
+ other - An error occured.
+
+--*/
+{
+ PXE_CPB_RECEIVE CpbReceive;
+ PXE_DB_RECEIVE DbReceive;
+ EFI_STATUS Status;
+ UINT64 FreeTxBuffer[DEFAULT_TX_DESCRIPTORS];
+ UINT32 j;
+ UINT32 i;
+
+ Status = EFI_SUCCESS;
+ j = 0;
+
+ while (j < PHY_LOOPBACK_ITERATIONS) {
+ Status = e1000_Transmit (
+ GigAdapterInfo,
+ (UINT64) &PxeCpbTransmit,
+ PXE_OPFLAGS_TRANSMIT_WHOLE
+ );
+ _DisplayBuffersAndDescriptors (GigAdapterInfo);
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("e1000_Transmit error Status %X. Iteration=%d\n", Status, j));
+ DEBUGWAIT (CRITICAL);
+ break;
+ }
+
+ //
+ // Wait a little, then check to see if the packet has arrived
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ RX_BUFFER_SIZE,
+ (VOID **) &CpbReceive.BufferAddr
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("AllocatePool error Status %X. Iteration=%d\n", Status, j));
+ DEBUGWAIT (CRITICAL);
+ break;
+ }
+
+ CpbReceive.BufferLen = RX_BUFFER_SIZE;
+ i = 0;
+ do {
+ Status = e1000_Receive (
+ GigAdapterInfo,
+ (UINT64) &CpbReceive,
+ (UINT64) &DbReceive
+ );
+ gBS->Stall (10);
+ i++;
+ if (i > 100000) {
+ DEBUGPRINT(CRITICAL, ("ERROR: No receive data timeout! Iteration=%d\n", i));
+ break;
+ }
+ } while (Status == PXE_STATCODE_NO_DATA);
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("e1000_Receive Status %X\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ if (CompareMem ((VOID *) (UINTN) CpbReceive.BufferAddr, (VOID *) (UINTN) Packet, TEST_PACKET_SIZE) == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUGPRINT (CRITICAL, ("PHY LOOPBACK FAILED, Corrupt Packet Data!\n"));
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ e1000_FreeTxBuffers (
+ GigAdapterInfo,
+ DEFAULT_TX_DESCRIPTORS,
+ FreeTxBuffer
+ );
+
+ j++;
+ gBS->FreePool ((VOID *) ((UINTN) CpbReceive.BufferAddr));
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+GigUndiPhyLoopback (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Sets up the adapter to run the Phy loopback test and then calls
+ the loop which will iterate through the test.
+
+ Arguments: GigUndiPrivateData - Pointer to adapter data.
+
+ Returns:
+ EFI_SUCCESS - The Phy loopback test passed.
+ EFI_DEVICE_ERROR - Phy loopback test failed
+ EFI_INVALID_PARAMETER - Some other error occured.
+--*/
+{
+ PXE_CPB_TRANSMIT PxeCpbTransmit;
+ UINT8 ReceiveStarted;
+ EFI_STATUS Status;
+
+ ReceiveStarted = GigUndiPrivateData->NicInfo.ReceiveStarted;
+ GigUndiPrivateData->NicInfo.DriverBusy = TRUE;
+
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.Block %X\n", (UINTN) GigUndiPrivateData->NicInfo.Block));
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.MapMem %X\n", (UINTN) GigUndiPrivateData->NicInfo.MapMem));
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.Delay %X\n", (UINTN) GigUndiPrivateData->NicInfo.Delay));
+ DEBUGPRINT (DIAG, ("GigUndiPrivateData->NicInfo.MemIo %X\n", (UINTN) GigUndiPrivateData->NicInfo.MemIo));
+ DEBUGWAIT (DIAG);
+
+ //
+ // Initialize and start the UNDI driver if it has not already been done
+ //
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (e1000_Inititialize (&GigUndiPrivateData->NicInfo) != PXE_STATCODE_SUCCESS) {
+ DEBUGPRINT (CRITICAL, ("Error initializing adapter!\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto error;
+ }
+
+ //
+ // Put the PHY into loopback mode,
+ //
+ if (e1000_set_phy_loopback (&GigUndiPrivateData->NicInfo.hw, SPEED_1000)) {
+ DEBUGPRINT (DIAG, ("PHY loopback mode set successful\n"));
+ } else {
+ DEBUGPRINT (CRITICAL, ("ERROR: PHY loopback not set!\n"));
+ DEBUGWAIT (CRITICAL);
+ Status = EFI_UNSUPPORTED;
+ goto error;
+ }
+
+ DEBUGWAIT (DIAG);
+
+ //
+ // Enable the receive unit
+ //
+ e1000_ReceiveEnable (&GigUndiPrivateData->NicInfo);
+
+ //
+ // Build our packet, and send it out the door.
+ //
+ DEBUGPRINT (DIAG, ("Building Packet\n"));
+ _BuildPacket (&GigUndiPrivateData->NicInfo);
+
+ PxeCpbTransmit.MediaheaderLen = sizeof (ETHERNET_HDR);
+ PxeCpbTransmit.DataLen = TEST_PACKET_SIZE - sizeof (ETHERNET_HDR);
+ PxeCpbTransmit.FrameAddr = (UINTN) Packet;
+ PxeCpbTransmit.reserved = 0;
+ DEBUGPRINT (DIAG, ("Packet length = %d\n", PxeCpbTransmit.DataLen));
+ DEBUGPRINT (DIAG, ("Packet = %X FrameAddr = %X\n", (UINTN) Packet, PxeCpbTransmit.FrameAddr));
+ DEBUGPRINT (DIAG, ("Packet data:\n"));
+// for (i = 0; i < PxeCpbTransmit.DataLen; i++) {
+// DEBUGPRINT (DIAG, ("%d: %x ", i, ((UINT8 *) ((UINTN) PxeCpbTransmit.FrameAddr))[i]));
+// }
+
+ DEBUGWAIT (DIAG);
+
+ Status = GigUndiRunPhyLoopback (&GigUndiPrivateData->NicInfo, PxeCpbTransmit);
+ DEBUGPRINT (DIAG, ("PHY Loopback test returns %r\n", Status));
+
+ e1000_ReceiveDisable(&GigUndiPrivateData->NicInfo);
+
+ DEBUGWAIT (DIAG);
+
+error:
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("Error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ //
+ // After PHY loopback test completes we need to perform a full reset of the adapter.
+ // If the adapter was initialized on entry then force a full reset of the adapter.
+ // Also reenable the receive unit if it was enabled before we started the PHY loopback test.
+ //
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (GigUndiPrivateData->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigUndiPrivateData->NicInfo);
+ DEBUGPRINT(DIAG, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(DIAG, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigUndiPrivateData->NicInfo);
+ }
+ }
+ DEBUGPRINT(DIAG, ("ADAPTER RESET COMPLETE\n"));
+
+ GigUndiPrivateData->NicInfo.DriverBusy = FALSE;
+
+ return Status;
+}
+
+EFI_STATUS
+GigUndiDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ )
+/*++
+
+ Routine Description:
+ Runs diagnostics on a controller.
+
+ Arguments:
+ This - A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL instance.
+ ControllerHandle - The handle of the controller to run diagnostics on.
+ ChildHandle - The handle of the child controller to run diagnostics on
+ This is an optional parameter that may be NULL. It will
+ be NULL for device drivers. It will also be NULL for a
+ bus drivers that wish to run diagnostics on the bus
+ controller. It will not be NULL for a bus driver that
+ wishes to run diagnostics on one of its child controllers.
+ DiagnosticType - Indicates type of diagnostics to perform on the controller
+ specified by ControllerHandle and ChildHandle. See
+ "Related Definitions" for the list of supported types.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language in which the optional
+ error message should be returned in Buffer, and it must
+ match one of the languages specified in SupportedLanguages.
+ The number of languages supported by a driver is up to
+ the driver writer.
+ ErrorType - A GUID that defines the format of the data returned in
+ Buffer.
+ BufferSize - The size, in bytes, of the data returned in Buffer.
+ Buffer - A buffer that contains a Null-terminated Unicode string
+ plus some additional data whose format is defined by
+ ErrorType. Buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility
+ to free it with a call to FreePool().
+
+ Returns:
+ EFI_SUCCESS - The controller specified by ControllerHandle and
+ ChildHandle passed the diagnostic.
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - ErrorType is NULL.
+ EFI_INVALID_PARAMETER - BufferType is NULL.
+ EFI_INVALID_PARAMETER - Buffer is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support
+ running diagnostics for the controller specified
+ by ControllerHandle and ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ type of diagnostic specified by DiagnosticType.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+ EFI_OUT_OF_RESOURCES - There are not enough resources available to complete
+ the diagnostics.
+ EFI_OUT_OF_RESOURCES - There are not enough resources available to return
+ the status information in ErrorType, BufferSize,
+ and Buffer.
+ EFI_DEVICE_ERROR - The controller specified by ControllerHandle and
+ ChildHandle did not pass the diagnostic.
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ GigUndiPrivateData = NULL;
+
+ if (DiagnosticType == EfiDriverDiagnosticTypeManufacturing) {
+ DEBUGPRINT (CRITICAL, ("DiagnosticType == EfiDriverDiagnosticTypeManufacturing\n"));
+ DEBUGWAIT (CRITICAL);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ DEBUGPRINT (DIAG, (" OpenProtocol Status = %8X\n", Status));
+
+ if (Status != EFI_ALREADY_STARTED) {
+ DEBUGPRINT (CRITICAL, ("EFI_ALREADY_STARTED\n"));
+ DEBUGWAIT (CRITICAL);
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (DIAG, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("OpenProtocol error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+
+ switch (DiagnosticType) {
+ case EfiDriverDiagnosticTypeStandard:
+ if (e1000_validate_nvm_checksum(&GigUndiPrivateData->NicInfo.hw) == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUGPRINT (CRITICAL, ("e1000_validate_nvm_checksum error!\n"));
+ DEBUGWAIT (CRITICAL);
+ Status = EFI_DEVICE_ERROR;
+ }
+ break;
+ case EfiDriverDiagnosticTypeExtended:
+ Status = GigUndiPhyLoopback(GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("GigUndiPhyLoopback error Status %X\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+ break;
+ default:
+ DEBUGPRINT (CRITICAL, ("DiagnosticType unsupported!\n"));
+ DEBUGWAIT (CRITICAL);
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c
new file mode 100755
index 0000000..a22b183
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.c
@@ -0,0 +1,1126 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "FirmwareManagement.h"
+
+EFI_STATUS
+GetImageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ );
+
+EFI_STATUS
+FrmGetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ );
+
+EFI_STATUS
+SetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ );
+
+EFI_STATUS
+CheckImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ );
+
+EFI_STATUS
+GetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ );
+
+EFI_STATUS
+SetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ );
+
+EFI_GUID gEfiFirmwareManagementProtocolGuid = EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
+
+#define HAF_ROM_PCI_DATA_STRUCT_SIG "PCIR"
+
+#pragma pack(1)
+typedef struct {
+ UINT8 PciSignature[4]; /* PCIR */
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 VpdOffset; /* Pointer to optional Vital Product Data */
+ UINT16 DataStructLength;
+ UINT8 DataStructRev;
+ UINT8 ClassCode[3];
+ UINT16 ImageLength;
+ UINT16 CodeRevision;
+ UINT8 CodeType;
+ UINT8 IndicatorByte;
+ UINT16 Reserved;
+} PCI_ROM_STRUCTURE;
+
+#pragma pack(1)
+typedef struct {
+ UINT16 Signature; /* 0xAA55 */
+ UINT16 InitializationSize; /* Overall Size of Image */
+ UINT32 EfiSignature; /* EF1 */
+ UINT16 EfiSubsystem;
+ UINT16 EfiMachineType;
+ UINT16 CompressionType;
+ UINT8 Reserved[8];
+ UINT16 ImageHeaderOffset;
+ UINT16 PciOffset; /* Pointer to the PCI ROM Data Structure */
+ UINT8 Padding[2];
+} EFI_ROM_HEADER;
+
+#pragma pack(1)
+typedef struct _CLP_ROM_HEADER
+{
+ UINT16 Signature;
+ UINT8 InitializationSize;
+ UINT8 Entry[4];
+ UINT8 Checksum;
+ UINT8 RomSignature[4];
+ UINT8 LomBit;
+ UINT8 reserved1;
+ UINT32 pxe_offset;
+ UINT8 pxe_size;
+ UINT32 iscsi_offset;
+ UINT8 iscsi_size;
+ UINT16 PciDsOffset;
+ UINT16 PnpOffset;
+ UINT16 reserved2;
+ UINT16 VersionOffset;
+} CLP_ROM_HEADER;
+
+#pragma pack(1)
+typedef struct _PXE_ROM_HEADER
+{
+ UINT16 Signature;
+ UINT8 InitializationSize;
+ UINT8 Entry[4];
+ UINT8 Checksum;
+ UINT16 VendorOffset;
+ UINT8 reserved[12];
+ UINT16 RomIdOffset;
+ UINT16 PciDsOffset;
+ UINT16 PnpOffset;
+ UINT16 RplOffset;
+ UINT16 VersionOffset;
+} PXE_ROM_HEADER;
+
+#pragma pack(1)
+typedef struct _FLB_HEADER
+{
+ UINT32 FlbTag;
+ UINT8 Length;
+ UINT8 Checksum;
+ UINT32 ImageSize;
+ UINT16 PciVendor;
+ UINT16 PciDevice[16];
+ UINT8 FileName[14];
+ UINT8 MajVersion;
+ UINT8 MinVersion;
+ UINT8 BldNumber;
+ UINT8 ImageType;
+} FLB_HEADER;
+
+#pragma pack(1)
+typedef struct _PNP_ROM_HEADER
+{
+ UINT8 PnpSignature[4];
+ UINT8 StructRev;
+ UINT8 StructLength;
+ UINT16 NextStruct;
+ UINT8 reserved1;
+ UINT8 StructCksum;
+ UINT32 DeviceID;
+ UINT16 MFGString;
+ UINT16 ProdString;
+ UINT8 BaseClass;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 DevInd;
+ UINT16 BC;
+ UINT16 DV;
+ UINT16 BEV;
+ UINT8 reserved2[2];
+ UINT16 SRIV;
+} PNP_ROM_HEADER;
+#pragma pack()
+
+
+#pragma pack()
+
+#define FLB_TAG 0x21424C46
+#define CLP_SIG "$CLP"
+#define PXE_ROM_SIG "!PXE"
+#define UNDI_ROMID_SIG "UNDI"
+#define EFI_ROM_SIG 0x0EF1
+#define PCI_DATA_STRUCT_SIG "PCIR"
+
+
+#define PCI_ROM_BLOCK_SIZE 512
+#define PCI_ROM_LAST_INDICATOR 0x80
+
+
+//
+// Macro to return the offset of a member within a struct. This
+// looks like it dereferences a null pointer, but it doesn't really.
+//
+#define STRUCT_OFFSET(Structure,Member) ((UINTN)&(((Structure *)0)->Member))
+
+
+
+EFI_STATUS
+GetImageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ )
+/*++
+
+ Routine Description:
+ Returns information about the current firmware image(s) of the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageInfoSize - A pointer to the size, in bytes, of the ImageInfo buffer.
+ ImageInfo - A pointer to the buffer in which firmware places the current image(s) information.
+ DescriptorVersion - A pointer to the location in which firmware returns the version number
+ associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ DescriptorCount - A pointer to the location in which firmware returns the number of descriptors or
+ firmware images within this device.
+ DescriptorSize - A pointer to the location in which firmware returns the size, in bytes,
+ of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+ Returns:
+ EFI Status code.
+
+--*/
+
+{
+ DEBUGPRINT (IMAGE, ("GetImageInfo\n"));
+
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+FrmGetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ )
+/*++
+
+ Routine Description:
+ Retrieves a copy of the firmware image from the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageIndex - A unique number identifying the firmware image(s) within the device.
+ Image - Points to the buffer where the current image is copied to.
+ ImageSize - On entry, points to the size of the buffer pointed to by
+ Image, in bytes. On return, points to the length of the image, in bytes.
+
+ Returns:
+ EFI Status code.
+
+--*/
+{
+ DEBUGPRINT (IMAGE, ("FrmGetImage\n"));
+
+ return EFI_UNSUPPORTED;
+}
+
+BOOLEAN
+_VerifyImageSize (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINTN ImageSize
+ )
+/*++
+
+ Routine Description:
+ Verifies image will fit in device flash.
+
+ Arguments:
+ GigUndiPrivateData - Pointer to adapter structure
+ ImageSize - Size of image to flash to adapter
+
+ Returns:
+ TRUE - image will fit on flash
+ FALSE - Image is too big
+
+--*/
+{
+ UINT16 Word;
+ UINTN FlashSize;
+
+ e1000_read_nvm (&GigUndiPrivateData->NicInfo.hw, INIT_CONTROL_WORD_2, 1, &Word);
+ DEBUGPRINT (IMAGE, ("INIT_CONTROL_WORD_2 %x\n", Word));
+
+ //
+ // Calculate flash size in bytes
+ //
+ FlashSize = (Word & FLASH_SIZE_MASK) >> FLASH_SIZE_SHIFT;
+ DEBUGPRINT (IMAGE, ("FlashSize bitmask = %x\n", FlashSize));
+ FlashSize = (64 * 1024) << FlashSize;
+ DEBUGPRINT (IMAGE, ("Usable FlashSize in bytes %d\n", FlashSize));
+
+ if (FlashSize < ImageSize) {
+ DEBUGPRINT (CRITICAL, ("ERROR: Flash size too small. ImageSize=%d > FlashSize=%d\n", ImageSize, FlashSize));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOLEAN
+_CheckFlashImageSupport (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINT8 *Image,
+ IN UINTN ImageSize,
+ OUT UINT8 **ImageToProgram,
+ OUT UINTN *SizeToProgram
+ )
+/*++
+
+ Routine Description:
+ Checks that the FLB image has support for this device ID, and makes sure the
+ image type is the same as what is currently programmed on the adapter.
+
+ Arguments:
+ GigUndiPrivateData - Pointer to adapter structure
+ Image - Pointer to the image to program
+ ImageSize - Size of image to flash to adapter
+ ImageToProgram - Returned pointer to the image to program to the flash
+ SizeToProgram - Size of the image contained in the FLB to program
+
+ Returns:
+ TRUE - Image is compatible with device
+ FALSE - Image is not compatible
+
+--*/
+{
+ EFI_ROM_HEADER *EfiRomHeader;
+ CLP_ROM_HEADER *ClpRomHeader;
+ FLB_HEADER *FlbHeader;
+ PXE_ROM_HEADER *PxeRomHeader;
+ PCI_ROM_STRUCTURE *PciRomStructure;
+ UINTN i;
+ UINTN Offset;
+ UINT16 ImageType;
+ UINT16 EepromCapabilities;
+
+ Offset = 0;
+ ImageType = 0;
+
+ do {
+ //
+ // Check the FLB header to make sure this it supports this device
+ //
+ FlbHeader = (FLB_HEADER*) &Image[Offset];
+ if (FlbHeader->FlbTag != FLB_TAG) {
+ DEBUGPRINT (CRITICAL, ("ERROR: Invalid FLB tag.\n"));
+ return FALSE;
+ }
+
+
+ DEBUGPRINT (IMAGE, ("FLB Device ID list: "));
+ for (i = 0; i < 16; i++) {
+ DEBUGPRINT (IMAGE, ("%04x ", FlbHeader->PciDevice[i]));
+ if (FlbHeader->PciDevice[i] == GigUndiPrivateData->NicInfo.hw.device_id) {
+ DEBUGPRINT (IMAGE, ("\nFound FLB device ID match: %04x\n", FlbHeader->PciDevice[i]));
+ goto ImageFound;
+ }
+ }
+
+ if (i == 16) {
+ DEBUGPRINT (CRITICAL, ("\nERROR: FLB does not support device\n"));
+ }
+
+ //
+ // Check for concatenated FLB image
+ //
+ Offset += FlbHeader->ImageSize + sizeof (FLB_HEADER);
+ DEBUGPRINT (IMAGE, ("Checking for next FLB header. Curent FLB image size: %d\n", FlbHeader->ImageSize));
+ if ((Offset + sizeof (FLB_HEADER)) >= ImageSize) {
+ DEBUGPRINT (IMAGE, ("No concatenated FLB header, bailing.\n"));
+ return FALSE;
+ }
+ }while (1);
+
+ImageFound:
+ Offset += sizeof(FLB_HEADER);
+ *ImageToProgram = &Image[Offset];
+ *SizeToProgram = FlbHeader->ImageSize;
+
+ do {
+
+ //
+ // Check if this is a SMCLP header
+ //
+ ClpRomHeader = (CLP_ROM_HEADER*) &Image[Offset];
+ DEBUGPRINT (IMAGE, ("Offset = %d\n", Offset));
+
+ if (ClpRomHeader->Signature != 0xAA55) {
+ DEBUGPRINT (CRITICAL, ("Invalid PCI option ROM signature: %04x\n", ClpRomHeader->Signature));
+ return FALSE;
+ }
+
+ if (CompareMem(ClpRomHeader->RomSignature, CLP_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found CLP header\n"));
+ ImageType |= EEPROM_SMCLP_BIT;
+
+ if (ClpRomHeader->pxe_offset != 0) {
+ DEBUGPRINT(IMAGE, ("Found PXE image\n"));
+ ImageType |= EEPROM_PXE_BIT;
+ }
+
+ if (ClpRomHeader->iscsi_offset != 0) {
+ DEBUGPRINT(IMAGE, ("Found iSCSI image"));
+ ImageType |= EEPROM_ISCSI_BIT;
+ }
+ }
+
+ //
+ // Check if this is a PXE header
+ //
+ PxeRomHeader = (PXE_ROM_HEADER*) &Image[Offset];
+ if (CompareMem((VOID*) &Image[Offset + PxeRomHeader->RomIdOffset], UNDI_ROMID_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found PXE header\n"));
+ ImageType |= EEPROM_PXE_BIT;
+ }
+
+ //
+ // Check if this is a EFI header
+ //
+ EfiRomHeader = (EFI_ROM_HEADER*) &Image[Offset];
+ if (EfiRomHeader->EfiSignature == EFI_ROM_SIG) {
+ DEBUGPRINT(IMAGE, ("Found EFI image\n"));
+ ImageType |= EEPROM_EFI_BIT;
+ }
+
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &Image[Offset + EfiRomHeader->PciOffset];
+ if (CompareMem(PciRomStructure->PciSignature, PCI_DATA_STRUCT_SIG, 4) != 0) {
+ DEBUGPRINT(CRITICAL, ("Invalid PCI ROM Structure.\n"));
+ return FALSE;
+ }
+
+ if ((PciRomStructure->IndicatorByte & PCI_ROM_LAST_INDICATOR) == PCI_ROM_LAST_INDICATOR) {
+ DEBUGPRINT(IMAGE, ("PCI last image indicator byte set.\n"));
+ break;
+ }
+
+ Offset += (PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE);
+ } while (1);
+
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, EEPROM_CAPABILITIES_WORD, 1, &EepromCapabilities);
+ DEBUGPRINT(IMAGE, ("EepromCapabilities = %04x, ImageType = %04x\n", EepromCapabilities, ImageType));
+ if ((ImageType & EEPROM_TYPE_MASK) == (EepromCapabilities & EEPROM_TYPE_MASK)) {
+ DEBUGPRINT(IMAGE, ("Imagetypes match!\n"));
+ return TRUE;
+ }
+ DEBUGPRINT(CRITICAL, ("FLB image type different from image programmed to card!\n"));
+ return FALSE;
+}
+
+VOID
+_UpdateFlashFwChecksumRom(
+ IN UINT8* Buffer,
+ IN UINT32 Len,
+ IN UINT32 Offset
+ )
+/*++
+
+ Routine Description:
+ Calculates a checksum for a image
+
+ Arguments:
+ Buffer - image to checksum
+ Len - length of image
+ Offset - location to put the checksum
+
+ Returns:
+ VOID
+
+--*/
+{
+ UINT8 *MyBuffer;
+ UINT16 Sum = 0;
+ UINT32 Count = 0;
+
+ if (Buffer == NULL)
+ {
+ return;
+ }
+
+ MyBuffer = (UINT8*) Buffer;
+
+ //
+ // first, clear anything in the checksum field
+ //
+ MyBuffer[Offset] = 0;
+
+ //
+ // add it up
+ //
+ for (Count = 0; Count < Len; Count++)
+ {
+ Sum += MyBuffer[Count];
+ }
+
+ //
+ // stuff it in
+ //
+ MyBuffer[Offset] = 0 - (UINT8)(Sum & 0xFF);
+}
+
+
+VOID
+_UpdateFlashFwChecksumPnP(
+ IN UINT8* Buffer
+ )
+/*++
+
+ Routine Description:
+ Updates the checksum and PNP header of the image
+
+ Arguments:
+ Buffer - Pointer to the option ROM image to update
+
+ Returns:
+ VOID
+
+--*/
+{
+ PXE_ROM_HEADER* RomHeader;
+ PNP_ROM_HEADER* PnpHeader;
+
+ if (Buffer == NULL)
+ {
+ return;
+ }
+
+ //
+ // The PXE ROM header and CLP ROM header both have the PnPOffset member
+ //
+ RomHeader = (PXE_ROM_HEADER *)Buffer;
+ if (RomHeader->PnpOffset)
+ {
+ DEBUGPRINT (IMAGE, ("Updating PNP checksum\n"));
+ PnpHeader = (PNP_ROM_HEADER *)&Buffer[RomHeader->PnpOffset];
+ _UpdateFlashFwChecksumRom(
+ (UINT8 *)PnpHeader,
+ PnpHeader->StructLength * 16,
+ STRUCT_OFFSET(PNP_ROM_HEADER, StructCksum)
+ );
+ }
+}
+
+BOOLEAN
+_UpdateChecksumAndId(
+ IN OUT UINT8 *ImageBuffer,
+ IN UINTN SizeToProgram,
+ IN UINT16 DeviceId
+ )
+/*++
+
+ Routine Description:
+ Updates the checksum and device ID of the image.
+
+ Arguments:
+ ImageBuffer - Pointer to the option ROM image to update
+ SizeToProgram - Size of image pointed to by ImageBuffer
+ DeviceId - PCI device ID to set in the PCI ROM header
+
+ Returns:
+ TRUE if successful, FALSE if image is invalid
+
+--*/
+{
+ EFI_ROM_HEADER *EfiRomHeader;
+ CLP_ROM_HEADER *ClpRomHeader;
+ PXE_ROM_HEADER *PxeRomHeader;
+ PCI_ROM_STRUCTURE *PciRomStructure;
+ UINTN Offset;
+
+ Offset = 0;
+
+ do {
+
+ //
+ // Check if this is a SMCLP header
+ //
+ ClpRomHeader = (CLP_ROM_HEADER*) &ImageBuffer[Offset];
+ DEBUGPRINT (IMAGE, ("Offset = %d\n", Offset));
+
+ if (ClpRomHeader->Signature != 0xAA55) {
+ DEBUGPRINT (CRITICAL, ("Invalid PCI option ROM signature: %04x\n", ClpRomHeader->Signature));
+ return FALSE;
+ }
+
+ if (CompareMem(ClpRomHeader->RomSignature, CLP_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found CLP header, setting device ID %04x\n", DeviceId));
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + ClpRomHeader->PciDsOffset];
+ PciRomStructure->DeviceId = DeviceId;
+ _UpdateFlashFwChecksumPnP((UINT8*) ClpRomHeader);
+ _UpdateFlashFwChecksumRom(
+ (UINT8*) ClpRomHeader,
+ PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE,
+ STRUCT_OFFSET(CLP_ROM_HEADER, Checksum)
+ );
+ }
+
+ //
+ // Check if this is a PXE header
+ //
+ PxeRomHeader = (PXE_ROM_HEADER*) &ImageBuffer[Offset];
+ if (CompareMem((VOID*) &ImageBuffer[Offset + PxeRomHeader->RomIdOffset], UNDI_ROMID_SIG, 4) == 0) {
+ DEBUGPRINT (IMAGE, ("Found PXE header, setting device ID %04x\n", DeviceId));
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + PxeRomHeader->PciDsOffset];
+ PciRomStructure->DeviceId = DeviceId;
+ _UpdateFlashFwChecksumPnP((UINT8*) PxeRomHeader);
+ _UpdateFlashFwChecksumRom(
+ (UINT8*) PxeRomHeader,
+ PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE,
+ STRUCT_OFFSET(PXE_ROM_HEADER, Checksum)
+ );
+ }
+
+ //
+ // Check if this is a EFI header
+ //
+ EfiRomHeader = (EFI_ROM_HEADER*) &ImageBuffer[Offset];
+ if (EfiRomHeader->EfiSignature == EFI_ROM_SIG) {
+ DEBUGPRINT(IMAGE, ("Found EFI image, setting device ID %04x\n", DeviceId));
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + EfiRomHeader->PciOffset];
+ PciRomStructure->DeviceId = DeviceId;
+ }
+
+ PciRomStructure = (PCI_ROM_STRUCTURE*) &ImageBuffer[Offset + EfiRomHeader->PciOffset];
+ if (CompareMem(PciRomStructure->PciSignature, PCI_DATA_STRUCT_SIG, 4) != 0) {
+ DEBUGPRINT(CRITICAL, ("Invalid PCI ROM Structure.\n"));
+ return FALSE;
+ }
+
+ if ((PciRomStructure->IndicatorByte & PCI_ROM_LAST_INDICATOR) == PCI_ROM_LAST_INDICATOR) {
+ DEBUGPRINT(IMAGE, ("PCI last image indicator byte set.\n"));
+ break;
+ }
+
+ Offset += (PciRomStructure->ImageLength * PCI_ROM_BLOCK_SIZE);
+ } while (1);
+
+ return TRUE;
+
+}
+
+EFI_STATUS
+ProgramFlashImage(
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ UINT8 *ImageBuffer,
+ UINTN SizeToProgram
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIoProtocol;
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Reg;
+ UINTN BarIndex;
+ UINTN FlashOffset;
+ UINTN i;
+ UINT8 Byte;
+
+ PciIoProtocol = GigUndiPrivateData->NicInfo.PciIo;
+
+ //
+ // Clear the FWE bits to enable the flash erase
+ //
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLASHOP);
+ DEBUGPRINT(IMAGE, ("E1000_FLASHOP=%08x\n", Reg));
+
+ DEBUGPRINT (IMAGE, ("ProgramFlashImage: Beginning flash erase\n"));
+ DEBUGWAIT(IMAGE);
+ e1000_ClearRegBits(&GigUndiPrivateData->NicInfo, E1000_EECD, FLASH_WRITE_MASK);
+ gBS->Stall(1);
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD);
+ DEBUGPRINT(IMAGE, ("E1000_EECD=%08x\n", Reg));
+
+ e1000_SetRegBits(&GigUndiPrivateData->NicInfo, E1000_FLA, E1000_FLA_FL_ER);
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ DEBUGPRINT(IMAGE, ("E1000_FLA=%08x\n", Reg));
+ gBS->Stall(1);
+ DEBUGPRINT (IMAGE, ("Wait for flash erase completion\n"));
+
+ i = 0;
+ do {
+ gBS->Stall(1000);
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ i++;
+ if (i > 20000) {
+ DEBUGPRINT (IMAGE, ("Flash erase failed, E1000_FLA=%08x\n", Reg));
+ return EFI_DEVICE_ERROR;
+ }
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+ DEBUGPRINT (IMAGE, ("Flash erase complete\n"));
+
+ //
+ // Enable flash writes
+ //
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD);
+ Reg = (Reg & ~FLASH_WRITE_MASK) | FLASH_WRITE_ENABLE;
+ E1000_WRITE_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD, Reg);
+
+ do {
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+
+ //
+ // Begin writing to the flash.
+ //
+ BarIndex = 1; // On pre-82580 the flash is memory mapped to PCI BAR 1
+ FlashOffset = 0;
+ if (GigUndiPrivateData->NicInfo.hw.mac.type == e1000_82580) {
+ BarIndex = 0; // On 82580 the flash is memory mapped to PCI BAR 0
+ FlashOffset = FLASH_OFFSET_82580;
+ }
+
+ DEBUGPRINT (IMAGE, ("Beginning flash write\n"));
+ //
+ // On 82580 the flash is memory mapped after the devices general register set in BAR 0
+ //
+ for (i = 0; i < SizeToProgram; i++) {
+
+ PciIoProtocol->Mem.Write (
+ PciIoProtocol,
+ EfiPciIoWidthUint8,
+ BarIndex,
+ i + FlashOffset,
+ 1,
+ (VOID *) &ImageBuffer[i]
+ );
+
+ do {
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+
+ PciIoProtocol->Mem.Read (
+ PciIoProtocol,
+ EfiPciIoWidthUint8,
+ BarIndex,
+ i + FlashOffset,
+ 1,
+ (VOID *) &Byte
+ );
+
+ //
+ // If the value read back does not match the value written, erase the flash so we do
+ // not leave a bad image on the card, and return an error.
+ //
+ if (ImageBuffer[i] != Byte) {
+ DEBUGPRINT (CRITICAL, ("Error writing flash at offset %x. Wrote=%02x, Read=%02x\n", i, ImageBuffer[i], Byte));
+ e1000_ClearRegBits(&GigUndiPrivateData->NicInfo, E1000_EECD, FLASH_WRITE_MASK);
+ e1000_SetRegBits(&GigUndiPrivateData->NicInfo, E1000_FLA, E1000_FLA_FL_ER);
+
+ do {
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_FLA);
+ } while ((Reg & E1000_FLA_FL_BUSY) != 0);
+ DEBUGPRINT (CRITICAL, ("Flash erase complete\n"));
+
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ }
+
+ gBS->FreePool(ImageBuffer);
+
+ DEBUGPRINT (IMAGE, ("Flash write complete\n"));
+
+ //
+ // Disable flash writes
+ //
+ Reg = E1000_READ_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD);
+ Reg = (Reg & ~FLASH_WRITE_MASK) | FLASH_WRITE_DISABLE;
+ E1000_WRITE_REG(&GigUndiPrivateData->NicInfo.hw, E1000_EECD, Reg);
+
+ return Status;
+}
+
+
+EFI_STATUS
+SetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ )
+/*++
+
+ Routine Description:
+ Updates the firmware image of the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageIndex - A unique number identifying the firmware image(s) within the device. The number is
+ between 1 and DescriptorCount.
+ Image - Points to the new image.
+ ImageSize - Size of the new image in bytes.
+ VendorCode - This enables vendor to implement vendor-specific firmware image update policy.
+ Progress - A function used by the driver to report the progress of the firmware update.
+ AbortReason - A pointer to a pointer to a null-terminated Unicode string providing more
+ details for the aborted operation. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller�s responsibility to free it with a call to FreePool().
+
+ Returns:
+ EFI Status code.
+
+--*/
+{
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ UINT8 *ImageToProgram;
+ UINTN SizeToProgram;
+ BOOLEAN Supported;
+ UINT8 *ImageBuffer;
+ EFI_STATUS Status;
+
+ ImageToProgram = NULL;
+ SizeToProgram = 0;
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_FIRMWARE_MANAGEMENT(This);
+
+ Supported = _CheckFlashImageSupport (
+ GigUndiPrivateData,
+ (UINT8*) Image,
+ ImageSize,
+ &ImageToProgram,
+ &SizeToProgram
+ );
+
+ if (!Supported) {
+ if (gBS->AllocatePool (EfiBootServicesData, 80, (VOID **) AbortReason) == EFI_SUCCESS) {
+ UnicodeSPrint(*AbortReason, 80, L"ERROR: Incorrect image type for adapter");
+ }
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUGPRINT (IMAGE, ("ImageToProgram = %02X %02X, ImageSize %d\n", ImageToProgram[0], ImageToProgram[1], SizeToProgram));
+
+ //
+ // Verify the image will fit in flash
+ //
+ if (_VerifyImageSize ( GigUndiPrivateData, SizeToProgram) == FALSE) {
+ if (gBS->AllocatePool (EfiBootServicesData, 80, (VOID **) AbortReason) == EFI_SUCCESS) {
+ UnicodeSPrint(*AbortReason, 80, L"ERROR: Image too large for adapter flash");
+ }
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate malleable buffer to copy image into so we can set checksum and device ID
+ // in image headers
+ //
+ Status = gBS->AllocatePool (EfiBootServicesData, ImageSize, (VOID **) &ImageBuffer);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT (CRITICAL, ("AllocatePool failed %r\n", Status));
+ return Status;
+ }
+
+ CopyMem (ImageBuffer, ImageToProgram, SizeToProgram);
+
+ if (_UpdateChecksumAndId(ImageBuffer, SizeToProgram, GigUndiPrivateData->NicInfo.hw.device_id) == FALSE) {
+ DEBUGPRINT (CRITICAL, ("_UpdateChecksumAndId failed.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ProgramFlashImage(GigUndiPrivateData, ImageBuffer, SizeToProgram);
+
+ if (Status == EFI_DEVICE_ERROR) {
+ if ( gBS->AllocatePool (EfiBootServicesData, 80, (VOID **) AbortReason)== EFI_SUCCESS ) {
+ UnicodeSPrint(*AbortReason, 80, (L"ERROR: flash write failed"));
+ }
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+CheckImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ )
+/*++
+
+ Routine Description:
+ Checks if the firmware image is valid for the device.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ ImageIndex - A unique number identifying the firmware image(s) within the device. The number is between 1 and DescriptorCount.
+ Image - Points to the new image.
+ ImageSize - Size of the new image in bytes.
+ ImageUpdatable - Indicates if the new image is valid for update. It also provides, if available, additional information if the
+ image is invalid.
+
+ Returns:
+ EFI Status code.
+
+--*/
+{
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ UINT8 *ImageToProgram;
+ UINTN SizeToProgram;
+ BOOLEAN Supported;
+
+ ImageToProgram = NULL;
+ SizeToProgram = 0;
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_FIRMWARE_MANAGEMENT(This);
+
+ DEBUGPRINT (IMAGE, ("CheckImage\n"));
+
+ Supported = _CheckFlashImageSupport (
+ GigUndiPrivateData,
+ (UINT8*) Image,
+ ImageSize,
+ &ImageToProgram,
+ &SizeToProgram
+ );
+
+ if (!Supported) {
+ DEBUGPRINT (IMAGE, ("Image invalid.\n"));
+ *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUGPRINT (IMAGE, ("Image valid.\n"));
+ *ImageUpdatable = IMAGE_UPDATABLE_VALID;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ )
+/*++
+
+ Routine Description:
+ Returns information about the firmware package.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ PackageVersion - A version number that represents all the firmware images in the device.
+ PackageVersionName - A pointer to a pointer to a null-terminated Unicode string
+ representing the package version name.
+ PackageVersionNameMaxLen - The maximum length of package version name if device supports
+ update of package version name.
+ AttributesSupported - Package attributes that are supported by this device. See �Package
+ Attribute Definitions� for possible returned values of this parameter. A value of 1
+ indicates the attribute is supported and the current setting value is indicated in
+ AttributesSetting.
+ AttributesSetting - Package attributes. See �Package Attribute Definitions� for possible
+ returned values of this parameter.
+
+ Returns:
+ EFI_SUCCESS - The package information was successfully returned.
+ EFI_UNSUPPORTED - The operation is not supported.
+
+--*/
+{
+ DEBUGPRINT (IMAGE, ("GetPackageInfo\n"));
+
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+SetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ )
+/*++
+
+ Routine Description:
+ Updates information about the firmware package.
+
+ Arguments:
+ This - A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ Image - Points to the authentication image. Null if authentication is not required.
+ ImageSize - Size of the authentication image in bytes. 0 if authentication is not required.
+ VendorCode - This enables vendor to implement vendor-specific firmware image update policy.
+ Null indicates the caller did not specify this policy or use the default policy.
+ PackageVersion - The new package version.
+ PackageVersionName - A pointer to the new null-terminated Unicode string representing the
+ package version name. The string length is equal to or less than the value returned in
+ PackageVersionNameMaxLen.
+
+ Returns:
+ EFI_SUCCESS - The device was successfully updated with the new package information
+ EFI_INVALID_PARAMETER - The PackageVersionName length is longer than the value returned
+ in PackageVersionNameMaxLen.
+ EFI_UNSUPPORTED - The operation is not supported.
+ EFI_SECURITY_VIOLATION - The operation could not be performed due to an authentication
+ failure.
+--*/
+{
+ DEBUGPRINT (IMAGE, ("SetPackageInfo\n"));
+
+ return EFI_UNSUPPORTED;
+
+}
+
+EFI_STATUS
+InitFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Installs the Firmware Management protocol on the device handle.
+
+ Arguments:
+ XgbeUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if Firmware Management protocol interface installed
+ correctly, otherwise EFI error code is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT (IMAGE, ("InitFirmwareManagementProtocol\n"));
+
+ GigUndiPrivateData->FirmwareManagement.GetImageInfo = GetImageInfo;
+ GigUndiPrivateData->FirmwareManagement.GetImage = FrmGetImage;
+ GigUndiPrivateData->FirmwareManagement.SetImage = SetImage;
+ GigUndiPrivateData->FirmwareManagement.CheckImage = CheckImage;
+ GigUndiPrivateData->FirmwareManagement.GetPackageInfo = GetPackageInfo;
+ GigUndiPrivateData->FirmwareManagement.SetPackageInfo = SetPackageInfo;
+
+ Status = gBS->InstallProtocolInterface (
+ &GigUndiPrivateData->DeviceHandle,
+ &gEfiFirmwareManagementProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &GigUndiPrivateData->FirmwareManagement
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("InstallProtocolInterface error: %r\n", Status));
+ return Status;
+ }
+ DEBUGPRINT (IMAGE, ("Install Firmware Management Protocol success: %r\n", Status));
+
+ return Status;
+}
+
+
+EFI_STATUS
+UninstallFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Installs the Firmware Management protocol on the device handle.
+
+ Arguments:
+ XgbeUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if Firmware Management protocol interface installed
+ correctly, otherwise EFI error code is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT (IMAGE, ("InitFirmwareManagementProtocol\n"));
+
+ Status = gBS->UninstallProtocolInterface (
+ GigUndiPrivateData->DeviceHandle,
+ &gEfiFirmwareManagementProtocolGuid,
+ &GigUndiPrivateData->FirmwareManagement
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("UninstallProtocolInterface error: %r\n", Status));
+ return Status;
+ }
+ DEBUGPRINT (IMAGE, ("Uninstall Firmware Management Protocol success: %r\n", Status));
+
+ return Status;
+}
+
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h
new file mode 100755
index 0000000..7c9e224
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/FirmwareManagement.h
@@ -0,0 +1,216 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _FRMMGMT_H_
+#define _FRMMGMT_H_
+
+#include "e1000.h"
+
+#define EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID \
+{ 0x86c77a67, 0xb97, 0x4633, { 0xa1, 0x87, 0x49, 0x10, \
+0x4d, 0x6, 0x85, 0xc7 } }
+
+//**************************************************************
+// Image Attribute Definitions
+//**************************************************************
+#define IMAGE_ATTRIBUTE_IMAGE_UPDATABLE 0x0000000000000001
+#define IMAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002
+#define IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004
+#define IMAGE_ATTRIBUTE_IN_USE 0x0000000000000008
+
+//**************************************************************
+// Image Compatibility Definitions
+//**************************************************************
+#define IMAGE_COMPATIBILITY_CHECK_SUPPORTED 0x0000000000000001
+
+//**************************************************************
+// Package Attribute Definitions
+//**************************************************************
+#define PACKAGE_ATTRIBUTE_VERSION_UPDATABLE 0x0000000000000001
+#define PACKAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002
+#define PACKAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004
+
+//**************************************************************
+// ImageUpdatable Definitions
+//**************************************************************
+#define IMAGE_UPDATABLE_VALID 0x0000000000000001
+#define IMAGE_UPDATABLE_INVALID 0x0000000000000002
+#define IMAGE_UPDATABLE_INVALID_TYPE 0x0000000000000004
+#define IMAGE_UPDATABLE_INVALID_OLD 0x0000000000000008
+
+//**************************************************************
+// Descriptor Version
+//**************************************************************
+#define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION 1
+
+#define E1000_FLASHOP 0x103C
+
+//
+// EEC register FLASH commands
+//
+#define FLASH_WRITE_DISABLE 0x0010
+#define FLASH_WRITE_ENABLE 0x0020
+#define FLASH_WRITE_ERASE 0x0000
+#define FLASH_WRITE_MASK 0x0030
+
+//
+// Flash Access Register
+//
+#define E1000_FLA_FL_SCK 0x00000001 /* Serial Flash Clock */
+#define E1000_FLA_FL_CS 0x00000002 /* Serial Flash Chip Select (CS) */
+#define E1000_FLA_FL_SI 0x00000004 /* Serial Flash Serial Data In */
+#define E1000_FLA_FL_SO 0x00000008 /* Serial Flash Serial Data Out */
+#define E1000_FLA_FL_REQ 0x00000010 /* Request flash access */
+#define E1000_FLA_FL_GNT 0x00000020 /* Grant flash access */
+#define E1000_FLA_FL_BUSY 0x40000000 /* Flash busy */
+#define E1000_FLA_FL_ER 0x80000000 /* Flash erase */
+
+//
+// Start of flash memory in memory mapped IO BAR on 82580
+//
+#define FLASH_OFFSET_82580 (128 * 1024)
+
+//**************************************************************
+// Image Attribute � Authentication Required
+//**************************************************************
+//typedef struct {
+// UINT64 MonotonicCount;
+// WIN_CERTIFICATE_UEFI_GUID AuthInfo;
+//} EFI_FIRMWARE_IMAGE_AUTHENTICATION;
+
+//**************************************************************
+// EFI_FIRMWARE_IMAGE_DESCRIPTOR
+//**************************************************************
+typedef struct {
+ UINT8 ImageIndex;
+ EFI_GUID ImageTypeId;
+ UINT64 ImageId;
+ CHAR16 *ImageIdName;
+ UINT32 Version;
+ CHAR16 *VersionName;
+ UINTN Size;
+ UINT64 AttributesSupported;
+ UINT64 AttributesSetting;
+ UINT64 Compatibilities;
+} EFI_FIRMWARE_IMAGE_DESCRIPTOR;
+
+//
+// Anonymous declarations to get the rest of the file to compile
+//
+typedef struct _EFI_FIRMWARE_MANAGEMENT_PROTOCOL EFI_FIRMWARE_MANAGEMENT_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE_INFO) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS) (
+ IN UINTN Completion
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_IMAGE) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_CHECK_IMAGE) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_PACKAGE_INFO) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_PACKAGE_INFO) (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ );
+
+typedef struct _EFI_FIRMWARE_MANAGEMENT_PROTOCOL {
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE_INFO GetImageInfo;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_IMAGE GetImage;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_IMAGE SetImage;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_CHECK_IMAGE CheckImage;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GET_PACKAGE_INFO GetPackageInfo;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_SET_PACKAGE_INFO SetPackageInfo;
+} EFI_FIRMWARE_MANAGEMENT_PROTOCOL;
+
+
+
+#endif /* _FRMMGMT_H_ */
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf
new file mode 100755
index 0000000..8b1ef62
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/LanIntelE1000Dxe.inf
@@ -0,0 +1,99 @@
+#/*++
+#
+# Copyright (c) 2008, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+# Module Name:
+#
+# LanIntelE1000Dxe.inf
+#
+# Abstract:
+#
+# Component description file for Undi module
+#
+#--*/
+
+[defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LanIntelE1000Dxe
+ FILE_GUID = BB801A52-C90F-4EDE-91B2-82520888CBC3
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 0.1
+
+ ENTRY_POINT = InitializeGigUNDIDriver
+
+[sources.common]
+ inventorystrings.uni
+ inventory.vfr
+ brand.h
+ clp.h
+ clp.c
+ ComponentName.c
+ Decode.c
+ DriverConfiguration.c
+ DriverDiagnostics.c
+ e1000.h
+ e1000.c
+ e1000_80003es2lan.h
+ e1000_80003es2lan.c
+ e1000_82571.h
+ e1000_82571.c
+ e1000_82575.h
+ e1000_82575.c
+ e1000_api.h
+ e1000_api.c
+ e1000_defines.h
+ e1000_hw.h
+ e1000_ich8lan.h
+ e1000_ich8lan.c
+ e1000_mac.h
+ e1000_mac.c
+ e1000_manage.h
+ e1000_manage.c
+ e1000_nvm.h
+ e1000_nvm.c
+ e1000_osdep.h
+ e1000_osdep.c
+ e1000_phy.h
+ e1000_phy.c
+ e1000_regs.h
+ FirmwareManagement.h
+ FirmwareManagement.c
+ hii.h
+ hii.c
+ ieee_define.h
+ init.c
+ NVDataStruc.h
+ startstop.h
+ startstop.c
+ vlan.h
+ vlan.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ HiiLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiDriverSupportedEfiVersionProtocolGuid
+ gEfiHiiConfigAccessProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiNetworkInterfaceIdentifierProtocolGuid_31
+ gEfiPciIoProtocolGuid
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h
new file mode 100755
index 0000000..f4964a5
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/NVDataStruc.h
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 2007-2010, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ NVDataStruc.h
+
+Abstract:
+
+ NVData structure used by the sample driver
+
+Revision History:
+
+--*/
+
+#ifndef _NVDATASTRUC_H
+#define _NVDATASTRUC_H
+
+#define E1000_HII_FORM_GUID \
+ { \
+ 0x77f2ea2f, 0x4312, 0x4569, { 0x85, 0xc4, 0x58, 0x3a, 0xcd, 0x8d, 0xb7, 0xe2 } \
+ }
+
+#define E1000_HII_DATA_GUID \
+ { \
+ 0xa31abb16, 0xc627, 0x475b, { 0x98, 0x8e, 0x7e, 0xe0, 0x77, 0x67, 0x40, 0xf3 } \
+ }
+
+#define VAR_EQ_TEST_NAME 0x100
+
+#define FORM_2 0x1235
+
+#define LABEL_START 0x1236
+#define LABEL_END 0x2223
+
+#define LINK_SPEED_AUTO_NEG 0x00
+#define LINK_SPEED_10HALF 0x01
+#define LINK_SPEED_10FULL 0x02
+#define LINK_SPEED_100HALF 0x03
+#define LINK_SPEED_100FULL 0x04
+#define LINK_SPEED_NO_CONFIGURE_AUTO 0x10
+
+#define WOL_DISABLE 0x00
+#define WOL_ENABLE 0x01
+#define WOL_NA 0x02
+
+#define OROM_DISABLE 0x00
+#define OROM_ENABLE 0x01
+
+
+#pragma pack(1)
+typedef struct {
+ UINT8 OptionRomEnable;
+ UINT8 LinkSpeed;
+ UINT8 WolEnable;
+} GIG_DRIVER_CONFIGURATION;
+#pragma pack()
+
+#endif
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h
new file mode 100755
index 0000000..377c590
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/brand.h
@@ -0,0 +1,159 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+typedef struct {
+ UINT16 vendor_id;
+ UINT16 subvendor_id;
+ UINT16 device_id;
+ UINT16 subsystem_id;
+ CHAR16 *brand_string;
+} BRAND_STRUCT;
+
+BRAND_STRUCT branding_table[] =
+{
+#ifndef NO_BRANDING_SUPPORT
+
+#ifndef NO_82571_SUPPORT
+ {0x8086, 0x0000, 0x105E, 0x0000, L"Intel(R) PRO/1000 PT Dual Port Network Connection"},
+ {0x8086, 0x8086, 0x105E, 0x005E, L"Intel(R) PRO/1000 PT Dual Port Server Connection"},
+ {0x8086, 0x8086, 0x105E, 0x115E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x8086, 0x105E, 0x125E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x8086, 0x105E, 0x135E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x103C, 0x105E, 0x704E, L"Intel(R) PRO/1000 PT Dual Port Server Adapter"},
+ {0x8086, 0x103C, 0x105E, 0x7044, L"HP NC360T PCIe DP Gigabit Server Adapter"},
+ {0x8086, 0x0000, 0x105F, 0x0000, L"Intel(R) PRO/1000 PF Dual Port Server Adapter"},
+ {0x8086, 0x103C, 0x105F, 0x704F, L"Intel(R) PRO/1000 PF Dual Port Server Adapter"},
+ {0x8086, 0x0000, 0x1060, 0x0000, L"Intel(R) PRO/1000 PB Dual Port Server Connection"},
+ {0x8086, 0x0000, 0x10A4, 0x0000, L"Intel(R) PRO/1000 PT Quad Port Server Adapter"},
+ {0x8086, 0x108E, 0x10D5, 0xF1BC, L"Intel(R) Gigabit PT Quad Port Server ExpressModule"},
+ {0x8086, 0x0000, 0x10A5, 0x0000, L"Intel(R) PRO/1000 PF Quad Port Server Adapter"},
+ {0x8086, 0x0000, 0x10BC, 0x0000, L"Intel(R) PRO/1000 PT Quad Port LP server Adapter"},
+ {0x8086, 0x103C, 0x10BC, 0x704B, L"HP NC364T PCIe Quad Port Gigabit Server Adapter"},
+ {0x8086, 0x8086, 0x107D, 0x1082, L"Intel(R) PRO/1000 PT Server Adapter"},
+ {0x8086, 0x8086, 0x107D, 0x1092, L"Intel(R) PRO/1000 PT Server Adapter"},
+ {0x8086, 0x8086, 0x107D, 0x1084, L"Intel(R) PRO/1000 PT Server Adapter"},
+ {0x8086, 0x0000, 0x107D, 0x0000, L"Intel(R) PRO/1000 PT Network Connection"},
+ {0x8086, 0x0000, 0x107E, 0x0000, L"Intel(R) PRO/1000 PF Network Connection"},
+ {0x8086, 0x8086, 0x107E, 0x1084, L"Intel(R) PRO/1000 PF Server Adapter"},
+ {0x8086, 0x8086, 0x107E, 0x1094, L"Intel(R) PRO/1000 PF Server Adapter"},
+ {0x8086, 0x8086, 0x107E, 0x1085, L"Intel(R) PRO/1000 PF Server Adapter"},
+ {0x8086, 0x0000, 0x107F, 0x0000, L"Intel(R) PRO/1000 PB Server Connection"},
+ {0x8086, 0x0000, 0x10B9, 0x0000, L"Intel(R) PRO/1000 PT Desktop Adapter"},
+ {0x8086, 0x103C, 0x10B9, 0x704A, L"HP NC110T PCIe Gigabit Server Adapter"},
+ {0x8086, 0x0000, 0x108B, 0x0000, L"Intel(R) PRO/1000 PM Network Connection"},
+ {0x8086, 0x0000, 0x108C, 0x0000, L"Intel(R) PRO/1000 PM Network Connection"},
+ {0x8086, 0x0000, 0x109A, 0x0000, L"Intel(R) PRO/1000 PL Network Connection"},
+#ifndef NO_82574_SUPPORT
+ {0x8086, 0x0000, 0x10D3, 0x0000, L"Intel(R) 82574L Gigabit Network Connection"},
+ {0x8086, 0x8086, 0x10D3, 0xA01F, L"Intel(R) Gigabit CT Desktop Adapter"},
+ {0x8086, 0x8086, 0x10D3, 0x0001, L"Intel(R) Gigabit CT2 Desktop Adapter"},
+ {0x8086, 0x103C, 0x10D3, 0x1785, L"HP NC112i 1-port Ethernet Server Adapter"},
+ {0x8086, 0x0000, 0x10F6, 0x0000, L"Intel(R) 82574L Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x150C, 0x0000, L"Intel(R) 82583V Gigabit Network Connection"},
+#endif
+#endif /* NO_82571_SUPPORT */
+
+#ifndef NO_80003ES2LAN_SUPPORT
+ {0x8086, 0x0000, 0x1096, 0x0000, L"Intel(R) PRO/1000 EB Network Connection "},
+ {0x8086, 0x10F1, 0x1096, 0x2692, L"Intel(R) PRO/1000 EB1 Network Connection "},
+ {0x8086, 0x1734, 0x1096, 0x10A8, L"Intel(R) PRO/1000 EB1 Network Connection "},
+ {0x8086, 0x0000, 0x1098, 0x0000, L"Intel(R) PRO/1000 EB Backplane Connection "},
+ {0x8086, 0x0000, 0x10BA, 0x0000, L"Intel(R) PRO/1000 EB1 Network Connection "},
+ {0x8086, 0x0000, 0x10BB, 0x0000, L"Intel(R) PRO/1000 EB1 Backplane Connection "},
+#endif /* NO_80003ES2LAN_SUPPORT */
+
+#ifndef NO_ICH8LAN_SUPPORT
+ {0x8086, 0x1179, 0x1049, 0x0001, L"82566MM Network Connection"},
+ {0x8086, 0x0000, 0x1049, 0x0000, L"Intel(R) 82566MM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x104A, 0x0000, L"Intel(R) 82566DM Gigabit Network Connection"},
+ {0x8086, 0x17AA, 0x104A, 0x1012, L"Intel(R) 82566DM Gigabit Platform LAN Connect"},
+ {0x8086, 0x17AA, 0x104A, 0x100F, L"Intel(R) 82566DM Gigabit Platform LAN Connect"},
+ {0x8086, 0x0000, 0x104B, 0x0000, L"Intel(R) 82566DC Gigabit Network Connection"},
+ {0x8086, 0x1179, 0x104C, 0x0001, L"82562V Network Connection"},
+ {0x8086, 0x1179, 0x104D, 0x0001, L"82566MC Network Connection"},
+ {0x8086, 0x0000, 0x104D, 0x0000, L"Intel(R) 82566MC Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10BF, 0x0000, L"Intel(R) 82567LF Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10F5, 0x0000, L"Intel(R) 82567LM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CB, 0x0000, L"Intel(R) 82567V Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10BD, 0x0000, L"Intel(R)82566DM-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10E5, 0x0000, L"Intel(R) 82567LM-4 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x294C, 0x0000, L"Intel(R) 82566DC-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CC, 0x0000, L"Intel(R) 82567LM-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CD, 0x0000, L"Intel(R) 82567LF-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10CE, 0x0000, L"Intel(R) 82567V-2 Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10EA, 0x0000, L"Intel(R) 82577LM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10EB, 0x0000, L"Intel(R) 82577LC Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10EF, 0x0000, L"Intel(R) 82578DM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10F0, 0x0000, L"Intel(R) 82578DC Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x1502, 0x0000, L"Intel(R) 82579LM Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x1503, 0x0000, L"Intel(R) 82579V Gigabit Network Connection"},
+#endif /* NO_ICH8LAN_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+#ifndef NO_82576_SUPPORT
+ {0x8086, 0x0000, 0x10C9, 0x0000, L"Intel(R) 82576 Gigabit Dual Port Network Connection"},
+ {0x8086, 0x8086, 0x10C9, 0x0000, L"Intel(R) Gigabit ET Dual Port Server Adapter"},
+ {0x8086, 0x0000, 0x10E6, 0x0000, L"Intel(R) 82576 Gigabit Dual Port Network Connection"},
+ {0x8086, 0x8086, 0x10E6, 0x0000, L"Intel(R) Gigabit EF Dual Port Server Adapter"},
+ {0x8086, 0x0000, 0x10E7, 0x0000, L"Intel(R) 82576 Gigabit Dual Port Server Network Connection"},
+ {0x8086, 0x8086, 0x10E8, 0xA02B, L"Intel(R) Gigabit ET Quad Port Server Adapter"},
+ {0x8086, 0x8086, 0x10E8, 0xA02C, L"Intel(R) Gigabit ET Quad Port Server Adapter"},
+ {0x8086, 0x8086, 0x1526, 0xA05C, L"Intel(R) Gigabit ET2 Quad Port Server Adapter"},
+ {0x8086, 0x8086, 0x1526, 0xA06C, L"Intel(R) Gigabit ET2 Quad Port Server Adapter"},
+ {0x8086, 0x0000, 0x150A, 0x0000, L"Intel(R) 82576NS Gigabit Ethernet Controller"},
+ {0x8086, 0x0000, 0x1518, 0x0000, L"Intel(R) 82576NS SerDes Gigabit Ethernet Controller"},
+ {0x8086, 0x0000, 0x150D, 0xA10C, L"Intel(R) Gigabit ET Quad Port Mezzanine Card"},
+#endif /* NO_82576_SUPPORT */
+ {0x8086, 0x0000, 0x10A7, 0x0000, L"Intel(R) 82575EB Gigabit Network Connection"},
+ {0x8086, 0x0000, 0x10A9, 0x0000, L"Intel(R) 82575EB Gigabit Backplane Connection"},
+ {0x8086, 0x0000, 0x10D6, 0x0000, L"Intel(R) Gigabit VT Quad Port Server Adapter"},
+#endif /* NO_82575_SUPPORT */
+
+ {0x8086, 0x0000, 0x150E, 0x0000, L"Intel(R) 82580 Gigabit Network Connection"},
+ {0x8086, 0x103C, 0x150E, 0x1780, L"HP NC365T PCIe Quad Port Gigabit Server Adapter"},
+ {0x8086, 0x0000, 0x150F, 0x0000, L"Intel(R) 82580 Gigabit Fiber Network Connection"},
+ {0x8086, 0x0000, 0x1510, 0x0000, L"Intel(R) 82580 Gigabit Backplane Connection"},
+ {0x8086, 0x0000, 0x1511, 0x0000, L"Intel(R) 82580 Gigabit SFP Connection"},
+ {0x8086, 0x8086, 0x150E, 0x12A1, L"Intel(R) Ethernet Server Adapter I340-T4"},
+ {0x8086, 0x8086, 0x150E, 0x12A2, L"Intel(R) Ethernet Server Adapter I340-T4"},
+ {0x8086, 0x8086, 0x1516, 0x12B1, L"Intel(R) Ethernet Server Adapter I340-T2"},
+ {0x8086, 0x8086, 0x1516, 0x12B2, L"Intel(R) Ethernet Server Adapter I340-T2"},
+ {0x8086, 0x8086, 0x1527, 0x0001, L"Intel(R) Ethernet Server Adapter I340-F4"},
+ {0x8086, 0x8086, 0x1527, 0x0002, L"Intel(R) Ethernet Server Adapter I340-F4"},
+
+
+#else /* N0_BRANDING_SUPPORT */
+ {0x8086, 0x8086, 0x0000, 0x0000, L"Intel(R) PRO/1000 Network Connection"},
+#endif /* N0_BRANDING_SUPPORT */
+ {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, L" "}
+};
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt
new file mode 100755
index 0000000..ec30705
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/build_instructions.txt
@@ -0,0 +1,63 @@
+Tiano EDK1 Build Instructions for Intel(R) PRO/1000 Network Connections Driver
+Copyright 2008-2010, Intel Corporation, All Rights Reserved
+
+
+INSTRUCTIONS
+============
+ The make files included in this source package allow the PRO/1000 driver
+ binary to be built as part of the Tiano Core EDK1 source tree. Before
+ building the driver you must download the Tiano Core EDK1 release source
+ from www.tianocore.org and build the tree for your target architecture
+ following the instructions from that site.
+ Follow the below steps to integrate the PRO/1000 driver into the Tiano Core
+ source tree:
+
+ 1. Unzip all files into the following EDK1 sub-directory:
+ \Sample\Bus\Pci\GigUndi
+
+ 2a. (x86-64 or x86 UEFI builds) Open the file X64.dsc in the sub-directory
+ \Sample\Platform\X64\Build. Add the following line to the file in the
+ section labeled "# Network Boot": Sample\Bus\Pci\GigUndi\gig_edk1.inf
+ This will add the PRO/1000 driver to the list of targets for the EDK1 build
+ process. The X64.dsc file has separate sections for x86 and x86-64 builds.
+ The reference to the gig_edk1.inf file must be placed in the correct section
+ for the target architecture, or placed in both sections to build for both
+ x86 and x86-64 architectures.
+
+ 2b. (Itanium IPF Build) Open the file IPF.dsc in the sub-directory
+ \Sample\Platform\IPF\Build. Add the following line to the list of targets in
+ the file: Sample\Bus\Pci\GigUndi\gig_edk1.inf
+
+ 3. Run "nmake" from the platform \Sample\Platform\<ARCH> directory. This
+ will build the EDK1 source tree including the PRO/1000 driver. The resultant
+ executable, gigundi.efi, will be created in the .UEFI\IPF, .UEFI\X64, or
+ .UEFI\IA32 sub-directory depending on the target architecture.
+
+
+CONTROLLER SPECIFIC BUILD INSTRUCTIONS (OPTIONAL)
+=================================================
+ Two example *.inf build files are included with the PRO/1000 source which
+ create a driver binary supporting only a specific network controller family.
+ These *.inf file will result in a smaller binary size by excluding code not
+ needed by the controller.
+
+ gig_82575_edk1.inf: This file will generate a driver specific to the 82575
+ family of network controllers. To build a driver specific to the 82575
+ controller, follow the build instructions in the previous section, but
+ replace "gig_edk1.inf" with "gig_82575_edk1.inf".
+
+ gig_ich_edk1.inf: This file will generate a driver specific to the ICH
+ LAN-On-Motherboard network connections such as ICH8, and ICH9. To build a
+ driver specific to ICH network connections, follow the build instructions in
+ the previous section, but replace "gig_edk1.inf" with "gig_ich_edk1.inf".
+
+ gig_edk1.inf: This file will generate a driver supporting all Intel PRO/1000
+ network connections. To generate this driver binary follow the build
+ instructions in the previous section.
+
+
+
+
+
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c
new file mode 100755
index 0000000..0ed2b34
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.c
@@ -0,0 +1,514 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "clp.h"
+
+
+EFI_GUID gEfiPlatformToDriverConfigurationProtocolGuid = EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL_GUID;
+
+VOID
+EepromMacAddressSet(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 *MacAddress
+);
+
+
+INTN
+FindKey(
+ IN CHAR8 *Key,
+ IN EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock
+ )
+/*++
+
+Routine Description:
+ Find key in CLP command line.
+
+Arguments:
+ Key - Key to find on CLP command line.
+ ClpBlock - Pointer to the CLP structure.
+
+Returns:
+ If key found, returns the index of the last character in the key.
+ If key not found, returns -1.
+
+--*/
+{
+ UINTN i = 0;
+ UINTN j = 0;
+ CHAR8 *CharPtr = ClpBlock->CLPCommand;
+
+ DEBUGPRINT(CLP, ("FindKey()\n"));
+ DEBUGPRINT(CLP, ("CLPCommandLength=%d \n", ClpBlock->CLPCommandLength));
+
+ for (; i < ClpBlock->CLPCommandLength; i++) {
+ if (Key[j] == CharPtr[i]) {
+ DEBUGPRINT(CLP, ("Match j=%d i=%d ", j, i));
+ DEBUGPRINT(CLP, ("Key[j]=%c CharPtr[i]=%c\n", Key[j], CharPtr[i]));
+ j++;
+ }
+ else
+ j = 0;
+
+ if (Key[j] == '\0' && j > 0) {
+ j=0;
+ DEBUGPRINT(CLP, ("Found key: "));
+ while (Key[j] != '\0') {
+ DEBUGPRINT(CLP, ("%c", Key[j]));
+ j++;
+ }
+ DEBUGPRINT(CLP, ("\n"));
+ break;
+ }
+ }
+
+ if (i >= ClpBlock->CLPCommandLength) {
+ j=0;
+ DEBUGPRINT(CLP, ("Did not find key!: "));
+ while (Key[j] != '\0') {
+ DEBUGPRINT(CLP, ("%c", Key[j]));
+ j++;
+ }
+ DEBUGPRINT(CLP, ("\n"));
+ return -1;
+ }
+ DEBUGPRINT(CLP, ("Returning index=%d\n", i));
+ return i;
+}
+
+
+BOOLEAN
+ProcessAddressKey(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock
+ )
+/*++
+
+Routine Description:
+ Processes alternate MAC address with the "Address" key present.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+ ClpBlock - Pointer to the CLP structure.
+
+Returns:
+ FALSE - MAC Address not set.
+ TRUE - Successfully set MAC Address.
+
+--*/
+{
+ INTN i = -1;
+ UINTN j = 0;
+ CHAR8 *CharPtr = ClpBlock->CLPCommand;
+ UINT8 Uint8 = 0;
+ UINT16 MacAddr[3] = {0};
+ UINT8 *MacAddress = (UINT8*) MacAddr; // Necessary to preserve 16-bit alignment on IA64 for call to e1000_read_nvm
+
+ //
+ // Process MAC address
+ //
+ DEBUGPRINT(CLP, ("ProcessAddressKey()\n"));
+ DEBUGPRINT(CLP, ("CLPCommandLength=%d \n", ClpBlock->CLPCommandLength));
+
+ DEBUGPRINT(CLP, ("Search for equals sign\n"));
+ i = FindKey("=", ClpBlock);
+ if (i == -1) {
+ return FALSE;
+ }
+
+ DEBUGPRINT(CLP, ("FindKey returned index=%d\n", i));
+
+ while (CharPtr[i] != '\0') {
+ if (CharPtr[i] >= '0' && CharPtr[i] <= '9') {
+ Uint8 = CharPtr[i] - '0';
+ DEBUGPRINT(CLP, ("%X ", Uint8));
+ }
+ else
+ if (CharPtr[i] >= 'A' && CharPtr[i] <= 'F') {
+ Uint8 = CharPtr[i] - 'A' + 10;
+ DEBUGPRINT(CLP, ("%X ", Uint8));
+ }
+ else
+ if (CharPtr[i] >= 'a' && CharPtr[i] <= 'f') {
+ Uint8 = CharPtr[i] - 'a' + 10;
+ DEBUGPRINT(CLP, ("%X ", Uint8));
+ }
+ else {
+ i++;
+ continue;
+ }
+
+ //
+ // Assign the MAC address to the final value.
+ //
+ if (j & 1) {
+ MacAddress[j/2] |= Uint8;
+ }
+ else
+ {
+ MacAddress[j/2] |= Uint8 << 4;
+ }
+ j++;
+ if (j >= 12) {
+ break;
+ }
+ i++;
+ }
+
+ DEBUGPRINT(CLP, ("\n"));
+
+ if (j < 6) {
+ DEBUGPRINT(CLP, ("Incomplete MAC address\n"));
+ return FALSE;
+ } else {
+ DEBUGPRINT(CLP, ("MAC=%X-%X-%X-%X-%X-%X\n", MacAddress[0], MacAddress[1], MacAddress[2],
+ MacAddress[3], MacAddress[4], MacAddress[5]));
+ }
+
+ DEBUGPRINT(CLP, ("Calling EepromMacAddressSet\n"));
+ EepromMacAddressSet(GigAdapter, MacAddr);
+ return TRUE;
+}
+
+
+BOOLEAN
+ProcessClp(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock
+ )
+/*++
+
+Routine Description:
+ Processes CLP command line parameters.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+ ClpBlock - Pointer to the CLP structure.
+
+Returns:
+ PXE_STATCODE
+
+--*/
+{
+ DEBUGPRINT(CLP, ("ProcessClp()\n"));
+
+ DEBUGPRINT(CLP, ("Search for key\n"));
+ if (FindKey("Address", ClpBlock) != -1) {
+ return ProcessAddressKey(GigAdapter, ClpBlock);
+ }
+ return FALSE;
+}
+
+
+VOID
+EepromMacAddressSet(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 *MacAddress
+)
+/*++
+
+Routine Description:
+ Sets the override MAC address to the default value.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+ MacAddress - Value to set the MAC address to.
+
+Returns:
+ VOID
+
+--*/
+{
+ UINT16 MacOffset;
+ UINT16 OldMacAddress[3];
+#if (DBG_LVL&CLP)
+ UINT8 *MacAddr = (UINT8*) MacAddress;
+#endif
+
+ DEBUGPRINT(CLP, ("MAC=%X-%X-%X-%X-%X-%X\n", MacAddr[0], MacAddr[1], MacAddr[2],
+ MacAddr[3], MacAddr[4], MacAddr[5]));
+
+ //
+ // Determine the location of the card.
+ //
+ GigAdapter->PciIo->GetLocation (
+ GigAdapter->PciIo,
+ &GigAdapter->Segment,
+ &GigAdapter->Bus,
+ &GigAdapter->Device,
+ &GigAdapter->Function
+ );
+
+ //
+ // Read the address where the override MAC address is stored.
+ //
+ e1000_read_nvm (&GigAdapter->hw, NVM_ALT_MAC_ADDR_PTR, 1, &MacOffset);
+
+ if (MacOffset == 0xFFFF) {
+ DEBUGPRINT(CLP, ("Invalid offset for alt MAC address\n"));
+ return;
+ }
+
+ DEBUGPRINT(CLP, ("MAC addresses at offset %X\n", MacOffset));
+
+ //
+ // Adjust the MAC address offset if this is the second port (function 1), or the
+ // third or fourth port (Barton Hills)
+ //
+ MacOffset = MacOffset + (UINT16) (3*GigAdapter->Function);
+
+ //
+ // Read the current stored MAC address to see if it needs to be changed
+ //
+ e1000_read_nvm (&GigAdapter->hw, MacOffset, 3, OldMacAddress);
+
+ if ((MacAddress[0] != OldMacAddress[0]) || (MacAddress[1] != OldMacAddress[1]) ||
+ (MacAddress[2] != OldMacAddress[2])) {
+ DEBUGPRINT(CLP, ("Updating MAC addresses in EEPROM\n"));
+ e1000_write_nvm(&GigAdapter->hw, MacOffset, 3, MacAddress);
+ } else {
+ DEBUGPRINT(CLP, ("No need to update MAC addresses in EEPROM\n"));
+ }
+
+}
+
+
+VOID
+EepromMacAddressDefault(
+ IN GIG_DRIVER_DATA *GigAdapter
+)/*++
+
+Routine Description:
+ Sets the override MAC address back to FF-FF-FF-FF-FF-FF to disable.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ PXE_STATCODE
+
+--*/
+{
+ UINT16 MacOffset;
+ UINT16 MacAddress[3];
+ UINT16 MacDefault[3] = {0xFFFF, 0xFFFF, 0xFFFF};
+
+ //
+ // Determine the location of the card.
+ //
+ GigAdapter->PciIo->GetLocation (
+ GigAdapter->PciIo,
+ &GigAdapter->Segment,
+ &GigAdapter->Bus,
+ &GigAdapter->Device,
+ &GigAdapter->Function
+ );
+
+ //
+ // Read the address where the override MAC address is stored.
+ //
+ e1000_read_nvm (&GigAdapter->hw, NVM_ALT_MAC_ADDR_PTR, 1, &MacOffset);
+
+ if (MacOffset == 0xFFFF) {
+ DEBUGPRINT(CLP, ("Invalid offset for alt MAC address\n"));
+ return;
+ }
+
+ DEBUGPRINT(CLP, ("MAC addresses at offset %X\n", MacOffset));
+
+ //
+ // Adjust the MAC address offset if this is the second port (function 1)
+ //
+ MacOffset = MacOffset + (UINT16) (3*GigAdapter->Function);
+
+ //
+ // Read the current stored MAC address to see if it needs to be changed
+ //
+ e1000_read_nvm (&GigAdapter->hw, MacOffset, 3, (UINT16*) MacAddress);
+
+ if ((MacAddress[0] != 0xFFFF) || (MacAddress[1] != 0xFFFF) || (MacAddress[2] != 0xFFFF)) {
+ DEBUGPRINT(CLP, ("Setting default MAC addresses in EEPROM\n"));
+ e1000_write_nvm(&GigAdapter->hw, MacOffset, 3, MacDefault);
+ } else {
+ DEBUGPRINT(CLP, ("No need to update MAC addresses in EEPROM\n"));
+ }
+
+}
+
+
+EFI_STATUS
+ClpEntry(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Entry point for EFI CLP code. Searches for CLP interface and attempts to get CLP parameters.
+
+Arguments:
+ This - Handle to driver binding protocol
+ Controller - Controller handle associated with the CLP instance
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ EFI_STATUS
+
+--*/
+{
+ EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL *ClpProt;
+ EFI_STATUS Status;
+ UINTN Instance = 0;
+ EFI_GUID *ParameterTypeGuid;
+ UINTN ParameterBlockSize;
+ EFI_PLATFORM_CONFIGURATION_ACTION Action;
+ EFI_CONFIGURE_CLP_PARAMETER_BLK *ClpBlock;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ BOOLEAN AltMacSet = FALSE;
+ UINTN i;
+
+ DEBUGPRINT(CLP, ("ClpEntry()\n"));
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPlatformToDriverConfigurationProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CLP, ("LocateHandleBuffer returns %r\n", Status));
+ return Status;
+ }
+
+ if (HandleCount == 0) {
+ DEBUGPRINT(CLP, ("CLP Interface not found, restoring default MAC address.\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUGPRINT(CLP, ("HandleCount=%d\n", HandleCount));
+
+ Status = gBS->OpenProtocol (
+ HandleBuffer[0],
+ &gEfiPlatformToDriverConfigurationProtocolGuid,
+ (VOID **) &ClpProt,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CLP, ("Error finding CLP protocol: %r\n", Status));
+ return Status;
+ }
+ DEBUGPRINT(CLP, ("HandleCount=%d\n", HandleCount));
+
+ while (Instance < 10) {
+ DEBUGPRINT(CLP, ("Calling CLP->Query\n"));
+ Status = ClpProt->Query(
+ ClpProt,
+ Controller,
+ NULL,
+ &Instance,
+ &ParameterTypeGuid,
+ (VOID*) &ClpBlock,
+ &ParameterBlockSize
+ );
+
+ DEBUGPRINT(CLP, ("CLP Query returns: %r\n", Status));
+ if (Status == EFI_NOT_FOUND || EFI_ERROR(Status)) {
+ break;
+ }
+
+ DEBUGPRINT(CLP, ("Instance=%d\n", Instance));
+ DEBUGPRINT(CLP, ("ParameterBlockSize=%d\n", ParameterBlockSize));
+
+ DEBUGPRINT(CLP, ("CLPCommandLength=%d \n", ClpBlock->CLPCommandLength));
+ DEBUGPRINT(CLP, ("CLPCommand="));
+ for (i = 0; i < ClpBlock->CLPCommandLength; i++) {
+ DEBUGPRINT(CLP, ("%c", ClpBlock->CLPCommand[i]));
+ }
+ DEBUGPRINT(CLP, ("\n"));
+
+ DEBUGPRINT(CLP, ("Calling ProcessCLP\n"));
+ if (ProcessClp(GigAdapter, ClpBlock) == TRUE) {
+ DEBUGPRINT(CLP, ("Set Alt MAC address\n"));
+ AltMacSet = TRUE;
+ }
+
+ Action = EfiPlatformConfigurationActionNone;
+ ClpBlock->CLPReturnString = "Success";
+ ClpBlock->CLPReturnStringLength = 8;
+ ClpBlock->CLPCmdStatus = 0;
+ ClpBlock->CLPErrorValue = 2;
+ ClpBlock->CLPMsgCode = 0;
+
+ DEBUGPRINT(CLP, ("Calling CLP Response @ %X...", ClpProt->Response));
+ Status = ClpProt->Response (
+ ClpProt,
+ Controller,
+ NULL,
+ &Instance,
+ ParameterTypeGuid,
+ (VOID*) ClpBlock,
+ sizeof(EFI_CONFIGURE_CLP_PARAMETER_BLK),
+ Action
+ );
+
+ DEBUGPRINT(CLP, ("CLP Response returns: %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ Instance++;
+ }
+
+ if (AltMacSet == FALSE) {
+ DEBUGPRINT(CLP, ("Setting CLP back to default.\n"));
+ EepromMacAddressDefault(GigAdapter);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPlatformToDriverConfigurationProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ DEBUGWAIT(CLP);
+
+ return Status;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h
new file mode 100755
index 0000000..9405942
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/clp.h
@@ -0,0 +1,100 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _CLP_H_
+#define _CLP_H_
+
+#define EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL_GUID \
+ { 0x642cd590, 0x8059, 0x4c0a, { 0xa9, 0x58, 0xc5, 0xec, 0x7, 0xd2, 0x3c, 0x4b } }
+
+typedef enum {
+ EfiPlatformConfigurationActionNone = 0,
+ EfiPlatformConfigurationActionStopController = 1,
+ EfiPlatformConfigurationActionRestartController = 2,
+ EfiPlatformConfigurationActionRestartPlatform = 3,
+ EfiPlatformConfigurationActionNvramFailed = 4,
+ EfiPlatformConfigurationActionMaximum
+} EFI_PLATFORM_CONFIGURATION_ACTION;
+
+#define EFI_PLATFORM_TO_DRIVER_CONFIGURATION_CLP_GUID \
+ {0x345ecc0e, 0xcb6, 0x4b75, 0xbb, 0x57, 0x1b, 0x12, 0x9c, 0x47, 0x33,0x3e)
+
+typedef struct _EFI_CONFIGURE_CLP_PARAMETER_BLK {
+ CHAR8 *CLPCommand;
+ UINT32 CLPCommandLength;
+ CHAR8 *CLPReturnString;
+ UINT32 CLPReturnStringLength;
+ UINT8 CLPCmdStatus;
+ UINT8 CLPErrorValue;
+ UINT16 CLPMsgCode;
+} EFI_CONFIGURE_CLP_PARAMETER_BLK;
+
+typedef struct _EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PLATFORM_TO_DRIVER_CONFIGURATION_QUERY) (
+ IN EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINTN *Instance,
+ OUT EFI_GUID **ParameterTypeGuid,
+ OUT VOID **ParameterBlock,
+ OUT UINTN *ParameterBlockSize
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PLATFORM_TO_DRIVER_CONFIGURATION_RESPONSE) (
+ IN EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINTN *Instance,
+ IN EFI_GUID *ParameterTypeGuid,
+ IN VOID *ParameterBlock,
+ IN UINTN ParameterBlockSize,
+ IN EFI_PLATFORM_CONFIGURATION_ACTION ConfigurationAction
+ );
+
+struct _EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL {
+ EFI_PLATFORM_TO_DRIVER_CONFIGURATION_QUERY Query;
+ EFI_PLATFORM_TO_DRIVER_CONFIGURATION_RESPONSE Response;
+};
+
+EFI_STATUS
+ClpEntry(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ GIG_DRIVER_DATA *GigAdapter
+ );
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c
new file mode 100755
index 0000000..e215d41
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.c
@@ -0,0 +1,2222 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern GIG_DRIVER_DATA *e1000_NIC_Data; // is actually an array of structures
+
+//
+// Global variables for blocking IO
+//
+STATIC BOOLEAN gInitializeLock = TRUE;
+STATIC EFI_LOCK gLock;
+
+
+VOID
+_DisplayBuffersAndDescriptors (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+
+//
+// Local Functions
+//
+BOOLEAN
+e1000_DownShift (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+UINTN
+e1000_SetFilter (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 NewFilter,
+ UINT64 cpb,
+ UINT32 cpbsize
+ );
+
+UINTN
+e1000_Statistics (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 DBaddr,
+ UINT16 DBsize
+ );
+
+VOID
+e1000_TxRxConfigure (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+UINTN
+e1000_SetInterruptState (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+BOOLEAN
+e1000_WaitForAutoNeg (
+ IN GIG_DRIVER_DATA *GigAdapter
+ );
+
+//
+// end function prototypes
+//
+
+VOID
+e1000_BlockIt (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ UINT32 flag
+ )
+/*++
+
+Routine Description:
+ Implements IO blocking when reading DMA memory.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on.
+ flag - Block flag
+Returns:
+
+--*/
+{
+ if (GigAdapter->Block != NULL) {
+ (*GigAdapter->Block) (GigAdapter->Unique_ID, flag);
+ } else {
+ if (gInitializeLock) {
+ EfiInitializeLock (&gLock, TPL_NOTIFY);
+ gInitializeLock = FALSE;
+ }
+
+ if (flag != 0) {
+ EfiAcquireLock (&gLock);
+ } else {
+ EfiReleaseLock (&gLock);
+ }
+ }
+}
+
+VOID
+e1000_MapMem (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT64 VirtualAddress,
+ IN UINT32 Size,
+ OUT UINTN *MappedAddress
+ )
+/*++
+
+Routine Description:
+ Maps a virtual address to a physical address. This is necessary for runtime functionality and also
+ on some platforms that have a chipset that cannot allow DMAs above 4GB.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on.
+ VirtualAddress - Virtual Address of the data buffer to map.
+ Size - Minimum size of the buffer to map.
+ MappedAddress - Pointer to store the address of the mapped buffer.
+Returns:
+
+--*/
+{
+ if (GigAdapter->MapMem != NULL) {
+ (*GigAdapter->MapMem) (
+ GigAdapter->Unique_ID,
+ VirtualAddress,
+ Size,
+ TO_DEVICE,
+ (UINT64) MappedAddress
+ );
+ //
+ // Workaround: on some systems mapmem may not be implemented correctly, so just
+ // pass back the original address
+ //
+ if (*MappedAddress == 0) {
+ *((UINTN*) MappedAddress) = (UINTN) VirtualAddress;
+ }
+ } else {
+ *((UINTN*) MappedAddress) = (UINTN) VirtualAddress;
+ }
+}
+
+VOID
+e1000_UnMapMem (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT64 VirtualAddress,
+ IN UINT32 Size,
+ IN UINT64 MappedAddress
+ )
+/*++
+
+Routine Description:
+ Maps a virtual address to a physical address. This is necessary for runtime functionality and also
+ on some platforms that have a chipset that cannot allow DMAs above 4GB.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on.
+ VirtualAddress - Virtual Address of the data buffer to map.
+ Size - Minimum size of the buffer to map.
+ MappedAddress - Pointer to store the address of the mapped buffer.
+Returns:
+
+--*/
+{
+ if (GigAdapter->UnMapMem != NULL) {
+ (*GigAdapter->UnMapMem) (
+ GigAdapter->Unique_ID,
+ VirtualAddress,
+ Size,
+ TO_DEVICE,
+ (UINT64) MappedAddress
+ );
+ }
+}
+
+VOID
+e1000_MemCopy (
+ IN UINT8* Dest,
+ IN UINT8* Source,
+ IN UINT32 Count
+ )
+/*++
+Routine Description:
+ This is the drivers copy function so it does not need to rely on the BootServices
+ copy which goes away at runtime. This copy function allows 64-bit or 32-bit copies
+ depending on platform architecture. On Itanium we must check that both addresses
+ are naturally aligned before attempting a 64-bit copy.
+
+Arguments:
+ Dest - Destination memory pointer to copy data to.
+ Source - Source memory pointer.
+Returns:
+ VOID
+--*/
+
+{
+ UINT32 BytesToCopy;
+ UINT32 IntsToCopy;
+ UINTN* SourcePtr;
+ UINTN* DestPtr;
+ UINT8* SourceBytePtr;
+ UINT8* DestBytePtr;
+
+
+ IntsToCopy = Count / sizeof(UINTN);
+ BytesToCopy = Count % sizeof(UINTN);
+#ifdef EFI64
+ //
+ // Itanium cannot handle memory accesses that are not naturally aligned. Determine
+ // if 64-bit copy is even possible with these start addresses.
+ //
+ if (( ( ((UINTN) Source) & 0x0007) != 0) || (( ((UINTN) Dest) & 0x0007) != 0) ) {
+ IntsToCopy = 0;
+ BytesToCopy = Count;
+ }
+#endif
+
+ SourcePtr = (UINTN*) Source;
+ DestPtr = (UINTN*) Dest;
+
+ while (IntsToCopy > 0) {
+ *DestPtr = *SourcePtr;
+ SourcePtr++;
+ DestPtr++;
+ IntsToCopy--;
+ }
+
+ //
+ // Copy the leftover bytes.
+ //
+ SourceBytePtr = (UINT8*) SourcePtr;
+ DestBytePtr = (UINT8*) DestPtr;
+ while (BytesToCopy > 0) {
+ *DestBytePtr = *SourceBytePtr;
+ SourceBytePtr++;
+ DestBytePtr++;
+ BytesToCopy--;
+ }
+}
+
+
+BOOLEAN
+e1000_DownShift (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Wait for up to 30 seconds for two pair downshift to complete
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+
+Returns:
+ TRUE if two pair downshift was successful and link was established
+ FALSE otherwise
+
+--*/
+{
+ UINTN i;
+ UINT32 Status;
+
+ DEBUGPRINT (E1000, ("e1000_DownShift: Attempting downshift\n"));
+
+ i = 0;
+ for (i = 0; i < 30; i++) {
+ DelayInMilliseconds (1000);
+ Status = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ DEBUGPRINT(E1000, ("Status = %x\n", Status));
+ if ((Status & E1000_STATUS_LU) != 0) {
+ DEBUGPRINT(E1000, ("Successfully established link\n"));
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+UINTN
+e1000_Statistics (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 DBaddr,
+ UINT16 DBsize
+ )
+/*++
+
+Routine Description:
+ copies the stats from our local storage to the protocol storage.
+ which means it will read our read and clear numbers, so some adding is required before
+ we copy it over to the protocol.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+ DBaddr - The data block address
+ DBsize - The data block size
+
+Returns:
+ PXE Status code
+
+--*/
+{
+ PXE_DB_STATISTICS *DbPtr;
+ struct e1000_hw *hw;
+ struct e1000_hw_stats *st;
+ UINTN stat;
+
+ hw = &GigAdapter->hw;
+ st = &GigAdapter->stats;
+
+#define UPDATE_OR_RESET_STAT(sw_reg, hw_reg) \
+ do { \
+ st->sw_reg = DBaddr ? st->sw_reg + E1000_READ_REG (hw, hw_reg) : 0; \
+ } while (0)
+
+ {
+ UPDATE_OR_RESET_STAT (crcerrs, E1000_CRCERRS);
+ }
+
+ UPDATE_OR_RESET_STAT (gprc, E1000_GPRC);
+ UPDATE_OR_RESET_STAT (bprc, E1000_BPRC);
+ UPDATE_OR_RESET_STAT (mprc, E1000_MPRC);
+ UPDATE_OR_RESET_STAT (roc, E1000_ROC);
+ UPDATE_OR_RESET_STAT (prc64, E1000_PRC64);
+ UPDATE_OR_RESET_STAT (prc127, E1000_PRC127);
+ UPDATE_OR_RESET_STAT (prc255, E1000_PRC255);
+ UPDATE_OR_RESET_STAT (prc511, E1000_PRC511);
+ UPDATE_OR_RESET_STAT (prc1023, E1000_PRC1023);
+ UPDATE_OR_RESET_STAT (prc1522, E1000_PRC1522);
+
+ UPDATE_OR_RESET_STAT (symerrs, E1000_SYMERRS);
+ UPDATE_OR_RESET_STAT (mpc, E1000_MPC);
+ UPDATE_OR_RESET_STAT (scc, E1000_SCC);
+ UPDATE_OR_RESET_STAT (ecol, E1000_ECOL);
+ UPDATE_OR_RESET_STAT (mcc, E1000_MCC);
+ UPDATE_OR_RESET_STAT (latecol, E1000_LATECOL);
+ UPDATE_OR_RESET_STAT (dc, E1000_DC);
+ UPDATE_OR_RESET_STAT (sec, E1000_SEC);
+ UPDATE_OR_RESET_STAT (rlec, E1000_RLEC);
+ UPDATE_OR_RESET_STAT (xonrxc, E1000_XONRXC);
+ UPDATE_OR_RESET_STAT (xontxc, E1000_XONTXC);
+ UPDATE_OR_RESET_STAT (xoffrxc, E1000_XOFFRXC);
+ UPDATE_OR_RESET_STAT (xofftxc, E1000_XOFFTXC);
+ UPDATE_OR_RESET_STAT (fcruc, E1000_FCRUC);
+ UPDATE_OR_RESET_STAT (gptc, E1000_GPTC);
+ UPDATE_OR_RESET_STAT (rnbc, E1000_RNBC);
+ UPDATE_OR_RESET_STAT (ruc, E1000_RUC);
+ UPDATE_OR_RESET_STAT (rfc, E1000_RFC);
+ UPDATE_OR_RESET_STAT (rjc, E1000_RJC);
+ UPDATE_OR_RESET_STAT (tpr, E1000_TPR);
+ UPDATE_OR_RESET_STAT (ptc64, E1000_PTC64);
+ UPDATE_OR_RESET_STAT (ptc127, E1000_PTC127);
+ UPDATE_OR_RESET_STAT (ptc255, E1000_PTC255);
+ UPDATE_OR_RESET_STAT (ptc511, E1000_PTC511);
+ UPDATE_OR_RESET_STAT (ptc1023, E1000_PTC1023);
+ UPDATE_OR_RESET_STAT (ptc1522, E1000_PTC1522);
+ UPDATE_OR_RESET_STAT (mptc, E1000_MPTC);
+ UPDATE_OR_RESET_STAT (bptc, E1000_BPTC);
+
+ //
+ // used for adaptive IFS
+ //
+ hw->mac.tx_packet_delta = E1000_READ_REG (hw, E1000_TPT);
+ st->tpt = DBaddr ? st->tpt + hw->mac.tx_packet_delta : 0;
+ hw->mac.collision_delta = E1000_READ_REG (hw, E1000_COLC);
+ st->colc = DBaddr ? st->colc + hw->mac.collision_delta : 0;
+
+ {
+ UPDATE_OR_RESET_STAT (algnerrc, E1000_ALGNERRC);
+ UPDATE_OR_RESET_STAT (rxerrc, E1000_RXERRC);
+ UPDATE_OR_RESET_STAT (tncrs, E1000_TNCRS);
+ UPDATE_OR_RESET_STAT (cexterr, E1000_CEXTERR);
+ UPDATE_OR_RESET_STAT (tsctc, E1000_TSCTC);
+ UPDATE_OR_RESET_STAT (tsctfc, E1000_TSCTFC);
+ }
+
+ if (!DBaddr) {
+ return PXE_STATCODE_SUCCESS;
+ }
+
+ DbPtr = (PXE_DB_STATISTICS *) (UINTN) DBaddr;
+
+ //
+ // Fill out the OS statistics structure
+ // To Add/Subtract stats, include/delete the lines in pairs.
+ // E.g., adding a new stat would entail adding these two lines:
+ // stat = PXE_STATISTICS_NEW_STAT_XXX; SET_SUPPORT;
+ // DbPtr->Data[stat] = st->xxx;
+ //
+ DbPtr->Supported = 0;
+
+#define SET_SUPPORT(S) \
+ do { \
+ stat = PXE_STATISTICS_##S; \
+ DbPtr->Supported |= (1 << stat); \
+ } while (0)
+#define UPDATE_EFI_STAT(S, b) \
+ do { \
+ SET_SUPPORT (S); \
+ DbPtr->Data[stat] = st->b; \
+ } while (0)
+
+ {
+ UPDATE_EFI_STAT (RX_TOTAL_FRAMES, tpr);
+ }
+
+ UPDATE_EFI_STAT (RX_GOOD_FRAMES, gprc);
+ UPDATE_EFI_STAT (RX_UNDERSIZE_FRAMES, ruc);
+ UPDATE_EFI_STAT (RX_OVERSIZE_FRAMES, roc);
+ UPDATE_EFI_STAT (RX_DROPPED_FRAMES, rnbc);
+ SET_SUPPORT (RX_UNICAST_FRAMES);
+ DbPtr->Data[stat] = (st->gprc - st->bprc - st->mprc);
+ UPDATE_EFI_STAT (RX_BROADCAST_FRAMES, bprc);
+ UPDATE_EFI_STAT (RX_MULTICAST_FRAMES, mprc);
+ SET_SUPPORT (RX_CRC_ERROR_FRAMES);
+ DbPtr->Data[stat] = (st->crcerrs + st->algnerrc);
+ UPDATE_EFI_STAT (TX_TOTAL_FRAMES, tpt);
+ UPDATE_EFI_STAT (TX_GOOD_FRAMES, gptc);
+ SET_SUPPORT (TX_UNICAST_FRAMES);
+ DbPtr->Data[stat] = (st->gptc - st->bptc - st->mptc);
+ UPDATE_EFI_STAT (TX_BROADCAST_FRAMES, bptc);
+ UPDATE_EFI_STAT (TX_MULTICAST_FRAMES, mptc);
+ UPDATE_EFI_STAT (COLLISIONS, colc);
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+
+UINTN
+e1000_Transmit (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 cpb,
+ UINT16 opflags
+ )
+/*++
+
+Routine Description:
+ Takes a command block pointer (cpb) and sends the frame. Takes either one fragment or many
+ and places them onto the wire. Cleanup of the send happens in the function UNDI_Status in DECODE.C
+
+Arguments:
+ GigAdapter - Pointer to the instance data
+ cpb - The command parameter block address. 64 bits since this is Itanium(tm)
+ processor friendly
+ opflags - The operation flags, tells if there is any special sauce on this transmit
+
+Returns:
+ PXE_STATCODE_SUCCESS if the frame goes out,
+ PXE_STATCODE_DEVICE_FAILURE if it didn't
+ PXE_STATCODE_BUSY if they need to call again later.
+
+--*/
+{
+ PXE_CPB_TRANSMIT_FRAGMENTS *TxFrags;
+ PXE_CPB_TRANSMIT *TxBuffer;
+ E1000_TRANSMIT_DESCRIPTOR *TransmitDescriptor;
+ UINT32 i;
+ INT16 WaitMsec;
+
+/* DEBUGPRINT(E1000, ("e1000_Transmit\n"));
+ DEBUGPRINT(E1000, ("TCTL=%X\r\n", E1000_READ_REG(&GigAdapter->hw, E1000_TCTL)));
+ for (i = 0; i < DEFAULT_TX_DESCRIPTORS; i++) {
+ DEBUGPRINT(E1000, ("buffer=%X ", GigAdapter->tx_ring[i].buffer_addr));
+ DEBUGPRINT(E1000, ("len=%X ", GigAdapter->tx_ring[i].lower.flags.length));
+ DEBUGPRINT(E1000, ("cmd=%X ", GigAdapter->tx_ring[i].lower.flags.cmd));
+ DEBUGPRINT(E1000, ("status=%X ", GigAdapter->tx_ring[i].upper.fields.status));
+ DEBUGPRINT(E1000, ("special=%X\n", GigAdapter->tx_ring[i].upper.fields.special));
+ }
+*/
+
+ //
+ // Transmit buffers must be freed by the upper layer before we can transmit any more.
+ //
+ if (GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind] != 0) {
+ DEBUGPRINT(CRITICAL, ("TX buffers have all been used! cur_tx=%d\n", GigAdapter->cur_tx_ind));
+ for (i = 0; i < DEFAULT_TX_DESCRIPTORS; i++) {
+ DEBUGPRINT(CRITICAL, ("%x ", GigAdapter->TxBufferUnmappedAddr[i]));
+ }
+ DEBUGWAIT(CRITICAL);
+
+ //
+ // According to UEFI spec we should return PXE_STATCODE_BUFFER_FULL, but SNP is not implemented to recognize this
+ // callback.
+ //
+ return PXE_STATCODE_QUEUE_FULL;
+ }
+
+ //
+ // Make some short cut pointers so we don't have to worry about typecasting later.
+ // If the TX has fragments we will use the
+ // tx_tpr_f pointer, otherwise the tx_ptr_l (l is for linear)
+ //
+ TxBuffer = (PXE_CPB_TRANSMIT *) (UINTN) cpb;
+ TxFrags = (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb;
+
+ //
+ // quicker pointer to the next available Tx descriptor to use.
+ //
+ TransmitDescriptor = &GigAdapter->tx_ring[GigAdapter->cur_tx_ind];
+
+ //
+ // Opflags will tell us if this Tx has fragments
+ // So far the linear case (the no fragments case, the else on this if) is the majority
+ // of all frames sent.
+ //
+ if (opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) {
+ //
+ // this count cannot be more than 8;
+ //
+ DEBUGPRINT(E1000, ("Fragments %x\n", TxFrags->FragCnt));
+
+ //
+ // for each fragment, give it a descriptor, being sure to keep track of the number used.
+ //
+ for (i = 0; i < TxFrags->FragCnt; i++) {
+ //
+ // Put the size of the fragment in the descriptor
+ //
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind] = TxFrags->FragDesc[i].FragAddr;
+ e1000_MapMem(
+ GigAdapter,
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind],
+ TxFrags->FragDesc[i].FragLen,
+ (UINTN*) &TransmitDescriptor->buffer_addr
+ );
+
+ TransmitDescriptor->lower.flags.length = (UINT16) TxFrags->FragDesc[i].FragLen;
+ TransmitDescriptor->lower.data = (E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS);
+
+ if (GigAdapter->VlanEnable) {
+ DEBUGPRINT (VLAN, ("1: Setting VLAN tag = %d\n", GigAdapter->VlanTag));
+ TransmitDescriptor->upper.fields.special = GigAdapter->VlanTag;
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_VLE;
+ }
+
+ //
+ // If this is the last fragment we must also set the EOP bit
+ //
+ if ((i + 1) == TxFrags->FragCnt) {
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_EOP;
+ }
+ //
+ // move our software counter passed the frame we just used, watching for wrapping
+ //
+ DEBUGPRINT(E1000, ("Advancing TX pointer %x\n", GigAdapter->cur_tx_ind));
+ GigAdapter->cur_tx_ind++;
+ if (GigAdapter->cur_tx_ind >= DEFAULT_TX_DESCRIPTORS) {
+ GigAdapter->cur_tx_ind = 0;
+ }
+ TransmitDescriptor = &GigAdapter->tx_ring[GigAdapter->cur_tx_ind];
+ }
+ } else {
+ DEBUGPRINT(E1000, ("No Fragments\n"));
+
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind] = TxBuffer->FrameAddr;
+ e1000_MapMem(
+ GigAdapter,
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->cur_tx_ind],
+ TxBuffer->DataLen + TxBuffer->MediaheaderLen,
+ (UINTN*) &TransmitDescriptor->buffer_addr
+ );
+
+ DEBUGPRINT(E1000, ("Packet buffer at %x\n", TransmitDescriptor->buffer_addr));
+
+ //
+ // Set the proper bits to tell the chip that this is the last descriptor in the send,
+ // and be sure to tell us when its done.
+ // EOP - End of packet
+ // IFCs - Insert FCS (Ethernet CRC)
+ // RS - Report Status
+ //
+ TransmitDescriptor->lower.data = (E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS);
+ TransmitDescriptor->upper.fields.status = 0;
+ if (GigAdapter->VlanEnable) {
+ DEBUGPRINT (VLAN, ("2: Setting VLAN tag = %d\n", GigAdapter->VlanTag));
+ TransmitDescriptor->upper.fields.special = GigAdapter->VlanTag;
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_VLE;
+ }
+ TransmitDescriptor->lower.data |= E1000_TXD_CMD_EOP;
+ TransmitDescriptor->lower.flags.length = (UINT16) ((UINT16) TxBuffer->DataLen + TxBuffer->MediaheaderLen);
+
+ DEBUGPRINT(E1000, ("BuffAddr=%x, ", TransmitDescriptor->buffer_addr));
+ DEBUGPRINT(E1000, ("Cmd=%x,", TransmitDescriptor->lower.flags.cmd));
+ DEBUGPRINT(E1000, ("Cso=%x,", TransmitDescriptor->lower.flags.cso));
+ DEBUGPRINT(E1000, ("Len=%x,", TransmitDescriptor->lower.flags.length));
+ DEBUGPRINT(E1000, ("Status=%x,", TransmitDescriptor->upper.fields.status));
+ DEBUGPRINT(E1000, ("Special=%x,", TransmitDescriptor->upper.fields.special));
+ DEBUGPRINT(E1000, ("Css=%x\n", TransmitDescriptor->upper.fields.css));
+
+ //
+ // In the zero fragment case, we need to add the header size to the payload size to accurately tell the hw how big is the packet.
+ //
+ //
+ // Move our software counter passed the frame we just used, watching for wrapping
+ //
+ GigAdapter->cur_tx_ind++;
+ if (GigAdapter->cur_tx_ind >= DEFAULT_TX_DESCRIPTORS) {
+ GigAdapter->cur_tx_ind = 0;
+ }
+ }
+
+#if (DBG_LVL&TX)
+ DEBUGPRINT(TX, ("Packet length = %d\n", TransmitDescriptor->lower.flags.length));
+ DEBUGPRINT(TX, ("Packet data:\n"));
+ for (i = 0; i < 32; i++) {
+ DEBUGPRINT(TX, ("%x ", ((UINT16 *) ((UINTN) TransmitDescriptor->buffer_addr))[i]));
+ }
+#endif
+
+ //
+ // Turn on the blocking function so we don't get swapped out
+ // Then move the Tail pointer so the HW knows to start processing the TX we just setup.
+ //
+ DEBUGWAIT(E1000);
+ e1000_BlockIt (GigAdapter, TRUE);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDT(0), GigAdapter->cur_tx_ind);
+ e1000_BlockIt (GigAdapter, FALSE);
+
+ //
+ // If the opflags tells us to wait for the packet to hit the wire, we will wait.
+ //
+ if ((opflags & PXE_OPFLAGS_TRANSMIT_BLOCK) != 0) {
+ WaitMsec = 1000;
+
+ while ((TransmitDescriptor->upper.fields.status & E1000_TXD_STAT_DD) == 0) {
+ DelayInMilliseconds (10);
+ WaitMsec -= 10;
+ if (WaitMsec <= 0) {
+ break;
+ }
+ }
+
+ //
+ // If we waited for a while, and it didn't finish then the HW must be bad.
+ //
+ if ((TransmitDescriptor->upper.fields.status & E1000_TXD_STAT_DD) == 0) {
+ DEBUGPRINT(CRITICAL, ("ERROR: Network device transmit failure\n"));
+ return PXE_STATCODE_DEVICE_FAILURE;
+ } else {
+ DEBUGPRINT(E1000, ("Transmit success\n"));
+ }
+ }
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+UINTN
+e1000_Receive (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT64 cpb,
+ UINT64 db
+ )
+/*++
+
+Routine Description:
+ Copies the frame from our internal storage ring (As pointed to by GigAdapter->rx_ring) to the command block
+ passed in as part of the cpb parameter. The flow: Ack the interrupt, setup the pointers, find where the last
+ block copied is, check to make sure we have actually received something, and if we have then we do a lot of work.
+ The packet is checked for errors, size is adjusted to remove the CRC, adjust the amount to copy if the buffer is smaller
+ than the packet, copy the packet to the EFI buffer, and then figure out if the packet was targetted at us, broadcast, multicast
+ or if we are all promiscuous. We then put some of the more interesting information (protocol, src and dest from the packet) into the
+ db that is passed to us. Finally we clean up the frame, set the return value to _SUCCESS, and inc the cur_rx_ind, watching
+ for wrapping. Then with all the loose ends nicely wrapped up, fade to black and return.
+
+Arguments:
+ GigAdapter - pointer to the driver data
+ cpb - Pointer (Ia-64 friendly) to the command parameter block. The frame will be placed inside of it.
+ db - The data buffer. The out of band method of passing pre-digested information to the protocol.
+
+Returns:
+ PXE_STATCODE, either _NO_DATA if there is no data, or _SUCCESS if we passed the goods to the protocol.
+
+--*/
+{
+ PXE_CPB_RECEIVE *CpbReceive;
+ PXE_DB_RECEIVE *DbReceive;
+ PXE_FRAME_TYPE PacketType;
+ E1000_RECEIVE_DESCRIPTOR *ReceiveDescriptor;
+ ETHER_HEADER *EtherHeader;
+ PXE_STATCODE StatCode;
+ UINT16 TempLen;
+#if (DBG_LVL&CRITICAL)
+#if (DBG_LVL&RX)
+ UINT32 Rdh;
+ UINT32 Rdt;
+#endif
+#endif
+
+ PacketType = PXE_FRAME_TYPE_NONE;
+ StatCode = PXE_STATCODE_NO_DATA;
+
+
+ //
+ // acknowledge the interrupts
+ //
+ E1000_READ_REG (&GigAdapter->hw, E1000_ICR);
+
+/*
+ DEBUGPRINT(E1000, ("e1000_Receive\n"));
+ DEBUGPRINT(E1000, ("RCTL=%X ", E1000_READ_REG(&GigAdapter->hw, E1000_RCTL)));
+ DEBUGPRINT(E1000, ("RDH0=%x ", (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_RDH(0))));
+ DEBUGPRINT(E1000, ("RDT0=%x\n", (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_RDT(0))));
+ DEBUGPRINT(E1000, ("RDBAL=%x desc=%X\n", E1000_READ_REG (&GigAdapter->hw, E1000_RDBAL),
+ (UINTN) GigAdapter->rx_ring));
+ rar_low = E1000_READ_REG_ARRAY(&GigAdapter->hw, E1000_RA, 0);
+ rar_high = E1000_READ_REG_ARRAY(&GigAdapter->hw, E1000_RA, 1);
+ DEBUGPRINT(E1000, ("Receive Addr = %X %X\n", rar_high, rar_low));
+
+ for (i = 0; i < DEFAULT_RX_DESCRIPTORS; i++) {
+ DEBUGPRINT(E1000, ("buffer=%X ", GigAdapter->rx_ring[i].buffer_addr));
+ DEBUGPRINT(E1000, ("csum=%X ", GigAdapter->rx_ring[i].csum));
+ DEBUGPRINT(E1000, ("special=%X ", GigAdapter->rx_ring[i].special));
+ DEBUGPRINT(E1000, ("status=%X ", GigAdapter->rx_ring[i].status));
+ DEBUGPRINT(E1000, ("len=%X ", GigAdapter->rx_ring[i].length));
+ DEBUGPRINT(E1000, ("err=%X\n", GigAdapter->rx_ring[i].errors));
+ }
+*/
+
+ //
+ // Make quick copies of the buffer pointers so we can use them without fear of corrupting the originals
+ //
+ CpbReceive = (PXE_CPB_RECEIVE *) (UINTN) cpb;
+ DbReceive = (PXE_DB_RECEIVE *) (UINTN) db;
+
+ //
+ // Get a pointer to the buffer that should have a rx in it, IF one is really there.
+ //
+ ReceiveDescriptor = &GigAdapter->rx_ring[GigAdapter->cur_rx_ind];
+
+#if (DBG_LVL&CRITICAL)
+#if (DBG_LVL&RX)
+ if (ReceiveDescriptor->buffer_addr != GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind]) {
+ DEBUGPRINT(CRITICAL, ("GetStatus ERROR: Rx buff mismatch on desc %d: expected %X, actual %X\n",
+ GigAdapter->cur_rx_ind,
+ GigAdapter->DebugRxBuffer[GigAdapter->cur_rx_ind],
+ ReceiveDescriptor->buffer_addr
+ ));
+ }
+
+ Rdt = E1000_READ_REG (&GigAdapter->hw, E1000_RDT(0));
+ Rdh = E1000_READ_REG (&GigAdapter->hw, E1000_RDH(0));
+ if (Rdt == Rdh) {
+ DEBUGPRINT(CRITICAL, ("Receive ERROR: RX Buffers Full!\n"));
+ }
+#endif
+#endif
+
+ if ((ReceiveDescriptor->status & (E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD)) != 0) {
+ //
+ // Just to make sure we don't try to copy a zero length, only copy a positive sized packet.
+ //
+ if ((ReceiveDescriptor->length != 0) && (ReceiveDescriptor->errors == 0)) {
+
+ //
+ // If the buffer passed us is smaller than the packet, only copy the size of the buffer.
+ //
+ TempLen = ReceiveDescriptor->length;
+ if (ReceiveDescriptor->length > (INT16) CpbReceive->BufferLen) {
+ TempLen = (UINT16) CpbReceive->BufferLen;
+ }
+
+ //
+ // Copy the packet from our list to the EFI buffer.
+ //
+ e1000_MemCopy ((UINT8 *) (UINTN) CpbReceive->BufferAddr, (UINT8 *) (UINTN) ReceiveDescriptor->buffer_addr, TempLen);
+
+#if (DBG_LVL & RX)
+ DEBUGPRINT(RX, ("Packet Data \n"));
+ for (i = 0; i < TempLen; i++) {
+ DEBUGPRINT(RX, ("%x ", PacketPtr[i]));
+ }
+ DEBUGPRINT(RX, ("\n"));
+#endif
+ //
+ // Fill the DB with needed information
+ //
+ DbReceive->FrameLen = ReceiveDescriptor->length; // includes header
+ DbReceive->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
+
+ EtherHeader = (ETHER_HEADER *) (UINTN) ReceiveDescriptor->buffer_addr;
+
+ //
+ // Figure out if the packet was meant for us, was a broadcast, multicast or we
+ // recieved a frame in promiscuous mode.
+ //
+ if (E1000_COMPARE_MAC(EtherHeader->dest_addr, GigAdapter->hw.mac.addr) == 0) {
+ PacketType = PXE_FRAME_TYPE_UNICAST;
+ DEBUGPRINT(E1000, ("unicast packet for us.\n"));
+ } else
+ if (E1000_COMPARE_MAC(EtherHeader->dest_addr, GigAdapter->BroadcastNodeAddress) == 0) {
+ PacketType = PXE_FRAME_TYPE_BROADCAST;
+ DEBUGPRINT(E1000, ("broadcast packet.\n"));
+ } else {
+ //
+ // That leaves multicast or we must be in promiscuous mode. Check for the Mcast bit in the address.
+ // otherwise its a promiscuous receive.
+ //
+ if ((EtherHeader->dest_addr[0] & 1) == 1) {
+ PacketType = PXE_FRAME_TYPE_MULTICAST;
+ DEBUGPRINT(E1000, ("multicast packet.\n"));
+ } else {
+ PacketType = PXE_FRAME_TYPE_PROMISCUOUS;
+ DEBUGPRINT(E1000, ("unicast promiscuous.\n"));
+ }
+ }
+ DbReceive->Type = PacketType;
+ DEBUGPRINT(E1000, ("PacketType %x\n", PacketType));
+
+ //
+ // Put the protocol (UDP, TCP/IP) in the data buffer.
+ //
+ DbReceive->Protocol = EtherHeader->type;
+ DEBUGPRINT(E1000, ("protocol %x\n", EtherHeader->type));
+
+ E1000_COPY_MAC(DbReceive->SrcAddr, EtherHeader->src_addr);
+ E1000_COPY_MAC(DbReceive->DestAddr, EtherHeader->dest_addr);
+
+ StatCode = PXE_STATCODE_SUCCESS;
+ } else {
+ DEBUGPRINT(CRITICAL, ("ERROR: Received zero sized packet or receive error!\n"));
+ }
+ //
+ // Clean up the packet
+ //
+ ReceiveDescriptor->status = 0;
+ ReceiveDescriptor->length = 0;
+
+ //
+ // Move the current cleaned buffer pointer, being careful to wrap it as needed. Then update the hardware,
+ // so it knows that an additional buffer can be used.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), GigAdapter->cur_rx_ind);
+ GigAdapter->cur_rx_ind++;
+ if (GigAdapter->cur_rx_ind == DEFAULT_RX_DESCRIPTORS) {
+ GigAdapter->cur_rx_ind = 0;
+ }
+ }
+
+ return StatCode;
+};
+
+UINTN
+e1000_SetInterruptState (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Allows the protocol to control our interrupt behaviour.
+
+Arguments:
+ GigAdapter - Pointer to the driver structure
+
+Returns:
+ PXE_STATCODE_SUCCESS
+
+--*/
+{
+ UINT32 SetIntMask;
+
+ SetIntMask = 0;
+
+ DEBUGPRINT(E1000, ("e1000_SetInterruptState\n"));
+
+ //
+ // Start with no Interrupts.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_IMC, 0xFFFFFFFF);
+
+ //
+ // Mask the RX interrupts
+ //
+ if (GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) {
+ SetIntMask = (E1000_ICR_RXT0 | E1000_ICR_RXSEQ | E1000_ICR_RXDMT0 | E1000_ICR_RXO | E1000_ICR_RXCFG | SetIntMask);
+ DEBUGPRINT(E1000, ("Mask the RX interrupts\n"));
+ }
+
+ //
+ // Mask the TX interrupts
+ //
+ if (GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) {
+ SetIntMask = (E1000_ICR_TXDW | E1000_ICR_TXQE | SetIntMask);
+ DEBUGPRINT(E1000, ("Mask the TX interrupts\n"));
+ }
+
+ //
+ // Mask the CMD interrupts
+ //
+ if (GigAdapter->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) {
+ SetIntMask =
+ (
+ E1000_ICR_GPI_EN0 |
+ E1000_ICR_GPI_EN1 |
+ E1000_ICR_GPI_EN2 |
+ E1000_ICR_GPI_EN3 |
+ E1000_ICR_LSC |
+ SetIntMask
+ );
+ DEBUGPRINT(E1000, ("Mask the CMD interrupts\n"));
+ }
+
+ //
+ // Now we have all the Ints we want, so let the hardware know.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_IMS, SetIntMask);
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Stop the hardware and put it all (including the PHY) into a known good state.
+
+Arguments:
+ GigAdapter - Pointer to the driver structure
+
+Returns:
+ PXE_STATCODE_SUCCESS
+
+--*/
+{
+ UINT32 Reg;
+
+ DEBUGPRINT(E1000, ("e1000_Shutdown - adapter stop\n"));
+
+ //
+ // Disable the transmit and receive DMA
+ //
+ e1000_ReceiveDisable (GigAdapter);
+
+ Reg = E1000_READ_REG (&GigAdapter->hw, E1000_TCTL);
+ Reg = (Reg & ~E1000_TCTL_EN);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TCTL, Reg);
+
+ //
+ // Disable the receive unit so the hardware does not continue to DMA packets to memory.
+ // Also release the software semaphore.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_SWSM, 0);
+ e1000_PciFlush(&GigAdapter->hw);
+
+ //
+ // This delay is to ensure in flight DMA and receive descriptor flush
+ // have time to complete.
+ //
+ DelayInMilliseconds (10);
+
+ GigAdapter->ReceiveStarted = FALSE;
+ GigAdapter->Rx_Filter = 0;
+
+ return PXE_STATCODE_SUCCESS;
+};
+
+UINTN
+e1000_Reset (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 OpFlags
+ )
+/*++
+
+Routine Description:
+ Resets the hardware and put it all (including the PHY) into a known good state.
+
+Arguments:
+ GigAdapter - The pointer to our context data
+ OpFlags - The information on what else we need to do.
+
+Returns:
+ PXE_STATCODE_SUCCESS
+
+--*/
+{
+
+ UINT32 TempReg;
+
+ DEBUGPRINT(E1000, ("e1000_Reset\n"));
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+
+ //
+ // Spanning Tree Workaround:
+ // If link is up and valid then we will not do a PHY reset. This ensures
+ // we do not need to drop link and spanning tree does not need to restart.
+ // If link is up and we see Gigabit Half-Duplex then we know link is invalid
+ // and we need to do a PHY reset.
+ //
+ GigAdapter->hw.phy.reset_disable = TRUE;
+
+ if ((TempReg & E1000_STATUS_LU) != 0) {
+ if (((TempReg & E1000_STATUS_FD) == 0) && ((TempReg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_1000)) {
+ DEBUGPRINT(E1000, ("BAD LINK - 1Gig/Half - Enabling PHY reset\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ //
+ // Since link is in a bad state we also need to make sure that we do a full reset down below
+ //
+ GigAdapter->HwInitialized = FALSE;
+ }
+ }
+
+ //
+ // Put the E1000 into a known state by resetting the transmit
+ // and receive units of the E1000 and masking/clearing all
+ // interrupts.
+ // If the hardware has already been started then don't bother with a reset
+ // We want to make sure we do not have to restart autonegotiation and two-pair
+ // downshift.
+ //
+ if (GigAdapter->HwInitialized == FALSE) {
+ e1000_reset_hw (&GigAdapter->hw);
+
+ //
+ // Now that the structures are in place, we can configure the hardware to use it all.
+ //
+ if (e1000_init_hw (&GigAdapter->hw) == 0) {
+ DEBUGPRINT(E1000, ("e1000_init_hw success\n"));
+ } else {
+ DEBUGPRINT(CRITICAL, ("Hardware Init failed\n"));
+ return PXE_STATCODE_NOT_STARTED;
+ }
+ }
+ else
+ {
+ DEBUGPRINT(E1000, ("Skipping adapter reset\n"));
+ }
+
+
+ if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
+ UINT16 SaveFilter;
+
+ SaveFilter = GigAdapter->Rx_Filter;
+
+ //
+ // if we give the filter same as Rx_Filter, this routine will not set mcast list
+ // (it thinks there is no change)
+ // to force it, we will reset that flag in the Rx_Filter
+ //
+ GigAdapter->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ e1000_SetFilter (GigAdapter, SaveFilter, (UINT64) 0, (UINT32) 0);
+ }
+
+ if (OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) {
+ GigAdapter->int_mask = 0; // disable the interrupts
+ }
+
+ e1000_SetInterruptState (GigAdapter);
+
+ return PXE_STATCODE_SUCCESS;
+}
+
+VOID
+e1000_SetSpeedDuplex(
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ GigAdapter - Sets the force speed and duplex settings for the adapter based on
+ EEPROM settings and data set by the SNP
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ VOID
+
+--*/
+{
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+
+ DEBUGPRINT(E1000, ("e1000_SetSpeedDuplex\n"));
+
+ //
+ // Copy forced speed and duplex settings to shared code structure
+ //
+ if ((GigAdapter->LinkSpeed == 10) && (GigAdapter->DuplexMode == PXE_FORCE_HALF_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 10-Half\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ if ((GigAdapter->LinkSpeed == 100) && (GigAdapter->DuplexMode == PXE_FORCE_HALF_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 100-Half\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ if ((GigAdapter->LinkSpeed == 10) && (GigAdapter->DuplexMode == PXE_FORCE_FULL_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 10-Full\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ if ((GigAdapter->LinkSpeed == 100) && (GigAdapter->DuplexMode == PXE_FORCE_FULL_DUPLEX)) {
+ DEBUGPRINT(E1000, ("Force 100-Full\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ }
+
+ //
+ // Check for forced speed and duplex
+ // The EEPROM settings will override settings passed by the SNP
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ if(E1000_READ_REG(&GigAdapter->hw, E1000_STATUS) & E1000_STATUS_FUNC_1) {
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ } else {
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ }
+
+ e1000_read_nvm(&GigAdapter->hw, SetupOffset, 1, &SetupWord);
+ e1000_read_nvm(&GigAdapter->hw, ConfigOffset, 1, &CustomConfigWord);
+
+ if ((CustomConfigWord & SIG_MASK) == SIG) {
+ switch (SetupWord & (FSP_MASK | FDP_FULL_DUPLEX_BIT))
+ {
+ case (FDP_FULL_DUPLEX_BIT | FSP_100MBS):
+ DEBUGPRINT(E1000, ("Forcing 100 Full from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ case (FDP_FULL_DUPLEX_BIT | FSP_10MBS):
+ DEBUGPRINT(E1000, ("Forcing 10 Full from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ case (FSP_100MBS):
+ DEBUGPRINT(E1000, ("Forcing 100 Half from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ case (FSP_10MBS):
+ DEBUGPRINT(E1000, ("Forcing 10 Half from EEPROM\n"));
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.mac.autoneg = 0;
+ GigAdapter->hw.mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ GigAdapter->HwInitialized = FALSE;
+ break;
+ default:
+ GigAdapter->hw.mac.autoneg = 1;
+ break;
+ }
+ }
+}
+
+
+EFI_STATUS
+e1000_FirstTimeInit (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This function is called as early as possible during driver start to ensure the
+ hardware has enough time to autonegotiate when the real SNP device initialize call
+ is made.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ EFI_STATUS
+
+--*/
+{
+ PCI_CONFIG_HEADER *PciConfigHeader;
+ UINT32 *TempBar;
+ UINT8 BarIndex;
+ EFI_STATUS Status;
+ UINT32 ScStatus;
+ UINT32 Reg;
+ UINT16 i;
+
+ DEBUGPRINT(E1000, ("e1000_FirstTimeInit\n"));
+
+ GigAdapter->DriverBusy = FALSE;
+
+ //
+ // Read all the registers from the device's PCI Configuration space
+ //
+ GigAdapter->PciIo->Pci.Read (
+ GigAdapter->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ MAX_PCI_CONFIG_LEN,
+ GigAdapter->PciConfig
+ );
+
+ PciConfigHeader = (PCI_CONFIG_HEADER *) GigAdapter->PciConfig;
+
+ //
+ // Enumerate through the PCI BARs for the device to determine which one is
+ // the IO BAR. Save the index of the BAR into the adapter info structure.
+ //
+ TempBar = &PciConfigHeader->BaseAddressReg_0;
+ for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
+ DEBUGPRINT(E1000, ("BAR = %X\n", *TempBar));
+ if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {
+ //
+ // This is a 64-bit memory bar, skip this and the
+ // next bar as well.
+ //
+ TempBar++;
+ }
+
+ //
+ // Find the IO BAR and save it's number into IoBar
+ //
+ if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {
+ //
+ // Here is the IO Bar - save it to the Gigabit adapter struct.
+ //
+ GigAdapter->IoBarIndex = BarIndex;
+ break;
+ }
+
+ //
+ // Advance the pointer to the next bar in PCI config space
+ //
+ TempBar++;
+ }
+
+ GigAdapter->PciIo->GetLocation (
+ GigAdapter->PciIo,
+ &GigAdapter->Segment,
+ &GigAdapter->Bus,
+ &GigAdapter->Device,
+ &GigAdapter->Function
+ );
+
+ DEBUGPRINT(INIT, ("GigAdapter->IoBarIndex = %X\n", GigAdapter->IoBarIndex));
+ DEBUGPRINT(INIT, ("PCI Command Register = %X\n", PciConfigHeader->Command));
+ DEBUGPRINT(INIT, ("PCI Status Register = %X\n", PciConfigHeader->Status));
+ DEBUGPRINT(INIT, ("PCI VendorID = %X\n", PciConfigHeader->VendorID));
+ DEBUGPRINT(INIT, ("PCI DeviceID = %X\n", PciConfigHeader->DeviceID));
+ DEBUGPRINT(INIT, ("PCI SubVendorID = %X\n", PciConfigHeader->SubVendorID));
+ DEBUGPRINT(INIT, ("PCI SubSystemID = %X\n", PciConfigHeader->SubSystemID));
+ DEBUGPRINT(INIT, ("PCI Segment = %X\n", GigAdapter->Segment));
+ DEBUGPRINT(INIT, ("PCI Bus = %X\n", GigAdapter->Bus));
+ DEBUGPRINT(INIT, ("PCI Device = %X\n", GigAdapter->Device));
+ DEBUGPRINT(INIT, ("PCI Function = %X\n", GigAdapter->Function));
+
+ ZeroMem (GigAdapter->BroadcastNodeAddress, PXE_MAC_LENGTH);
+ SetMem (GigAdapter->BroadcastNodeAddress, PXE_HWADDR_LEN_ETHER, 0xFF);
+
+ //
+ // Initialize all parameters needed for the shared code
+ //
+ GigAdapter->hw.hw_addr = (UINT8*) (UINTN) PciConfigHeader->BaseAddressReg_0;
+ GigAdapter->hw.back = GigAdapter;
+ GigAdapter->hw.vendor_id = PciConfigHeader->VendorID;
+ GigAdapter->hw.device_id = PciConfigHeader->DeviceID;
+ GigAdapter->hw.revision_id = (UINT8) PciConfigHeader->RevID;
+ GigAdapter->hw.subsystem_vendor_id = PciConfigHeader->SubVendorID;
+ GigAdapter->hw.subsystem_device_id = PciConfigHeader->SubSystemID;
+ GigAdapter->hw.revision_id = (UINT8) PciConfigHeader->RevID;
+
+ GigAdapter->hw.mac.autoneg = TRUE;
+ GigAdapter->hw.fc.current_mode = e1000_fc_full;
+ GigAdapter->hw.fc.requested_mode = e1000_fc_full;
+
+ GigAdapter->hw.phy.autoneg_wait_to_complete = FALSE;
+ GigAdapter->hw.phy.reset_disable = FALSE;
+ GigAdapter->hw.phy.autoneg_advertised = E1000_ALL_SPEED_DUPLEX;
+ GigAdapter->hw.phy.autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ //
+ // We need to set the IO bar to zero for the shared code because the EFI PCI protocol
+ // gets the BAR for us.
+ //
+ GigAdapter->hw.io_base = 0;
+
+ //
+ //
+ // This variable is set only to make the flash shared code work on ICH8.
+ // Set to 1 because the flash BAR will always be BAR 1.
+ //
+ GigAdapter->hw.flash_address = (UINT8*) ((UINTN)1);
+
+ if (e1000_set_mac_type (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Unsupported MAC type!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (e1000_setup_init_funcs (&GigAdapter->hw, TRUE) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("e1000_setup_init_funcs failed!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Reg = E1000_READ_REG(&GigAdapter->hw, E1000_CTRL_EXT);
+ if ((Reg & E1000_CTRL_EXT_DRV_LOAD) != 0) {
+ DEBUGPRINT (CRITICAL, ("iSCSI Boot detected on port!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(E1000, ("Calling e1000_get_bus_info\n"));
+ if (e1000_get_bus_info (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Could not read bus information\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(E1000, ("Calling e1000_read_mac_addr\n"));
+ if (e1000_read_mac_addr (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Could not read MAC address\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(INIT, ("MAC Address: "));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(INIT, ("%2x ", GigAdapter->hw.mac.perm_addr[i]));
+ }
+ DEBUGPRINT(INIT, ("\n"));
+
+
+ ScStatus = e1000_reset_hw (&GigAdapter->hw);
+ if (ScStatus != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("e1000_reset_hw returns %d\n", ScStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Now that the structures are in place, we can configure the hardware to use it all.
+ //
+ ScStatus = e1000_init_hw (&GigAdapter->hw);
+ if (ScStatus == E1000_SUCCESS) {
+ DEBUGPRINT(E1000, ("e1000_init_hw success\n"));
+ Status = EFI_SUCCESS;
+ GigAdapter->HwInitialized = TRUE;
+ } else {
+ DEBUGPRINT(CRITICAL, ("Hardware Init failed status=%x\n", ScStatus));
+ GigAdapter->HwInitialized = FALSE;
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ //
+ // According to EAS the transmit and receive head and tail can only be written by
+ // software after a hardware reset and before enabling transmit and receive units.
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDH(0), 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDH(0), 0);
+ GigAdapter->cur_tx_ind = 0;
+ GigAdapter->xmit_done_head = 0;
+ GigAdapter->cur_rx_ind = 0;
+
+#ifndef NO_82571_SUPPORT
+ //
+ // On 82571 based adapters if either port is reset then the MAC address will be loaded into the EEPROM
+ // If the user overrides the default MAC address using the StnAddr command then the 82571 will reset the MAC address
+ // the next time either port is reset. This check resets the MAC address to the default value specified by the user.
+ //
+ if (GigAdapter->hw.mac.type == e1000_82571 && GigAdapter->MacAddrOverride) {
+ DEBUGPRINT(E1000, ("RESETING STATION ADDRESS\n"));
+ e1000_rar_set (&GigAdapter->hw, GigAdapter->hw.mac.addr, 0);
+ }
+#endif
+
+ Reg = E1000_READ_REG(&GigAdapter->hw, E1000_CTRL_EXT);
+ Reg |= E1000_CTRL_EXT_DRV_LOAD;
+ E1000_WRITE_REG(&GigAdapter->hw, E1000_CTRL_EXT, Reg);
+
+ return Status;
+};
+
+
+PXE_STATCODE
+e1000_Inititialize (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Initializes the gigabit adapter, setting up memory addresses, MAC Addresses,
+ Type of card, etc.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ PXE_STATCODE
+
+--*/
+{
+ PXE_STATCODE PxeStatcode;
+
+ DEBUGPRINT(E1000, ("e1000_Inititialize\n"));
+
+ PxeStatcode = PXE_STATCODE_SUCCESS;
+
+ ZeroMem ((VOID *) ((UINTN) GigAdapter->MemoryPtr), MEMORY_NEEDED);
+
+
+ DEBUGWAIT (E1000);
+
+ e1000_SetSpeedDuplex(GigAdapter);
+
+ //
+ // If the hardware has already been initialized then don't bother with a reset
+ // We want to make sure we do not have to restart autonegotiation and two-pair
+ // downshift.
+ //
+ if (GigAdapter->HwInitialized == FALSE) {
+ DEBUGPRINT(E1000, ("Initializing hardware!\n"));
+
+ if (e1000_init_hw (&GigAdapter->hw) == 0) {
+ DEBUGPRINT(E1000, ("e1000_init_hw success\n"));
+ PxeStatcode = PXE_STATCODE_SUCCESS;
+ GigAdapter->HwInitialized = TRUE;
+ } else {
+ DEBUGPRINT(CRITICAL, ("Hardware Init failed\n"));
+ PxeStatcode = PXE_STATCODE_NOT_STARTED;
+ }
+ }
+ else
+ {
+ DEBUGPRINT(E1000, ("Skipping adapter reset\n"));
+ PxeStatcode = PXE_STATCODE_SUCCESS;
+ }
+
+ if (PxeStatcode == PXE_STATCODE_SUCCESS) {
+ e1000_TxRxConfigure (GigAdapter);
+ }
+
+ //
+ // Re-read the MAC address. The CLP configured MAC address is being reset by
+ // hardware to the factory address after init, so we need to reset it here.
+ //
+ if (e1000_read_mac_addr (&GigAdapter->hw) != E1000_SUCCESS) {
+ DEBUGPRINT(CRITICAL, ("Could not read MAC address.\n"));
+ }
+
+ DEBUGWAIT (E1000);
+
+ return PxeStatcode;
+};
+
+VOID
+e1000_TxRxConfigure (
+ GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Initializes the transmit and receive resources for the adapter.
+
+Arguments:
+ GigAdapter - Pointer to adapter structure
+
+Returns:
+ VOID
+
+--*/
+{
+ UINT32 TempReg;
+ UINT32 *MemPtr;
+ UINT16 i;
+
+ DEBUGPRINT(E1000, ("e1000_TxRxConfigure\n"));
+
+ e1000_ReceiveDisable(GigAdapter);
+
+ //
+ // Setup the receive ring
+ //
+ GigAdapter->rx_ring = (E1000_RECEIVE_DESCRIPTOR *) (UINTN)
+ ( (GigAdapter->MemoryPtr + BYTE_ALIGN_64) & 0xFFFFFFFFFFFFFF80 );
+
+ //
+ // Setup TX ring
+ //
+ GigAdapter->tx_ring = (E1000_TRANSMIT_DESCRIPTOR *) ((UINT8 *) GigAdapter->rx_ring + (sizeof (E1000_RECEIVE_DESCRIPTOR) * DEFAULT_RX_DESCRIPTORS));
+ DEBUGPRINT(E1000, (
+ "Rx Ring %x Tx Ring %X RX size %X \n",
+ GigAdapter->rx_ring,
+ GigAdapter->tx_ring,
+ (sizeof (E1000_RECEIVE_DESCRIPTOR) * DEFAULT_RX_DESCRIPTORS)
+ ));
+
+ ZeroMem ((VOID *) GigAdapter->TxBufferUnmappedAddr, DEFAULT_TX_DESCRIPTORS * sizeof(UINT64));
+
+ //
+ // Since we already have the size of the TX Ring, use it to setup the local receive buffers
+ //
+ GigAdapter->local_rx_buffer = (LOCAL_RX_BUFFER *) ((UINT8 *) GigAdapter->tx_ring + (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS));
+ DEBUGPRINT(E1000, (
+ "Tx Ring %x Added %x\n",
+ GigAdapter->tx_ring,
+ ((UINT8 *) GigAdapter->tx_ring + (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS))
+ ));
+ DEBUGPRINT(E1000, (
+ "Local Rx Buffer %X size %X\n",
+ GigAdapter->local_rx_buffer,
+ (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS)
+ ));
+
+ //
+ // now to link the RX Ring to the local buffers
+ //
+ for (i = 0; i < DEFAULT_RX_DESCRIPTORS; i++) {
+ GigAdapter->rx_ring[i].buffer_addr = (UINT64) ((UINTN)GigAdapter->local_rx_buffer[i].RxBuffer);
+ GigAdapter->DebugRxBuffer[i] = GigAdapter->rx_ring[i].buffer_addr;
+ GigAdapter->rx_ring[i].status = E1000_RXD_STAT_IXSM;
+ DEBUGPRINT(E1000, ("Rx Local Buffer %X\n", (GigAdapter->rx_ring[i]).buffer_addr));
+ }
+ //
+ // Setup the RDBA, RDLEN
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDBAL(0), (UINT32) (UINTN) (GigAdapter->rx_ring));
+
+#if 0 //OM
+ //
+ // Set the MemPtr to the high dword of the rx_ring so we can store it in RDBAH0.
+ // Right shifts do not seem to work with the EFI compiler so we do it like this for now.
+ //
+ MemAddr = (UINT64) (UINTN) GigAdapter->rx_ring;
+ MemPtr = &((UINT32) MemAddr);
+ MemPtr++;
+#else
+ MemPtr = (UINT32*)(((UINTN)GigAdapter->rx_ring) >> 32);
+#endif
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDBAH(0), *MemPtr);
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDLEN(0), (sizeof (E1000_RECEIVE_DESCRIPTOR) * DEFAULT_RX_DESCRIPTORS));
+
+ DEBUGPRINT(E1000, ("Rdbal0 %X\n", (UINT32) E1000_READ_REG(&GigAdapter->hw, E1000_RDBAL(0))));
+ DEBUGPRINT(E1000, ("RdBah0 %X\n", (UINT32) E1000_READ_REG(&GigAdapter->hw, E1000_RDBAH(0))));
+ DEBUGPRINT(E1000, ("Rx Ring %X\n", GigAdapter->rx_ring));
+ //
+ // Set the transmit tail equal to the head pointer (we do not want hardware to try to
+ // transmit packets yet).
+ //
+ GigAdapter->cur_tx_ind = (UINT16) E1000_READ_REG (&GigAdapter->hw, E1000_TDH(0));
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDT(0), GigAdapter->cur_tx_ind);
+ GigAdapter->xmit_done_head = GigAdapter->cur_tx_ind;
+
+ GigAdapter->cur_rx_ind = (UINT16) E1000_READ_REG(&GigAdapter->hw, E1000_RDH(0));
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), GigAdapter->cur_rx_ind);
+
+ if (GigAdapter->hw.mac.type != e1000_82575 &&
+ GigAdapter->hw.mac.type != e1000_82576 &&
+ GigAdapter->hw.mac.type != e1000_82580
+ )
+ {
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_SRRCTL (0), E1000_SRRCTL_DESCTYPE_LEGACY);
+
+ e1000_SetRegBits (GigAdapter, E1000_RXDCTL (0), E1000_RXDCTL_QUEUE_ENABLE);
+ i = 0;
+ do {
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RXDCTL (0));
+ i++;
+ if ((TempReg & E1000_RXDCTL_QUEUE_ENABLE) != 0) {
+ DEBUGPRINT (E1000, ("RX queue enabled, after attempt i = %d\n", i));
+ break;
+ }
+
+ DelayInMicroseconds (GigAdapter, 1);
+ } while (i < 1000);
+
+ if (i >= 1000) {
+ DEBUGPRINT (CRITICAL, ("Enable RX queue failed!\n"));
+ }
+ }
+
+
+#ifndef NO_82575_SUPPORT
+ if (GigAdapter->hw.mac.type != e1000_82575 &&
+ GigAdapter->hw.mac.type != e1000_82576 &&
+ GigAdapter->hw.mac.type != e1000_82580
+ )
+#endif
+ {
+ //
+ // Set the software tail pointer just behind head to give hardware the entire ring
+ //
+ if (GigAdapter->cur_rx_ind == 0) {
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), DEFAULT_RX_DESCRIPTORS - 1);
+ } else {
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), GigAdapter->cur_rx_ind - 1);
+ }
+ }
+
+ //
+ // Zero out PSRCTL to use default packet size settings in RCTL
+ //
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_PSRCTL, 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_MRQC, 0);
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDBAL(0), (UINT32) (UINTN) (GigAdapter->tx_ring));
+#if 0 //OM
+ MemAddr = (UINT64) (UINTN) GigAdapter->tx_ring;
+ MemPtr = &((UINT32) MemAddr);
+ MemPtr++;
+#else
+ MemPtr = (UINT32*)(((UINTN)GigAdapter->tx_ring) >> 32);
+#endif
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDBAH(0), *MemPtr);
+ DEBUGPRINT(E1000, ("TdBah0 %X\n", *MemPtr));
+ DEBUGWAIT(E1000);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TDLEN(0), (sizeof (E1000_TRANSMIT_DESCRIPTOR) * DEFAULT_TX_DESCRIPTORS));
+
+ if (GigAdapter->hw.mac.type == e1000_82580) {
+ e1000_SetRegBits (GigAdapter, E1000_TXDCTL (0), E1000_TXDCTL_QUEUE_ENABLE);
+
+ for (i = 0; i < 1000; i++) {
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_TXDCTL (0));
+ if ((TempReg & E1000_TXDCTL_QUEUE_ENABLE) != 0) {
+ DEBUGPRINT (E1000, ("TX queue enabled, after attempt i = %d\n", i));
+ break;
+ }
+
+ DelayInMicroseconds (GigAdapter, 1);
+ }
+ if (i >= 1000) {
+ DEBUGPRINT (CRITICAL, ("Enable TX queue failed!\n"));
+ }
+ }
+
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_TCTL);
+ TempReg = (TempReg | E1000_TCTL_EN | E1000_TCTL_PSP);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_TCTL, TempReg);
+
+ e1000_PciFlush(&GigAdapter->hw);
+}
+
+UINTN
+e1000_SetFilter (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT16 NewFilter,
+ UINT64 cpb,
+ UINT32 cpbsize
+ )
+/*++
+
+Routine Description:
+ Stops the receive unit.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+ NewFilter - A PXE_OPFLAGS bit field indicating what filters to use.
+ cpb -
+Returns:
+ None
+
+--*/
+// GC_TODO: cpbsize - add argument and description to function comment
+{
+ PXE_CPB_RECEIVE_FILTERS *CpbReceiveFilter;
+ UINT32 UpdateRCTL;
+ UINT16 CfgFilter;
+ UINT16 OldFilter;
+ UINT16 MulticastCount;
+ UINT16 i;
+ UINT16 j;
+
+ DEBUGPRINT(E1000, ("e1000_SetFilter\n"));
+
+ CpbReceiveFilter = (PXE_CPB_RECEIVE_FILTERS *) (UINTN) cpb;
+ OldFilter = GigAdapter->Rx_Filter;
+
+ //
+ // only these bits need a change in the configuration
+ // actually change in bcast requires configure but we ignore that change
+ //
+ CfgFilter = PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
+ PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST |
+ PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+
+ if ((OldFilter & CfgFilter) != (NewFilter & CfgFilter)) {
+ //
+ // Put the card into the proper mode...
+ //
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ e1000_ReceiveDisable (GigAdapter);
+
+ }
+
+ UpdateRCTL = E1000_READ_REG (&GigAdapter->hw, E1000_RCTL);
+
+ if (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS) {
+ //
+ // add the UPE bit to the variable to be written to the RCTL
+ //
+ UpdateRCTL |= E1000_RCTL_UPE;
+ }
+
+ if (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) {
+ //
+ // add the BAM bit to the variable to be written to the RCTL
+ //
+ UpdateRCTL |= E1000_RCTL_BAM;
+ }
+
+ if (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) {
+ //
+ // add the MPE bit to the variable to be written to the RCTL
+ //
+ UpdateRCTL |= E1000_RCTL_MPE;
+ }
+
+ UpdateRCTL |= E1000_RCTL_BAM;
+ GigAdapter->Rx_Filter = NewFilter;
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, UpdateRCTL);
+ }
+
+ //
+ // check if mcast setting changed
+ //
+ if ((
+ (NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=
+ (OldFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST)
+ ) ||
+ (CpbReceiveFilter != NULL)
+ ) {
+
+
+ //
+ // copy the list
+ //
+ if (CpbReceiveFilter != NULL) {
+ UINT8 McAddrList[MAX_MCAST_ADDRESS_CNT][ETH_ADDR_LEN];
+
+ MulticastCount = GigAdapter->McastList.Length = (UINT16) (cpbsize / PXE_MAC_LENGTH);
+ DEBUGPRINT(E1000, ("E1000: MulticastCount=%d\n", MulticastCount));
+
+ ZeroMem(GigAdapter->McastList.McAddr, MAX_MCAST_ADDRESS_CNT*PXE_MAC_LENGTH);
+ CopyMem(
+ GigAdapter->McastList.McAddr,
+ (VOID*)(UINTN) CpbReceiveFilter->MCastList,
+ cpbsize
+ );
+
+ //
+ // Copy the multicast address list into a form that can be accepted by the
+ // shared code.
+ //
+ for (i = 0; (i < MulticastCount && i < MAX_MCAST_ADDRESS_CNT); i++) {
+ DEBUGPRINT(E1000, ("E1000: MulticastAddress %d:", i));
+ for (j = 0; j < ETH_ADDR_LEN; j++) {
+ McAddrList[i][j] = GigAdapter->McastList.McAddr[i][j];
+ DEBUGPRINT(E1000, ("%02x", CpbReceiveFilter->MCastList[i][j]));
+ }
+ DEBUGPRINT(E1000, ("\n"));
+ }
+
+ e1000_BlockIt (GigAdapter, TRUE);
+ e1000_update_mc_addr_list (
+ &GigAdapter->hw,
+ &McAddrList[0][0],
+ MulticastCount
+ );
+ e1000_BlockIt (GigAdapter, FALSE);
+
+ }
+
+ //
+ // are we setting the list or resetting??
+ //
+ if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ DEBUGPRINT(E1000, ("E1000: Creating new multicast list.\n"));
+ GigAdapter->Rx_Filter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ } else {
+ DEBUGPRINT(E1000, ("E1000: Disabling multicast list.\n"));
+ GigAdapter->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
+ }
+
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ e1000_ReceiveDisable (GigAdapter);
+ }
+ }
+
+ if (NewFilter != 0) {
+ //
+ // Enable unicast and start the RU
+ //
+ GigAdapter->Rx_Filter |= (NewFilter | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST);
+ e1000_ReceiveEnable (GigAdapter);
+ } else {
+ //
+ // may be disabling everything!
+ //
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ e1000_ReceiveDisable (GigAdapter);
+ }
+
+ GigAdapter->Rx_Filter = NewFilter;
+ }
+
+ return 0;
+};
+
+VOID
+e1000_ReceiveDisable (
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Stops the receive unit.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ E1000_RECEIVE_DESCRIPTOR *ReceiveDesc;
+ UINT32 TempReg;
+ UINTN i;
+ UINT32 RxdCtl;
+
+
+ DEBUGPRINT(E1000, ("e1000_ReceiveDisable\n"));
+
+ if (GigAdapter->ReceiveStarted == FALSE) {
+ DEBUGPRINT(CRITICAL, ("Receive unit already disabled!\n"));
+ return;
+ }
+
+ if (GigAdapter->hw.mac.type == e1000_82571) {
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RCTL);
+ TempReg &= ~E1000_RCTL_EN;
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, TempReg);
+ }
+
+ //
+ // On I82575 the ring must be reset when the recieve unit is disabled.
+ //
+ if (GigAdapter->hw.mac.type == e1000_82575
+ || GigAdapter->hw.mac.type == e1000_82576
+ || GigAdapter->hw.mac.type == e1000_82580
+ )
+ {
+ e1000_ClearRegBits(GigAdapter, E1000_RXDCTL(0), E1000_RXDCTL_QUEUE_ENABLE);
+ do {
+ gBS->Stall(1);
+ RxdCtl = E1000_READ_REG (&GigAdapter->hw, E1000_RXDCTL(0));
+ } while((RxdCtl & E1000_RXDCTL_QUEUE_ENABLE) != 0);
+ DEBUGPRINT (E1000, ("Receiver Disabled\n"));
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDH(0), 0);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), 0);
+ GigAdapter->cur_rx_ind = 0;
+ }
+
+ if (GigAdapter->hw.mac.type == e1000_82575
+ || GigAdapter->hw.mac.type == e1000_82576
+ || GigAdapter->hw.mac.type == e1000_82580
+ || GigAdapter->hw.mac.type == e1000_82571) {
+ // Clean up any left over packets
+ //
+ ReceiveDesc = GigAdapter->rx_ring;
+ for (i = 0; i < DEFAULT_RX_DESCRIPTORS; i++) {
+ ReceiveDesc->length = 0;
+ ReceiveDesc->status = 0;
+ ReceiveDesc->errors = 0;
+ ReceiveDesc++;
+ }
+ }
+
+ GigAdapter->ReceiveStarted = FALSE;
+ return ;
+}
+
+VOID
+e1000_ReceiveEnable (
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ Starts the receive unit.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ None
+
+--*/
+{
+ UINT32 TempReg;
+
+ DEBUGPRINT(E1000, ("e1000_ReceiveEnable\n"));
+
+ if (GigAdapter->ReceiveStarted == TRUE) {
+ DEBUGPRINT(CRITICAL, ("Receive unit already started!\n"));
+ return;
+ }
+
+ GigAdapter->Int_Status = 0;
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RCTL);
+ TempReg |= (E1000_RCTL_EN | E1000_RCTL_BAM);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RCTL, TempReg);
+
+ //
+ // Move the tail descriptor to begin receives on I82575
+ //
+#ifndef NO_82575_SUPPORT
+ if (GigAdapter->hw.mac.type == e1000_82575
+#ifndef NO_82576_SUPPORT
+ || GigAdapter->hw.mac.type == e1000_82576
+ || GigAdapter->hw.mac.type == e1000_82580
+#endif
+ ) {
+ if (GigAdapter->hw.mac.type == e1000_82575) {
+ e1000_rx_fifo_flush_82575(&GigAdapter->hw);
+ }
+
+ e1000_SetRegBits(GigAdapter, E1000_RXDCTL(0), E1000_RXDCTL_QUEUE_ENABLE);
+ do {
+ gBS->Stall(1);
+ TempReg = E1000_READ_REG (&GigAdapter->hw, E1000_RXDCTL(0));
+ } while((TempReg & E1000_RXDCTL_QUEUE_ENABLE) == 0);
+
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDT(0), DEFAULT_RX_DESCRIPTORS - 1);
+ E1000_WRITE_REG (&GigAdapter->hw, E1000_RDH(0), 0);
+ GigAdapter->cur_rx_ind = (UINT16) E1000_READ_REG(&GigAdapter->hw, E1000_RDH(0));
+
+ }
+#endif
+
+ GigAdapter->ReceiveStarted = TRUE;
+}
+
+BOOLEAN
+e1000_WaitForAutoNeg (
+ IN GIG_DRIVER_DATA *GigAdapter
+ )
+/*++
+
+Routine Description:
+ This routine blocks until auto-negotiation completes or times out (after 4.5 seconds).
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ TRUE - Auto-negotiation completed successfully,
+ FALSE - Auto-negotiation did not complete (i.e., timed out)
+
+--*/
+{
+ BOOLEAN AutoNegComplete;
+ UINTN i;
+ UINT16 Reg;
+ UINT32 Status;
+
+ AutoNegComplete = FALSE;
+ Status = 0;
+
+ DEBUGPRINT(E1000, ("e1000_WaitForAutoNeg\n"));
+
+ if (!GigAdapter->CableDetect) {
+ //
+ // Caller specified not to detect cable, so we return TRUE.
+ //
+ DEBUGPRINT(E1000, ("Cable detection disabled.\n"));
+ return TRUE;
+ }
+
+ //
+ // The shared code will wait for autonegotiation, so if link is not up by the time
+ // we reach this function then either we have no link, or are trying to two-pair
+ // downshift. In the case of a two pair downshift we will wait up to 30 seconds for
+ // link to come back up.
+ //
+ for (i=0; i<500; i++) {
+ Status = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ if ((Status & E1000_STATUS_LU) != 0) {
+ DEBUGPRINT(E1000, ("Successfully established link on retry %d\n", i));
+ return TRUE;
+ }
+ DelayInMilliseconds (10);
+ }
+ DEBUGPRINT(E1000, ("Link up not detected\n"));
+
+ if (GigAdapter->hw.phy.type == e1000_phy_igp) {
+ DEBUGPRINT(E1000, ("IGP PHY\n"));
+ //
+ // Workaround: read the PHY register up to three times to see if it comes up
+ // if not then we exit.
+ //
+ for (i = 5; i != 0; i--) {
+ e1000_read_phy_reg (&GigAdapter->hw, PHY_1000T_STATUS, &Reg);
+ if (Reg != 0) {
+ AutoNegComplete = e1000_DownShift (GigAdapter);
+ break;
+ }
+ DelayInMilliseconds (1000);
+ Status = E1000_READ_REG (&GigAdapter->hw, E1000_STATUS);
+ if ((Status & E1000_STATUS_LU) != 0) {
+ AutoNegComplete = TRUE;
+ break;
+ }
+ }
+
+ } else if (GigAdapter->hw.phy.type == e1000_phy_m88){
+
+ //
+ // We are on a Marvel PHY that supports 2-pair downshift
+ // Check the real time link status bit to see if there is actually a cable connected
+ // If so then we will attempt to downshift, if not then we will report failure
+ // Wait for up to 30 seconds for real time link detected
+ //
+ for (i = 3000; i != 0; i--) {
+ DEBUGPRINT(E1000, ("."));
+ e1000_read_phy_reg (&GigAdapter->hw, M88E1000_PHY_SPEC_STATUS, &Reg);
+ if ((Reg & M88E1000_PSSR_LINK) != 0) {
+ DEBUGPRINT(E1000, ("e1000_DownShift - Real Time Link Detected\n"));
+ AutoNegComplete = e1000_DownShift (GigAdapter);
+ break;
+ }
+
+ DelayInMilliseconds (10);
+ }
+ }
+
+ DEBUGPRINT(E1000, ("Return %d\n", AutoNegComplete));
+ DEBUGWAIT (E1000);
+ return AutoNegComplete;
+}
+
+UINT16
+e1000_FreeTxBuffers(
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 NumEntries,
+ OUT UINT64 *TxBuffer
+ )
+ /*++
+
+Routine Description:
+ Free TX buffers that have been transmitted by the hardware.
+
+Arguments:
+ GigAdapter - Pointer to the NIC data structure information which the UNDI driver is layering on.
+ NumEntries - Number of entries in the array which can be freed.
+ TxBuffer - Array to pass back free TX buffer
+
+Returns:
+ Number of TX buffers written.
+
+--*/
+
+{
+ E1000_TRANSMIT_DESCRIPTOR *TransmitDescriptor;
+ UINT32 Tdh;
+ UINT16 i;
+
+ DEBUGPRINT(E1000, ("e1000_FreeTxBuffers\n"));
+
+ //
+ // Read the TX head posistion so we can see which packets have been sent out on the wire.
+ //
+ Tdh = E1000_READ_REG (&GigAdapter->hw, E1000_TDH(0));
+ DEBUGPRINT(E1000, ("TDH = %d, GigAdapter->xmit_done_head = %d\n", Tdh, GigAdapter->xmit_done_head));
+
+ //
+ // If Tdh does not equal xmit_done_head then we will fill all the transmitted buffer
+ // addresses between Tdh and xmit_done_head into the completed buffers array
+ //
+ i = 0;
+ do {
+ if (i >= NumEntries) {
+ DEBUGPRINT(E1000, ("Exceeded number of DB entries, i=%d, NumEntries=%d\n", i, NumEntries));
+ break;
+ }
+
+ TransmitDescriptor = &GigAdapter->tx_ring[GigAdapter->xmit_done_head];
+ if ((TransmitDescriptor->upper.fields.status & E1000_TXD_STAT_DD) != 0) {
+
+ if (GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head] == 0) {
+ DEBUGPRINT(CRITICAL, ("ERROR: TX buffer complete without being marked used!\n"));
+ break;
+ }
+
+ DEBUGPRINT(E1000, ("Writing buffer address %d, %x\n", i, TxBuffer[i]));
+ TxBuffer[i] = GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head];
+ i++;
+
+ e1000_UnMapMem (
+ GigAdapter,
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head],
+ TransmitDescriptor->lower.flags.length,
+ TransmitDescriptor->buffer_addr
+ );
+ GigAdapter->TxBufferUnmappedAddr[GigAdapter->xmit_done_head] = 0;
+ TransmitDescriptor->upper.fields.status = 0;
+
+ GigAdapter->xmit_done_head++;
+ if (GigAdapter->xmit_done_head >= DEFAULT_TX_DESCRIPTORS) {
+ GigAdapter->xmit_done_head = 0;
+ }
+ } else {
+ DEBUGPRINT(E1000, ("TX Descriptor %d not done\n", GigAdapter->xmit_done_head));
+ break;
+ }
+ } while (Tdh != GigAdapter->xmit_done_head);
+ return i;
+}
+
+UINT32
+e1000_SetRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ )
+/*++
+
+Routine Description:
+ Sets specified bits in a device register
+
+Arguments:
+ GigAdapter - Pointer to the device instance
+ Register - Register to write
+ BitMask - Bits to set
+
+Returns:
+ Data - Returns the value read from the PCI register.
+
+--*/
+{
+ UINT32 TempReg;
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, Register);
+ TempReg |= BitMask;
+ E1000_WRITE_REG (&GigAdapter->hw, Register, TempReg);
+
+ return TempReg;
+}
+
+UINT32
+e1000_ClearRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ )
+/*++
+
+Routine Description:
+ Clears specified bits in a device register
+
+Arguments:
+ GigAdapter - Pointer to the device instance
+ Register - Register to write
+ BitMask - Bits to clear
+
+Returns:
+ Data - Returns the value read from the PCI register.
+
+--*/
+
+{
+ UINT32 TempReg;
+
+ TempReg = E1000_READ_REG (&GigAdapter->hw, Register);
+ TempReg &= ~BitMask;
+ E1000_WRITE_REG (&GigAdapter->hw, Register, TempReg);
+
+ return TempReg;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h
new file mode 100755
index 0000000..3d88093
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000.h
@@ -0,0 +1,680 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+#define MAJORVERSION 4
+#define MINORVERSION 4
+#define BUILDNUMBER 6
+
+
+#include "e1000_api.h"
+#include "vlan.h"
+#include "hii.h"
+#include "FirmwareManagement.h"
+#include "startstop.h"
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DriverSupportedEfiVersion.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/NetworkInterfaceIdentifier.h>
+#include <Protocol/PciIo.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+//
+// Debug levels for driver DEBUG_PRINT statements
+//
+#define NONE 0
+#define INIT (1 << 0)
+#define DECODE (1 << 1)
+#define E1000 (1 << 2)
+#define SHARED (1 << 3)
+#define DIAG (1 << 4)
+#define CFG (1 << 5)
+#define IO (1 << 6)
+#define VLAN (1 << 7)
+#define CRITICAL (1 << 8)
+#define CLP (1 << 9)
+#define TX (1 << 10)
+#define RX (1 << 11)
+#define HW (1 << 12)
+#define HII (1 << 13)
+#define IMAGE (1 << 14)
+#define WAIT (1 << 15)
+
+#ifndef DBG_LVL
+#define DBG_LVL (NONE)
+#endif
+
+#define MAX_NIC_INTERFACES 256
+
+//
+// Device and Vendor IDs
+//
+#define INTEL_VENDOR_ID 0x8086
+#define E1000_VENDOR_ID INTEL_VENDOR_ID
+#define E1000_SUBVENDOR_ID 0x8086
+
+
+#define TWO_PAIR_DOWNSHIFT_TIMEOUT 30
+
+//
+// PCI Base Address Register Bits
+//
+#define PCI_BAR_IO_MASK 0x00000003
+#define PCI_BAR_IO_MODE 0x00000001
+
+#define PCI_BAR_MEM_MASK 0x0000000F
+#define PCI_BAR_MEM_MODE 0x00000000
+#define PCI_BAR_MEM_64BIT 0x00000004
+
+//
+// Bit fields for the PCI command register
+//
+#define PCI_COMMAND_MWI 0x10
+#define PCI_COMMAND_MASTER 0x04
+#define PCI_COMMAND_MEM 0x02
+#define PCI_COMMAND_IO 0x01
+#define PCI_COMMAND 0x04
+#define PCI_LATENCY_TIMER 0x0D
+
+//
+// PCI Capability IDs
+//
+#define PCI_EX_CAP_ID 0x10
+#define PCI_CAP_PTR_ENDPOINT 0x00
+
+//
+// PCI Configuration Space Register Offsets
+//
+#define PCI_CAP_PTR 0x34 // PCI Capabilities pointer
+
+//
+// Register offsets for IO Mode read/write
+//
+#define IO_MODE_IOADDR 0x00
+#define IO_MODE_IODATA 0x04
+
+#define ETHER_MAC_ADDR_LEN 6
+
+//
+// PBA constants
+//
+#define E1000_PBA_16K 0x0010 // 16KB, default TX allocation
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030 // 48KB, default RX allocation
+
+
+//
+// EEPROM Word Defines:
+//
+#define INIT_CONTROL_WORD_2 0x0F
+
+//
+// Initialization Control Word 2 indicates flash size
+// 000: 64KB, 001: 128KB, 010: 256KB, 011: 512KB, 100: 1MB, 101: 2MB, 110: 4MB, 111: 8MB
+// The Flash size impacts the requested memory space for the Flash and expansion ROM BARs.
+//
+#define FLASH_SIZE_MASK 0x0700
+#define FLASH_SIZE_SHIFT 8
+
+//
+// "Main Setup Options Word"
+//
+#define SETUP_OPTIONS_WORD 0x30
+#define SETUP_OPTIONS_WORD_LANB 0x34
+#define SETUP_OPTIONS_WORD_LANC 0x38
+#define SETUP_OPTIONS_WORD_LAND 0x3A
+
+#define FDP_FULL_DUPLEX_BIT 0x1000
+#define FSP_100MBS 0x0800
+#define FSP_10MBS 0x0400
+#define FSP_AUTONEG 0x0000
+#define FSP_MASK 0x0C00
+#define DISPLAY_SETUP_MESSAGE 0x0100
+
+// UEFI 2.3 spec (Errata B) add following new definitions to UNDI interface:
+
+//
+// Return current media status.
+//
+#define PXE_OPFLAGS_GET_MEDIA_STATUS 0x0004
+
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK 0x0002
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED 0x0000
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED 0x0002
+
+//
+// This flag is set if there is no media detected.
+//
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA 0x0040
+
+//
+// "Configuration Customization Word"
+//
+#define CONFIG_CUSTOM_WORD 0x31
+#define CONFIG_CUSTOM_WORD_LANB 0x35
+#define CONFIG_CUSTOM_WORD_LANC 0x39
+#define CONFIG_CUSTOM_WORD_LAND 0x3B
+
+#define SIG 0x4000
+#define SIG_MASK 0xC000
+
+#define EEPROM_CAPABILITIES_WORD 0x33
+#define EEPROM_CAPABILITIES_SIG 0x4000
+#define EEPROM_CAPABILITIES_SIG_MASK 0xC000
+#define EEPROM_BC_BIT 0x0001
+#define EEPROM_UNDI_BIT 0x0002
+#define EEPROM_PXE_BIT (EEPROM_BC_BIT | EEPROM_UNDI_BIT)
+#define EEPROM_RPL_BIT 0x0004
+#define EEPROM_EFI_BIT 0x0008
+#define EEPROM_FCOE_BIT 0x0020
+#define EEPROM_ISCSI_BIT 0x0010
+#define EEPROM_LEGACY_BIT (EEPROM_PXE_BIT | EEPROM_ISCSI_BIT)
+#define EEPROM_SMCLP_BIT 0x0040
+#define EEPROM_TYPE_MASK (EEPROM_BC_BIT | EEPROM_UNDI_BIT | EEPROM_EFI_BIT | EEPROM_ISCSI_BIT)
+#define EEPROM_ALL_BITS (EEPROM_TYPE_MASK | EEPROM_RPL_BIT)
+
+#define COMPATIBILITY_WORD 0x03
+#define COMPATABILITY_LOM_BIT 0x0800 // bit 11
+//
+// UNDI_CALL_TABLE.state can have the following values
+//
+#define DONT_CHECK -1
+#define ANY_STATE -1
+#define MUST_BE_STARTED 1
+#define MUST_BE_INITIALIZED 2
+
+#define EFI_OPTIONAL_PTR 0x00000001
+#define EFI_INTERNAL_PTR 0x00000004 // Pointer to internal runtime data
+#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
+
+#define GIG_UNDI_DEV_SIGNATURE SIGNATURE_32('P','R','0','g')
+#define GIG_UNDI_PRIVATE_DATA_FROM_THIS(a) CR(a, GIG_UNDI_PRIVATE_DATA, NIIProtocol_31, GIG_UNDI_DEV_SIGNATURE)
+#define GIG_UNDI_PRIVATE_DATA_FROM_DEVICE_PATH(a) \
+ CR(a, GIG_UNDI_PRIVATE_DATA, Undi32BaseDevPath, GIG_UNDI_DEV_SIGNATURE)
+#define GIG_UNDI_PRIVATE_DATA_FROM_FIRMWARE_MANAGEMENT(a) \
+ CR(a, GIG_UNDI_PRIVATE_DATA, FirmwareManagement, GIG_UNDI_DEV_SIGNATURE)
+#define GIG_UNDI_PRIVATE_DATA_FROM_DRIVER_STOP(a) \
+ CR(a, GIG_UNDI_PRIVATE_DATA, DriverStop, GIG_UNDI_DEV_SIGNATURE)
+
+//
+// Macro to compare MAC addresses. Returns TRUE if the MAC addresses match.
+// a and b must be UINT8 pointers to the first byte of MAC address.
+//
+#ifdef EFI64
+#define E1000_COMPARE_MAC(a, b) \
+ ( (a[0]==b[0]) && (a[1]==b[1]) && (a[2]==b[2]) && (a[3]==b[3]) && (a[4]==b[4]) && (a[5]==b[5]))
+#else
+#define E1000_COMPARE_MAC(a, b) \
+ ( *((UINT32*) a) == *((UINT32*) b) ) && ( *((UINT16*) (a+4)) == *((UINT16*) (b+4)) )
+#endif
+
+#ifdef EFI64
+#define E1000_COPY_MAC(a, b) \
+ a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; a[3]=b[3]; a[4]=b[4]; a[5]=b[5];
+#else
+#define E1000_COPY_MAC(a, b) \
+ *((UINT32*) a) = *((UINT32*) b); *((UINT16*) (a+4)) = *((UINT16*) (b+4))
+#endif
+
+
+typedef struct {
+ UINT16 cpbsize;
+ UINT16 dbsize;
+ UINT16 opflags;
+ UINT16 state;
+ void (*api_ptr)();
+} UNDI_CALL_TABLE;
+
+typedef struct {
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *InterfacePointer;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathPointer;
+} NII_ENTRY;
+
+typedef struct NII_CONFIG_ENTRY {
+ UINT32 NumEntries;
+ UINT32 Reserved;
+ struct NII_CONFIG_ENTRY *NextLink;
+ NII_ENTRY NiiEntry[MAX_NIC_INTERFACES];
+} NII_TABLE;
+
+typedef struct _EFI_PRO1000_COM_PROTOCOL {
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol_31;
+} EFI_PRO1000_COM_PROTOCOL;
+
+typedef VOID (*ptr)(VOID);
+typedef VOID (*bsptr_30)(UINTN);
+typedef VOID (*virtphys_30)(UINT64, UINT64);
+typedef VOID (*block_30)(UINT32);
+typedef VOID (*mem_io_30)(UINT8, UINT8, UINT64, UINT64);
+
+typedef VOID (*bsptr)(UINT64, UINTN);
+typedef VOID (*virtphys)(UINT64, UINT64, UINT64);
+typedef VOID (*block)(UINT64, UINT32);
+typedef VOID (*mem_io)(UINT64, UINT8, UINT8, UINT64, UINT64);
+
+typedef VOID (*map_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);
+typedef VOID (*unmap_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);
+typedef VOID (*sync_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);
+
+//
+// Global Variable
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gGigUndiDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gGigUndiComponentName;
+EFI_TIME gTime;
+
+#pragma pack(1)
+typedef struct eth {
+ UINT8 dest_addr[PXE_HWADDR_LEN_ETHER];
+ UINT8 src_addr[PXE_HWADDR_LEN_ETHER];
+ UINT16 type;
+} ETHER_HEADER;
+
+#pragma pack(1)
+typedef struct PCI_CONFIG_HEADER_s {
+ UINT16 VendorID;
+ UINT16 DeviceID;
+ UINT16 Command;
+ UINT16 Status;
+ UINT16 RevID;
+ UINT16 ClassID;
+ UINT8 CacheLineSize;
+ UINT8 LatencyTimer;
+ UINT8 HeaderType;
+ UINT8 BIST;
+ UINT32 BaseAddressReg_0;
+ UINT32 BaseAddressReg_1;
+ UINT32 BaseAddressReg_2;
+ UINT32 BaseAddressReg_3;
+ UINT32 BaseAddressReg_4;
+ UINT32 BaseAddressReg_5;
+ UINT32 CardBusCISPtr;
+ UINT16 SubVendorID;
+ UINT16 SubSystemID;
+ UINT32 ExpansionROMBaseAddr;
+ UINT8 CapabilitiesPtr;
+ UINT8 reserved1;
+ UINT16 Reserved2;
+ UINT32 Reserved3;
+ UINT8 int_line;
+ UINT8 int_pin;
+ UINT8 Min_gnt;
+ UINT8 Max_lat;
+} PCI_CONFIG_HEADER;
+#pragma pack()
+
+typedef struct e1000_rx_desc E1000_RECEIVE_DESCRIPTOR;
+
+
+//
+// TX Buffer size including crc and padding
+//
+#define RX_BUFFER_SIZE 2048
+
+#define DEFAULT_RX_DESCRIPTORS 8
+#define DEFAULT_TX_DESCRIPTORS 8
+
+//
+// Macro to conver byte memory requirement into pages
+//
+#define UNDI_MEM_PAGES(x) (((x) - 1) / 4096 + 1)
+
+#pragma pack(1)
+typedef struct _LocalReceiveBuffer {
+ UINT8 RxBuffer[RX_BUFFER_SIZE - (sizeof(UINT64))];
+ UINT64 BufferUsed;
+} LOCAL_RX_BUFFER, *PLOCAL_RX_BUFFER;
+#pragma pack()
+
+typedef struct e1000_tx_desc E1000_TRANSMIT_DESCRIPTOR;
+
+//
+// If using a serial flash, this struct will be filled with the
+// proper offsets, since I82540 and I82541 use different registers
+// for Flash manipulation.
+//
+typedef struct _SERIAL_FLASH_OFFSETS
+{
+ struct
+ {
+ UINT32 RegisterOffset;
+ UINT32 Sck;
+ UINT32 Cs;
+ } FlashClockRegister;
+ struct
+ {
+ UINT32 RegisterOffset;
+ UINT32 Si;
+ UINT32 So;
+ UINT8 SoPosition;
+ } FlashDataRegister;
+
+} SERIAL_FLASH_OFFSETS;
+
+
+typedef struct _DRIVER_DATA_ {
+ UINT16 State; // stopped, started or initialized
+
+ struct e1000_hw hw;
+ struct e1000_hw_stats stats;
+
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+
+ SERIAL_FLASH_OFFSETS SerialFlashOffsets;
+
+ UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
+
+ UINT32 PciConfig[MAX_PCI_CONFIG_LEN];
+ UINT32 NVData[MAX_EEPROM_LEN];
+
+ UINTN HwInitialized;
+ UINTN DriverBusy;
+ UINT16 LinkSpeed; // requested (forced) link speed
+ UINT8 DuplexMode; // requested duplex
+ UINT8 CableDetect; // 1 to detect and 0 not to detect the cable
+ UINT8 LoopBack;
+
+ UINT16 SetupWord;
+ UINT16 BackupSetupWord;
+ UINT16 CustomConfigWord;
+
+ UINT64 Unique_ID;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ VOID (*Delay)(UINT64, UINTN);
+ VOID (*Virt2Phys)(UINT64 unq_id, UINT64 virtual_addr, UINT64 physical_ptr);
+ VOID (*Block)(UINT64 unq_id, UINT32 enable);
+ VOID (*MemIo)(UINT64 unq_id, UINT8 read_write, UINT8 len, UINT64 port,
+ UINT64 buf_addr);
+ VOID (*MapMem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ UINT32 Direction, UINT64 mapped_addr);
+ VOID (*UnMapMem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ UINT32 Direction, UINT64 mapped_addr);
+ VOID (*SyncMem)(UINT64 unq_id, UINT64 virtual_addr,
+ UINT32 size, UINT32 Direction, UINT64 mapped_addr);
+
+ UINT8 IoBarIndex;
+
+ UINT64 MemoryPtr;
+ UINT32 MemoryLength;
+
+ UINT16 Rx_Filter;
+ UINT16 int_mask;
+ UINT16 Int_Status;
+
+ struct _McastList{
+ UINT16 Length;
+ UINT8 McAddr[MAX_MCAST_ADDRESS_CNT][PXE_MAC_LENGTH]; // 8*32 is the size
+ } McastList;
+
+ UINT16 cur_rx_ind;
+ UINT16 cur_tx_ind;
+ UINT8 ReceiveStarted;
+ E1000_RECEIVE_DESCRIPTOR *rx_ring;
+ E1000_TRANSMIT_DESCRIPTOR *tx_ring;
+ LOCAL_RX_BUFFER *local_rx_buffer;
+ UINT16 xmit_done_head;
+ UINT64 TxBufferUnmappedAddr[DEFAULT_TX_DESCRIPTORS];
+ BOOLEAN MacAddrOverride;
+ UINT64 DebugRxBuffer[DEFAULT_RX_DESCRIPTORS];
+ BOOLEAN VlanEnable;
+ UINT16 VlanTag;
+ BOOLEAN FlashWriteInProgress;
+
+ UINTN VersionFlag; // Indicates UNDI version 3.0 or 3.1
+} GIG_DRIVER_DATA, *PADAPTER_STRUCT;
+
+typedef struct {
+ UINTN Signature;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NIIProtocol_31;
+ EFI_PRO1000_COM_PROTOCOL EfiPro1000Com;
+ EFI_HANDLE ControllerHandle;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *Undi32BaseDevPath;
+ EFI_DEVICE_PATH_PROTOCOL *Undi32DevPath;
+ GIG_DRIVER_DATA NicInfo;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ CHAR16 *Brand;
+
+ // HII Configuration
+ EFI_HII_HANDLE HiiHandle;
+ GIG_DRIVER_CONFIGURATION Configuration;
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ EFI_GUID HiiFormGuid;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_DRIVER_STOP_PROTOCOL DriverStop;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL FirmwareManagement;
+
+} GIG_UNDI_PRIVATE_DATA;
+
+struct GIG_UNDI_DMA_RESOURCES {
+ E1000_RECEIVE_DESCRIPTOR rx_ring[DEFAULT_RX_DESCRIPTORS];
+ E1000_TRANSMIT_DESCRIPTOR tx_ring[DEFAULT_TX_DESCRIPTORS];
+ LOCAL_RX_BUFFER rx_buffer[DEFAULT_RX_DESCRIPTORS];
+};
+
+#define BYTE_ALIGN_64 0x7F
+
+//
+// We need enough space to store TX descriptors, RX descriptors,
+// RX buffers, and enough left over to do a 64 byte alignment.
+//
+#define MEMORY_NEEDED (sizeof(struct GIG_UNDI_DMA_RESOURCES)+BYTE_ALIGN_64)
+
+#define FOUR_GIGABYTE (UINT64)0x100000000
+
+//
+// functions defined in init.c
+//
+
+VOID
+GetUndiControllerName (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+//
+// functions defined in decode.c
+//
+VOID e1000_UNDI_GetState();
+VOID e1000_UNDI_Start();
+VOID e1000_UNDI_Stop();
+VOID e1000_UNDI_GetInitInfo();
+VOID e1000_UNDI_GetConfigInfo();
+VOID e1000_UNDI_Initialize();
+VOID e1000_UNDI_Reset();
+VOID e1000_UNDI_Shutdown();
+VOID e1000_UNDI_Interrupt();
+VOID e1000_UNDI_RecFilter();
+VOID e1000_UNDI_StnAddr();
+VOID e1000_UNDI_Statistics();
+VOID e1000_UNDI_ip2mac();
+VOID e1000_UNDI_NVData();
+VOID e1000_UNDI_Status();
+
+VOID
+e1000_UNDI_FillHeader (
+ IN PXE_CDB *CdbPtr,
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+VOID e1000_UNDI_Transmit();
+VOID e1000_UNDI_Receive();
+
+VOID e1000_UNDI_APIEntry();
+
+VOID WaitForEnter(VOID);
+
+PXE_STATCODE
+e1000_Inititialize (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+EFI_STATUS
+e1000_FirstTimeInit (
+ GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+VOID
+e1000_ReceiveEnable (
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+VOID
+e1000_ReceiveDisable (
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+UINTN
+e1000_Transmit (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ UINT64 cpb,
+ UINT16 opflags
+ );
+
+UINTN
+e1000_Receive (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ UINT64 cpb,
+ UINT64 db
+ );
+
+UINTN
+e1000_Reset (
+ GIG_DRIVER_DATA *GigAdapterInfo,
+ UINT16 OpFlags
+ );
+
+UINTN
+e1000_Shutdown (
+ GIG_DRIVER_DATA *GigAdapter
+ );
+
+
+UINT16
+e1000_FreeTxBuffers (
+ IN GIG_DRIVER_DATA *GigAdapter,
+ IN UINT16 NumEntries,
+ OUT UINT64 *TxBuffer
+ );
+
+VOID
+EepromMacAddressDefault(
+ IN GIG_DRIVER_DATA *GigAdapter
+ );
+
+VOID
+e1000_MemCopy (
+ IN UINT8* Dest,
+ IN UINT8* Source,
+ IN UINT32 Count
+ );
+
+UINT32
+e1000_SetRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ );
+
+UINT32
+e1000_ClearRegBits (
+ GIG_DRIVER_DATA *GigAdapter,
+ UINT32 Register,
+ UINT32 BitMask
+ );
+
+//
+// This is the Macro Section
+//
+#if DBG_LVL
+#define DEBUGPRINT(lvl, msg) \
+ if ((DBG_LVL & lvl) != 0) Aprint msg;
+#define DEBUGWAIT(lvl) \
+ if (((DBG_LVL | WAIT) & lvl) == (DBG_LVL | WAIT)) WaitForEnter();
+#define DEBUGPRINTTIME(lvl) \
+ if ((DBG_LVL & lvl) != 0) gRT->GetTime (&gTime, NULL);; \
+ DEBUGPRINT(lvl, ("Timestamp - %dH:%dM:%dS:%dNS\n", \
+ gTime.Hour, gTime.Minute, gTime.Second, gTime.Nanosecond));
+#else
+// Comment out the debug stuff
+#define DEBUGPRINT(lvl, msg)
+#define DEBUGWAIT(lvl)
+#endif
+
+//
+// Time translations.
+//
+VOID DelayInMicroseconds (IN GIG_DRIVER_DATA *GigAdapter, UINTN MicroSeconds);
+#define DelayInMilliseconds(x) DelayInMicroseconds(GigAdapter, x*1000)
+
+#endif // _E1000_H_
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c
new file mode 100755
index 0000000..1233479
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.c
@@ -0,0 +1,1561 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 80003ES2LAN Gigabit Ethernet Controller (Copper)
+ * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_release_phy_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset,
+ UINT16 *data);
+STATIC INT32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset,
+ UINT16 data);
+STATIC INT32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+STATIC INT32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_hw_80003es2lan(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
+static INT32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask);
+static INT32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, UINT16 duplex);
+static INT32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
+static INT32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
+static INT32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data);
+static INT32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 data);
+static INT32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask);
+STATIC INT32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
+
+/*
+ * A table for the GG82563 cable length where the range is defined
+ * with a lower bound at "index" and the upper bound at
+ * "index + 5".
+ */
+static const UINT16 e1000_gg82563_cable_length_table[] =
+ { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+#define GG82563_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_gg82563_cable_length_table) / \
+ sizeof(e1000_gg82563_cable_length_table[0]))
+
+/**
+ * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_init_phy_params_80003es2lan");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ goto out;
+ } else {
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+ phy->type = e1000_phy_gg82563;
+
+ phy->ops.acquire = e1000_acquire_phy_80003es2lan;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.check_reset_block = e1000_check_reset_block_generic;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_80003es2lan;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.release = e1000_release_phy_80003es2lan;
+ phy->ops.reset = e1000_phy_hw_reset_generic;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
+
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan;
+ phy->ops.get_cable_length = e1000_get_cable_length_80003es2lan;
+ phy->ops.read_reg = e1000_read_phy_reg_gg82563_80003es2lan;
+ phy->ops.write_reg = e1000_write_phy_reg_gg82563_80003es2lan;
+
+ phy->ops.cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan;
+
+ /* This can only be done after all function pointers are setup. */
+ ret_val = e1000_get_phy_id(hw);
+
+ /* Verify phy id */
+ if (phy->id != GG82563_E_PHY_ID) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT16 size;
+
+ DEBUGFUNC("e1000_init_nvm_params_80003es2lan");
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ nvm->type = e1000_nvm_eeprom_spi;
+
+ size = (UINT16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+
+ /*
+ * Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+
+ /* EEPROM access above 16k is unsupported */
+ if (size > 14)
+ size = 14;
+ nvm->word_size = 1 << size;
+
+ /* Function Pointers */
+ nvm->ops.acquire = e1000_acquire_nvm_80003es2lan;
+ nvm->ops.read = e1000_read_nvm_eerd;
+ nvm->ops.release = e1000_release_nvm_80003es2lan;
+ nvm->ops.update = e1000_update_nvm_checksum_generic;
+ nvm->ops.valid_led_default = e1000_valid_led_default_generic;
+ nvm->ops.validate = e1000_validate_nvm_checksum_generic;
+ nvm->ops.write = e1000_write_nvm_80003es2lan;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ DEBUGFUNC("e1000_init_mac_params_80003es2lan");
+
+ /* Set media type and media-dependent function pointers */
+ switch (hw->device_id) {
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
+ mac->ops.setup_physical_interface =
+ e1000_setup_fiber_serdes_link_generic;
+ break;
+ default:
+ hw->phy.media_type = e1000_media_type_copper;
+ mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+ mac->ops.setup_physical_interface =
+ e1000_setup_copper_link_80003es2lan;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /* ARC supported; valid only if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+ ? TRUE : FALSE;
+ /* Adaptive IFS not supported */
+ mac->adaptive_ifs = FALSE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+ /* reset */
+ mac->ops.reset_hw = e1000_reset_hw_80003es2lan;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_80003es2lan;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_generic;
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* writing VFTA */
+ mac->ops.write_vfta = e1000_write_vfta_generic;
+ /* clearing VFTA */
+ mac->ops.clear_vfta = e1000_clear_vfta_generic;
+ /* read mac address */
+ mac->ops.read_mac_addr = e1000_read_mac_addr_80003es2lan;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_generic;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_generic;
+ mac->ops.led_off = e1000_led_off_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan;
+ /* link info */
+ mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan;
+
+ /* set lan id for port to determine which phy lock to use */
+ hw->mac.ops.set_lan_id(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_function_pointers_80003es2lan - Init ESB2 func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_80003es2lan");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan;
+ hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan;
+}
+
+/**
+ * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to acquire access rights to the correct PHY.
+ **/
+STATIC INT32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_acquire_phy_80003es2lan");
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_release_phy_80003es2lan - Release rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to release access rights to the correct PHY.
+ **/
+STATIC void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_release_phy_80003es2lan");
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the semaphore to access the Kumeran interface.
+ *
+ **/
+STATIC INT32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_acquire_mac_csr_80003es2lan");
+
+ mask = E1000_SWFW_CSR_SM;
+
+ return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_release_mac_csr_80003es2lan - Release rights to access Kumeran Register
+ * @hw: pointer to the HW structure
+ *
+ * Release the semaphore used to access the Kumeran interface
+ **/
+STATIC void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+ UINT16 mask;
+
+ DEBUGFUNC("e1000_release_mac_csr_80003es2lan");
+
+ mask = E1000_SWFW_CSR_SM;
+
+ e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the semaphore to access the EEPROM.
+ **/
+STATIC INT32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_acquire_nvm_80003es2lan");
+
+ ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_acquire_nvm_generic(hw);
+
+ if (ret_val)
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Release the semaphore used to access the EEPROM.
+ **/
+STATIC void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_80003es2lan");
+
+ e1000_release_nvm_generic(hw);
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+static INT32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+ UINT32 swmask = mask;
+ UINT32 fwmask = mask << 16;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 i = 0, timeout = 50;
+
+ DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan");
+
+ while (i < timeout) {
+ if (e1000_get_hw_semaphore_generic(hw)) {
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask)
+ * or other software thread using resource (swmask)
+ */
+ e1000_put_hw_semaphore_generic(hw);
+ msec_delay_irq(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+
+ DEBUGFUNC("e1000_release_swfw_sync_80003es2lan");
+
+ while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS)
+ ; /* Empty */
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+}
+
+/**
+ * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: pointer to the data returned from the operation
+ *
+ * Read the GG82563 PHY register.
+ **/
+STATIC INT32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+ UINT32 page_select;
+ UINT16 temp;
+
+ DEBUGFUNC("e1000_read_phy_reg_gg82563_80003es2lan");
+
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+ page_select = GG82563_PHY_PAGE_SELECT;
+ } else {
+ /*
+ * Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+ }
+
+ temp = (UINT16)((UINT16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
+ if (ret_val) {
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) {
+ /*
+ * The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ usec_delay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+
+ if (((UINT16)offset >> GG82563_PAGE_SHIFT) != temp) {
+ ret_val = -E1000_ERR_PHY;
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ usec_delay(200);
+
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ usec_delay(200);
+ } else {
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+ }
+
+ e1000_release_phy_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: value to write to the register
+ *
+ * Write to the GG82563 PHY register.
+ **/
+STATIC INT32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+ UINT32 page_select;
+ UINT16 temp;
+
+ DEBUGFUNC("e1000_write_phy_reg_gg82563_80003es2lan");
+
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+ page_select = GG82563_PHY_PAGE_SELECT;
+ } else {
+ /*
+ * Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+ }
+
+ temp = (UINT16)((UINT16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
+ if (ret_val) {
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ if (hw->dev_spec._80003es2lan.mdic_wa_enable == TRUE) {
+ /*
+ * The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ usec_delay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+
+ if (((UINT16)offset >> GG82563_PAGE_SHIFT) != temp) {
+ ret_val = -E1000_ERR_PHY;
+ e1000_release_phy_80003es2lan(hw);
+ goto out;
+ }
+
+ usec_delay(200);
+
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ usec_delay(200);
+ } else {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+ }
+
+ e1000_release_phy_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_80003es2lan - Write to ESB2 NVM
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @words: number of words to write
+ * @data: buffer of data to write to the NVM
+ *
+ * Write "words" of data to the ESB2 NVM.
+ **/
+STATIC INT32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data)
+{
+ DEBUGFUNC("e1000_write_nvm_80003es2lan");
+
+ return e1000_write_nvm_spi(hw, offset, words, data);
+}
+
+/**
+ * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete
+ * @hw: pointer to the HW structure
+ *
+ * Wait a specific amount of time for manageability processes to complete.
+ * This is a function pointer entry point called by the phy module.
+ **/
+STATIC INT32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+ DEBUGFUNC("e1000_get_cfg_done_80003es2lan");
+
+ if (hw->bus.func == 1)
+ mask = E1000_NVM_CFG_DONE_PORT_1;
+
+ while (timeout) {
+ if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
+ break;
+ msec_delay(1);
+ timeout--;
+ }
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+ ret_val = -E1000_ERR_RESET;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
+ * @hw: pointer to the HW structure
+ *
+ * Force the speed and duplex settings onto the PHY. This is a
+ * function pointer entry point called by the phy module.
+ **/
+STATIC INT32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_80003es2lan");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ /*
+ * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("GG82563 PSCR: %X\n", phy_data);
+
+ ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ /* Reset the phy to commit changes. */
+ phy_data |= MII_CR_RESET;
+
+ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ usec_delay(1);
+
+ if (hw->phy.autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link "
+ "on GG82563 phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ /*
+ * We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = e1000_phy_reset_dsp_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Resetting the phy means we need to verify the TX_CLK corresponds
+ * to the link speed. 10Mbps -> 2.5MHz, else 25MHz.
+ */
+ phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+ if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
+ phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
+ else
+ phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
+
+ /*
+ * In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_80003es2lan - Set approximate cable length
+ * @hw: pointer to the HW structure
+ *
+ * Find the approximate cable length as measured by the GG82563 PHY.
+ * This is a function pointer entry point called by the phy module.
+ **/
+STATIC INT32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data, index;
+
+ DEBUGFUNC("e1000_get_cable_length_80003es2lan");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
+ if (ret_val)
+ goto out;
+
+ index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+
+ if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+ phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_link_up_info_80003es2lan - Report speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to speed buffer
+ * @duplex: pointer to duplex buffer
+ *
+ * Retrieve the current speed and duplex configuration.
+ **/
+STATIC INT32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_link_up_info_80003es2lan");
+
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw,
+ speed,
+ duplex);
+ hw->phy.ops.cfg_on_link_up(hw);
+ } else {
+ ret_val = e1000_get_speed_and_duplex_fiber_serdes_generic(hw,
+ speed,
+ duplex);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_80003es2lan - Reset the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Perform a global reset to the ESB2 controller.
+ **/
+STATIC INT32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_80003es2lan");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+ e1000_release_phy_80003es2lan(hw);
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ goto out;
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_80003es2lan - Initialize the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
+ **/
+STATIC INT32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 reg_data;
+ INT32 ret_val;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_init_hw_80003es2lan");
+
+ e1000_initialize_hw_bits_80003es2lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val)
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+
+ /* Disabling VLAN filtering */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ mac->ops.clear_vfta(hw);
+
+ /* Setup the receive address. */
+ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
+
+ /* ...for both queues. */
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
+
+ /* Enable retransmit on late collisions */
+ reg_data = E1000_READ_REG(hw, E1000_TCTL);
+ reg_data |= E1000_TCTL_RTLC;
+ E1000_WRITE_REG(hw, E1000_TCTL, reg_data);
+
+ /* Configure Gigabit Carry Extend Padding */
+ reg_data = E1000_READ_REG(hw, E1000_TCTL_EXT);
+ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+ reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TCTL_EXT, reg_data);
+
+ /* Configure Transmit Inter-Packet Gap */
+ reg_data = E1000_READ_REG(hw, E1000_TIPG);
+ reg_data &= ~E1000_TIPG_IPGT_MASK;
+ reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TIPG, reg_data);
+
+ reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
+ reg_data &= ~0x00100000;
+ E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
+
+ /* default to TRUE to enable the MDIC W/A */
+ hw->dev_spec._80003es2lan.mdic_wa_enable = TRUE;
+
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET >>
+ E1000_KMRNCTRLSTA_OFFSET_SHIFT,
+ &i);
+ if (!ret_val) {
+ if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) ==
+ E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
+ hw->dev_spec._80003es2lan.mdic_wa_enable = FALSE;
+ }
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_80003es2lan(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_initialize_hw_bits_80003es2lan");
+
+ /* Transmit Descriptor Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TARC(0));
+ reg &= ~(0xF << 27); /* 30:27 */
+ if (hw->phy.media_type != e1000_media_type_copper)
+ reg &= ~(1 << 20);
+ E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TARC(1));
+ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+
+ return;
+}
+
+/**
+ * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
+ * @hw: pointer to the HW structure
+ *
+ * Setup some GG82563 PHY registers for obtaining link
+ **/
+static INT32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT32 ctrl_ext;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_copper_link_setup_gg82563_80003es2lan");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (phy->reset_disable)
+ goto skip_reset;
+
+#endif
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ /* Use 25MHz for both link down and 1000Base-T for Tx clock. */
+ data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
+
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+ switch (phy->mdix) {
+ case 1:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+ break;
+ case 2:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+ break;
+ case 0:
+ default:
+ data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ break;
+ }
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ if (phy->disable_polarity_correction)
+ data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data);
+ if (ret_val)
+ goto out;
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = hw->phy.ops.commit(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ goto out;
+ }
+
+#ifndef NO_PHY_RESET_DISABLE
+skip_reset:
+#endif
+ /* Bypass Rx and Tx FIFO's */
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+ E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+ E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+ &data);
+ if (ret_val)
+ goto out;
+ data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+ data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL_2, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL_2, data);
+ if (ret_val)
+ goto out;
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Do not init these registers when the HW is in IAMT mode, since the
+ * firmware will have already initialized them. We only initialize
+ * them if the HW is not in IAMT mode.
+ */
+ if (!(hw->mac.ops.check_mng_mode(hw))) {
+ /* Enable Electrical Idle on the PHY */
+ data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_PWR_MGMT_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Workaround: Disable padding in Kumeran interface in the MAC
+ * and in the PHY to avoid CRC errors.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_INBAND_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data |= GG82563_ICR_DIS_PADDING;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_INBAND_CTRL, data);
+ if (ret_val)
+ goto out;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Essentially a wrapper for setting up all things "copper" related.
+ * This is a function pointer entry point called by the mac module.
+ **/
+STATIC INT32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+ UINT16 reg_data;
+
+ DEBUGFUNC("e1000_setup_copper_link_80003es2lan");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /*
+ * Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps.
+ */
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
+ 0xFFFF);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+ reg_data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cfg_on_link_up_80003es2lan - es2 link configuration after link-up
+ * @hw: pointer to the HW structure
+ * @duplex: current duplex setting
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * 10/100 operation.
+ **/
+static INT32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 speed;
+ UINT16 duplex;
+
+ DEBUGFUNC("e1000_configure_on_link_up");
+
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw,
+ &speed,
+ &duplex);
+ if (ret_val)
+ goto out;
+
+ if (speed == SPEED_1000)
+ ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
+ else
+ ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, duplex);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
+ * @hw: pointer to the HW structure
+ * @duplex: current duplex setting
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * 10/100 operation.
+ **/
+static INT32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, UINT16 duplex)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 tipg;
+ UINT32 i = 0;
+ UINT16 reg_data, reg_data2;
+
+ DEBUGFUNC("e1000_configure_kmrn_for_10_100");
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, E1000_TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TIPG, tipg);
+
+ do {
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data2);
+ if (ret_val)
+ goto out;
+ i++;
+ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
+ * @hw: pointer to the HW structure
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * gigabit operation.
+ **/
+static INT32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 reg_data, reg_data2;
+ UINT32 tipg;
+ UINT32 i = 0;
+
+ DEBUGFUNC("e1000_configure_kmrn_for_1000");
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = E1000_READ_REG(hw, E1000_TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ E1000_WRITE_REG(hw, E1000_TIPG, tipg);
+
+ do {
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ ®_data2);
+ if (ret_val)
+ goto out;
+ i++;
+ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_kmrn_reg_80003es2lan - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquire semaphore, then read the PHY register at offset
+ * using the kumeran interface. The information retrieved is stored in data.
+ * Release the semaphore before exiting.
+ **/
+static INT32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_kmrn_reg_80003es2lan");
+
+ ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
+ *data = (UINT16)kmrnctrlsta;
+
+ e1000_release_mac_csr_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_kmrn_reg_80003es2lan - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquire semaphore, then write the data to PHY register
+ * at the offset using the kumeran interface. Release semaphore
+ * before exiting.
+ **/
+static INT32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 data)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_kmrn_reg_80003es2lan");
+
+ ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
+ if (ret_val)
+ goto out;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | data;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ e1000_release_mac_csr_80003es2lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_mac_addr_80003es2lan - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_mac_addr_80003es2lan");
+
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw)
+{
+ /* If the management interface is not enabled, then power down */
+ if (!(hw->mac.ops.check_mng_mode(hw) ||
+ hw->phy.ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+STATIC void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_80003es2lan");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_PRC64);
+ E1000_READ_REG(hw, E1000_PRC127);
+ E1000_READ_REG(hw, E1000_PRC255);
+ E1000_READ_REG(hw, E1000_PRC511);
+ E1000_READ_REG(hw, E1000_PRC1023);
+ E1000_READ_REG(hw, E1000_PRC1522);
+ E1000_READ_REG(hw, E1000_PTC64);
+ E1000_READ_REG(hw, E1000_PTC127);
+ E1000_READ_REG(hw, E1000_PTC255);
+ E1000_READ_REG(hw, E1000_PTC511);
+ E1000_READ_REG(hw, E1000_PTC1023);
+ E1000_READ_REG(hw, E1000_PTC1522);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ E1000_READ_REG(hw, E1000_ICRXPTC);
+ E1000_READ_REG(hw, E1000_ICRXATC);
+ E1000_READ_REG(hw, E1000_ICTXPTC);
+ E1000_READ_REG(hw, E1000_ICTXATC);
+ E1000_READ_REG(hw, E1000_ICTXQEC);
+ E1000_READ_REG(hw, E1000_ICTXQMTC);
+ E1000_READ_REG(hw, E1000_ICRXDMTC);
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h
new file mode 100755
index 0000000..252905d
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_80003es2lan.h
@@ -0,0 +1,103 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_80003ES2LAN_H_
+#define _E1000_80003ES2LAN_H_
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
+#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
+#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000
+
+#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C
+#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disabled */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000
+ /* 1=Reverse Auto-Negotiation */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_2_5 0x0006
+#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-100M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define GG82563_DSPD_CABLE_LENGTH 0x0007
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+
+/* Max number of times Kumeran read/write should be validated */
+#define GG82563_MAX_KMRN_RETRY 0x5
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
+ /* 1=Enable SERDES Electrical Idle */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c
new file mode 100755
index 0000000..2140738
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.c
@@ -0,0 +1,2042 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 82571EB Gigabit Ethernet Controller
+ * 82571EB Gigabit Ethernet Controller (Copper)
+ * 82571EB Gigabit Ethernet Controller (Fiber)
+ * 82571PT Gigabit PT Quad Port Server ExpressModule
+ * 82572EI Gigabit Ethernet Controller (Copper)
+ * 82572EI Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller
+ * 82573V Gigabit Ethernet Controller (Copper)
+ * 82573E Gigabit Ethernet Controller (Copper)
+ * 82573L Gigabit Ethernet Controller
+#ifndef NO_82574_SUPPORT
+ * 82574L Gigabit Network Connection
+ * 82583V Gigabit Network Connection
+#endif
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_82571(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_write_nvm_82571(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_get_cfg_done_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_reset_hw_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_init_hw_82571(struct e1000_hw *hw);
+STATIC void e1000_clear_vfta_82571(struct e1000_hw *hw);
+#ifndef NO_82574_SUPPORT
+STATIC BOOLEAN e1000_check_mng_mode_82574(struct e1000_hw *hw);
+STATIC INT32 e1000_led_on_82574(struct e1000_hw *hw);
+#endif /* NO_82574_SUPPORT */
+STATIC INT32 e1000_setup_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
+STATIC INT32 e1000_valid_led_default_82571(struct e1000_hw *hw, UINT16 *data);
+STATIC void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+static INT32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw);
+static INT32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
+static INT32 e1000_get_phy_id_82571(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
+static INT32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw);
+#ifndef NO_82574_SUPPORT
+static INT32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw);
+#endif /* NO_82574_SUPPORT */
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
+static INT32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_read_mac_addr_82571(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_82571(struct e1000_hw *hw);
+
+/**
+ * e1000_init_phy_params_82571 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_phy_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_init_phy_params_82571");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ goto out;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+
+ phy->ops.check_reset_block = e1000_check_reset_block_generic;
+ phy->ops.reset = e1000_phy_hw_reset_generic;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82571;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_82571;
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ phy->type = e1000_phy_igp_2;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_82571;
+ phy->ops.get_info = e1000_get_phy_info_igp;
+ phy->ops.check_polarity = e1000_check_polarity_igp;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
+ phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
+ phy->ops.read_reg = e1000_read_phy_reg_igp;
+ phy->ops.write_reg = e1000_write_phy_reg_igp;
+ phy->ops.acquire = e1000_get_hw_semaphore_82571;
+ phy->ops.release = e1000_put_hw_semaphore_82571;
+
+ /* This uses above function pointers */
+ ret_val = e1000_get_phy_id_82571(hw);
+
+ /* Verify PHY ID */
+ if (phy->id != IGP01E1000_I_PHY_ID) {
+ ret_val = -E1000_ERR_PHY;
+ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+ goto out;
+ }
+ break;
+ case e1000_82573:
+ phy->type = e1000_phy_m88;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.read_reg = e1000_read_phy_reg_m88;
+ phy->ops.write_reg = e1000_write_phy_reg_m88;
+ phy->ops.acquire = e1000_get_hw_semaphore_82571;
+ phy->ops.release = e1000_put_hw_semaphore_82571;
+
+ /* This uses above function pointers */
+ ret_val = e1000_get_phy_id_82571(hw);
+
+ /* Verify PHY ID */
+ if (phy->id != M88E1111_I_PHY_ID) {
+ ret_val = -E1000_ERR_PHY;
+ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+ goto out;
+ }
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ //E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
+
+ phy->type = e1000_phy_bm;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.read_reg = e1000_read_phy_reg_bm2;
+ phy->ops.write_reg = e1000_write_phy_reg_bm2;
+ phy->ops.acquire = e1000_get_hw_semaphore_82574;
+ phy->ops.release = e1000_put_hw_semaphore_82574;
+
+ /* This uses above function pointers */
+ ret_val = e1000_get_phy_id_82571(hw);
+ /* Verify PHY ID */
+ if (phy->id != BME1000_E_PHY_ID_R2) {
+ ret_val = -E1000_ERR_PHY;
+ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+ goto out;
+ }
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_82571 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT16 size;
+
+ DEBUGFUNC("e1000_init_nvm_params_82571");
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (((eecd >> 15) & 0x3) == 0x3) {
+ nvm->type = e1000_nvm_flash_hw;
+ nvm->word_size = 2048;
+ /*
+ * Autonomous Flash update bit must be cleared due
+ * to Flash update issue.
+ */
+ eecd &= ~E1000_EECD_AUPDEN;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ break;
+ }
+ /* Fall Through */
+ default:
+ nvm->type = e1000_nvm_eeprom_spi;
+ size = (UINT16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ /*
+ * Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+
+ /* EEPROM access above 16k is unsupported */
+ if (size > 14)
+ size = 14;
+ nvm->word_size = 1 << size;
+ break;
+ }
+
+ /* Function Pointers */
+ switch (hw->mac.type) {
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ nvm->ops.acquire = e1000_get_hw_semaphore_82574;
+ nvm->ops.release = e1000_put_hw_semaphore_82574;
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ nvm->ops.acquire = e1000_acquire_nvm_82571;
+ nvm->ops.release = e1000_release_nvm_82571;
+ break;
+ }
+ nvm->ops.read = e1000_read_nvm_eerd;
+ nvm->ops.update = e1000_update_nvm_checksum_82571;
+ nvm->ops.validate = e1000_validate_nvm_checksum_82571;
+ nvm->ops.valid_led_default = e1000_valid_led_default_82571;
+ nvm->ops.write = e1000_write_nvm_82571;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_mac_params_82571 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_mac_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 swsm = 0;
+ UINT32 swsm2 = 0;
+ BOOLEAN force_clear_smbi = FALSE;
+
+ DEBUGFUNC("e1000_init_mac_params_82571");
+
+ /* Set media type and media-dependent function pointers */
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ hw->phy.media_type = e1000_media_type_fiber;
+ mac->ops.setup_physical_interface =
+ e1000_setup_fiber_serdes_link_82571;
+ mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
+ mac->ops.get_link_up_info =
+ e1000_get_speed_and_duplex_fiber_serdes_generic;
+ break;
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82572EI_SERDES:
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ mac->ops.setup_physical_interface =
+ e1000_setup_fiber_serdes_link_82571;
+ mac->ops.check_for_link = e1000_check_for_serdes_link_82571;
+ mac->ops.get_link_up_info =
+ e1000_get_speed_and_duplex_fiber_serdes_generic;
+ break;
+#ifndef NO_82574_SUPPORT
+#endif /* NO_82574_SUPPORT */
+ default:
+ hw->phy.media_type = e1000_media_type_copper;
+ mac->ops.setup_physical_interface =
+ e1000_setup_copper_link_82571;
+ mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+ mac->ops.get_link_up_info =
+ e1000_get_speed_and_duplex_copper_generic;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* Adaptive IFS supported */
+ mac->adaptive_ifs = TRUE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+ /* reset */
+ mac->ops.reset_hw = e1000_reset_hw_82571;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_82571;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_82571;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* writing VFTA */
+ mac->ops.write_vfta = e1000_write_vfta_generic;
+ /* clearing VFTA */
+ mac->ops.clear_vfta = e1000_clear_vfta_82571;
+ /* read mac address */
+ mac->ops.read_mac_addr = e1000_read_mac_addr_82571;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_generic;
+ /* turn off LED */
+ mac->ops.led_off = e1000_led_off_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82571;
+
+ /* MAC-specific function pointers */
+ switch (hw->mac.type) {
+ case e1000_82573:
+ mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+ mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+ mac->ops.led_on = e1000_led_on_generic;
+
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /*
+ * ARC supported; valid only if manageability features are
+ * enabled.
+ */
+ mac->arc_subsystem_valid =
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+ ? TRUE : FALSE;
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+ mac->ops.check_mng_mode = e1000_check_mng_mode_82574;
+ mac->ops.led_on = e1000_led_on_82574;
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+ mac->ops.led_on = e1000_led_on_generic;
+
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ break;
+ }
+
+ /*
+ * Ensure that the inter-port SWSM.SMBI lock bit is clear before
+ * first NVM or PHY acess. This should be done for single-port
+ * devices, and for one port only on dual-port devices so that
+ * for those devices we can still use the SMBI lock to synchronize
+ * inter-port accesses to the PHY & NVM.
+ */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ swsm2 = E1000_READ_REG(hw, E1000_SWSM2);
+
+ if (!(swsm2 & E1000_SWSM2_LOCK)) {
+ /* Only do this for the first interface on this card */
+ E1000_WRITE_REG(hw, E1000_SWSM2,
+ swsm2 | E1000_SWSM2_LOCK);
+ force_clear_smbi = TRUE;
+ } else
+ force_clear_smbi = FALSE;
+ break;
+ default:
+ force_clear_smbi = TRUE;
+ break;
+ }
+
+ if (force_clear_smbi) {
+ /* Make sure SWSM.SMBI is clear */
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ if (swsm & E1000_SWSM_SMBI) {
+ /* This bit should not be set on a first interface, and
+ * indicates that the bootagent or EFI code has
+ * improperly left this bit enabled
+ */
+ DEBUGOUT("Please update your 82571 Bootagent\n");
+ }
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm & ~E1000_SWSM_SMBI);
+ }
+
+ /*
+ * Initialze device specific counter of SMBI acquisition
+ * timeouts.
+ */
+ hw->dev_spec._82571.smb_counter = 0;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_function_pointers_82571 - Init func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_82571");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_82571;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_82571;
+ hw->phy.ops.init_params = e1000_init_phy_params_82571;
+}
+
+/**
+ * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+static INT32 e1000_get_phy_id_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+#ifndef NO_82574_SUPPORT
+ UINT16 phy_id = 0;
+#endif /* NO_82574_SUPPORT */
+
+ DEBUGFUNC("e1000_get_phy_id_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /*
+ * The 82571 firmware may still be configuring the PHY.
+ * In this case, we cannot access the PHY until the
+ * configuration is done. So we explicitly set the
+ * PHY ID.
+ */
+ phy->id = IGP01E1000_I_PHY_ID;
+ break;
+ case e1000_82573:
+ ret_val = e1000_get_phy_id(hw);
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id = (UINT32)(phy_id << 16);
+ usec_delay(20);
+ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id |= (UINT32)(phy_id);
+ phy->revision = (UINT32)(phy_id & ~PHY_REVISION_MASK);
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+#ifndef NO_82574_SUPPORT
+out:
+#endif /* NO_82574_SUPPORT */
+ return ret_val;
+}
+
+/**
+ * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+static INT32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 sw_timeout = hw->nvm.word_size + 1;
+ INT32 fw_timeout = hw->nvm.word_size + 1;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_82571");
+
+ /*
+ * If we have timedout 3 times on trying to acquire
+ * the inter-port SMBI semaphore, there is old code
+ * operating on the other port, and it is not
+ * releasing SMBI. Modify the number of times that
+ * we try for the semaphore to interwork with this
+ * older code.
+ */
+ if (hw->dev_spec._82571.smb_counter > 2)
+ sw_timeout = 1;
+
+ /* Get the SW semaphore */
+ while (i < sw_timeout) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ usec_delay(50);
+ i++;
+ }
+
+ if (i == sw_timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ hw->dev_spec._82571.smb_counter++;
+ }
+ /* Get the FW semaphore. */
+ for (i = 0; i < fw_timeout; i++) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ usec_delay(50);
+ }
+
+ if (i == fw_timeout) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_82571(hw);
+ DEBUGOUT("Driver can't access the NVM\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82571 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_generic");
+
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ * e1000_get_hw_semaphore_82573 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore during reset.
+ *
+ **/
+static INT32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_82573");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+ do {
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ break;
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ msec_delay(2);
+ i++;
+ } while (i < MDIO_OWNERSHIP_TIMEOUT);
+
+ if (i == MDIO_OWNERSHIP_TIMEOUT) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_82573(hw);
+ DEBUGOUT("Driver can't access the PHY\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82573 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used during reset.
+ *
+ **/
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_82573");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+}
+
+#ifndef NO_82574_SUPPORT
+/**
+ * e1000_get_hw_semaphore_82574 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM.
+ *
+ **/
+static INT32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_get_hw_semaphore_82574");
+
+ //E1000_MUTEX_LOCK(&hw->dev_spec._82571.swflag_mutex);
+ return e1000_get_hw_semaphore_82573(hw);
+}
+
+/**
+ * e1000_put_hw_semaphore_82574 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ *
+ **/
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_put_hw_semaphore_82574");
+
+ e1000_put_hw_semaphore_82573(hw);
+ //E1000_MUTEX_UNLOCK(&hw->dev_spec._82571.swflag_mutex);
+}
+
+#endif /* NO_82574_SUPPORT */
+/**
+ * e1000_acquire_nvm_82571 - Request for access to the EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * To gain access to the EEPROM, first we must obtain a hardware semaphore.
+ * Then for non-82573 hardware, set the EEPROM access request bit and wait
+ * for EEPROM access grant bit. If the access grant bit is not set, release
+ * hardware semaphore.
+ **/
+STATIC INT32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_acquire_nvm_82571");
+
+ ret_val = e1000_get_hw_semaphore_82571(hw);
+ if (ret_val)
+ goto out;
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+ break;
+ default:
+ ret_val = e1000_acquire_nvm_generic(hw);
+ break;
+ }
+
+ if (ret_val)
+ e1000_put_hw_semaphore_82571(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_82571 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+STATIC void e1000_release_nvm_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_82571");
+
+ e1000_release_nvm_generic(hw);
+ e1000_put_hw_semaphore_82571(hw);
+}
+
+/**
+ * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * For non-82573 silicon, write data to EEPROM at offset using SPI interface.
+ *
+ * If e1000_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+STATIC INT32 e1000_write_nvm_82571(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_nvm_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ ret_val = e1000_write_nvm_spi(hw, offset, words, data);
+ break;
+ default:
+ ret_val = -E1000_ERR_NVM;
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_82571 - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+STATIC INT32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ UINT32 eecd;
+ INT32 ret_val;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_update_nvm_checksum_82571");
+
+ ret_val = e1000_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * If our nvm is an EEPROM, then we're done
+ * otherwise, commit the checksum to the flash NVM.
+ */
+ if (hw->nvm.type != e1000_nvm_flash_hw)
+ goto out;
+
+ /* Check for pending operations. */
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msec_delay(1);
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Reset the firmware if using STM opcode. */
+ if ((E1000_READ_REG(hw, E1000_FLOP) & 0xFF00) == E1000_STM_OPCODE) {
+ /*
+ * The enabling of and the actual reset must be done
+ * in two write cycles.
+ */
+ E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET_ENABLE);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET);
+ }
+
+ /* Commit the write to flash */
+ eecd = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msec_delay(1);
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+STATIC INT32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_validate_nvm_checksum_82571");
+
+ if (hw->nvm.type == e1000_nvm_flash_hw)
+ e1000_fix_nvm_checksum_82571(hw);
+
+ return e1000_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * After checking for invalid values, poll the EEPROM to ensure the previous
+ * command has completed before trying to write the next word. After write
+ * poll for completion.
+ *
+ * If e1000_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+static INT32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 i, eewr = 0;
+ INT32 ret_val = 0;
+
+ DEBUGFUNC("e1000_write_nvm_eewr_82571");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
+ ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+ E1000_NVM_RW_REG_START;
+
+ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+
+ E1000_WRITE_REG(hw, E1000_EEWR, eewr);
+
+ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cfg_done_82571 - Poll for configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Reads the management control register for the config done bit to be set.
+ **/
+STATIC INT32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
+{
+ INT32 timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_get_cfg_done_82571");
+
+ while (timeout) {
+ if (E1000_READ_REG(hw, E1000_EEMNGCTL) &
+ E1000_NVM_CFG_DONE_PORT_0)
+ break;
+ msec_delay(1);
+ timeout--;
+ }
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+ ret_val = -E1000_ERR_RESET;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When activating LPLU
+ * this function also disables smart speed and vice versa. LPLU will not be
+ * activated unless the device autonegotiation advertisement meets standards
+ * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function
+ * pointer entry point only called by PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d0_lplu_state_82571");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(phy->ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ goto out;
+
+ if (active) {
+ data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else {
+ data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_82571 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state.
+ **/
+STATIC INT32 e1000_reset_hw_82571(struct e1000_hw *hw)
+{
+ UINT32 ctrl, ctrl_ext;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_82571");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ /*
+ * Must acquire the MDIO ownership before MAC reset.
+ * Ownership defaults to firmware after a reset.
+ */
+ switch (hw->mac.type) {
+ case e1000_82573:
+ ret_val = e1000_get_hw_semaphore_82573(hw);
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+ ret_val = e1000_get_hw_semaphore_82574(hw);
+ break;
+#endif /* NO_82574_SUPPORT */
+ default:
+ break;
+ }
+ if (ret_val)
+ DEBUGOUT("Cannot acquire MDIO ownership\n");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+#ifndef NO_82574_SUPPORT
+ /* Must release MDIO ownership and mutex after MAC reset. */
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ e1000_put_hw_semaphore_82574(hw);
+ break;
+ default:
+ break;
+ }
+
+#endif /* NO_82574_SUPPORT */
+ if (hw->nvm.type == e1000_nvm_flash_hw) {
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ goto out;
+
+ /*
+ * Phy configuration from NVM just starts after EECD_AUTO_RD is set.
+ * Need to wait for Phy configuration completion before accessing
+ * NVM and Phy.
+ */
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ msec_delay(25);
+ break;
+ default:
+ break;
+ }
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ if (hw->mac.type == e1000_82571) {
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ e1000_set_laa_state_82571(hw, TRUE);
+ }
+
+ /* Reinitialize the 82571 serdes link state machine */
+ if (hw->phy.media_type == e1000_media_type_internal_serdes)
+ hw->mac.serdes_link_state = e1000_serdes_link_down;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_82571 - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation.
+ **/
+STATIC INT32 e1000_init_hw_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 reg_data;
+ INT32 ret_val;
+ UINT16 i, rar_count = mac->rar_entry_count;
+
+ DEBUGFUNC("e1000_init_hw_82571");
+
+ e1000_initialize_hw_bits_82571(hw);
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val)
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+
+ /* Disabling VLAN filtering */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ mac->ops.clear_vfta(hw);
+
+ /* Setup the receive address. */
+ /*
+ * If, however, a locally administered address was assigned to the
+ * 82571, we must reserve a RAR for it to work around an issue where
+ * resetting one port will reload the MAC on the other port.
+ */
+ if (e1000_get_laa_state_82571(hw))
+ rar_count--;
+ e1000_init_rx_addrs_generic(hw, rar_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
+
+ /* ...for both queues. */
+ switch (mac->type) {
+ case e1000_82573:
+ e1000_enable_tx_pkt_filtering_generic(hw);
+#ifndef NO_82574_SUPPORT
+ /* fall through */
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ reg_data = E1000_READ_REG(hw, E1000_GCR);
+ reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ E1000_WRITE_REG(hw, E1000_GCR, reg_data);
+ break;
+ default:
+ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
+ break;
+ }
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_82571(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_initialize_hw_bits_82571");
+
+ /* Transmit Descriptor Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TARC(0));
+ reg &= ~(0xF << 27); /* 30:27 */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
+ break;
+ default:
+ break;
+ }
+ E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TARC(1));
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg &= ~((1 << 29) | (1 << 30));
+ reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
+ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+ break;
+ default:
+ break;
+ }
+
+ /* Device Control */
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ reg = E1000_READ_REG(hw, E1000_CTRL);
+ reg &= ~(1 << 29);
+ E1000_WRITE_REG(hw, E1000_CTRL, reg);
+ break;
+ default:
+ break;
+ }
+
+ /* Extended Device Control */
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg &= ~(1 << 23);
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+ break;
+ default:
+ break;
+ }
+
+ if (hw->mac.type == e1000_82571) {
+ reg = E1000_READ_REG(hw, E1000_PBA_ECC);
+ reg |= E1000_PBA_ECC_CORR_EN;
+ E1000_WRITE_REG(hw, E1000_PBA_ECC, reg);
+ }
+
+ /*
+ * Workaround for hardware errata.
+ * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572
+ */
+ if ((hw->mac.type == e1000_82571) ||
+ (hw->mac.type == e1000_82572)) {
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_DMA_DYN_CLK_EN;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+ }
+
+#ifndef NO_82574_SUPPORT
+ /* PCI-Ex Control Registers */
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ reg = E1000_READ_REG(hw, E1000_GCR);
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_GCR, reg);
+
+ /*
+ * Workaround for hardware errata.
+ * apply workaround for hardware errata documented in errata
+ * docs Fixes issue where some error prone or unreliable PCIe
+ * completions are occurring, particularly with ASPM enabled.
+ * Without fix, issue can cause tx timeouts.
+ */
+ reg = E1000_READ_REG(hw, E1000_GCR2);
+ reg |= 1;
+ E1000_WRITE_REG(hw, E1000_GCR2, reg);
+ break;
+ default:
+ break;
+ }
+
+#endif /* NO_82574_SUPPORT */
+ return;
+}
+
+/**
+ * e1000_clear_vfta_82571 - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * Clears the register array which contains the VLAN filter table by
+ * setting all the values to 0.
+ **/
+STATIC void e1000_clear_vfta_82571(struct e1000_hw *hw)
+{
+ UINT32 offset;
+ UINT32 vfta_value = 0;
+ UINT32 vfta_offset = 0;
+ UINT32 vfta_bit_in_reg = 0;
+
+ DEBUGFUNC("e1000_clear_vfta_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (hw->mng_cookie.vlan_id != 0) {
+ /*
+ * The VFTA is a 4096b bit-field, each identifying
+ * a single VLAN ID. The following operations
+ * determine which 32b entry (i.e. offset) into the
+ * array we want to set the VLAN ID (i.e. bit) of
+ * the manageability unit.
+ */
+ vfta_offset = (hw->mng_cookie.vlan_id >>
+ E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
+ vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+ E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+ }
+ break;
+ default:
+ break;
+ }
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ /*
+ * If the offset we want to clear is the same offset of the
+ * manageability VLAN ID, then clear all bits except that of
+ * the manageability unit.
+ */
+ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
+ E1000_WRITE_FLUSH(hw);
+ }
+}
+
+#ifndef NO_82574_SUPPORT
+/**
+ * e1000_check_mng_mode_82574 - Check manageability is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Reads the NVM Initialization Control Word 2 and returns TRUE
+ * (>0) if any manageability is enabled, else FALSE (0).
+ **/
+STATIC BOOLEAN e1000_check_mng_mode_82574(struct e1000_hw *hw)
+{
+ UINT16 data;
+
+ DEBUGFUNC("e1000_check_mng_mode_82574");
+
+ hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+ return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
+}
+
+/**
+ * e1000_led_on_82574 - Turn LED on
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED on.
+ **/
+STATIC INT32 e1000_led_on_82574(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ UINT32 i;
+
+ DEBUGFUNC("e1000_led_on_82574");
+
+ ctrl = hw->mac.ledctl_mode2;
+ if (!(E1000_STATUS_LU & E1000_READ_REG(hw, E1000_STATUS))) {
+ /*
+ * If no link, then turn LED on by setting the invert bit
+ * for each LED that's "on" (0x0E) in ledctl_mode2.
+ */
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
+ }
+ E1000_WRITE_REG(hw, E1000_LEDCTL, ctrl);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_check_phy_82574 - check 82574 phy hung state
+ * @hw: pointer to the HW structure
+ *
+ * Returns whether phy is hung or not
+ **/
+BOOLEAN e1000_check_phy_82574(struct e1000_hw *hw)
+{
+ UINT16 status_1kbt = 0;
+ UINT16 receive_errors = 0;
+ BOOLEAN phy_hung = FALSE;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_phy_82574");
+
+ /*
+ * Read PHY Receive Error counter first, if its is max - all F's then
+ * read the Base1000T status register If both are max then PHY is hung.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, E1000_RECEIVE_ERROR_COUNTER,
+ &receive_errors);
+ if (ret_val)
+ goto out;
+ if (receive_errors == E1000_RECEIVE_ERROR_MAX) {
+ ret_val = hw->phy.ops.read_reg(hw, E1000_BASE1000T_STATUS,
+ &status_1kbt);
+ if (ret_val)
+ goto out;
+ if ((status_1kbt & E1000_IDLE_ERROR_COUNT_MASK) ==
+ E1000_IDLE_ERROR_COUNT_MASK)
+ phy_hung = TRUE;
+ }
+out:
+ return phy_hung;
+}
+
+#endif /* NO_82574_SUPPORT */
+
+/**
+ * e1000_setup_link_82571 - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+STATIC INT32 e1000_setup_link_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_setup_link_82571");
+
+ /*
+ * 82573 does not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (hw->fc.requested_mode == e1000_fc_default)
+ hw->fc.requested_mode = e1000_fc_full;
+ break;
+ default:
+ break;
+ }
+ return e1000_setup_link_generic(hw);
+}
+
+/**
+ * e1000_setup_copper_link_82571 - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Configures the link for auto-neg or forced speed and duplex. Then we check
+ * for link, once link is established calls to configure collision distance
+ * and flow control are called.
+ **/
+STATIC INT32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_setup_copper_link_82571");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
+#ifndef NO_82574_SUPPORT
+ case e1000_phy_bm:
+#endif /* NO_82574_SUPPORT */
+ ret_val = e1000_copper_link_setup_m88(hw);
+ break;
+ case e1000_phy_igp_2:
+ ret_val = e1000_copper_link_setup_igp(hw);
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes links.
+ * Upon successful setup, poll for link.
+ **/
+STATIC INT32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_setup_fiber_serdes_link_82571");
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /*
+ * If SerDes loopback mode is entered, there is no form
+ * of reset to take the adapter out of that mode. So we
+ * have to explicitly take the adapter out of loopback
+ * mode. This prevents drivers from twiddling their thumbs
+ * if another tool failed to take it out of loopback mode.
+ */
+ E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+ break;
+ default:
+ break;
+ }
+
+ return e1000_setup_fiber_serdes_link_generic(hw);
+}
+
+/**
+ * e1000_check_for_serdes_link_82571 - Check for link (Serdes)
+ * @hw: pointer to the HW structure
+ *
+ * Reports the link state as up or down.
+ *
+ * If autonegotiation is supported by the link partner, the link state is
+ * determined by the result of autonegotiation. This is the most likely case.
+ * If autonegotiation is not supported by the link partner, and the link
+ * has a valid signal, force the link up.
+ *
+ * The link state is represented internally here by 4 states:
+ *
+ * 1) down
+ * 2) autoneg_progress
+ * 3) autoneg_complete (the link sucessfully autonegotiated)
+ * 4) forced_up (the link has been forced up, it did not autonegotiate)
+ *
+ **/
+STATIC INT32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 rxcw;
+ UINT32 ctrl;
+ UINT32 status;
+ UINT32 txcw;
+ UINT32 i;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_for_serdes_link_82571");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+ if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
+
+ /* Receiver is synchronized with no invalid bits. */
+ switch (mac->serdes_link_state) {
+ case e1000_serdes_link_autoneg_complete:
+ if (!(status & E1000_STATUS_LU)) {
+ /*
+ * We have lost link, retry autoneg before
+ * reporting link failure
+ */
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("AN_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = TRUE;
+ }
+ break;
+
+ case e1000_serdes_link_forced_up:
+ /*
+ * If we are receiving /C/ ordered sets, re-enable
+ * auto-negotiation in the TXCW register and disable
+ * forced link in the Device Control register in an
+ * attempt to auto-negotiate with our link partner.
+ * If the partner code word is null, stop forcing
+ * and restart auto negotiation.
+ */
+ if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW)) {
+ /* Enable autoneg, and unforce link up */
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL,
+ (ctrl & ~E1000_CTRL_SLU));
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("FORCED_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = TRUE;
+ }
+ break;
+
+ case e1000_serdes_link_autoneg_progress:
+ if (rxcw & E1000_RXCW_C) {
+ /*
+ * We received /C/ ordered sets, meaning the
+ * link partner has autonegotiated, and we can
+ * trust the Link Up (LU) status bit.
+ */
+ if (status & E1000_STATUS_LU) {
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_complete;
+ DEBUGOUT("AN_PROG -> AN_UP\n");
+ mac->serdes_has_link = TRUE;
+ } else {
+ /* Autoneg completed, but failed. */
+ mac->serdes_link_state =
+ e1000_serdes_link_down;
+ DEBUGOUT("AN_PROG -> DOWN\n");
+ }
+ } else {
+ /*
+ * The link partner did not autoneg.
+ * Force link up and full duplex, and change
+ * state to forced.
+ */
+ E1000_WRITE_REG(hw, E1000_TXCW,
+ (mac->txcw & ~E1000_TXCW_ANE));
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Configure Flow Control after link up. */
+ ret_val =
+ e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error config flow control\n");
+ break;
+ }
+ mac->serdes_link_state =
+ e1000_serdes_link_forced_up;
+ mac->serdes_has_link = TRUE;
+ DEBUGOUT("AN_PROG -> FORCED_UP\n");
+ }
+ break;
+
+ case e1000_serdes_link_down:
+ default:
+ /*
+ * The link was down but the receiver has now gained
+ * valid sync, so lets see if we can bring the link
+ * up.
+ */
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL,
+ (ctrl & ~E1000_CTRL_SLU));
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("DOWN -> AN_PROG\n");
+ break;
+ }
+ } else {
+ if (!(rxcw & E1000_RXCW_SYNCH)) {
+ mac->serdes_has_link = FALSE;
+ mac->serdes_link_state = e1000_serdes_link_down;
+ DEBUGOUT("ANYSTATE -> DOWN\n");
+ } else {
+ /*
+ * Check several times, if Sync and Config
+ * both are consistently 1 then simply ignore
+ * the Invalid bit and restart Autoneg
+ */
+ for (i = 0; i < AN_RETRY_COUNT; i++) {
+ usec_delay(10);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+ if ((rxcw & E1000_RXCW_IV) &&
+ !((rxcw & E1000_RXCW_SYNCH) &&
+ (rxcw & E1000_RXCW_C))) {
+ mac->serdes_has_link = FALSE;
+ mac->serdes_link_state =
+ e1000_serdes_link_down;
+ DEBUGOUT("ANYSTATE -> DOWN\n");
+ break;
+ }
+ }
+
+ if (i == AN_RETRY_COUNT) {
+ txcw = E1000_READ_REG(hw, E1000_TXCW);
+ txcw |= E1000_TXCW_ANE;
+ E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("ANYSTATE -> AN_PROG\n");
+ }
+ }
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_valid_led_default_82571 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+STATIC INT32 e1000_valid_led_default_82571(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_82571");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ if (*data == ID_LED_RESERVED_F746)
+ *data = ID_LED_DEFAULT_82573;
+ break;
+ default:
+ if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_laa_state_82571 - Get locally administered address state
+ * @hw: pointer to the HW structure
+ *
+ * Retrieve and return the current locally administered address state.
+ **/
+BOOLEAN e1000_get_laa_state_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_get_laa_state_82571");
+
+ if (hw->mac.type != e1000_82571)
+ return FALSE;
+
+ return hw->dev_spec._82571.laa_is_present;
+}
+
+/**
+ * e1000_set_laa_state_82571 - Set locally administered address state
+ * @hw: pointer to the HW structure
+ * @state: enable/disable locally administered address
+ *
+ * Enable/Disable the current locally administered address state.
+ **/
+void e1000_set_laa_state_82571(struct e1000_hw *hw, BOOLEAN state)
+{
+ DEBUGFUNC("e1000_set_laa_state_82571");
+
+ if (hw->mac.type != e1000_82571)
+ return;
+
+ hw->dev_spec._82571.laa_is_present = state;
+
+ /* If workaround is activated... */
+ if (state)
+ /*
+ * Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed, the actual LAA is in one of the RARs and no
+ * incoming packets directed to this port are dropped.
+ * Eventually the LAA will be in RAR[0] and RAR[14].
+ */
+ e1000_rar_set_generic(hw, hw->mac.addr,
+ hw->mac.rar_entry_count - 1);
+ return;
+}
+
+/**
+ * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Verifies that the EEPROM has completed the update. After updating the
+ * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If
+ * the checksum fix is not implemented, we need to set the bit and update
+ * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect,
+ * we need to return bad checksum.
+ **/
+static INT32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_fix_nvm_checksum_82571");
+
+ if (nvm->type != e1000_nvm_flash_hw)
+ goto out;
+
+ /*
+ * Check bit 4 of word 10h. If it is 0, firmware is done updating
+ * 10h-12h. Checksum may need to be fixed.
+ */
+ ret_val = nvm->ops.read(hw, 0x10, 1, &data);
+ if (ret_val)
+ goto out;
+
+ if (!(data & 0x10)) {
+ /*
+ * Read 0x23 and check bit 15. This bit is a 1
+ * when the checksum has already been fixed. If
+ * the checksum is still wrong and this bit is a
+ * 1, we need to return bad checksum. Otherwise,
+ * we need to set this bit to a 1 and update the
+ * checksum.
+ */
+ ret_val = nvm->ops.read(hw, 0x23, 1, &data);
+ if (ret_val)
+ goto out;
+
+ if (!(data & 0x8000)) {
+ data |= 0x8000;
+ ret_val = nvm->ops.write(hw, 0x23, 1, &data);
+ if (ret_val)
+ goto out;
+ ret_val = nvm->ops.update(hw);
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+
+/**
+ * e1000_read_mac_addr_82571 - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_mac_addr_82571");
+
+ if (hw->mac.type == e1000_82571) {
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_82571 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ struct e1000_mac_info *mac = &hw->mac;
+
+ if (!(phy->ops.check_reset_block))
+ return;
+
+ /* If the management interface is not enabled, then power down */
+ if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+STATIC void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_82571");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_PRC64);
+ E1000_READ_REG(hw, E1000_PRC127);
+ E1000_READ_REG(hw, E1000_PRC255);
+ E1000_READ_REG(hw, E1000_PRC511);
+ E1000_READ_REG(hw, E1000_PRC1023);
+ E1000_READ_REG(hw, E1000_PRC1522);
+ E1000_READ_REG(hw, E1000_PTC64);
+ E1000_READ_REG(hw, E1000_PTC127);
+ E1000_READ_REG(hw, E1000_PTC255);
+ E1000_READ_REG(hw, E1000_PTC511);
+ E1000_READ_REG(hw, E1000_PTC1023);
+ E1000_READ_REG(hw, E1000_PTC1522);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ E1000_READ_REG(hw, E1000_ICRXPTC);
+ E1000_READ_REG(hw, E1000_ICRXATC);
+ E1000_READ_REG(hw, E1000_ICTXPTC);
+ E1000_READ_REG(hw, E1000_ICTXATC);
+ E1000_READ_REG(hw, E1000_ICTXQEC);
+ E1000_READ_REG(hw, E1000_ICTXQMTC);
+ E1000_READ_REG(hw, E1000_ICRXDMTC);
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h
new file mode 100755
index 0000000..987a827
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82571.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_82571_H_
+#define _E1000_82571_H_
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_ON2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define AN_RETRY_COUNT 5 /* Autoneg Retry Count value */
+
+#ifndef NO_82574_SUPPORT
+/* Intr Throttling - RW */
+#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n)))
+
+#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAC_MASK_82574 0x01F00000
+
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+
+#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
+
+#define E1000_BASE1000T_STATUS 10
+#define E1000_IDLE_ERROR_COUNT_MASK 0xFF
+#define E1000_RECEIVE_ERROR_COUNTER 21
+#define E1000_RECEIVE_ERROR_MAX 0xFFFF
+BOOLEAN e1000_check_phy_82574(struct e1000_hw *hw);
+#endif /* NO_82574_SUPPORT */
+BOOLEAN e1000_get_laa_state_82571(struct e1000_hw *hw);
+void e1000_set_laa_state_82571(struct e1000_hw *hw, BOOLEAN state);
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c
new file mode 100755
index 0000000..ca1e35b
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.c
@@ -0,0 +1,2030 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 82575EB Gigabit Network Connection
+ * 82575EB Gigabit Backplane Connection
+ * 82575GB Gigabit Network Connection
+ * 82576 Gigabit Network Connection
+ * 82576 Quad Port Gigabit Mezzanine Adapter
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_phy_82575(struct e1000_hw *hw);
+STATIC void e1000_release_phy_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_82575(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_check_for_link_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_get_cfg_done_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_get_link_up_info_82575(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+STATIC INT32 e1000_init_hw_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data);
+STATIC INT32 e1000_reset_hw_82575(struct e1000_hw *hw);
+#ifndef NO_82580_SUPPORT
+STATIC INT32 e1000_reset_hw_82580(struct e1000_hw *hw);
+STATIC INT32 e1000_read_phy_reg_82580(struct e1000_hw *hw,
+ UINT32 offset, UINT16 *data);
+STATIC INT32 e1000_write_phy_reg_82580(struct e1000_hw *hw,
+ UINT32 offset, UINT16 data);
+#endif /* NO_82580_SUPPORT */
+STATIC INT32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_setup_copper_link_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_serdes_link_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_valid_led_default_82575(struct e1000_hw *hw, UINT16 *data);
+STATIC INT32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw,
+ UINT32 offset, UINT16 data);
+STATIC void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask);
+static INT32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex);
+static INT32 e1000_get_phy_id_82575(struct e1000_hw *hw);
+STATIC void e1000_release_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask);
+static BOOLEAN e1000_sgmii_active_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_reset_init_script_82575(struct e1000_hw *hw);
+STATIC INT32 e1000_read_mac_addr_82575(struct e1000_hw *hw);
+STATIC void e1000_config_collision_dist_82575(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_82575(struct e1000_hw *hw);
+#ifndef NO_82576_SUPPORT
+STATIC void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw);
+STATIC void e1000_power_up_serdes_link_82575(struct e1000_hw *hw);
+#endif
+STATIC INT32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw);
+#ifndef NO_82580_SUPPORT
+STATIC INT32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw);
+
+static const UINT16 e1000_82580_rxpbs_table[] =
+ { 36, 72, 144, 1, 2, 4, 8, 16,
+ 35, 70, 140 };
+#define E1000_82580_RXPBS_TABLE_SIZE \
+ (sizeof(e1000_82580_rxpbs_table)/sizeof(UINT16))
+
+#endif /* NO_82580_SUPPORT */
+
+/**
+ * e1000_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
+ * @hw: pointer to the HW structure
+ *
+ * Called to determine if the I2C pins are being used for I2C or as an
+ * external MDIO interface since the two options are mutually exclusive.
+ **/
+STATIC BOOLEAN e1000_sgmii_uses_mdio_82575(struct e1000_hw *hw)
+{
+ UINT32 reg = 0;
+ BOOLEAN ext_mdio = FALSE;
+
+ DEBUGFUNC("e1000_sgmii_uses_mdio_82575");
+
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ reg = E1000_READ_REG(hw, E1000_MDIC);
+ ext_mdio = !!(reg & E1000_MDIC_DEST);
+ break;
+#ifndef NO_82580_SUPPORT
+ case e1000_82580:
+ reg = E1000_READ_REG(hw, E1000_MDICNFG);
+ ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);
+ break;
+#endif /* NO_82580_SUPPORT */
+ default:
+ break;
+ }
+ return ext_mdio;
+}
+
+/**
+ * e1000_init_phy_params_82575 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_phy_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 ctrl_ext;
+
+ DEBUGFUNC("e1000_init_phy_params_82575");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ goto out;
+ }
+
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_82575;
+
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+
+ phy->ops.acquire = e1000_acquire_phy_82575;
+ phy->ops.check_reset_block = e1000_check_reset_block_generic;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_82575;
+ phy->ops.release = e1000_release_phy_82575;
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+
+ if (e1000_sgmii_active_82575(hw)) {
+ phy->ops.reset = e1000_phy_hw_reset_sgmii_82575;
+ ctrl_ext |= E1000_CTRL_I2C_ENA;
+ } else {
+ phy->ops.reset = e1000_phy_hw_reset_generic;
+ ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+ }
+
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+#ifndef NO_82580_SUPPORT
+ e1000_reset_mdicnfg_82580(hw);
+
+#endif /* NO_82580_SUPPORT */
+ if (e1000_sgmii_active_82575(hw) && !e1000_sgmii_uses_mdio_82575(hw)) {
+ phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575;
+ phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575;
+#ifndef NO_82580_SUPPORT
+ } else if (hw->mac.type >= e1000_82580) {
+ phy->ops.read_reg = e1000_read_phy_reg_82580;
+ phy->ops.write_reg = e1000_write_phy_reg_82580;
+#endif /* NO_82580_SUPPORT */
+ } else {
+ phy->ops.read_reg = e1000_read_phy_reg_igp;
+ phy->ops.write_reg = e1000_write_phy_reg_igp;
+ }
+
+ /* Set phy->phy_addr and phy->id. */
+ ret_val = e1000_get_phy_id_82575(hw);
+
+ /* Verify phy id and set remaining function pointers */
+ switch (phy->id) {
+ case M88E1111_I_PHY_ID:
+ phy->type = e1000_phy_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ break;
+ case IGP03E1000_E_PHY_ID:
+#ifndef NO_82576_SUPPORT
+ case IGP04E1000_E_PHY_ID:
+#endif /* NO_82576_SUPPORT */
+ phy->type = e1000_phy_igp_3;
+ phy->ops.check_polarity = e1000_check_polarity_igp;
+ phy->ops.get_info = e1000_get_phy_info_igp;
+ phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82575;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
+ break;
+#ifndef NO_82580_SUPPORT
+ case I82580_I_PHY_ID:
+ phy->type = e1000_phy_82580;
+ phy->ops.check_polarity = e1000_check_polarity_82577;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82577;
+ phy->ops.get_cable_length = e1000_get_cable_length_82577;
+ phy->ops.get_info = e1000_get_phy_info_82577;
+ break;
+#endif
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_82575 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_nvm_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT16 size;
+
+ DEBUGFUNC("e1000_init_nvm_params_82575");
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ nvm->type = e1000_nvm_eeprom_spi;
+
+ size = (UINT16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+
+ /*
+ * Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+
+ /* EEPROM access above 16k is unsupported */
+ if (size > 14)
+ size = 14;
+ nvm->word_size = 1 << size;
+
+ /* Function Pointers */
+ nvm->ops.acquire = e1000_acquire_nvm_82575;
+ nvm->ops.read = e1000_read_nvm_eerd;
+ nvm->ops.release = e1000_release_nvm_82575;
+ nvm->ops.update = e1000_update_nvm_checksum_generic;
+ nvm->ops.valid_led_default = e1000_valid_led_default_82575;
+ nvm->ops.validate = e1000_validate_nvm_checksum_generic;
+ nvm->ops.write = e1000_write_nvm_spi;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_mac_params_82575 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_init_mac_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+ UINT32 ctrl_ext = 0;
+
+ DEBUGFUNC("e1000_init_mac_params_82575");
+
+ /* Set media type */
+ /*
+ * The 82575 uses bits 22:23 for link mode. The mode can be changed
+ * based on the EEPROM. We cannot rely upon device ID. There
+ * is no distinguishable difference between fiber and internal
+ * SerDes mode on the 82575. There can be an external PHY attached
+ * on the SGMII interface. For this, we'll set sgmii_active to TRUE.
+ */
+ hw->phy.media_type = e1000_media_type_copper;
+ dev_spec->sgmii_active = FALSE;
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
+ case E1000_CTRL_EXT_LINK_MODE_SGMII:
+ dev_spec->sgmii_active = TRUE;
+ break;
+#ifndef NO_82580_SUPPORT
+ case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
+#endif
+ case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+#ifndef NO_82576_SUPPORT
+ /* Set uta register count */
+ mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
+#endif
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+#ifndef NO_82576_SUPPORT
+ if (mac->type == e1000_82576)
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
+#endif
+#ifndef NO_82580_SUPPORT
+ if (mac->type == e1000_82580)
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /* ARC supported; valid only if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+ ? TRUE : FALSE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+ /* reset */
+#ifndef NO_82580_SUPPORT
+ if (mac->type >= e1000_82580)
+ mac->ops.reset_hw = e1000_reset_hw_82580;
+ else
+#endif /* NO_82580_SUPPORT */
+ mac->ops.reset_hw = e1000_reset_hw_82575;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_82575;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_generic;
+ /* physical interface link setup */
+ mac->ops.setup_physical_interface =
+ (hw->phy.media_type == e1000_media_type_copper)
+ ? e1000_setup_copper_link_82575
+ : e1000_setup_serdes_link_82575;
+#ifndef NO_82576_SUPPORT
+ /* physical interface shutdown */
+ mac->ops.shutdown_serdes = e1000_shutdown_serdes_link_82575;
+ /* physical interface power up */
+ mac->ops.power_up_serdes = e1000_power_up_serdes_link_82575;
+#endif /* NO_82576_SUPPORT */
+ /* check for link */
+ mac->ops.check_for_link = e1000_check_for_link_82575;
+ /* receive address register setting */
+ mac->ops.rar_set = e1000_rar_set_generic;
+ /* read mac address */
+ mac->ops.read_mac_addr = e1000_read_mac_addr_82575;
+ /* configure collision distance */
+ mac->ops.config_collision_dist = e1000_config_collision_dist_82575;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* writing VFTA */
+ mac->ops.write_vfta = e1000_write_vfta_generic;
+ /* clearing VFTA */
+ mac->ops.clear_vfta = e1000_clear_vfta_generic;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_generic;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_generic;
+ mac->ops.led_off = e1000_led_off_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82575;
+ /* link info */
+ mac->ops.get_link_up_info = e1000_get_link_up_info_82575;
+
+ /* set lan id for port to determine which phy lock to use */
+ hw->mac.ops.set_lan_id(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_function_pointers_82575 - Init func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82575(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_82575");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_82575;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_82575;
+ hw->phy.ops.init_params = e1000_init_phy_params_82575;
+}
+
+/**
+ * e1000_acquire_phy_82575 - Acquire rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * Acquire access rights to the correct PHY.
+ **/
+STATIC INT32 e1000_acquire_phy_82575(struct e1000_hw *hw)
+{
+ UINT16 mask = E1000_SWFW_PHY0_SM;
+
+ DEBUGFUNC("e1000_acquire_phy_82575");
+
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_SWFW_PHY1_SM;
+#ifndef NO_82580_SUPPORT
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_SWFW_PHY2_SM;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_SWFW_PHY3_SM;
+#endif /* NO_82580_SUPPORT */
+
+ return e1000_acquire_swfw_sync_82575(hw, mask);
+}
+
+/**
+ * e1000_release_phy_82575 - Release rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to release access rights to the correct PHY.
+ **/
+STATIC void e1000_release_phy_82575(struct e1000_hw *hw)
+{
+ UINT16 mask = E1000_SWFW_PHY0_SM;
+
+ DEBUGFUNC("e1000_release_phy_82575");
+
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_SWFW_PHY1_SM;
+#ifndef NO_82580_SUPPORT
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_SWFW_PHY2_SM;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_SWFW_PHY3_SM;
+#endif /* NO_82580_SUPPORT */
+
+ e1000_release_swfw_sync_82575(hw, mask);
+}
+
+/**
+ * e1000_read_phy_reg_sgmii_82575 - Read PHY register using sgmii
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the serial gigabit media independent
+ * interface and stores the retrieved information in data.
+ **/
+STATIC INT32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data)
+{
+ INT32 ret_val = -E1000_ERR_PARAM;
+
+ DEBUGFUNC("e1000_read_phy_reg_sgmii_82575");
+
+ if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+ DEBUGOUT1("PHY Address %u is out of range\n", offset);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_phy_reg_i2c(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_sgmii_82575 - Write PHY register using sgmii
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset using the serial gigabit
+ * media independent interface.
+ **/
+STATIC INT32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw, UINT32 offset,
+ UINT16 data)
+{
+ INT32 ret_val = -E1000_ERR_PARAM;
+
+ DEBUGFUNC("e1000_write_phy_reg_sgmii_82575");
+
+ if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+ DEBUGOUT1("PHY Address %d is out of range\n", offset);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_write_phy_reg_i2c(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_id_82575 - Retrieve PHY addr and id
+ * @hw: pointer to the HW structure
+ *
+ * Retrieves the PHY address and ID for both PHY's which do and do not use
+ * sgmi interface.
+ **/
+STATIC INT32 e1000_get_phy_id_82575(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_id;
+ UINT32 ctrl_ext;
+ UINT32 mdic;
+
+ DEBUGFUNC("e1000_get_phy_id_82575");
+
+ /*
+ * For SGMII PHYs, we try the list of possible addresses until
+ * we find one that works. For non-SGMII PHYs
+ * (e.g. integrated copper PHYs), an address of 1 should
+ * work. The result of this function should mean phy->phy_addr
+ * and phy->id are set correctly.
+ */
+ if (!e1000_sgmii_active_82575(hw)) {
+ phy->addr = 1;
+ ret_val = e1000_get_phy_id(hw);
+ goto out;
+ }
+
+ if (e1000_sgmii_uses_mdio_82575(hw)) {
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ mdic = E1000_READ_REG(hw, E1000_MDIC);
+ mdic &= E1000_MDIC_PHY_MASK;
+ phy->addr = mdic >> E1000_MDIC_PHY_SHIFT;
+ break;
+#ifndef NO_82580_SUPPORT
+ case e1000_82580:
+ mdic = E1000_READ_REG(hw, E1000_MDICNFG);
+ mdic &= E1000_MDICNFG_PHY_MASK;
+ phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
+ break;
+#endif /* NO_82580_SUPPORT */
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ break;
+ }
+ ret_val = e1000_get_phy_id(hw);
+ goto out;
+ }
+
+ /* Power on sgmii phy if it is disabled */
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(300);
+
+ /*
+ * The address field in the I2CCMD register is 3 bits and 0 is invalid.
+ * Therefore, we need to test 1-7
+ */
+ for (phy->addr = 1; phy->addr < 8; phy->addr++) {
+ ret_val = e1000_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id);
+ if (ret_val == E1000_SUCCESS) {
+ DEBUGOUT2("Vendor ID 0x%08X read at address %u\n",
+ phy_id,
+ phy->addr);
+ /*
+ * At the time of this writing, The M88 part is
+ * the only supported SGMII PHY product.
+ */
+ if (phy_id == M88_VENDOR)
+ break;
+ } else {
+ DEBUGOUT1("PHY address %u was unreadable\n",
+ phy->addr);
+ }
+ }
+
+ /* A valid PHY type couldn't be found. */
+ if (phy->addr == 8) {
+ phy->addr = 0;
+ ret_val = -E1000_ERR_PHY;
+ } else {
+ ret_val = e1000_get_phy_id(hw);
+ }
+
+ /* restore previous sfp cage power state */
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_hw_reset_sgmii_82575 - Performs a PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Resets the PHY using the serial gigabit media independent interface.
+ **/
+STATIC INT32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_phy_hw_reset_sgmii_82575");
+
+ /*
+ * This isn't a TRUE "hard" reset, but is the only reset
+ * available to us at this time.
+ */
+
+ DEBUGOUT("Soft resetting SGMII attached PHY...\n");
+
+ if (!(hw->phy.ops.write_reg))
+ goto out;
+
+ /*
+ * SFP documentation requires the following to configure the SPF module
+ * to work on SGMII. No further documentation is given.
+ */
+ ret_val = hw->phy.ops.write_reg(hw, 0x1B, 0x8084);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.commit(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d0_lplu_state_82575");
+
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ goto out;
+
+ if (active) {
+ data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else {
+ data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_acquire_nvm_82575 - Request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the necessary semaphores for exclusive access to the EEPROM.
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+STATIC INT32 e1000_acquire_nvm_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_acquire_nvm_82575");
+
+ ret_val = e1000_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_acquire_nvm_generic(hw);
+
+ if (ret_val)
+ e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_82575 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ * then release the semaphores acquired.
+ **/
+STATIC void e1000_release_nvm_82575(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_82575");
+
+ e1000_release_nvm_generic(hw);
+ e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * e1000_acquire_swfw_sync_82575 - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+STATIC INT32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+ UINT32 swmask = mask;
+ UINT32 fwmask = mask << 16;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+ DEBUGFUNC("e1000_acquire_swfw_sync_82575");
+
+ while (i < timeout) {
+ if (e1000_get_hw_semaphore_generic(hw)) {
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask)
+ * or other software thread using resource (swmask)
+ */
+ e1000_put_hw_semaphore_generic(hw);
+ msec_delay_irq(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_swfw_sync_82575 - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+STATIC void e1000_release_swfw_sync_82575(struct e1000_hw *hw, UINT16 mask)
+{
+ UINT32 swfw_sync;
+
+ DEBUGFUNC("e1000_release_swfw_sync_82575");
+
+ while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS);
+ /* Empty */
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_generic(hw);
+}
+
+/**
+ * e1000_get_cfg_done_82575 - Read config done bit
+ * @hw: pointer to the HW structure
+ *
+ * Read the management control register for the config done bit for
+ * completion status. NOTE: silicon which is EEPROM-less will fail trying
+ * to read the config done bit, so an error is *ONLY* logged and returns
+ * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon
+ * would not be able to be reset or change link.
+ **/
+STATIC INT32 e1000_get_cfg_done_82575(struct e1000_hw *hw)
+{
+ INT32 timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+ DEBUGFUNC("e1000_get_cfg_done_82575");
+
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_NVM_CFG_DONE_PORT_1;
+#ifndef NO_82580_SUPPORT
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_NVM_CFG_DONE_PORT_2;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_NVM_CFG_DONE_PORT_3;
+#endif /* NO_82580_SUPPORT */
+ while (timeout) {
+ if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
+ break;
+ msec_delay(1);
+ timeout--;
+ }
+ if (!timeout)
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+
+ /* If EEPROM is not marked present, init the PHY manually */
+ if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+ (hw->phy.type == e1000_phy_igp_3))
+ e1000_phy_init_script_igp3(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_link_up_info_82575 - Get link speed/duplex info
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * This is a wrapper function, if using the serial gigabit media independent
+ * interface, use PCS to retrieve the link speed and duplex information.
+ * Otherwise, use the generic function to get the link speed and duplex info.
+ **/
+STATIC INT32 e1000_get_link_up_info_82575(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_link_up_info_82575");
+
+ if (hw->phy.media_type != e1000_media_type_copper)
+ ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, speed,
+ duplex);
+ else
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed,
+ duplex);
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_link_82575 - Check for link
+ * @hw: pointer to the HW structure
+ *
+ * If sgmii is enabled, then use the pcs register to determine link, otherwise
+ * use the generic interface for determining link.
+ **/
+STATIC INT32 e1000_check_for_link_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 speed, duplex;
+
+ DEBUGFUNC("e1000_check_for_link_82575");
+
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, &speed,
+ &duplex);
+ /*
+ * Use this flag to determine if link needs to be checked or
+ * not. If we have link clear the flag so that we do not
+ * continue to check for link.
+ */
+ hw->mac.get_link_status = !hw->mac.serdes_has_link;
+ } else {
+ ret_val = e1000_check_for_copper_link_generic(hw);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_power_up_serdes_link_82575 - Power up the serdes link after shutdown
+ * @hw: pointer to the HW structure
+ **/
+STATIC void e1000_power_up_serdes_link_82575(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_power_up_serdes_link_82575");
+
+ if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+ !e1000_sgmii_active_82575(hw))
+ return;
+
+ /* Enable PCS to turn on link */
+ reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
+ reg |= E1000_PCS_CFG_PCS_EN;
+ E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
+
+ /* Power up the laser */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_SDP3_DATA;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+ /* flush the write to verify completion */
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+}
+
+/**
+ * e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Using the physical coding sub-layer (PCS), retrieve the current speed and
+ * duplex, then store the values in the pointers provided.
+ **/
+static INT32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 pcs;
+
+ DEBUGFUNC("e1000_get_pcs_speed_and_duplex_82575");
+
+ /* Set up defaults for the return values of this function */
+ mac->serdes_has_link = FALSE;
+ *speed = 0;
+ *duplex = 0;
+
+ /*
+ * Read the PCS Status register for link state. For non-copper mode,
+ * the status register is not accurate. The PCS status register is
+ * used instead.
+ */
+ pcs = E1000_READ_REG(hw, E1000_PCS_LSTAT);
+
+ /*
+ * The link up bit determines when link is up on autoneg. The sync ok
+ * gets set once both sides sync up and agree upon link. Stable link
+ * can be determined by checking for both link up and link sync ok
+ */
+ if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) {
+ mac->serdes_has_link = TRUE;
+
+ /* Detect and store PCS speed */
+ if (pcs & E1000_PCS_LSTS_SPEED_1000) {
+ *speed = SPEED_1000;
+ } else if (pcs & E1000_PCS_LSTS_SPEED_100) {
+ *speed = SPEED_100;
+ } else {
+ *speed = SPEED_10;
+ }
+
+ /* Detect and store PCS duplex */
+ if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) {
+ *duplex = FULL_DUPLEX;
+ } else {
+ *duplex = HALF_DUPLEX;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_shutdown_serdes_link_82575 - Remove link during power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of serdes shut down sfp and PCS on driver unload
+ * when management pass thru is not enabled.
+ **/
+void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_shutdown_serdes_link_82575");
+
+ if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+ !e1000_sgmii_active_82575(hw))
+ return;
+
+ if (!e1000_enable_mng_pass_thru(hw)) {
+ /* Disable PCS to turn off link */
+ reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
+ reg &= ~E1000_PCS_CFG_PCS_EN;
+ E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
+
+ /* shutdown the laser */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg |= E1000_CTRL_EXT_SDP3_DATA;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+ /* flush the write to verify completion */
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+ }
+
+ return;
+}
+
+/**
+ * e1000_reset_hw_82575 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state.
+ **/
+STATIC INT32 e1000_reset_hw_82575(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_82575");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+ }
+
+ /* set the completion timeout for interface */
+ ret_val = e1000_set_pcie_completion_timeout(hw);
+ if (ret_val) {
+ DEBUGOUT("PCI-E Set completion timeout has failed.\n");
+ }
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ DEBUGOUT("Auto Read Done did not complete\n");
+ }
+
+ /* If EEPROM is not present, run manual init scripts */
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+ e1000_reset_init_script_82575(hw);
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_82575 - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation.
+ **/
+STATIC INT32 e1000_init_hw_82575(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ UINT16 i, rar_count = mac->rar_entry_count;
+
+ DEBUGFUNC("e1000_init_hw_82575");
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val) {
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+ }
+
+ /* Disabling VLAN filtering */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ mac->ops.clear_vfta(hw);
+
+ /* Setup the receive address */
+ e1000_init_rx_addrs_generic(hw, rar_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+#ifndef NO_82576_SUPPORT
+ /* Zero out the Unicast HASH table */
+ DEBUGOUT("Zeroing the UTA\n");
+ for (i = 0; i < mac->uta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0);
+
+#endif
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_82575(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_82575 - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Configures the link for auto-neg or forced speed and duplex. Then we check
+ * for link, once link is established calls to configure collision distance
+ * and flow control are called.
+ **/
+STATIC INT32 e1000_setup_copper_link_82575(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_setup_copper_link_82575");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ ret_val = e1000_setup_serdes_link_82575(hw);
+ if (ret_val)
+ goto out;
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (e1000_sgmii_active_82575(hw) && !hw->phy.reset_disable) {
+#else
+ if (e1000_sgmii_active_82575(hw)) {
+#endif
+ /* allow time for SFP cage time to power up phy */
+ msec_delay(300);
+
+ ret_val = hw->phy.ops.reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error resetting the PHY.\n");
+ goto out;
+ }
+ }
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
+ ret_val = e1000_copper_link_setup_m88(hw);
+ break;
+ case e1000_phy_igp_3:
+ ret_val = e1000_copper_link_setup_igp(hw);
+ break;
+#ifndef NO_82580_SUPPORT
+ case e1000_phy_82580:
+ ret_val = e1000_copper_link_setup_82577(hw);
+ break;
+#endif
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_setup_copper_link_generic(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_serdes_link_82575 - Setup link for serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configure the physical coding sub-layer (PCS) link. The PCS link is
+ * used on copper connections where the serialized gigabit media independent
+ * interface (sgmii), or serdes fiber is being used. Configures the link
+ * for auto-negotiation or forces speed/duplex.
+ **/
+STATIC INT32 e1000_setup_serdes_link_82575(struct e1000_hw *hw)
+{
+ UINT32 ctrl_ext, ctrl_reg, reg;
+ BOOLEAN pcs_autoneg;
+
+ DEBUGFUNC("e1000_setup_serdes_link_82575");
+
+ if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+ !e1000_sgmii_active_82575(hw))
+ return E1000_SUCCESS;
+
+ /*
+ * On the 82575, SerDes loopback mode persists until it is
+ * explicitly turned off or a power cycle is performed. A read to
+ * the register does not indicate its status. Therefore, we ensure
+ * loopback mode is disabled during initialization.
+ */
+ E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+
+ /* power on the sfp cage if present */
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+ ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl_reg |= E1000_CTRL_SLU;
+
+ /* set both sw defined pins on 82575/82576*/
+ if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576)
+ ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;
+
+ reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
+
+ /* default pcs_autoneg to the same setting as mac autoneg */
+ pcs_autoneg = hw->mac.autoneg;
+
+ switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
+ case E1000_CTRL_EXT_LINK_MODE_SGMII:
+ /* sgmii mode lets the phy handle forcing speed/duplex */
+ pcs_autoneg = TRUE;
+ /* autoneg time out should be disabled for SGMII mode */
+ reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
+ break;
+#ifndef NO_82580_SUPPORT
+ case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
+ /* disable PCS autoneg and support parallel detect only */
+ pcs_autoneg = FALSE;
+ /* fall through to default case */
+#endif
+ default:
+ /*
+ * non-SGMII modes only supports a speed of 1000/Full for the
+ * link so it is best to just force the MAC and let the pcs
+ * link either autoneg or be forced to 1000/Full
+ */
+ ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
+ E1000_CTRL_FD | E1000_CTRL_FRCDPX;
+
+ /* set speed of 1000/Full if speed/duplex is forced */
+ reg |= E1000_PCS_LCTL_FSV_1000 | E1000_PCS_LCTL_FDV_FULL;
+ break;
+ }
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
+
+ /*
+ * New SerDes mode allows for forcing speed or autonegotiating speed
+ * at 1gb. Autoneg should be default set by most drivers. This is the
+ * mode that will be compatible with older link partners and switches.
+ * However, both are supported by the hardware and some drivers/tools.
+ */
+ reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
+ E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
+
+ /*
+ * We force flow control to prevent the CTRL register values from being
+ * overwritten by the autonegotiated flow control values
+ */
+ reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+
+ if (pcs_autoneg) {
+ /* Set PCS register for autoneg */
+ reg |= E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */
+ E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */
+ DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg);
+ } else {
+ /* Set PCS register for forced link */
+ reg |= E1000_PCS_LCTL_FSD; /* Force Speed */
+ DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg);
+ }
+
+ E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg);
+
+ if (!e1000_sgmii_active_82575(hw))
+ e1000_force_mac_fc_generic(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_valid_led_default_82575 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+STATIC INT32 e1000_valid_led_default_82575(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_82575");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+ switch(hw->phy.media_type) {
+ case e1000_media_type_internal_serdes:
+ *data = ID_LED_DEFAULT_82575_SERDES;
+ break;
+ case e1000_media_type_copper:
+ default:
+ *data = ID_LED_DEFAULT;
+ break;
+ }
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_sgmii_active_82575 - Return sgmii state
+ * @hw: pointer to the HW structure
+ *
+ * 82575 silicon has a serialized gigabit media independent interface (sgmii)
+ * which can be enabled for use in the embedded applications. Simply
+ * return the current state of the sgmii interface.
+ **/
+static BOOLEAN e1000_sgmii_active_82575(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+ return dev_spec->sgmii_active;
+}
+
+/**
+ * e1000_reset_init_script_82575 - Inits HW defaults after reset
+ * @hw: pointer to the HW structure
+ *
+ * Inits recommended HW defaults after a reset when there is no EEPROM
+ * detected. This is only for the 82575.
+ **/
+STATIC INT32 e1000_reset_init_script_82575(struct e1000_hw* hw)
+{
+ DEBUGFUNC("e1000_reset_init_script_82575");
+
+ if (hw->mac.type == e1000_82575) {
+ DEBUGOUT("Running reset init script for 82575\n");
+ /* SerDes configuration via SERDESCTRL */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x00, 0x0C);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x01, 0x78);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x1B, 0x23);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x23, 0x15);
+
+ /* CCM configuration via CCMCTL register */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x14, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x10, 0x00);
+
+ /* PCIe lanes configuration */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x00, 0xEC);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x61, 0xDF);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x34, 0x05);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x2F, 0x81);
+
+ /* PCIe PLL Configuration */
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x02, 0x47);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x14, 0x00);
+ e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x10, 0x00);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_read_mac_addr_82575 - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_read_mac_addr_82575(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_mac_addr_82575");
+
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_config_collision_dist_82575 - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup.
+ **/
+STATIC void e1000_config_collision_dist_82575(struct e1000_hw *hw)
+{
+ UINT32 tctl_ext;
+
+ DEBUGFUNC("e1000_config_collision_dist_82575");
+
+ tctl_ext = E1000_READ_REG(hw, E1000_TCTL_EXT);
+
+ tctl_ext &= ~E1000_TCTL_EXT_COLD;
+ tctl_ext |= E1000_COLLISION_DISTANCE << E1000_TCTL_EXT_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, E1000_TCTL_EXT, tctl_ext);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_power_down_phy_copper_82575 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_82575(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+
+ if (!(phy->ops.check_reset_block))
+ return;
+
+ /* If the management interface is not enabled, then power down */
+ if (!(e1000_enable_mng_pass_thru(hw) || phy->ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_82575 - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+STATIC void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_82575");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_PRC64);
+ E1000_READ_REG(hw, E1000_PRC127);
+ E1000_READ_REG(hw, E1000_PRC255);
+ E1000_READ_REG(hw, E1000_PRC511);
+ E1000_READ_REG(hw, E1000_PRC1023);
+ E1000_READ_REG(hw, E1000_PRC1522);
+ E1000_READ_REG(hw, E1000_PTC64);
+ E1000_READ_REG(hw, E1000_PTC127);
+ E1000_READ_REG(hw, E1000_PTC255);
+ E1000_READ_REG(hw, E1000_PTC511);
+ E1000_READ_REG(hw, E1000_PTC1023);
+ E1000_READ_REG(hw, E1000_PTC1522);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ E1000_READ_REG(hw, E1000_ICRXPTC);
+ E1000_READ_REG(hw, E1000_ICRXATC);
+ E1000_READ_REG(hw, E1000_ICTXPTC);
+ E1000_READ_REG(hw, E1000_ICTXATC);
+ E1000_READ_REG(hw, E1000_ICTXQEC);
+ E1000_READ_REG(hw, E1000_ICTXQMTC);
+ E1000_READ_REG(hw, E1000_ICRXDMTC);
+
+ E1000_READ_REG(hw, E1000_CBTMPC);
+ E1000_READ_REG(hw, E1000_HTDPMC);
+ E1000_READ_REG(hw, E1000_CBRMPC);
+ E1000_READ_REG(hw, E1000_RPTHC);
+ E1000_READ_REG(hw, E1000_HGPTC);
+ E1000_READ_REG(hw, E1000_HTCBDPC);
+ E1000_READ_REG(hw, E1000_HGORCL);
+ E1000_READ_REG(hw, E1000_HGORCH);
+ E1000_READ_REG(hw, E1000_HGOTCL);
+ E1000_READ_REG(hw, E1000_HGOTCH);
+ E1000_READ_REG(hw, E1000_LENERRS);
+
+ /* This register should not be read in copper configurations */
+ if ((hw->phy.media_type == e1000_media_type_internal_serdes) ||
+ e1000_sgmii_active_82575(hw))
+ E1000_READ_REG(hw, E1000_SCVPC);
+}
+
+/**
+ * e1000_rx_fifo_flush_82575 - Clean rx fifo after RX enable
+ * @hw: pointer to the HW structure
+ *
+ * After rx enable if managability is enabled then there is likely some
+ * bad data at the start of the fifo and possibly in the DMA fifo. This
+ * function clears the fifos and flushes any packets that came in as rx was
+ * being enabled.
+ **/
+void e1000_rx_fifo_flush_82575(struct e1000_hw *hw)
+{
+ UINT32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
+ int i, ms_wait;
+
+ DEBUGFUNC("e1000_rx_fifo_workaround_82575");
+ if (hw->mac.type != e1000_82575 ||
+ !(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN))
+ return;
+
+ /* Disable all RX queues */
+ for (i = 0; i < 4; i++) {
+ rxdctl[i] = E1000_READ_REG(hw, E1000_RXDCTL(i));
+ E1000_WRITE_REG(hw, E1000_RXDCTL(i),
+ rxdctl[i] & ~E1000_RXDCTL_QUEUE_ENABLE);
+ }
+ /* Poll all queues to verify they have shut down */
+ for (ms_wait = 0; ms_wait < 10; ms_wait++) {
+ msec_delay(1);
+ rx_enabled = 0;
+ for (i = 0; i < 4; i++)
+ rx_enabled |= E1000_READ_REG(hw, E1000_RXDCTL(i));
+ if (!(rx_enabled & E1000_RXDCTL_QUEUE_ENABLE))
+ break;
+ }
+
+ if (ms_wait == 10)
+ DEBUGOUT("Queue disable timed out after 10ms\n");
+
+ /* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
+ * incoming packets are rejected. Set enable and wait 2ms so that
+ * any packet that was coming in as RCTL.EN was set is flushed
+ */
+ rfctl = E1000_READ_REG(hw, E1000_RFCTL);
+ E1000_WRITE_REG(hw, E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF);
+
+ rlpml = E1000_READ_REG(hw, E1000_RLPML);
+ E1000_WRITE_REG(hw, E1000_RLPML, 0);
+
+ rctl = E1000_READ_REG(hw, E1000_RCTL);
+ temp_rctl = rctl & ~(E1000_RCTL_EN | E1000_RCTL_SBP);
+ temp_rctl |= E1000_RCTL_LPE;
+
+ E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl);
+ E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl | E1000_RCTL_EN);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(2);
+
+ /* Enable RX queues that were previously enabled and restore our
+ * previous state
+ */
+ for (i = 0; i < 4; i++)
+ E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl[i]);
+ E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+ E1000_WRITE_FLUSH(hw);
+
+ E1000_WRITE_REG(hw, E1000_RLPML, rlpml);
+ E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
+
+ /* Flush receive errors generated by workaround */
+ E1000_READ_REG(hw, E1000_ROC);
+ E1000_READ_REG(hw, E1000_RNBC);
+ E1000_READ_REG(hw, E1000_MPC);
+}
+
+/**
+ * e1000_set_pcie_completion_timeout - set pci-e completion timeout
+ * @hw: pointer to the HW structure
+ *
+ * The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
+ * however the hardware default for these parts is 500us to 1ms which is less
+ * than the 10ms recommended by the pci-e spec. To address this we need to
+ * increase the value to either 10ms to 200ms for capability version 1 config,
+ * or 16ms to 55ms for version 2.
+ **/
+STATIC INT32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw)
+{
+ UINT32 gcr = E1000_READ_REG(hw, E1000_GCR);
+ INT32 ret_val = E1000_SUCCESS;
+#ifndef NO_PCIE_SUPPORT
+ UINT16 pcie_devctl2;
+#endif
+
+ /* only take action if timeout value is defaulted to 0 */
+ if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
+ goto out;
+
+ /*
+ * if capababilities version is type 1 we can write the
+ * timeout of 10ms to 200ms through the GCR register
+ */
+ if (!(gcr & E1000_GCR_CAP_VER2)) {
+ gcr |= E1000_GCR_CMPL_TMOUT_10ms;
+ goto out;
+ }
+
+#ifndef NO_PCIE_SUPPORT
+ /*
+ * for version 2 capabilities we need to write the config space
+ * directly in order to set the completion timeout value for
+ * 16ms to 55ms
+ */
+ ret_val = e1000_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+ if (ret_val)
+ goto out;
+
+ pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+ ret_val = e1000_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+#endif
+out:
+ /* disable completion timeout resend */
+ gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
+
+ E1000_WRITE_REG(hw, E1000_GCR, gcr);
+ return ret_val;
+}
+
+#ifndef NO_82576_SUPPORT
+
+/**
+ * e1000_vmdq_set_anti_spoofing_pf - enable or disable anti-spoofing
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ * @pf: Physical Function pool - do not set anti-spoofing for the PF
+ *
+ * enables/disables L2 switch anti-spoofing functionality.
+ **/
+void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, BOOLEAN enable, int pf)
+{
+ UINT32 dtxswc;
+
+ switch (hw->mac.type) {
+ case e1000_82576:
+ dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
+ if (enable) {
+ dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ /* The PF can spoof - it has to in order to
+ * support emulation mode NICs */
+ dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
+ } else {
+ dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ }
+ E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ *
+ * enables/disables L2 switch loopback functionality.
+ **/
+void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, BOOLEAN enable)
+{
+ UINT32 dtxswc;
+
+ switch (hw->mac.type) {
+ case e1000_82576:
+ dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
+ if (enable)
+ dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ else
+ dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+ break;
+ default:
+ /* Currently no other hardware supports loopback */
+ break;
+ }
+
+
+}
+
+/**
+ * e1000_vmdq_set_replication_pf - enable or disable vmdq replication
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ *
+ * enables/disables replication of packets across multiple pools.
+ **/
+void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, BOOLEAN enable)
+{
+ UINT32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL);
+
+ if (enable)
+ vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
+ else
+ vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN;
+
+ E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl);
+}
+
+#endif /* NO_82576_SUPPORT */
+#ifndef NO_82580_SUPPORT
+/**
+ * e1000_read_phy_reg_82580 - Read 82580 MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control register in the PHY at offset and stores the
+ * information read to data.
+ **/
+STATIC INT32 e1000_read_phy_reg_82580(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_read_phy_reg_82580");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_phy_reg_mdic(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_82580 - Write 82580 MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ **/
+STATIC INT32 e1000_write_phy_reg_82580(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_write_phy_reg_82580");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_write_phy_reg_mdic(hw, offset, data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits
+ * @hw: pointer to the HW structure
+ *
+ * This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
+ * the values found in the EEPROM. This addresses an issue in which these
+ * bits are not restored from EEPROM after reset.
+ **/
+STATIC INT32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 mdicnfg;
+ UINT16 nvm_data;
+
+ DEBUGFUNC("e1000_reset_mdicnfg_82580");
+
+ if (hw->mac.type != e1000_82580)
+ goto out;
+ if (!e1000_sgmii_active_82575(hw))
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
+ NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
+ &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG);
+ if (nvm_data & NVM_WORD24_EXT_MDIO)
+ mdicnfg |= E1000_MDICNFG_EXT_MDIO;
+ if (nvm_data & NVM_WORD24_COM_MDIO)
+ mdicnfg |= E1000_MDICNFG_COM_MDIO;
+ E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_82580 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets function or entire device (all ports, etc.)
+ * to a known state.
+ **/
+STATIC INT32 e1000_reset_hw_82580(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ /* BH SW mailbox bit in SW_FW_SYNC */
+ UINT16 swmbsw_mask = E1000_SW_SYNCH_MB;
+ UINT32 ctrl;
+ BOOLEAN global_device_reset = hw->dev_spec._82575.global_device_reset;
+
+ DEBUGFUNC("e1000_reset_hw_82580");
+
+ hw->dev_spec._82575.global_device_reset = FALSE;
+
+ /* Get current control state. */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ /* Determine whether or not a global dev reset is requested */
+ if (global_device_reset &&
+ e1000_acquire_swfw_sync_82575(hw, swmbsw_mask))
+ global_device_reset = FALSE;
+
+ if (global_device_reset &&
+ !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STAT_DEV_RST_SET))
+ ctrl |= E1000_CTRL_DEV_RST;
+ else
+ ctrl |= E1000_CTRL_RST;
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Add delay to insure DEV_RST has time to complete */
+ if (global_device_reset)
+ msec_delay(5);
+
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ DEBUGOUT("Auto Read Done did not complete\n");
+ }
+
+ /* If EEPROM is not present, run manual init scripts */
+ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+ e1000_reset_init_script_82575(hw);
+
+ /* clear global device reset status bit */
+ E1000_WRITE_REG(hw, E1000_STATUS, E1000_STAT_DEV_RST_SET);
+
+ /* Clear any pending interrupt events. */
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ ret_val = e1000_reset_mdicnfg_82580(hw);
+ if (ret_val)
+ DEBUGOUT("Could not reset MDICNFG based on EEPROM\n");
+
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+ /* Release semaphore */
+ if (global_device_reset)
+ e1000_release_swfw_sync_82575(hw, swmbsw_mask);
+
+ return ret_val;
+}
+
+/**
+ * e1000_rxpbs_adjust_82580 - adjust RXPBS value to reflect actual RX PBA size
+ * @data: data received by reading RXPBS register
+ *
+ * The 82580 uses a table based approach for packet buffer allocation sizes.
+ * This function converts the retrieved value into the correct table value
+ * 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7
+ * 0x0 36 72 144 1 2 4 8 16
+ * 0x8 35 70 140 rsv rsv rsv rsv rsv
+ */
+UINT16 e1000_rxpbs_adjust_82580(UINT32 data)
+{
+ UINT16 ret_val = 0;
+
+ if (data < E1000_82580_RXPBS_TABLE_SIZE)
+ ret_val = e1000_82580_rxpbs_table[data];
+
+ return ret_val;
+}
+#endif /* NO_82580_SUPPORT */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h
new file mode 100755
index 0000000..0471292
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_82575.h
@@ -0,0 +1,423 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_82575_H_
+#define _E1000_82575_H_
+
+#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_DEF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_OFF1_ON2))
+/*
+ * Receive Address Register Count
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * These entries are also used for MAC-based filtering.
+ */
+#ifndef NO_82576_SUPPORT
+/*
+ * For 82576, there are an additional set of RARs that begin at an offset
+ * separate from the first set of RARs.
+ */
+#endif
+#define E1000_RAR_ENTRIES_82575 16
+#ifndef NO_82576_SUPPORT
+#define E1000_RAR_ENTRIES_82576 24
+#endif
+#ifndef NO_82580_SUPPORT
+#define E1000_RAR_ENTRIES_82580 24
+#define E1000_SW_SYNCH_MB 0x00000100
+#define E1000_STAT_DEV_RST_SET 0x00100000
+#define E1000_CTRL_DEV_RST 0x20000000
+#endif
+
+
+/* SRRCTL bit definitions */
+#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000
+#ifndef NO_82580_SUPPORT
+#define E1000_SRRCTL_TIMESTAMP 0x40000000
+#endif
+#define E1000_SRRCTL_DROP_EN 0x80000000
+
+#define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F
+#define E1000_SRRCTL_BSIZEHDR_MASK 0x00003F00
+
+#define E1000_TX_HEAD_WB_ENABLE 0x1
+#define E1000_TX_SEQNUM_WB_ENABLE 0x2
+
+#define E1000_MRQC_ENABLE_RSS_4Q 0x00000002
+#define E1000_MRQC_ENABLE_VMDQ 0x00000003
+#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005
+#define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000
+#ifndef NO_82580_SUPPORT
+#define E1000_MRQC_ENABLE_RSS_8Q 0x00000002
+#endif /* Barton Hills HW */
+
+#define E1000_VMRCTL_MIRROR_PORT_SHIFT 8
+#define E1000_VMRCTL_MIRROR_DSTPORT_MASK (7 << E1000_VMRCTL_MIRROR_PORT_SHIFT)
+#define E1000_VMRCTL_POOL_MIRROR_ENABLE (1 << 0)
+#define E1000_VMRCTL_UPLINK_MIRROR_ENABLE (1 << 1)
+#define E1000_VMRCTL_DOWNLINK_MIRROR_ENABLE (1 << 2)
+
+#define E1000_EICR_TX_QUEUE ( \
+ E1000_EICR_TX_QUEUE0 | \
+ E1000_EICR_TX_QUEUE1 | \
+ E1000_EICR_TX_QUEUE2 | \
+ E1000_EICR_TX_QUEUE3)
+
+#define E1000_EICR_RX_QUEUE ( \
+ E1000_EICR_RX_QUEUE0 | \
+ E1000_EICR_RX_QUEUE1 | \
+ E1000_EICR_RX_QUEUE2 | \
+ E1000_EICR_RX_QUEUE3)
+
+#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE
+#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE
+
+#define EIMS_ENABLE_MASK ( \
+ E1000_EIMS_RX_QUEUE | \
+ E1000_EIMS_TX_QUEUE | \
+ E1000_EIMS_TCP_TIMER | \
+ E1000_EIMS_OTHER)
+
+/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
+#define E1000_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */
+#define E1000_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */
+#define E1000_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
+#define E1000_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */
+#define E1000_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */
+#define E1000_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */
+#define E1000_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */
+#define E1000_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */
+#define E1000_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */
+#define E1000_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */
+
+/* Receive Descriptor - Advanced */
+union e1000_adv_rx_desc {
+ struct {
+ UINT64 pkt_addr; /* Packet buffer address */
+ UINT64 hdr_addr; /* Header buffer address */
+ } read;
+ struct {
+ struct {
+ union {
+ UINT32 data;
+ struct {
+ UINT16 pkt_info; /*RSS type, Pkt type*/
+ UINT16 hdr_info; /* Split Header,
+ * header buffer len*/
+ } hs_rss;
+ } lo_dword;
+ union {
+ UINT32 rss; /* RSS Hash */
+ struct {
+ UINT16 ip_id; /* IP id */
+ UINT16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ UINT32 status_error; /* ext status/error */
+ UINT16 length; /* Packet length */
+ UINT16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+#define E1000_RXDADV_RSSTYPE_MASK 0x0000000F
+#define E1000_RXDADV_RSSTYPE_SHIFT 12
+#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
+#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
+#define E1000_RXDADV_SPLITHEADER_EN 0x00001000
+#define E1000_RXDADV_SPH 0x8000
+#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
+#ifndef NO_82580_SUPPORT
+#define E1000_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
+#endif
+#define E1000_RXDADV_ERR_HBO 0x00800000
+
+/* RSS Hash results */
+#define E1000_RXDADV_RSSTYPE_NONE 0x00000000
+#define E1000_RXDADV_RSSTYPE_IPV4_TCP 0x00000001
+#define E1000_RXDADV_RSSTYPE_IPV4 0x00000002
+#define E1000_RXDADV_RSSTYPE_IPV6_TCP 0x00000003
+#define E1000_RXDADV_RSSTYPE_IPV6_EX 0x00000004
+#define E1000_RXDADV_RSSTYPE_IPV6 0x00000005
+#define E1000_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
+#define E1000_RXDADV_RSSTYPE_IPV4_UDP 0x00000007
+#define E1000_RXDADV_RSSTYPE_IPV6_UDP 0x00000008
+#define E1000_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
+
+/* RSS Packet Types as indicated in the receive descriptor */
+#define E1000_RXDADV_PKTTYPE_NONE 0x00000000
+#define E1000_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */
+#define E1000_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPV4 hdr + extensions */
+#define E1000_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPV6 hdr present */
+#define E1000_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPV6 hdr + extensions */
+#define E1000_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */
+#define E1000_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */
+#define E1000_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */
+#define E1000_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */
+
+#ifndef NO_82576_SUPPORT
+#define E1000_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */
+#define E1000_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */
+#define E1000_RXDADV_PKTTYPE_LINKSEC 0x00004000 /* LinkSec Encap */
+#define E1000_RXDADV_PKTTYPE_ETQF 0x00008000 /* PKTTYPE is ETQF index */
+#define E1000_RXDADV_PKTTYPE_ETQF_MASK 0x00000070 /* ETQF has 8 indices */
+#define E1000_RXDADV_PKTTYPE_ETQF_SHIFT 4 /* Right-shift 4 bits */
+
+/* LinkSec results */
+/* Security Processing bit Indication */
+#define E1000_RXDADV_LNKSEC_STATUS_SECP 0x00020000
+#define E1000_RXDADV_LNKSEC_ERROR_BIT_MASK 0x18000000
+#define E1000_RXDADV_LNKSEC_ERROR_NO_SA_MATCH 0x08000000
+#define E1000_RXDADV_LNKSEC_ERROR_REPLAY_ERROR 0x10000000
+#define E1000_RXDADV_LNKSEC_ERROR_BAD_SIG 0x18000000
+
+#define E1000_RXDADV_IPSEC_STATUS_SECP 0x00020000
+#define E1000_RXDADV_IPSEC_ERROR_BIT_MASK 0x18000000
+#define E1000_RXDADV_IPSEC_ERROR_INVALID_PROTOCOL 0x08000000
+#define E1000_RXDADV_IPSEC_ERROR_INVALID_LENGTH 0x10000000
+#define E1000_RXDADV_IPSEC_ERROR_AUTHENTICATION_FAILED 0x18000000
+
+#endif
+/* Transmit Descriptor - Advanced */
+union e1000_adv_tx_desc {
+ struct {
+ UINT64 buffer_addr; /* Address of descriptor's data buf */
+ UINT32 cmd_type_len;
+ UINT32 olinfo_status;
+ } read;
+ struct {
+ UINT64 rsvd; /* Reserved */
+ UINT32 nxtseq_seed;
+ UINT32 status;
+ } wb;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
+#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
+#define E1000_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */
+#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
+#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
+#ifndef NO_82576_SUPPORT
+#define E1000_ADVTXD_MAC_LINKSEC 0x00040000 /* Apply LinkSec on packet */
+#endif /* NO_82576_SUPPORT */
+#define E1000_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
+#define E1000_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */
+#define E1000_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */
+#define E1000_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
+#define E1000_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */
+#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+
+/* Context descriptors */
+struct e1000_adv_tx_context_desc {
+ UINT32 vlan_macip_lens;
+ UINT32 seqnum_seed;
+ UINT32 type_tucmd_mlhl;
+ UINT32 mss_l4len_idx;
+};
+
+#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
+#define E1000_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */
+#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
+#define E1000_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */
+#define E1000_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
+#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */
+#define E1000_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */
+/* IPSec Encrypt Enable for ESP */
+#define E1000_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000
+#define E1000_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */
+#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
+#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
+/* Adv ctxt IPSec SA IDX mask */
+#define E1000_ADVTXD_IPSEC_SA_INDEX_MASK 0x000000FF
+/* Adv ctxt IPSec ESP len mask */
+#define E1000_ADVTXD_IPSEC_ESP_LEN_MASK 0x000000FF
+
+/* Additional Transmit Descriptor Control definitions */
+#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
+#define E1000_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */
+/* Tx Queue Arbitration Priority 0=low, 1=high */
+#define E1000_TXDCTL_PRIORITY 0x08000000
+
+/* Additional Receive Descriptor Control definitions */
+#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */
+#define E1000_RXDCTL_SWFLSH 0x04000000 /* Rx Desc. write-back flushing */
+
+/* Direct Cache Access (DCA) definitions */
+#define E1000_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */
+#define E1000_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */
+
+#define E1000_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */
+#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
+
+#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
+#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
+#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
+
+#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
+#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
+
+#ifndef NO_82576_SUPPORT
+#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */
+#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */
+#define E1000_DCA_TXCTRL_CPUID_SHIFT_82576 24 /* Tx CPUID */
+#define E1000_DCA_RXCTRL_CPUID_SHIFT_82576 24 /* Rx CPUID */
+
+/* Additional interrupt register bit definitions */
+#define E1000_ICR_LSECPNS 0x00000020 /* PN threshold - server */
+#define E1000_IMS_LSECPNS E1000_ICR_LSECPNS /* PN threshold - server */
+#define E1000_ICS_LSECPNS E1000_ICR_LSECPNS /* PN threshold - server */
+
+/* ETQF register bit definitions */
+#define E1000_ETQF_FILTER_ENABLE (1 << 26)
+#define E1000_ETQF_IMM_INT (1 << 29)
+#define E1000_ETQF_1588 (1 << 30)
+#define E1000_ETQF_QUEUE_ENABLE (1 << 31)
+/*
+ * ETQF filter list: one static filter per filter consumer. This is
+ * to avoid filter collisions later. Add new filters
+ * here!!
+ *
+ * Current filters:
+ * EAPOL 802.1x (0x888e): Filter 0
+ */
+#define E1000_ETQF_FILTER_EAPOL 0
+
+#define E1000_FTQF_VF_BP 0x00008000
+#define E1000_FTQF_1588_TIME_STAMP 0x08000000
+#define E1000_FTQF_MASK 0xF0000000
+#define E1000_FTQF_MASK_PROTO_BP 0x10000000
+#define E1000_FTQF_MASK_SOURCE_ADDR_BP 0x20000000
+#define E1000_FTQF_MASK_DEST_ADDR_BP 0x40000000
+#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000
+#endif /* NO_82576_SUPPORT */
+
+#ifndef NO_82576_SUPPORT
+#define E1000_NVM_APME_82575 0x0400
+#define MAX_NUM_VFS 8
+
+#define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */
+#define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */
+#define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */
+#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
+#define E1000_DTXSWC_LLE_SHIFT 16
+#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31) /* global VF LB enable */
+
+/* Easy defines for setting default pool, would normally be left a zero */
+#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
+#define E1000_VT_CTL_DEFAULT_POOL_MASK (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT)
+
+/* Other useful VMD_CTL register defines */
+#define E1000_VT_CTL_IGNORE_MAC (1 << 28)
+#define E1000_VT_CTL_DISABLE_DEF_POOL (1 << 29)
+#define E1000_VT_CTL_VM_REPL_EN (1 << 30)
+
+/* Per VM Offload register setup */
+#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
+#define E1000_VMOLR_LPE 0x00010000 /* Accept Long packet */
+#define E1000_VMOLR_RSSE 0x00020000 /* Enable RSS */
+#define E1000_VMOLR_AUPE 0x01000000 /* Accept untagged packets */
+#define E1000_VMOLR_ROMPE 0x02000000 /* Accept overflow multicast */
+#define E1000_VMOLR_ROPE 0x04000000 /* Accept overflow unicast */
+#define E1000_VMOLR_BAM 0x08000000 /* Accept Broadcast packets */
+#define E1000_VMOLR_MPME 0x10000000 /* Multicast promiscuous mode */
+#define E1000_VMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
+#define E1000_VMOLR_STRCRC 0x80000000 /* CRC stripping enable */
+
+
+#define E1000_VLVF_ARRAY_SIZE 32
+#define E1000_VLVF_VLANID_MASK 0x00000FFF
+#define E1000_VLVF_POOLSEL_SHIFT 12
+#define E1000_VLVF_POOLSEL_MASK (0xFF << E1000_VLVF_POOLSEL_SHIFT)
+#define E1000_VLVF_LVLAN 0x00100000
+#define E1000_VLVF_VLANID_ENABLE 0x80000000
+
+#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
+#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */
+
+#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+
+#define E1000_IOVCTL 0x05BBC
+#define E1000_IOVCTL_REUSE_VFQ 0x00000001
+
+#define E1000_RPLOLR_STRVLAN 0x40000000
+#define E1000_RPLOLR_STRCRC 0x80000000
+
+#define E1000_TCTL_EXT_COLD 0x000FFC00
+#define E1000_TCTL_EXT_COLD_SHIFT 10
+
+#define E1000_DTXCTL_8023LL 0x0004
+#define E1000_DTXCTL_VLAN_ADDED 0x0008
+#define E1000_DTXCTL_OOS_ENABLE 0x0010
+#define E1000_DTXCTL_MDP_EN 0x0020
+#define E1000_DTXCTL_SPOOF_INT 0x0040
+
+#define ALL_QUEUES 0xFFFF
+
+/* RX packet buffer size defines */
+#ifndef NO_82576_SUPPORT
+#define E1000_RXPBS_SIZE_MASK_82576 0x0000007F
+#endif
+void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, BOOLEAN enable);
+void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, BOOLEAN enable, int pf);
+void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, BOOLEAN enable);
+#endif /* NO_82576_SUPPORT */
+#ifndef NO_82580_SUPPORT
+UINT16 e1000_rxpbs_adjust_82580(UINT32 data);
+#endif
+#endif /* _E1000_82575_H_ */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c
new file mode 100755
index 0000000..029cbbc
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.c
@@ -0,0 +1,1248 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+/**
+ * e1000_init_mac_params - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * This function initializes the function pointers for the MAC
+ * set of functions. Called by drivers or by e1000_setup_init_funcs.
+ **/
+INT32 e1000_init_mac_params(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ if (hw->mac.ops.init_params) {
+ ret_val = hw->mac.ops.init_params(hw);
+ if (ret_val) {
+ DEBUGOUT("MAC Initialization Error\n");
+ goto out;
+ }
+ } else {
+ DEBUGOUT("mac.init_mac_params was NULL\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * This function initializes the function pointers for the NVM
+ * set of functions. Called by drivers or by e1000_setup_init_funcs.
+ **/
+INT32 e1000_init_nvm_params(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ if (hw->nvm.ops.init_params) {
+ ret_val = hw->nvm.ops.init_params(hw);
+ if (ret_val) {
+ DEBUGOUT("NVM Initialization Error\n");
+ goto out;
+ }
+ } else {
+ DEBUGOUT("nvm.init_nvm_params was NULL\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_phy_params - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * This function initializes the function pointers for the PHY
+ * set of functions. Called by drivers or by e1000_setup_init_funcs.
+ **/
+INT32 e1000_init_phy_params(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ if (hw->phy.ops.init_params) {
+ ret_val = hw->phy.ops.init_params(hw);
+ if (ret_val) {
+ DEBUGOUT("PHY Initialization Error\n");
+ goto out;
+ }
+ } else {
+ DEBUGOUT("phy.init_phy_params was NULL\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+
+out:
+ return ret_val;
+}
+
+
+/**
+ * e1000_set_mac_type - Sets MAC type
+ * @hw: pointer to the HW structure
+ *
+ * This function sets the mac type of the adapter based on the
+ * device ID stored in the hw structure.
+ * MUST BE FIRST FUNCTION CALLED (explicitly or through
+ * e1000_setup_init_funcs()).
+ **/
+INT32 e1000_set_mac_type(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_set_mac_type");
+
+ switch (hw->device_id) {
+#ifndef NO_82571_SUPPORT
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571PT_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+ mac->type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI:
+ case E1000_DEV_ID_82572EI_COPPER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82572EI_SERDES:
+ mac->type = e1000_82572;
+ break;
+ case E1000_DEV_ID_82573E:
+ case E1000_DEV_ID_82573E_IAMT:
+ case E1000_DEV_ID_82573L:
+ mac->type = e1000_82573;
+ break;
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_82574_SUPPORT
+ case E1000_DEV_ID_82574L:
+ case E1000_DEV_ID_82574LA:
+ mac->type = e1000_82574;
+ break;
+ case E1000_DEV_ID_82583V:
+ mac->type = e1000_82583;
+ break;
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_80003ES2LAN_SUPPORT
+ case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
+ mac->type = e1000_80003es2lan;
+ break;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case E1000_DEV_ID_ICH8_IFE:
+ case E1000_DEV_ID_ICH8_IFE_GT:
+ case E1000_DEV_ID_ICH8_IFE_G:
+ case E1000_DEV_ID_ICH8_IGP_M:
+ case E1000_DEV_ID_ICH8_IGP_M_AMT:
+ case E1000_DEV_ID_ICH8_IGP_AMT:
+ case E1000_DEV_ID_ICH8_IGP_C:
+ mac->type = e1000_ich8lan;
+ break;
+ case E1000_DEV_ID_ICH9_IFE:
+ case E1000_DEV_ID_ICH9_IFE_GT:
+ case E1000_DEV_ID_ICH9_IFE_G:
+ case E1000_DEV_ID_ICH9_IGP_M:
+ case E1000_DEV_ID_ICH9_IGP_M_AMT:
+ case E1000_DEV_ID_ICH9_IGP_M_V:
+ case E1000_DEV_ID_ICH9_IGP_AMT:
+ case E1000_DEV_ID_ICH9_BM:
+ case E1000_DEV_ID_ICH9_IGP_C:
+ case E1000_DEV_ID_ICH10_R_BM_LM:
+ case E1000_DEV_ID_ICH10_R_BM_LF:
+ case E1000_DEV_ID_ICH10_R_BM_V:
+ mac->type = e1000_ich9lan;
+ break;
+ case E1000_DEV_ID_PCH_D_HV_DM:
+ case E1000_DEV_ID_PCH_D_HV_DC:
+ case E1000_DEV_ID_PCH_M_HV_LM:
+ case E1000_DEV_ID_PCH_M_HV_LC:
+ case E1000_DEV_ID_PCH_LV_LM:
+ case E1000_DEV_ID_PCH_LV_V:
+ mac->type = e1000_pchlan;
+ break;
+ case E1000_DEV_ID_PCH2_LV_LM:
+ case E1000_DEV_ID_PCH2_LV_V:
+ mac->type = e1000_pch2lan;
+ break;
+#endif /*NO_ICH8LAN_SUPPORT */
+#ifndef NO_82575_SUPPORT
+ case E1000_DEV_ID_82575EB_COPPER:
+ case E1000_DEV_ID_82575EB_FIBER_SERDES:
+ case E1000_DEV_ID_82575GB_QUAD_COPPER:
+ mac->type = e1000_82575;
+ break;
+#ifndef NO_82576_SUPPORT
+ case E1000_DEV_ID_82576:
+ case E1000_DEV_ID_82576_FIBER:
+ case E1000_DEV_ID_82576_SERDES:
+ case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
+ case E1000_DEV_ID_82576_NS:
+ case E1000_DEV_ID_82576_NS_SERDES:
+ case E1000_DEV_ID_82576_SERDES_QUAD:
+ mac->type = e1000_82576;
+ break;
+#ifndef NO_82580_SUPPORT
+ case E1000_DEV_ID_82580_COPPER:
+ case E1000_DEV_ID_82580_FIBER:
+ case E1000_DEV_ID_82580_SERDES:
+ case E1000_DEV_ID_82580_SGMII:
+ case E1000_DEV_ID_82580_COPPER_DUAL:
+ case E1000_DEV_ID_82580_QUAD_FIBER:
+ mac->type = e1000_82580;
+ break;
+#endif /* NO_82580_SUPPORT */
+#endif /* NO_82576_SUPPORT */
+#endif /* NO_82575_SUPPORT */
+ default:
+ /* Should never have loaded on this device */
+ ret_val = -E1000_ERR_MAC_INIT;
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_setup_init_funcs - Initializes function pointers
+ * @hw: pointer to the HW structure
+ * @init_device: TRUE will initialize the rest of the function pointers
+ * getting the device ready for use. FALSE will only set
+ * MAC type and the function pointers for the other init
+ * functions. Passing FALSE will not generate any hardware
+ * reads or writes.
+ *
+ * This function must be called by a driver in order to use the rest
+ * of the 'shared' code files. Called by drivers only.
+ **/
+INT32 e1000_setup_init_funcs(struct e1000_hw *hw, BOOLEAN init_device)
+{
+ INT32 ret_val;
+
+ /* Can't do much good without knowing the MAC type. */
+ ret_val = e1000_set_mac_type(hw);
+ if (ret_val) {
+ DEBUGOUT("ERROR: MAC type could not be set properly.\n");
+ goto out;
+ }
+
+ if (!hw->hw_addr) {
+ DEBUGOUT("ERROR: Registers not mapped\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ /*
+ * Init function pointers to generic implementations. We do this first
+ * allowing a driver module to override it afterward.
+ */
+ e1000_init_mac_ops_generic(hw);
+#ifndef NO_NULL_OPS_SUPPORT
+ e1000_init_phy_ops_generic(hw);
+#endif /* NO_NULL_OPS_SUPPORT */
+ e1000_init_nvm_ops_generic(hw);
+
+ /*
+ * Set up the init function pointers. These are functions within the
+ * adapter family file that sets up function pointers for the rest of
+ * the functions in that family.
+ */
+ switch (hw->mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ case e1000_82583:
+#endif /* NO_82574_SUPPORT */
+ e1000_init_function_pointers_82571(hw);
+ break;
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+ e1000_init_function_pointers_80003es2lan(hw);
+ break;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ e1000_init_function_pointers_ich8lan(hw);
+ break;
+#endif
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+#ifndef NO_82576_SUPPORT
+ case e1000_82576:
+#endif
+#ifndef NO_82580_SUPPORT
+ case e1000_82580:
+#endif
+ e1000_init_function_pointers_82575(hw);
+ break;
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82576_SUPPORT
+#endif /* NO_82576_SUPPORT */
+ default:
+ DEBUGOUT("Hardware not supported\n");
+ ret_val = -E1000_ERR_CONFIG;
+ break;
+ }
+
+ /*
+ * Initialize the rest of the function pointers. These require some
+ * register reads/writes in some cases.
+ */
+ if (!(ret_val) && init_device) {
+ ret_val = e1000_init_mac_params(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_init_nvm_params(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_init_phy_params(hw);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_bus_info - Obtain bus information for adapter
+ * @hw: pointer to the HW structure
+ *
+ * This will obtain information about the HW bus for which the
+ * adapter is attached and stores it in the hw structure. This is a
+ * function pointer entry point called by drivers.
+ **/
+INT32 e1000_get_bus_info(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.get_bus_info)
+ return hw->mac.ops.get_bus_info(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_clear_vfta - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * This clears the VLAN filter table on the adapter. This is a function
+ * pointer entry point called by drivers.
+ **/
+void e1000_clear_vfta(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.clear_vfta)
+ hw->mac.ops.clear_vfta(hw);
+}
+
+/**
+ * e1000_write_vfta - Write value to VLAN filter table
+ * @hw: pointer to the HW structure
+ * @offset: the 32-bit offset in which to write the value to.
+ * @value: the 32-bit value to write at location offset.
+ *
+ * This writes a 32-bit value to a 32-bit offset in the VLAN filter
+ * table. This is a function pointer entry point called by drivers.
+ **/
+void e1000_write_vfta(struct e1000_hw *hw, UINT32 offset, UINT32 value)
+{
+ if (hw->mac.ops.write_vfta)
+ hw->mac.ops.write_vfta(hw, offset, value);
+}
+
+/**
+ * e1000_update_mc_addr_list - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ *
+ * Updates the Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000_update_mc_addr_list(struct e1000_hw *hw, UINT8 *mc_addr_list,
+ UINT32 mc_addr_count)
+{
+ if (hw->mac.ops.update_mc_addr_list)
+ hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
+ mc_addr_count);
+}
+
+/**
+ * e1000_force_mac_fc - Force MAC flow control
+ * @hw: pointer to the HW structure
+ *
+ * Force the MAC's flow control settings. Currently no func pointer exists
+ * and all implementations are handled in the generic version of this
+ * function.
+ **/
+INT32 e1000_force_mac_fc(struct e1000_hw *hw)
+{
+ return e1000_force_mac_fc_generic(hw);
+}
+
+/**
+ * e1000_check_for_link - Check/Store link connection
+ * @hw: pointer to the HW structure
+ *
+ * This checks the link condition of the adapter and stores the
+ * results in the hw->mac structure. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_check_for_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.check_for_link)
+ return hw->mac.ops.check_for_link(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_check_mng_mode - Check management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has manageability enabled.
+ * This is a function pointer entry point called by drivers.
+ **/
+BOOLEAN e1000_check_mng_mode(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.check_mng_mode)
+ return hw->mac.ops.check_mng_mode(hw);
+
+ return FALSE;
+}
+
+/**
+ * e1000_mng_write_dhcp_info - Writes DHCP info to host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface
+ * @length: size of the buffer
+ *
+ * Writes the DHCP information to the host interface.
+ **/
+INT32 e1000_mng_write_dhcp_info(struct e1000_hw *hw, UINT8 *buffer, UINT16 length)
+{
+ return e1000_mng_write_dhcp_info_generic(hw, buffer, length);
+}
+
+/**
+ * e1000_reset_hw - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state. This is a function pointer
+ * entry point called by drivers.
+ **/
+INT32 e1000_reset_hw(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.reset_hw)
+ return hw->mac.ops.reset_hw(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_init_hw - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation. This is a function
+ * pointer entry point called by drivers.
+ **/
+INT32 e1000_init_hw(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.init_hw)
+ return hw->mac.ops.init_hw(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_setup_link - Configures link and flow control
+ * @hw: pointer to the HW structure
+ *
+ * This configures link and flow control settings for the adapter. This
+ * is a function pointer entry point called by drivers. While modules can
+ * also call this, they probably call their own version of this function.
+ **/
+INT32 e1000_setup_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.setup_link)
+ return hw->mac.ops.setup_link(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_get_speed_and_duplex - Returns current speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to a 16-bit value to store the speed
+ * @duplex: pointer to a 16-bit value to store the duplex.
+ *
+ * This returns the speed and duplex of the adapter in the two 'out'
+ * variables passed in. This is a function pointer entry point called
+ * by drivers.
+ **/
+INT32 e1000_get_speed_and_duplex(struct e1000_hw *hw, UINT16 *speed, UINT16 *duplex)
+{
+ if (hw->mac.ops.get_link_up_info)
+ return hw->mac.ops.get_link_up_info(hw, speed, duplex);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_setup_led - Configures SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This prepares the SW controllable LED for use and saves the current state
+ * of the LED so it can be later restored. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_setup_led(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.setup_led)
+ return hw->mac.ops.setup_led(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_cleanup_led - Restores SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This restores the SW controllable LED to the value saved off by
+ * e1000_setup_led. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_cleanup_led(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.cleanup_led)
+ return hw->mac.ops.cleanup_led(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_blink_led - Blink SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This starts the adapter LED blinking. Request the LED to be setup first
+ * and cleaned up after. This is a function pointer entry point called by
+ * drivers.
+ **/
+INT32 e1000_blink_led(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.blink_led)
+ return hw->mac.ops.blink_led(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_id_led_init - store LED configurations in SW
+ * @hw: pointer to the HW structure
+ *
+ * Initializes the LED config in SW. This is a function pointer entry point
+ * called by drivers.
+ **/
+INT32 e1000_id_led_init(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.id_led_init)
+ return hw->mac.ops.id_led_init(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_on - Turn on SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * Turns the SW defined LED on. This is a function pointer entry point
+ * called by drivers.
+ **/
+INT32 e1000_led_on(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.led_on)
+ return hw->mac.ops.led_on(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_off - Turn off SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * Turns the SW defined LED off. This is a function pointer entry point
+ * called by drivers.
+ **/
+INT32 e1000_led_off(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.led_off)
+ return hw->mac.ops.led_off(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_reset_adaptive - Reset adaptive IFS
+ * @hw: pointer to the HW structure
+ *
+ * Resets the adaptive IFS. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+void e1000_reset_adaptive(struct e1000_hw *hw)
+{
+ e1000_reset_adaptive_generic(hw);
+}
+
+/**
+ * e1000_update_adaptive - Update adaptive IFS
+ * @hw: pointer to the HW structure
+ *
+ * Updates adapter IFS. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+void e1000_update_adaptive(struct e1000_hw *hw)
+{
+ e1000_update_adaptive_generic(hw);
+}
+
+/**
+ * e1000_disable_pcie_master - Disable PCI-Express master access
+ * @hw: pointer to the HW structure
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests. Currently no func pointer exists and all implementations are
+ * handled in the generic version of this function.
+ **/
+INT32 e1000_disable_pcie_master(struct e1000_hw *hw)
+{
+ return e1000_disable_pcie_master_generic(hw);
+}
+
+/**
+ * e1000_config_collision_dist - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup.
+ **/
+void e1000_config_collision_dist(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.config_collision_dist)
+ hw->mac.ops.config_collision_dist(hw);
+}
+
+/**
+ * e1000_rar_set - Sets a receive address register
+ * @hw: pointer to the HW structure
+ * @addr: address to set the RAR to
+ * @index: the RAR to set
+ *
+ * Sets a Receive Address Register (RAR) to the specified address.
+ **/
+void e1000_rar_set(struct e1000_hw *hw, UINT8 *addr, UINT32 index)
+{
+ if (hw->mac.ops.rar_set)
+ hw->mac.ops.rar_set(hw, addr, index);
+}
+
+/**
+ * e1000_validate_mdi_setting - Ensures valid MDI/MDIX SW state
+ * @hw: pointer to the HW structure
+ *
+ * Ensures that the MDI/MDIX SW state is valid.
+ **/
+INT32 e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.validate_mdi_setting)
+ return hw->mac.ops.validate_mdi_setting(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_hash_mc_addr - Determines address location in multicast table
+ * @hw: pointer to the HW structure
+ * @mc_addr: Multicast address to hash.
+ *
+ * This hashes an address to determine its location in the multicast
+ * table. Currently no func pointer exists and all implementations
+ * are handled in the generic version of this function.
+ **/
+UINT32 e1000_hash_mc_addr(struct e1000_hw *hw, UINT8 *mc_addr)
+{
+ return e1000_hash_mc_addr_generic(hw, mc_addr);
+}
+
+/**
+ * e1000_enable_tx_pkt_filtering - Enable packet filtering on TX
+ * @hw: pointer to the HW structure
+ *
+ * Enables packet filtering on transmit packets if manageability is enabled
+ * and host interface is enabled.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+BOOLEAN e1000_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+ return e1000_enable_tx_pkt_filtering_generic(hw);
+}
+
+/**
+ * e1000_mng_host_if_write - Writes to the manageability host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface buffer
+ * @length: size of the buffer
+ * @offset: location in the buffer to write to
+ * @sum: sum of the data (not checksum)
+ *
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient
+ * way. Also fills up the sum of the buffer in *buffer parameter.
+ **/
+INT32 e1000_mng_host_if_write(struct e1000_hw * hw, UINT8 *buffer, UINT16 length,
+ UINT16 offset, UINT8 *sum)
+{
+ if (hw->mac.ops.mng_host_if_write)
+ return hw->mac.ops.mng_host_if_write(hw, buffer, length,
+ offset, sum);
+
+ return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ * e1000_mng_write_cmd_header - Writes manageability command header
+ * @hw: pointer to the HW structure
+ * @hdr: pointer to the host interface command header
+ *
+ * Writes the command header after does the checksum calculation.
+ **/
+INT32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr)
+{
+ if (hw->mac.ops.mng_write_cmd_header)
+ return hw->mac.ops.mng_write_cmd_header(hw, hdr);
+
+ return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ * e1000_mng_enable_host_if - Checks host interface is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ * This function checks whether the HOST IF is enabled for command operation
+ * and also checks whether the previous command is completed. It busy waits
+ * in case of previous command is not completed.
+ **/
+INT32 e1000_mng_enable_host_if(struct e1000_hw * hw)
+{
+ if (hw->mac.ops.mng_enable_host_if)
+ return hw->mac.ops.mng_enable_host_if(hw);
+
+ return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ * e1000_wait_autoneg - Waits for autonegotiation completion
+ * @hw: pointer to the HW structure
+ *
+ * Waits for autoneg to complete. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+INT32 e1000_wait_autoneg(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.wait_autoneg)
+ return hw->mac.ops.wait_autoneg(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_check_reset_block - Verifies PHY can be reset
+ * @hw: pointer to the HW structure
+ *
+ * Checks if the PHY is in a state that can be reset or if manageability
+ * has it tied up. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_check_reset_block(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.check_reset_block)
+ return hw->phy.ops.check_reset_block(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_read_phy_reg - Reads PHY register
+ * @hw: pointer to the HW structure
+ * @offset: the register to read
+ * @data: the buffer to store the 16-bit read.
+ *
+ * Reads the PHY register and returns the value in data.
+ * This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_read_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ if (hw->phy.ops.read_reg)
+ return hw->phy.ops.read_reg(hw, offset, data);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_write_phy_reg - Writes PHY register
+ * @hw: pointer to the HW structure
+ * @offset: the register to write
+ * @data: the value to write.
+ *
+ * Writes the PHY register at offset with the value in data.
+ * This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_write_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ if (hw->phy.ops.write_reg)
+ return hw->phy.ops.write_reg(hw, offset, data);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_release_phy - Generic release PHY
+ * @hw: pointer to the HW structure
+ *
+ * Return if silicon family does not require a semaphore when accessing the
+ * PHY.
+ **/
+void e1000_release_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.release)
+ hw->phy.ops.release(hw);
+}
+
+/**
+ * e1000_acquire_phy - Generic acquire PHY
+ * @hw: pointer to the HW structure
+ *
+ * Return success if silicon family does not require a semaphore when
+ * accessing the PHY.
+ **/
+INT32 e1000_acquire_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.acquire)
+ return hw->phy.ops.acquire(hw);
+
+ return E1000_SUCCESS;
+}
+
+#ifndef NO_80003ES2LAN_SUPPORT
+/**
+ * e1000_cfg_on_link_up - Configure PHY upon link up
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_cfg_on_link_up(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.cfg_on_link_up)
+ return hw->phy.ops.cfg_on_link_up(hw);
+
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_80003ES2LAN_SUPPORT */
+/**
+ * e1000_read_kmrn_reg - Reads register using Kumeran interface
+ * @hw: pointer to the HW structure
+ * @offset: the register to read
+ * @data: the location to store the 16-bit value read.
+ *
+ * Reads a register out of the Kumeran interface. Currently no func pointer
+ * exists and all implementations are handled in the generic version of
+ * this function.
+ **/
+INT32 e1000_read_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return e1000_read_kmrn_reg_generic(hw, offset, data);
+}
+
+/**
+ * e1000_write_kmrn_reg - Writes register using Kumeran interface
+ * @hw: pointer to the HW structure
+ * @offset: the register to write
+ * @data: the value to write.
+ *
+ * Writes a register to the Kumeran interface. Currently no func pointer
+ * exists and all implementations are handled in the generic version of
+ * this function.
+ **/
+INT32 e1000_write_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return e1000_write_kmrn_reg_generic(hw, offset, data);
+}
+
+/**
+ * e1000_get_cable_length - Retrieves cable length estimation
+ * @hw: pointer to the HW structure
+ *
+ * This function estimates the cable length and stores them in
+ * hw->phy.min_length and hw->phy.max_length. This is a function pointer
+ * entry point called by drivers.
+ **/
+INT32 e1000_get_cable_length(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.get_cable_length)
+ return hw->phy.ops.get_cable_length(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_phy_info - Retrieves PHY information from registers
+ * @hw: pointer to the HW structure
+ *
+ * This function gets some information from various PHY registers and
+ * populates hw->phy values with it. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_get_phy_info(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.get_info)
+ return hw->phy.ops.get_info(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_phy_hw_reset - Hard PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Performs a hard PHY reset. This is a function pointer entry point called
+ * by drivers.
+ **/
+INT32 e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.reset)
+ return hw->phy.ops.reset(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_phy_commit - Soft PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Performs a soft PHY reset on those that apply. This is a function pointer
+ * entry point called by drivers.
+ **/
+INT32 e1000_phy_commit(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.commit)
+ return hw->phy.ops.commit(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_d0_lplu_state - Sets low power link up state for D0
+ * @hw: pointer to the HW structure
+ * @active: BOOLEANean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D0
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D0
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_set_d0_lplu_state(struct e1000_hw *hw, BOOLEAN active)
+{
+ if (hw->phy.ops.set_d0_lplu_state)
+ return hw->phy.ops.set_d0_lplu_state(hw, active);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_d3_lplu_state - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: BOOLEANean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained. This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_set_d3_lplu_state(struct e1000_hw *hw, BOOLEAN active)
+{
+ if (hw->phy.ops.set_d3_lplu_state)
+ return hw->phy.ops.set_d3_lplu_state(hw, active);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_read_mac_addr - Reads MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the MAC address out of the adapter and stores it in the HW structure.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_mac_addr(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.read_mac_addr)
+ return hw->mac.ops.read_mac_addr(hw);
+
+ return e1000_read_mac_addr_generic(hw);
+}
+
+/**
+ * e1000_read_pba_string - Read device part number string
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_pba_string(struct e1000_hw *hw, UINT8 *pba_num, UINT32 pba_num_size)
+{
+ return e1000_read_pba_string_generic(hw, pba_num, pba_num_size);
+}
+
+/**
+ * e1000_read_pba_length - Read device part number string length
+ * @hw: pointer to the HW structure
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number length from the EEPROM and
+ * stores the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_pba_length(struct e1000_hw *hw, UINT32 *pba_num_size)
+{
+ return e1000_read_pba_length_generic(hw, pba_num_size);
+}
+
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+/**
+ * e1000_read_pba_num - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+INT32 e1000_read_pba_num(struct e1000_hw *hw, UINT32 *pba_num)
+{
+ return e1000_read_pba_num_generic(hw, pba_num);
+}
+
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+/**
+ * e1000_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
+ * @hw: pointer to the HW structure
+ *
+ * Validates the NVM checksum is correct. This is a function pointer entry
+ * point called by drivers.
+ **/
+INT32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
+{
+ if (hw->nvm.ops.validate)
+ return hw->nvm.ops.validate(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_update_nvm_checksum - Updates NVM (EEPROM) checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the NVM checksum. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+INT32 e1000_update_nvm_checksum(struct e1000_hw *hw)
+{
+ if (hw->nvm.ops.update)
+ return hw->nvm.ops.update(hw);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_reload_nvm - Reloads EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ * extended control register.
+ **/
+void e1000_reload_nvm(struct e1000_hw *hw)
+{
+ if (hw->nvm.ops.reload)
+ hw->nvm.ops.reload(hw);
+}
+
+/**
+ * e1000_read_nvm - Reads NVM (EEPROM)
+ * @hw: pointer to the HW structure
+ * @offset: the word offset to read
+ * @words: number of 16-bit words to read
+ * @data: pointer to the properly sized buffer for the data.
+ *
+ * Reads 16-bit chunks of data from the NVM (EEPROM). This is a function
+ * pointer entry point called by drivers.
+ **/
+INT32 e1000_read_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ if (hw->nvm.ops.read)
+ return hw->nvm.ops.read(hw, offset, words, data);
+
+ return -E1000_ERR_CONFIG;
+}
+
+/**
+ * e1000_write_nvm - Writes to NVM (EEPROM)
+ * @hw: pointer to the HW structure
+ * @offset: the word offset to read
+ * @words: number of 16-bit words to write
+ * @data: pointer to the properly sized buffer for the data.
+ *
+ * Writes 16-bit chunks of data to the NVM (EEPROM). This is a function
+ * pointer entry point called by drivers.
+ **/
+INT32 e1000_write_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ if (hw->nvm.ops.write)
+ return hw->nvm.ops.write(hw, offset, words, data);
+
+ return E1000_SUCCESS;
+}
+
+#ifndef NO_82575_SUPPORT
+/**
+ * e1000_write_8bit_ctrl_reg - Writes 8bit Control register
+ * @hw: pointer to the HW structure
+ * @reg: 32bit register offset
+ * @offset: the register to write
+ * @data: the value to write.
+ *
+ * Writes the PHY register at offset with the value in data.
+ * This is a function pointer entry point called by drivers.
+ **/
+INT32 e1000_write_8bit_ctrl_reg(struct e1000_hw *hw, UINT32 reg, UINT32 offset,
+ UINT8 data)
+{
+ return e1000_write_8bit_ctrl_reg_generic(hw, reg, offset, data);
+}
+
+#endif /* NO_82575_SUPPORT */
+/**
+ * e1000_power_up_phy - Restores link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void e1000_power_up_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.power_up)
+ hw->phy.ops.power_up(hw);
+
+ e1000_setup_link(hw);
+}
+
+/**
+ * e1000_power_down_phy - Power down PHY
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void e1000_power_down_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.power_down)
+ hw->phy.ops.power_down(hw);
+}
+
+#ifndef NO_82576_SUPPORT
+/**
+ * e1000_power_up_fiber_serdes_link - Power up serdes link
+ * @hw: pointer to the HW structure
+ *
+ * Power on the optics and PCS.
+ **/
+void e1000_power_up_fiber_serdes_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.power_up_serdes)
+ hw->mac.ops.power_up_serdes(hw);
+}
+
+/**
+ * e1000_shutdown_fiber_serdes_link - Remove link during power down
+ * @hw: pointer to the HW structure
+ *
+ * Shutdown the optics and PCS on driver unload.
+ **/
+void e1000_shutdown_fiber_serdes_link(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.shutdown_serdes)
+ hw->mac.ops.shutdown_serdes(hw);
+}
+
+#endif /* NO_82576_SUPPORT */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h
new file mode 100755
index 0000000..9695ddb
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_api.h
@@ -0,0 +1,175 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_API_H_
+#define _E1000_API_H_
+
+#include "e1000_hw.h"
+
+#ifndef NO_82571_SUPPORT
+extern void e1000_init_function_pointers_82571(struct e1000_hw *hw);
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+extern void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw);
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+extern void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw);
+#endif
+#ifndef NO_82575_SUPPORT
+extern void e1000_init_function_pointers_82575(struct e1000_hw *hw);
+extern void e1000_rx_fifo_flush_82575(struct e1000_hw *hw);
+#ifndef NO_82576_SUPPORT
+extern void e1000_init_function_pointers_vf(struct e1000_hw *hw);
+extern void e1000_power_up_fiber_serdes_link(struct e1000_hw *hw);
+extern void e1000_shutdown_fiber_serdes_link(struct e1000_hw *hw);
+#endif
+#endif
+
+INT32 e1000_set_mac_type(struct e1000_hw *hw);
+INT32 e1000_setup_init_funcs(struct e1000_hw *hw, BOOLEAN init_device);
+INT32 e1000_init_mac_params(struct e1000_hw *hw);
+INT32 e1000_init_nvm_params(struct e1000_hw *hw);
+INT32 e1000_init_phy_params(struct e1000_hw *hw);
+INT32 e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_clear_vfta(struct e1000_hw *hw);
+void e1000_write_vfta(struct e1000_hw *hw, UINT32 offset, UINT32 value);
+INT32 e1000_force_mac_fc(struct e1000_hw *hw);
+INT32 e1000_check_for_link(struct e1000_hw *hw);
+INT32 e1000_reset_hw(struct e1000_hw *hw);
+INT32 e1000_init_hw(struct e1000_hw *hw);
+INT32 e1000_setup_link(struct e1000_hw *hw);
+INT32 e1000_get_speed_and_duplex(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+INT32 e1000_disable_pcie_master(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+void e1000_rar_set(struct e1000_hw *hw, UINT8 *addr, UINT32 index);
+UINT32 e1000_hash_mc_addr(struct e1000_hw *hw, UINT8 *mc_addr);
+void e1000_update_mc_addr_list(struct e1000_hw *hw,
+ UINT8 *mc_addr_list, UINT32 mc_addr_count);
+INT32 e1000_setup_led(struct e1000_hw *hw);
+INT32 e1000_cleanup_led(struct e1000_hw *hw);
+INT32 e1000_check_reset_block(struct e1000_hw *hw);
+INT32 e1000_blink_led(struct e1000_hw *hw);
+INT32 e1000_led_on(struct e1000_hw *hw);
+INT32 e1000_led_off(struct e1000_hw *hw);
+INT32 e1000_id_led_init(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+INT32 e1000_get_cable_length(struct e1000_hw *hw);
+INT32 e1000_validate_mdi_setting(struct e1000_hw *hw);
+INT32 e1000_read_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#ifndef NO_82575_SUPPORT
+INT32 e1000_write_8bit_ctrl_reg(struct e1000_hw *hw, UINT32 reg,
+ UINT32 offset, UINT8 data);
+#endif
+INT32 e1000_get_phy_info(struct e1000_hw *hw);
+void e1000_release_phy(struct e1000_hw *hw);
+INT32 e1000_acquire_phy(struct e1000_hw *hw);
+#ifndef NO_80003ES2LAN_SUPPORT
+INT32 e1000_cfg_on_link_up(struct e1000_hw *hw);
+#endif
+INT32 e1000_phy_hw_reset(struct e1000_hw *hw);
+INT32 e1000_phy_commit(struct e1000_hw *hw);
+void e1000_power_up_phy(struct e1000_hw *hw);
+void e1000_power_down_phy(struct e1000_hw *hw);
+INT32 e1000_read_mac_addr(struct e1000_hw *hw);
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+INT32 e1000_read_pba_num(struct e1000_hw *hw, UINT32 *part_num);
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+INT32 e1000_read_pba_string(struct e1000_hw *hw, UINT8 *pba_num,
+ UINT32 pba_num_size);
+INT32 e1000_read_pba_length(struct e1000_hw *hw, UINT32 *pba_num_size);
+void e1000_reload_nvm(struct e1000_hw *hw);
+INT32 e1000_update_nvm_checksum(struct e1000_hw *hw);
+INT32 e1000_validate_nvm_checksum(struct e1000_hw *hw);
+INT32 e1000_read_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data);
+INT32 e1000_read_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_nvm(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data);
+INT32 e1000_wait_autoneg(struct e1000_hw *hw);
+INT32 e1000_set_d3_lplu_state(struct e1000_hw *hw, BOOLEAN active);
+INT32 e1000_set_d0_lplu_state(struct e1000_hw *hw, BOOLEAN active);
+BOOLEAN e1000_check_mng_mode(struct e1000_hw *hw);
+BOOLEAN e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
+INT32 e1000_mng_enable_host_if(struct e1000_hw *hw);
+INT32 e1000_mng_host_if_write(struct e1000_hw *hw,
+ UINT8 *buffer, UINT16 length, UINT16 offset, UINT8 *sum);
+INT32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr);
+INT32 e1000_mng_write_dhcp_info(struct e1000_hw * hw,
+ UINT8 *buffer, UINT16 length);
+
+/*
+ * TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ * adapter = a pointer to struct e1000_hw
+ * status = the 8 bit status field of the Rx descriptor with EOP set
+ * error = the 8 bit error field of the Rx descriptor with EOP set
+ * length = the sum of all the length fields of the Rx descriptors that
+ * make up the current frame
+ * last_byte = the last byte of the frame DMAed by the hardware
+ * max_frame_length = the maximum frame length we want to accept.
+ * min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ * ...
+ * if (TBI_ACCEPT) {
+ * accept_frame = TRUE;
+ * e1000_tbi_adjust_stats(adapter, MacAddress);
+ * frame_length--;
+ * } else {
+ * accept_frame = FALSE;
+ * }
+ * ...
+ */
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION 0x0F
+
+#define TBI_ACCEPT(a, status, errors, length, last_byte, min_frame_size, max_frame_size) \
+ (e1000_tbi_sbp_enabled_82543(a) && \
+ (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+ ((last_byte) == CARRIER_EXTENSION) && \
+ (((status) & E1000_RXD_STAT_VP) ? \
+ (((length) > (min_frame_size - VLAN_TAG_SIZE)) && \
+ ((length) <= (max_frame_size + 1))) : \
+ (((length) > min_frame_size) && \
+ ((length) <= (max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h
new file mode 100755
index 0000000..188ae0a
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_defines.h
@@ -0,0 +1,1772 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define REQ_RX_DESCRIPTOR_MULTIPLE 8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME 0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_LSCWE 0x00000010 /* Link Status wake up enable */
+#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */
+#define E1000_WUC_SPM 0x80000000 /* Enable SPM */
+#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */
+#define E1000_WUC_FLX6_PHY 0x4000 /* Flexible Filter 6 Enable */
+#define E1000_WUC_FLX7_PHY 0x8000 /* Flexible Filter 7 Enable */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO_PHY 0x00000800 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0_PHY 0x00001000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1_PHY 0x00002000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2_PHY 0x00004000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3_PHY 0x00008000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX4_PHY 0x00000200 /* Flexible Filter 4 Enable */
+#define E1000_WUFC_FLX5_PHY 0x00000400 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
+#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_FLX6 0x00400000 /* Flexible Filter 6 Enable */
+#define E1000_WUFC_FLX7 0x00800000 /* Flexible Filter 7 Enable */
+#define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF /*Mask for all wakeup filters*/
+#define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 /*Mask for 4 flexible filters*/
+#define E1000_WUFC_ALL_FILTERS_PHY_6 0x0000F6FF /*Mask for 6 wakeup filters */
+#define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 /*Mask for 6 flexible filters*/
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_ALL_FILTERS_6 0x003F00FF /* Mask for all 6 wakeup filters*/
+#define E1000_WUFC_ALL_FILTERS_8 0x00FF00FF /* Mask for all 8 wakeup filters*/
+#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /*Mask for the 4 flexible filters */
+#define E1000_WUFC_FLX_FILTERS_6 0x003F0000 /* Mask for 6 flexible filters */
+#define E1000_WUFC_FLX_FILTERS_8 0x00FF0000 /* Mask for 8 flexible filters */
+#ifndef NO_82576_SUPPORT
+/*
+ * For 82576 to utilize Extended filter masks in addition to
+ * existing (filter) masks
+ */
+#define E1000_WUFC_EXT_FLX_FILTERS 0x00300000 /* Ext. FLX filter mask */
+#endif /* NO_82576_SUPPORT */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC E1000_WUFC_LNKC
+#define E1000_WUS_MAG E1000_WUFC_MAG
+#define E1000_WUS_EX E1000_WUFC_EX
+#define E1000_WUS_MC E1000_WUFC_MC
+#define E1000_WUS_BC E1000_WUFC_BC
+#define E1000_WUS_ARP E1000_WUFC_ARP
+#define E1000_WUS_IPV4 E1000_WUFC_IPV4
+#define E1000_WUS_IPV6 E1000_WUFC_IPV6
+#define E1000_WUS_FLX0_PHY E1000_WUFC_FLX0_PHY
+#define E1000_WUS_FLX1_PHY E1000_WUFC_FLX1_PHY
+#define E1000_WUS_FLX2_PHY E1000_WUFC_FLX2_PHY
+#define E1000_WUS_FLX3_PHY E1000_WUFC_FLX3_PHY
+#define E1000_WUS_FLX_FILTERS_PHY_4 E1000_WUFC_FLX_FILTERS_PHY_4
+#define E1000_WUS_FLX0 E1000_WUFC_FLX0
+#define E1000_WUS_FLX1 E1000_WUFC_FLX1
+#define E1000_WUS_FLX2 E1000_WUFC_FLX2
+#define E1000_WUS_FLX3 E1000_WUFC_FLX3
+#define E1000_WUS_FLX4 E1000_WUFC_FLX4
+#define E1000_WUS_FLX5 E1000_WUFC_FLX5
+#define E1000_WUS_FLX6 E1000_WUFC_FLX6
+#define E1000_WUS_FLX7 E1000_WUFC_FLX7
+#define E1000_WUS_FLX4_PHY E1000_WUFC_FLX4_PHY
+#define E1000_WUS_FLX5_PHY E1000_WUFC_FLX5_PHY
+#define E1000_WUS_FLX6_PHY 0x0400
+#define E1000_WUS_FLX7_PHY 0x0800
+#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS
+#define E1000_WUS_FLX_FILTERS_6 E1000_WUFC_FLX_FILTERS_6
+#define E1000_WUS_FLX_FILTERS_8 E1000_WUFC_FLX_FILTERS_8
+#define E1000_WUS_FLX_FILTERS_PHY_6 E1000_WUFC_FLX_FILTERS_PHY_6
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+/* Six Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX_6 6
+/* Eight Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX_8 8
+#ifndef NO_82576_SUPPORT
+/* Two Extended Flexible Filters are supported (82576) */
+#define E1000_EXT_FLEXIBLE_FILTER_COUNT_MAX 2
+#define E1000_FHFT_LENGTH_OFFSET 0xFC /* Length byte in FHFT */
+#define E1000_FHFT_LENGTH_MASK 0x0FF /* Length in lower byte */
+#endif
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6
+#define E1000_FFLT_SIZE_8 E1000_FLEXIBLE_FILTER_COUNT_MAX_8
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */
+/* Reserved (bits 4,5) in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
+#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
+/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* Direction of SDP3 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */
+#ifndef NO_82576_SUPPORT
+/* Physical Func Reset Done Indication */
+#define E1000_CTRL_EXT_PFRSTD 0x00004000
+#endif
+#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#ifndef NO_82580_SUPPORT
+#define E1000_CTRL_EXT_LINK_MODE_82580_MASK 0x01C00000 /*82580 bit 24:22*/
+#define E1000_CTRL_EXT_LINK_MODE_1000BASE_KX 0x00400000
+#endif
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000
+#define E1000_CTRL_EXT_EIAME 0x01000000
+#define E1000_CTRL_EXT_IRCA 0x00000001
+#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+#define E1000_CTRL_EXT_CANC 0x04000000 /* Int delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+#ifndef NO_82576_SUPPORT
+#endif /* NO_82576_SUPPORT */
+/* IAME enable bit (27) was removed in >= 82575 */
+#define E1000_CTRL_EXT_IAME 0x08000000 /* Int acknowledge Auto-mask */
+#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error
+ * detection enabled */
+#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity
+ * error detection enable */
+#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000
+#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
+#define E1000_CTRL_EXT_PHYPDEN 0x00100000
+#define E1000_I2CCMD_REG_ADDR_SHIFT 16
+#define E1000_I2CCMD_REG_ADDR 0x00FF0000
+#define E1000_I2CCMD_PHY_ADDR_SHIFT 24
+#define E1000_I2CCMD_PHY_ADDR 0x07000000
+#define E1000_I2CCMD_OPCODE_READ 0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE 0x00000000
+#define E1000_I2CCMD_RESET 0x10000000
+#define E1000_I2CCMD_READY 0x20000000
+#define E1000_I2CCMD_INTERRUPT_ENA 0x40000000
+#define E1000_I2CCMD_ERROR 0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR 255
+#define E1000_I2CCMD_PHY_TIMEOUT 200
+#ifndef NO_82576_SUPPORT
+#define E1000_IVAR_VALID 0x80
+#define E1000_GPIE_NSICR 0x00000001
+#define E1000_GPIE_MSIX_MODE 0x00000010
+#define E1000_GPIE_EIAME 0x40000000
+#define E1000_GPIE_PBA 0x80000000
+#endif /* NO_82576_SUPPORT */
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
+#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */
+#define E1000_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */
+#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */
+#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
+#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
+#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
+#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
+#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
+#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE 0x01000000
+#define E1000_RXDEXT_STATERR_SE 0x02000000
+#define E1000_RXDEXT_STATERR_SEQ 0x04000000
+#define E1000_RXDEXT_STATERR_CXE 0x10000000
+#define E1000_RXDEXT_STATERR_TCPE 0x20000000
+#define E1000_RXDEXT_STATERR_IPE 0x40000000
+#define E1000_RXDEXT_STATERR_RXE 0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+ E1000_RXD_ERR_CE | \
+ E1000_RXD_ERR_SE | \
+ E1000_RXD_ERR_SEQ | \
+ E1000_RXD_ERR_CXE | \
+ E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+ E1000_RXDEXT_STATERR_CE | \
+ E1000_RXDEXT_STATERR_SE | \
+ E1000_RXDEXT_STATERR_SEQ | \
+ E1000_RXDEXT_STATERR_CXE | \
+ E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_ENABLE_MASK 0x00000007
+#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT 0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_NEIGHBOR_EN 0x00004000
+#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST 0x00200000
+/* Enable IP address filtering */
+#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000
+#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */
+
+#define E1000_MANC2H_PORT_623 0x00000020 /* Port 0x26f */
+#define E1000_MANC2H_PORT_664 0x00000040 /* Port 0x298 */
+#define E1000_MDEF_PORT_623 0x00000800 /* Port 0x26f */
+#define E1000_MDEF_PORT_664 0x00000400 /* Port 0x298 */
+
+/* Receive Control */
+#define E1000_RCTL_RST 0x00000001 /* Software reset */
+#define E1000_RCTL_EN 0x00000002 /* enable */
+#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
+#define E1000_RCTL_UPE 0x00000008 /* unicast promisc enable */
+#define E1000_RCTL_MPE 0x00000010 /* multicast promisc enable */
+#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
+#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
+#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min thresh size */
+#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
+#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
+#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */
+#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
+#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
+#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
+#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
+#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */
+#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
+#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
+#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ * E1000_PSRCTL_BSIZE0_MASK) |
+ * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ * E1000_PSRCTL_BSIZE1_MASK) |
+ * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ * E1000_PSRCTL_BSIZE2_MASK) |
+ * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ * E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256], default=256
+ * value1 = [1024..64512], default=4096
+ * value2 = [0..64512], default=4096
+ * value3 = [0..64512], default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM 0x01
+#define E1000_SWFW_PHY0_SM 0x02
+#define E1000_SWFW_PHY1_SM 0x04
+#define E1000_SWFW_CSR_SM 0x08
+#ifndef NO_82580_SUPPORT
+#define E1000_SWFW_PHY2_SM 0x20
+#define E1000_SWFW_PHY3_SM 0x40
+#endif /* NO_82580_SUPPORT */
+
+/* FACTPS Definitions */
+#define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */
+/* Device Control */
+#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
+#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
+#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
+#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
+#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
+#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
+#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
+ * indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
+ * PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
+ * LINK_0 and LINK_1 pins */
+#define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */
+#define E1000_CTRL_LANPHYPC_VALUE 0x00020000 /* SW value of LANPHYPC */
+#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */
+#ifndef NO_82575_SUPPORT
+#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
+#endif
+#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST 0x04000000 /* Global reset */
+#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
+#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
+#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
+#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */
+
+/*
+ * Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
+
+#define E1000_CONNSW_ENRGSRC 0x4
+#define E1000_PCS_CFG_PCS_EN 8
+#define E1000_PCS_LCTL_FLV_LINK_UP 1
+#define E1000_PCS_LCTL_FSV_10 0
+#define E1000_PCS_LCTL_FSV_100 2
+#define E1000_PCS_LCTL_FSV_1000 4
+#define E1000_PCS_LCTL_FDV_FULL 8
+#define E1000_PCS_LCTL_FSD 0x10
+#define E1000_PCS_LCTL_FORCE_LINK 0x20
+#define E1000_PCS_LCTL_LOW_LINK_LATCH 0x40
+#define E1000_PCS_LCTL_FORCE_FCTRL 0x80
+#define E1000_PCS_LCTL_AN_ENABLE 0x10000
+#define E1000_PCS_LCTL_AN_RESTART 0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000
+#define E1000_PCS_LCTL_AN_SGMII_BYPASS 0x80000
+#define E1000_PCS_LCTL_AN_SGMII_TRIGGER 0x100000
+#define E1000_PCS_LCTL_FAST_LINK_TIMER 0x1000000
+#define E1000_PCS_LCTL_LINK_OK_FIX 0x2000000
+#define E1000_PCS_LCTL_CRS_ON_NI 0x4000000
+#define E1000_ENABLE_SERDES_LOOPBACK 0x0410
+
+#define E1000_PCS_LSTS_LINK_OK 1
+#define E1000_PCS_LSTS_SPEED_10 0
+#define E1000_PCS_LSTS_SPEED_100 2
+#define E1000_PCS_LSTS_SPEED_1000 4
+#define E1000_PCS_LSTS_DUPLEX_FULL 8
+#define E1000_PCS_LSTS_SYNK_OK 0x10
+#define E1000_PCS_LSTS_AN_COMPLETE 0x10000
+#define E1000_PCS_LSTS_AN_PAGE_RX 0x20000
+#define E1000_PCS_LSTS_AN_TIMED_OUT 0x40000
+#define E1000_PCS_LSTS_AN_REMOTE_FAULT 0x80000
+#define E1000_PCS_LSTS_AN_ERROR_RWS 0x100000
+
+/* Device Status */
+#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */
+#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
+#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */
+#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
+#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */
+#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state.
+ * Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
+#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */
+#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */
+#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution
+ * disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8 0x04000000
+#define E1000_STATUS_FUSE_9 0x08000000
+#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */
+
+/* Constants used to interpret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
+
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define PHY_FORCE_TIME 20
+
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL 0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_PHY_LED0_MODE_MASK 0x00000007
+#define E1000_PHY_LED0_IVRT 0x00000008
+#define E1000_PHY_LED0_BLINK 0x00000010
+#define E1000_PHY_LED0_MASK 0x0000001F
+
+#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020
+#define E1000_LEDCTL_LED0_IVRT 0x00000040
+#define E1000_LEDCTL_LED0_BLINK 0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_BLINK_RATE 0x00002000
+#define E1000_LEDCTL_LED1_IVRT 0x00004000
+#define E1000_LEDCTL_LED1_BLINK 0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000
+#define E1000_LEDCTL_LED2_IVRT 0x00400000
+#define E1000_LEDCTL_LED2_BLINK 0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000
+#define E1000_LEDCTL_LED3_IVRT 0x40000000
+#define E1000_LEDCTL_LED3_BLINK 0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000 0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP 0x2
+#define E1000_LEDCTL_MODE_ACTIVITY 0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10 0x5
+#define E1000_LEDCTL_MODE_LINK_100 0x6
+#define E1000_LEDCTL_MODE_LINK_1000 0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE 0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9
+#define E1000_LEDCTL_MODE_COLLISION 0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED 0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE 0xC
+#define E1000_LEDCTL_MODE_PAUSED 0xD
+#define E1000_LEDCTL_MODE_LED_ON 0xE
+#define E1000_LEDCTL_MODE_LED_OFF 0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_SHIFT 8 /* POPTS shift */
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+/* Extended desc bits for Linksec and timesync */
+
+/* Transmit Control */
+#define E1000_TCTL_RST 0x00000001 /* software reset */
+#define E1000_TCTL_EN 0x00000002 /* enable tx */
+#define E1000_TCTL_BCE 0x00000004 /* busy check enable */
+#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
+#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
+#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
+#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */
+#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
+
+/* Transmit Arbitration Count */
+#define E1000_TARC0_ENABLE 0x00000400 /* Enable Tx Queue 0 */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */
+#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
+#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS 0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT 1
+#define E1000_RFCTL_NFSW_DIS 0x00000040
+#define E1000_RFCTL_NFSR_DIS 0x00000080
+#define E1000_RFCTL_NFS_VER_MASK 0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT 8
+#define E1000_RFCTL_IPV6_DIS 0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800
+#define E1000_RFCTL_ACK_DIS 0x00001000
+#define E1000_RFCTL_ACKD_DIS 0x00002000
+#define E1000_RFCTL_IPFRSP_DIS 0x00004000
+#define E1000_RFCTL_EXTEN 0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+#define E1000_RFCTL_LEF 0x00040000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD 15
+#define E1000_CT_SHIFT 4
+#define E1000_COLLISION_DISTANCE 63
+#define E1000_COLD_SHIFT 12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_FIBER 9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK 0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT 10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT 20
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */
+
+#define ETHERNET_FCS_SIZE 4
+#define MAX_JUMBO_FRAME_SIZE 0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008
+#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16
+
+#define E1000_PHY_CTRL_SPD_EN 0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS 0x00050000
+
+/* PBA constants */
+#define E1000_PBA_6K 0x0006 /* 6KB */
+#define E1000_PBA_8K 0x0008 /* 8KB */
+#define E1000_PBA_10K 0x000A /* 10KB */
+#define E1000_PBA_12K 0x000C /* 12KB */
+#define E1000_PBA_14K 0x000E /* 14KB */
+#define E1000_PBA_16K 0x0010 /* 16KB */
+#define E1000_PBA_18K 0x0012
+#define E1000_PBA_20K 0x0014
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_26K 0x001A
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
+#define E1000_PBA_35K 0x0023
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030 /* 48KB */
+#define E1000_PBA_64K 0x0040 /* 64KB */
+
+#define E1000_PBS_16K E1000_PBA_16K
+#define E1000_PBS_24K E1000_PBA_24K
+
+#define IFS_MAX 80
+#define IFS_MIN 40
+#define IFS_RATIO 4
+#define IFS_STEP 10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
+
+#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO 0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB 0x00000100 /* VM MB event */
+#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD 0x00010000
+#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG 0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */
+#ifndef NO_82580_SUPPORT
+#define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */
+#endif
+#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver
+ * should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
+#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
+#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW
+ * bit in the FWSM */
+#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates
+ * an interrupt */
+#define E1000_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
+#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */
+#ifndef NO_82574_SUPPORT
+#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_82580_SUPPORT
+#define E1000_ICR_FER 0x00400000 /* Fatal Error */
+#endif /* NO_82580_SUPPORT */
+
+#ifndef NO_82571_SUPPORT
+/* PBA ECC Register */
+#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */
+#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */
+#define E1000_PBA_ECC_CORR_EN 0x00000001 /* Enable ECC error correction */
+#define E1000_PBA_ECC_STAT_CLR 0x00000002 /* Clear ECC error counter */
+#define E1000_PBA_ECC_INT_EN 0x00000004 /* Enable ICR bit 5 on ECC error */
+#endif /* NO_82571_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+/* Extended Interrupt Cause Read */
+#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */
+#define E1000_EICR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */
+#define E1000_EICR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */
+#define E1000_EICR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */
+#define E1000_EICR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */
+#define E1000_EICR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */
+#define E1000_EICR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */
+#define E1000_EICR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */
+#define E1000_EICR_TCP_TIMER 0x40000000 /* TCP Timer */
+#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */
+/* TCP Timer */
+#define E1000_TCPTIMER_KS 0x00000100 /* KickStart */
+#define E1000_TCPTIMER_COUNT_ENABLE 0x00000200 /* Count Enable */
+#define E1000_TCPTIMER_COUNT_FINISH 0x00000400 /* Count finish */
+#define E1000_TCPTIMER_LOOP 0x00000800 /* Loop */
+
+#endif /* NO_82575_SUPPORT */
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ)
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXT0 = Receiver Timer Interrupt (ring 0)
+ * o TXDW = Transmit Descriptor Written Back
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ * o LSC = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+ E1000_IMS_RXT0 | \
+ E1000_IMS_TXDW | \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ | \
+ E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW E1000_ICR_TXDW /* Tx desc written back */
+#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */
+#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD E1000_ICR_SRPD
+#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */
+#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */
+#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */
+#ifndef NO_82580_SUPPORT
+#define E1000_IMS_DRSTA E1000_ICR_DRSTA /* Device Reset Asserted */
+#endif
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+ * parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+ * parity error */
+#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer
+ * parity error */
+#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity
+ * error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+ * parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+ * parity error */
+#define E1000_IMS_DSW E1000_ICR_DSW
+#define E1000_IMS_PHYINT E1000_ICR_PHYINT
+#define E1000_IMS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_IMS_EPRST E1000_ICR_EPRST
+#ifndef NO_82574_SUPPORT
+#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
+#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
+#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
+#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */
+#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_82580_SUPPORT
+#define E1000_IMS_FER E1000_ICR_FER /* Fatal Error */
+#endif /* NO_82580_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+/* Extended Interrupt Mask Set */
+#define E1000_EIMS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EIMS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EIMS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EIMS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EIMS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EIMS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EIMS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EIMS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EIMS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EIMS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */
+
+#endif /* NO_82575_SUPPORT */
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW E1000_ICR_TXDW /* Tx desc written back */
+#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD E1000_ICR_SRPD
+#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */
+#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */
+#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */
+#ifndef NO_82580_SUPPORT
+#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Aserted */
+#endif
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+ * parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+ * parity error */
+#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer
+ * parity error */
+#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity
+ * error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+ * parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+ * parity error */
+#define E1000_ICS_DSW E1000_ICR_DSW
+#define E1000_ICS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_ICS_PHYINT E1000_ICR_PHYINT
+#define E1000_ICS_EPRST E1000_ICR_EPRST
+
+#ifndef NO_82575_SUPPORT
+/* Extended Interrupt Cause Set */
+#define E1000_EICS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EICS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EICS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EICS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EICS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EICS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EICS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EICS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EICS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EICS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */
+
+#define E1000_EITR_ITR_INT_MASK 0x0000FFFF
+/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
+#define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
+
+#endif /* NO_82575_SUPPORT */
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+/* Enable the counting of descriptors still to be processed. */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE 0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots. However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 15
+#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
+
+/* Error Codes */
+#define E1000_SUCCESS 0
+#define E1000_ERR_NVM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET 9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET 12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_MBX 15
+#define E1000_ERR_INVALID_ARGUMENT 16
+#define E1000_ERR_NO_SPACE 17
+#define E1000_ERR_NVM_PBA_SECTION 18
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT 50
+#define COPPER_LINK_UP_LIMIT 10
+#define PHY_AUTO_NEG_LIMIT 45
+#define PHY_FORCE_LIMIT 20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT 800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT 100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT 10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT 10
+
+/* Flow Control */
+#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */
+#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
+#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */
+#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */
+#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */
+#define E1000_TXCW_NP 0x00008000 /* TXCW next page */
+#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */
+#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */
+#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */
+#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */
+#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */
+#define E1000_RXCW_CC 0x10000000 /* Receive config change */
+#define E1000_RXCW_C 0x20000000 /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */
+
+#define E1000_TSYNCTXCTL_VALID 0x00000001 /* tx timestamp valid */
+#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable tx timestampping */
+
+#define E1000_TSYNCRXCTL_VALID 0x00000001 /* rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL 0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
+#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable rx timestampping */
+
+#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF
+#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01
+#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE 0x02
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE 0x03
+#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE 0x04
+
+#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK 0x00000F00
+#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE 0x0000
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE 0x0100
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE 0x0200
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE 0x0300
+#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE 0x0800
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE 0x0900
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE 0x0A00
+#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE 0x0B00
+#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE 0x0C00
+#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE 0x0D00
+
+#define E1000_TIMINCA_16NS_SHIFT 24
+#ifndef NO_82580_SUPPORT
+/* TUPLE Filtering Configuration */
+#define E1000_TTQF_DISABLE_MASK 0xF0008000 /* TTQF Disable Mask */
+#define E1000_TTQF_QUEUE_ENABLE 0x100 /* TTQF Queue Enable Bit */
+#define E1000_TTQF_PROTOCOL_MASK 0xFF /* TTQF Protocol Mask */
+/* TTQF TCP Bit, shift with E1000_TTQF_PROTOCOL SHIFT */
+#define E1000_TTQF_PROTOCOL_TCP 0x0
+/* TTQF UDP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */
+#define E1000_TTQF_PROTOCOL_UDP 0x1
+/* TTQF SCTP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */
+#define E1000_TTQF_PROTOCOL_SCTP 0x2
+#define E1000_TTQF_PROTOCOL_SHIFT 5 /* TTQF Protocol Shift */
+#define E1000_TTQF_QUEUE_SHIFT 16 /* TTQF Queue Shfit */
+#define E1000_TTQF_RX_QUEUE_MASK 0x70000 /* TTQF Queue Mask */
+#define E1000_TTQF_MASK_ENABLE 0x10000000 /* TTQF Mask Enable Bit */
+#define E1000_IMIR_CLEAR_MASK 0xF001FFFF /* IMIR Reg Clear Mask */
+#define E1000_IMIR_PORT_BYPASS 0x20000 /* IMIR Port Bypass Bit */
+#define E1000_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */
+#define E1000_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */
+
+#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */
+#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */
+#define E1000_MDICNFG_PHY_MASK 0x03E00000
+#define E1000_MDICNFG_PHY_SHIFT 21
+#endif /*Barton Hills HW */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP 0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004
+#define E1000_GCR_TXD_NO_SNOOP 0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020
+#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000
+#define E1000_GCR_CAP_VER2 0x00040000
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \
+ E1000_GCR_RXDSCW_NO_SNOOP | \
+ E1000_GCR_RXDSCR_NO_SNOOP | \
+ E1000_GCR_TXD_NO_SNOOP | \
+ E1000_GCR_TXDSCW_NO_SNOOP | \
+ E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local Tx is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Register */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */
+
+/* NVM Control */
+#define E1000_EECD_SK 0x00000001 /* NVM Clock */
+#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI 0x00000004 /* NVM Data In */
+#define E1000_EECD_DO 0x00000008 /* NVM Data Out */
+#define E1000_EECD_FWE_MASK 0x00000030
+#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES 0x00000100 /* NVM Present */
+#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_NVM_GRANT_ATTEMPTS
+#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT 22
+#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
+
+#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */
+#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */
+#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write regs */
+#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START 1 /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES 2000
+
+/* NVM Word Offsets */
+#define NVM_COMPAT 0x0003
+#define NVM_ID_LED_SETTINGS 0x0004
+#define NVM_VERSION 0x0005
+#define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */
+#define NVM_PHY_CLASS_WORD 0x0007
+#define NVM_INIT_CONTROL1_REG 0x000A
+#define NVM_INIT_CONTROL2_REG 0x000F
+#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define NVM_INIT_CONTROL3_PORT_B 0x0014
+#define NVM_INIT_3GIO_3 0x001A
+#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define NVM_INIT_CONTROL3_PORT_A 0x0024
+#define NVM_CFG 0x0012
+#define NVM_FLASH_VERSION 0x0032
+#define NVM_ALT_MAC_ADDR_PTR 0x0037
+#define NVM_CHECKSUM_REG 0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */
+#ifndef NO_82580_SUPPORT
+#define E1000_NVM_CFG_DONE_PORT_2 0x100000 /* ...for third port */
+#define E1000_NVM_CFG_DONE_PORT_3 0x200000 /* ...for fourth port */
+
+#define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
+
+/* Mask bits for fields in Word 0x24 of the NVM */
+#define NVM_WORD24_COM_MDIO 0x0008 /* MDIO interface shared */
+#define NVM_WORD24_EXT_MDIO 0x0004 /* MDIO accesses routed external */
+#endif /* NO_82580_SUPPORT */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK 0x3000
+#define NVM_WORD0F_PAUSE 0x1000
+#define NVM_WORD0F_ASM_DIR 0x2000
+#define NVM_WORD0F_ANE 0x0800
+#define NVM_WORD0F_SWPDIO_EXT_MASK 0x00F0
+#define NVM_WORD0F_LPLU 0x0001
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK 0x000C
+
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define NVM_COMPAT_LOM 0x0800
+
+/* length of string needed to store PBA number */
+#define E1000_PBANUM_LENGTH 11
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM 0xBABA
+
+#define NVM_MAC_ADDR_OFFSET 0
+#define NVM_PBA_OFFSET_0 8
+#define NVM_PBA_OFFSET_1 9
+#define NVM_PBA_PTR_GUARD 0xFAFA
+#define NVM_RESERVED_WORD 0xFFFF
+#define NVM_PHY_CLASS_A 0x8000
+#define NVM_SERDES_AMPLITUDE_MASK 0x000F
+#define NVM_SIZE_MASK 0x1C00
+#define NVM_SIZE_SHIFT 10
+#define NVM_WORD_SIZE_BASE_SHIFT 6
+#define NVM_SWDPIO_EXT_SHIFT 4
+
+#ifndef NO_MICROWIRE_SUPPORT
+/* NVM Commands - Microwire */
+#define NVM_READ_OPCODE_MICROWIRE 0x6 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_MICROWIRE 0x5 /* NVM write opcode */
+#define NVM_ERASE_OPCODE_MICROWIRE 0x7 /* NVM erase opcode */
+#define NVM_EWEN_OPCODE_MICROWIRE 0x13 /* NVM erase/write enable */
+#define NVM_EWDS_OPCODE_MICROWIRE 0x10 /* NVM erase/write disable */
+
+#endif /* NO_MICROWIRE_SUPPORT */
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */
+#define NVM_WRDI_OPCODE_SPI 0x04 /* NVM reset Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */
+#define NVM_WRSR_OPCODE_SPI 0x01 /* NVM write Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI 0x01
+#define NVM_STATUS_WEN_SPI 0x02
+#define NVM_STATUS_BP0_SPI 0x04
+#define NVM_STATUS_BP1_SPI 0x08
+#define NVM_STATUS_WPEN_SPI 0x80
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2 0x1
+#define ID_LED_DEF1_ON2 0x2
+#define ID_LED_DEF1_OFF2 0x3
+#define ID_LED_ON1_DEF2 0x4
+#define ID_LED_ON1_ON2 0x5
+#define ID_LED_ON1_OFF2 0x6
+#define ID_LED_OFF1_DEF2 0x7
+#define ID_LED_OFF1_ON2 0x8
+#define ID_LED_OFF1_OFF2 0x9
+
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#ifndef NO_PCIX_SUPPORT
+#define PCIX_COMMAND_REGISTER 0xE6
+#define PCIX_STATUS_REGISTER_LO 0xE8
+#define PCIX_STATUS_REGISTER_HI 0xEA
+#endif
+#define PCI_HEADER_TYPE_REGISTER 0x0E
+#define PCIE_LINK_STATUS 0x12
+#define PCIE_DEVICE_CONTROL2 0x28
+
+#ifndef NO_PCIX_SUPPORT
+#define PCIX_COMMAND_MMRBC_MASK 0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT 0x2
+#define PCIX_STATUS_HI_MMRBC_MASK 0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5
+#define PCIX_STATUS_HI_MMRBC_4K 0x3
+#define PCIX_STATUS_HI_MMRBC_2K 0x2
+#define PCIX_STATUS_LO_FUNC_MASK 0x7
+#endif
+#define PCI_HEADER_TYPE_MULTIFUNC 0x80
+#define PCIE_LINK_WIDTH_MASK 0x3F0
+#define PCIE_LINK_WIDTH_SHIFT 4
+#define PCIE_LINK_SPEED_MASK 0x0F
+#define PCIE_LINK_SPEED_2500 0x01
+#define PCIE_LINK_SPEED_5000 0x02
+#define PCIE_DEVICE_CONTROL2_16ms 0x0005
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN 6
+#endif
+
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1011_I_REV_4 0x04
+#define M88E1111_I_PHY_ID 0x01410CC0
+#define GG82563_E_PHY_ID 0x01410CA0
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+#define BME1000_E_PHY_ID 0x01410CB0
+#define BME1000_E_PHY_ID_R2 0x01410CB1
+#define I82577_E_PHY_ID 0x01540050
+#define I82578_E_PHY_ID 0x004DD040
+#define I82579_E_PHY_ID 0x01540090
+#ifndef NO_82580_SUPPORT
+#define I82580_I_PHY_ID 0x015403A0
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_82576_SUPPORT
+#define IGP04E1000_E_PHY_ID 0x02A80391
+#endif
+#define M88_VENDOR 0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
+#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_CLK125_DISABLE 0x0010
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+ * 0=Normal 10BASE-T Rx Threshold
+ */
+#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
+#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Tx */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380
+#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00
+
+#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020
+#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C
+
+/* BME1000 PHY Specific Control Register */
+#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */
+
+/*
+ * Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT 5
+#define GG82563_REG(page, reg) \
+ (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG 30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL \
+ GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS \
+ GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE \
+ GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2 \
+ GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR \
+ GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT \
+ GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2 \
+ GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT \
+ GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL \
+ GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL \
+ GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2 \
+ GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE \
+ GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL \
+ GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET \
+ GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID \
+ GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID \
+ GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL \
+ GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL \
+ GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+ GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL \
+ GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL \
+ GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC \
+ GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS \
+ GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY \
+ GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+ GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE \
+ GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+ GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC \
+ GG82563_REG(194, 26) /* Misc. */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK 0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK 0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE 0x04000000
+#define E1000_MDIC_OP_READ 0x08000000
+#define E1000_MDIC_READY 0x10000000
+#define E1000_MDIC_INT_EN 0x20000000
+#define E1000_MDIC_ERROR 0x40000000
+#define E1000_MDIC_DEST 0x80000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY 0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT 8
+#define E1000_GEN_POLL_TIMEOUT 640
+
+#ifndef NO_82576_SUPPORT
+/* LinkSec register fields */
+#define E1000_LSECTXCAP_SUM_MASK 0x00FF0000
+#define E1000_LSECTXCAP_SUM_SHIFT 16
+#define E1000_LSECRXCAP_SUM_MASK 0x00FF0000
+#define E1000_LSECRXCAP_SUM_SHIFT 16
+
+#define E1000_LSECTXCTRL_EN_MASK 0x00000003
+#define E1000_LSECTXCTRL_DISABLE 0x0
+#define E1000_LSECTXCTRL_AUTH 0x1
+#define E1000_LSECTXCTRL_AUTH_ENCRYPT 0x2
+#define E1000_LSECTXCTRL_AISCI 0x00000020
+#define E1000_LSECTXCTRL_PNTHRSH_MASK 0xFFFFFF00
+#define E1000_LSECTXCTRL_RSV_MASK 0x000000D8
+
+#define E1000_LSECRXCTRL_EN_MASK 0x0000000C
+#define E1000_LSECRXCTRL_EN_SHIFT 2
+#define E1000_LSECRXCTRL_DISABLE 0x0
+#define E1000_LSECRXCTRL_CHECK 0x1
+#define E1000_LSECRXCTRL_STRICT 0x2
+#define E1000_LSECRXCTRL_DROP 0x3
+#define E1000_LSECRXCTRL_PLSH 0x00000040
+#define E1000_LSECRXCTRL_RP 0x00000080
+#define E1000_LSECRXCTRL_RSV_MASK 0xFFFFFF33
+
+#endif /* NO_82576_SUPPORT */
+
+#ifndef NO_82580_SUPPORT
+/* DMA Coalescing register fields */
+#define E1000_DMACR_DMACWT_MASK 0x00003FFF /* DMA Coalescing
+ * Watchdog Timer */
+#define E1000_DMACR_DMACTHR_MASK 0x00FF0000 /* DMA Coalescing Receive
+ * Threshold */
+#define E1000_DMACR_DMACTHR_SHIFT 16
+#define E1000_DMACR_DMAC_LX_MASK 0x30000000 /* Lx when no PCIe
+ * transactions */
+#define E1000_DMACR_DMAC_LX_SHIFT 28
+#define E1000_DMACR_DMAC_EN 0x80000000 /* Enable DMA Coalescing */
+
+#define E1000_DMCTXTH_DMCTTHR_MASK 0x00000FFF /* DMA Coalescing Transmit
+ * Threshold */
+
+#define E1000_DMCTLX_TTLX_MASK 0x00000FFF /* Time to LX request */
+
+#define E1000_DMCRTRH_UTRESH_MASK 0x0007FFFF /* Receive Traffic Rate
+ * Threshold */
+#define E1000_DMCRTRH_LRPRCW 0x80000000 /* Rcv packet rate in
+ * current window */
+
+#define E1000_DMCCNT_CCOUNT_MASK 0x01FFFFFF /* DMA Coal Rcv Traffic
+ * Current Cnt */
+
+#define E1000_FCRTC_RTH_COAL_MASK 0x0003FFF0 /* Flow ctrl Rcv Threshold
+ * High val */
+#define E1000_FCRTC_RTH_COAL_SHIFT 4
+#define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision based
+ on DMA coal */
+#endif
+
+
+#ifndef UNREFERENCED_XPARAMETER
+#define UNREFERENCED_1PARAMETER(_p) (_p)
+#define UNREFERENCED_2PARAMETER(_p, _q) (_p); (_q);
+#define UNREFERENCED_3PARAMETER(_p, _q, _r) (_p); (_q); (_r);
+#define UNREFERENCED_4PARAMETER(_p, _q, _r, _s) (_p); (_q); (_r); (_s);
+#define UNREFERENCED_5PARAMETER(_p, _q, _r, _s, _t) (_p); (_q); (_r); (_s); (_t);
+#endif
+#endif /* _E1000_DEFINES_H_ */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h
new file mode 100755
index 0000000..a0018ab
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_hw.h
@@ -0,0 +1,868 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include "e1000_osdep.h"
+#include "e1000_regs.h"
+#include "e1000_defines.h"
+
+struct e1000_hw;
+
+#ifndef NO_82571_SUPPORT
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_82574_SUPPORT
+#define E1000_DEV_ID_82574L 0x10D3
+#define E1000_DEV_ID_82574LA 0x10F6
+#define E1000_DEV_ID_82583V 0x150C
+#endif /* NO_82574_SUPPORT */
+#ifndef NO_80003ES2LAN_SUPPORT
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+#endif /* NO_80003ES2LAN_SUPPORT */
+#ifndef NO_ICH8LAN_SUPPORT
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M 0x104D
+#define E1000_DEV_ID_ICH9_IGP_M 0x10BF
+#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5
+#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB
+#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD
+#define E1000_DEV_ID_ICH9_BM 0x10E5
+#define E1000_DEV_ID_ICH9_IGP_C 0x294C
+#define E1000_DEV_ID_ICH9_IFE 0x10C0
+#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3
+#define E1000_DEV_ID_ICH9_IFE_G 0x10C2
+#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC
+#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD
+#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE
+#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA
+#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB
+#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF
+#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0
+#define E1000_DEV_ID_PCH_LV_LM 0x1506
+#define E1000_DEV_ID_PCH_LV_V 0x1519
+#define E1000_DEV_ID_PCH2_LV_LM 0x1502
+#define E1000_DEV_ID_PCH2_LV_V 0x1503
+#endif /* NO_ICH8LAN_SUPPORT */
+#ifndef NO_82575_SUPPORT
+#ifndef NO_82576_SUPPORT
+#define E1000_DEV_ID_82576 0x10C9
+#define E1000_DEV_ID_82576_FIBER 0x10E6
+#define E1000_DEV_ID_82576_SERDES 0x10E7
+#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
+#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
+#define E1000_DEV_ID_82576_NS 0x150A
+#define E1000_DEV_ID_82576_NS_SERDES 0x1518
+#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
+#endif /* NO_82576_SUPPORT */
+#define E1000_DEV_ID_82575EB_COPPER 0x10A7
+#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
+#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82580_SUPPORT
+#define E1000_DEV_ID_82580_COPPER 0x150E
+#define E1000_DEV_ID_82580_FIBER 0x150F
+#define E1000_DEV_ID_82580_SERDES 0x1510
+#define E1000_DEV_ID_82580_SGMII 0x1511
+#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
+#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527
+#endif /* NO_82580_SUPPORT */
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_0 0
+#define E1000_FUNC_1 1
+#ifndef NO_82580_SUPPORT
+#define E1000_FUNC_2 2
+#define E1000_FUNC_3 3
+#endif /* Barton Hills HW */
+
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3
+#ifndef NO_82580_SUPPORT
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN2 6
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN3 9
+#endif /* Barton Hills HW */
+
+enum e1000_mac_type {
+ e1000_undefined = 0,
+#ifndef NO_82571_SUPPORT
+ e1000_82571,
+ e1000_82572,
+ e1000_82573,
+#ifndef NO_82574_SUPPORT
+ e1000_82574,
+ e1000_82583,
+#endif /* NO_82574_SUPPORT */
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ e1000_80003es2lan,
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ e1000_ich8lan,
+ e1000_ich9lan,
+ e1000_pchlan,
+ e1000_pch2lan,
+#endif
+#ifndef NO_82575_SUPPORT
+ e1000_82575,
+#ifndef NO_82576_SUPPORT
+ e1000_82576,
+#ifndef NO_82580_SUPPORT
+ e1000_82580,
+#endif
+#endif /* NO_82576_SUPPORT */
+#endif /* NO_82575_SUPPORT */
+ e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */
+};
+
+enum e1000_media_type {
+ e1000_media_type_unknown = 0,
+ e1000_media_type_copper = 1,
+ e1000_media_type_fiber = 2,
+ e1000_media_type_internal_serdes = 3,
+ e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+ e1000_nvm_unknown = 0,
+ e1000_nvm_none,
+ e1000_nvm_eeprom_spi,
+#ifndef NO_MICROWIRE_SUPPORT
+ e1000_nvm_eeprom_microwire,
+#endif
+ e1000_nvm_flash_hw,
+ e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+ e1000_nvm_override_none = 0,
+ e1000_nvm_override_spi_small,
+ e1000_nvm_override_spi_large,
+#ifndef NO_MICROWIRE_SUPPORT
+ e1000_nvm_override_microwire_small,
+ e1000_nvm_override_microwire_large
+#endif
+};
+
+enum e1000_phy_type {
+ e1000_phy_unknown = 0,
+ e1000_phy_none,
+ e1000_phy_m88,
+ e1000_phy_igp,
+ e1000_phy_igp_2,
+ e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
+ e1000_phy_bm,
+ e1000_phy_82578,
+ e1000_phy_82577,
+ e1000_phy_82579,
+#ifndef NO_82580_SUPPORT
+ e1000_phy_82580,
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_82576_SUPPORT
+ e1000_phy_vf,
+#endif
+};
+
+enum e1000_bus_type {
+ e1000_bus_type_unknown = 0,
+ e1000_bus_type_pci,
+ e1000_bus_type_pcix,
+ e1000_bus_type_pci_express,
+ e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+ e1000_bus_speed_unknown = 0,
+ e1000_bus_speed_33,
+ e1000_bus_speed_66,
+ e1000_bus_speed_100,
+ e1000_bus_speed_120,
+ e1000_bus_speed_133,
+ e1000_bus_speed_2500,
+ e1000_bus_speed_5000,
+ e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+ e1000_bus_width_unknown = 0,
+ e1000_bus_width_pcie_x1,
+ e1000_bus_width_pcie_x2,
+ e1000_bus_width_pcie_x4 = 4,
+ e1000_bus_width_pcie_x8 = 8,
+ e1000_bus_width_32,
+ e1000_bus_width_64,
+ e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+ e1000_1000t_rx_status_not_ok = 0,
+ e1000_1000t_rx_status_ok,
+ e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity {
+ e1000_rev_polarity_normal = 0,
+ e1000_rev_polarity_reversed,
+ e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+ e1000_fc_none = 0,
+ e1000_fc_rx_pause,
+ e1000_fc_tx_pause,
+ e1000_fc_full,
+ e1000_fc_default = 0xFF
+};
+
+enum e1000_ms_type {
+ e1000_ms_hw_default = 0,
+ e1000_ms_force_master,
+ e1000_ms_force_slave,
+ e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+ e1000_smart_speed_default = 0,
+ e1000_smart_speed_on,
+ e1000_smart_speed_off
+};
+
+enum e1000_serdes_link_state {
+ e1000_serdes_link_down = 0,
+ e1000_serdes_link_autoneg_progress,
+ e1000_serdes_link_autoneg_complete,
+ e1000_serdes_link_forced_up
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+ UINT64 buffer_addr; /* Address of the descriptor's data buffer */
+ UINT16 length; /* Length of data DMAed into data buffer */
+ UINT16 csum; /* Packet checksum */
+ UINT8 status; /* Descriptor status */
+ UINT8 errors; /* Descriptor Errors */
+ UINT16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+ struct {
+ UINT64 buffer_addr;
+ UINT64 reserved;
+ } read;
+ struct {
+ struct {
+ UINT32 mrq; /* Multiple Rx Queues */
+ union {
+ UINT32 rss; /* RSS Hash */
+ struct {
+ UINT16 ip_id; /* IP id */
+ UINT16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ UINT32 status_error; /* ext status/error */
+ UINT16 length;
+ UINT16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+ struct {
+ /* one buffer for protocol header(s), three data buffers */
+ UINT64 buffer_addr[MAX_PS_BUFFERS];
+ } read;
+ struct {
+ struct {
+ UINT32 mrq; /* Multiple Rx Queues */
+ union {
+ UINT32 rss; /* RSS Hash */
+ struct {
+ UINT16 ip_id; /* IP id */
+ UINT16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ UINT32 status_error; /* ext status/error */
+ UINT16 length0; /* length of buffer 0 */
+ UINT16 vlan; /* VLAN tag */
+ } middle;
+ struct {
+ UINT16 header_status;
+ UINT16 length[3]; /* length of buffers 1-3 */
+ } upper;
+ UINT64 reserved;
+ } wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+ UINT64 buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ UINT32 data;
+ struct {
+ UINT16 length; /* Data buffer length */
+ UINT8 cso; /* Checksum offset */
+ UINT8 cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ UINT32 data;
+ struct {
+ UINT8 status; /* Descriptor status */
+ UINT8 css; /* Checksum start */
+ UINT16 special;
+ } fields;
+ } upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+ union {
+ UINT32 ip_config;
+ struct {
+ UINT8 ipcss; /* IP checksum start */
+ UINT8 ipcso; /* IP checksum offset */
+ UINT16 ipcse; /* IP checksum end */
+ } ip_fields;
+ } lower_setup;
+ union {
+ UINT32 tcp_config;
+ struct {
+ UINT8 tucss; /* TCP checksum start */
+ UINT8 tucso; /* TCP checksum offset */
+ UINT16 tucse; /* TCP checksum end */
+ } tcp_fields;
+ } upper_setup;
+ UINT32 cmd_and_length;
+ union {
+ UINT32 data;
+ struct {
+ UINT8 status; /* Descriptor status */
+ UINT8 hdr_len; /* Header length */
+ UINT16 mss; /* Maximum segment size */
+ } fields;
+ } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+ UINT64 buffer_addr; /* Address of the descriptor's buffer address */
+ union {
+ UINT32 data;
+ struct {
+ UINT16 length; /* Data buffer length */
+ UINT8 typ_len_ext;
+ UINT8 cmd;
+ } flags;
+ } lower;
+ union {
+ UINT32 data;
+ struct {
+ UINT8 status; /* Descriptor status */
+ UINT8 popts; /* Packet Options */
+ UINT16 special;
+ } fields;
+ } upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+ UINT64 crcerrs;
+ UINT64 algnerrc;
+ UINT64 symerrs;
+ UINT64 rxerrc;
+ UINT64 mpc;
+ UINT64 scc;
+ UINT64 ecol;
+ UINT64 mcc;
+ UINT64 latecol;
+ UINT64 colc;
+ UINT64 dc;
+ UINT64 tncrs;
+ UINT64 sec;
+ UINT64 cexterr;
+ UINT64 rlec;
+ UINT64 xonrxc;
+ UINT64 xontxc;
+ UINT64 xoffrxc;
+ UINT64 xofftxc;
+ UINT64 fcruc;
+ UINT64 prc64;
+ UINT64 prc127;
+ UINT64 prc255;
+ UINT64 prc511;
+ UINT64 prc1023;
+ UINT64 prc1522;
+ UINT64 gprc;
+ UINT64 bprc;
+ UINT64 mprc;
+ UINT64 gptc;
+ UINT64 gorc;
+ UINT64 gotc;
+ UINT64 rnbc;
+ UINT64 ruc;
+ UINT64 rfc;
+ UINT64 roc;
+ UINT64 rjc;
+ UINT64 mgprc;
+ UINT64 mgpdc;
+ UINT64 mgptc;
+ UINT64 tor;
+ UINT64 tot;
+ UINT64 tpr;
+ UINT64 tpt;
+ UINT64 ptc64;
+ UINT64 ptc127;
+ UINT64 ptc255;
+ UINT64 ptc511;
+ UINT64 ptc1023;
+ UINT64 ptc1522;
+ UINT64 mptc;
+ UINT64 bptc;
+ UINT64 tsctc;
+ UINT64 tsctfc;
+ UINT64 iac;
+ UINT64 icrxptc;
+ UINT64 icrxatc;
+ UINT64 ictxptc;
+ UINT64 ictxatc;
+ UINT64 ictxqec;
+ UINT64 ictxqmtc;
+ UINT64 icrxdmtc;
+ UINT64 icrxoc;
+ UINT64 cbtmpc;
+ UINT64 htdpmc;
+ UINT64 cbrdpc;
+ UINT64 cbrmpc;
+ UINT64 rpthc;
+ UINT64 hgptc;
+ UINT64 htcbdpc;
+ UINT64 hgorc;
+ UINT64 hgotc;
+ UINT64 lenerrs;
+ UINT64 scvpc;
+ UINT64 hrmpc;
+ UINT64 doosync;
+};
+
+#ifndef NO_82576_SUPPORT
+#endif
+
+struct e1000_phy_stats {
+ UINT32 idle_errors;
+ UINT32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+ UINT32 signature;
+ UINT8 status;
+ UINT8 reserved0;
+ UINT16 vlan_id;
+ UINT32 reserved1;
+ UINT16 reserved2;
+ UINT8 reserved3;
+ UINT8 checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+ UINT8 command_id;
+ UINT8 command_length;
+ UINT8 command_options;
+ UINT8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH 252
+struct e1000_host_command_info {
+ struct e1000_host_command_header command_header;
+ UINT8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+ UINT8 command_id;
+ UINT8 checksum;
+ UINT16 reserved1;
+ UINT16 reserved2;
+ UINT16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+ struct e1000_host_mng_command_header command_header;
+ UINT8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+#include "e1000_manage.h"
+
+struct e1000_mac_operations {
+ /* Function pointers for the MAC. */
+ INT32 (*init_params)(struct e1000_hw *);
+ INT32 (*id_led_init)(struct e1000_hw *);
+ INT32 (*blink_led)(struct e1000_hw *);
+ INT32 (*check_for_link)(struct e1000_hw *);
+ BOOLEAN (*check_mng_mode)(struct e1000_hw *hw);
+ INT32 (*cleanup_led)(struct e1000_hw *);
+ void (*clear_hw_cntrs)(struct e1000_hw *);
+ void (*clear_vfta)(struct e1000_hw *);
+ INT32 (*get_bus_info)(struct e1000_hw *);
+ void (*set_lan_id)(struct e1000_hw *);
+ INT32 (*get_link_up_info)(struct e1000_hw *, UINT16 *, UINT16 *);
+ INT32 (*led_on)(struct e1000_hw *);
+ INT32 (*led_off)(struct e1000_hw *);
+ void (*update_mc_addr_list)(struct e1000_hw *, UINT8 *, UINT32);
+ INT32 (*reset_hw)(struct e1000_hw *);
+ INT32 (*init_hw)(struct e1000_hw *);
+#ifndef NO_82576_SUPPORT
+ void (*shutdown_serdes)(struct e1000_hw *);
+ void (*power_up_serdes)(struct e1000_hw *);
+#endif /* NO_82576_SUPPORT */
+ INT32 (*setup_link)(struct e1000_hw *);
+ INT32 (*setup_physical_interface)(struct e1000_hw *);
+ INT32 (*setup_led)(struct e1000_hw *);
+ void (*write_vfta)(struct e1000_hw *, UINT32, UINT32);
+ void (*config_collision_dist)(struct e1000_hw *);
+ void (*rar_set)(struct e1000_hw *, UINT8*, UINT32);
+ INT32 (*read_mac_addr)(struct e1000_hw *);
+ INT32 (*validate_mdi_setting)(struct e1000_hw *);
+ INT32 (*mng_host_if_write)(struct e1000_hw *, UINT8*, UINT16, UINT16, UINT8*);
+ INT32 (*mng_write_cmd_header)(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header*);
+ INT32 (*mng_enable_host_if)(struct e1000_hw *);
+ INT32 (*wait_autoneg)(struct e1000_hw *);
+};
+
+struct e1000_phy_operations {
+ INT32 (*init_params)(struct e1000_hw *);
+ INT32 (*acquire)(struct e1000_hw *);
+#ifndef NO_80003ES2LAN_SUPPORT
+ INT32 (*cfg_on_link_up)(struct e1000_hw *);
+#endif
+ INT32 (*check_polarity)(struct e1000_hw *);
+ INT32 (*check_reset_block)(struct e1000_hw *);
+ INT32 (*commit)(struct e1000_hw *);
+ INT32 (*force_speed_duplex)(struct e1000_hw *);
+ INT32 (*get_cfg_done)(struct e1000_hw *hw);
+ INT32 (*get_cable_length)(struct e1000_hw *);
+ INT32 (*get_info)(struct e1000_hw *);
+ INT32 (*read_reg)(struct e1000_hw *, UINT32, UINT16 *);
+ INT32 (*read_reg_locked)(struct e1000_hw *, UINT32, UINT16 *);
+ void (*release)(struct e1000_hw *);
+ INT32 (*reset)(struct e1000_hw *);
+ INT32 (*set_d0_lplu_state)(struct e1000_hw *, BOOLEAN);
+ INT32 (*set_d3_lplu_state)(struct e1000_hw *, BOOLEAN);
+ INT32 (*write_reg)(struct e1000_hw *, UINT32, UINT16);
+ INT32 (*write_reg_locked)(struct e1000_hw *, UINT32, UINT16);
+ void (*power_up)(struct e1000_hw *);
+ void (*power_down)(struct e1000_hw *);
+};
+
+struct e1000_nvm_operations {
+ INT32 (*init_params)(struct e1000_hw *);
+ INT32 (*acquire)(struct e1000_hw *);
+ INT32 (*read)(struct e1000_hw *, UINT16, UINT16, UINT16 *);
+ void (*release)(struct e1000_hw *);
+ void (*reload)(struct e1000_hw *);
+ INT32 (*update)(struct e1000_hw *);
+ INT32 (*valid_led_default)(struct e1000_hw *, UINT16 *);
+ INT32 (*validate)(struct e1000_hw *);
+ INT32 (*write)(struct e1000_hw *, UINT16, UINT16, UINT16 *);
+};
+
+struct e1000_mac_info {
+ struct e1000_mac_operations ops;
+ UINT8 addr[6];
+ UINT8 perm_addr[6];
+
+ enum e1000_mac_type type;
+
+ UINT32 collision_delta;
+ UINT32 ledctl_default;
+ UINT32 ledctl_mode1;
+ UINT32 ledctl_mode2;
+ UINT32 mc_filter_type;
+ UINT32 tx_packet_delta;
+ UINT32 txcw;
+
+ UINT16 current_ifs_val;
+ UINT16 ifs_max_val;
+ UINT16 ifs_min_val;
+ UINT16 ifs_ratio;
+ UINT16 ifs_step_size;
+ UINT16 mta_reg_count;
+#ifndef NO_82576_SUPPORT
+ UINT16 uta_reg_count;
+#endif
+
+ /* Maximum size of the MTA register table in all supported adapters */
+ #define MAX_MTA_REG 128
+ UINT32 mta_shadow[MAX_MTA_REG];
+ UINT16 rar_entry_count;
+
+ UINT8 forced_speed_duplex;
+
+ BOOLEAN adaptive_ifs;
+ BOOLEAN has_fwsm;
+ BOOLEAN arc_subsystem_valid;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ BOOLEAN asf_firmware_present;
+#endif
+ BOOLEAN autoneg;
+ BOOLEAN autoneg_failed;
+ BOOLEAN get_link_status;
+ BOOLEAN in_ifs_mode;
+ enum e1000_serdes_link_state serdes_link_state;
+ BOOLEAN serdes_has_link;
+ BOOLEAN tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+ struct e1000_phy_operations ops;
+ enum e1000_phy_type type;
+
+ enum e1000_1000t_rx_status local_rx;
+ enum e1000_1000t_rx_status remote_rx;
+ enum e1000_ms_type ms_type;
+ enum e1000_ms_type original_ms_type;
+ enum e1000_rev_polarity cable_polarity;
+ enum e1000_smart_speed smart_speed;
+
+ UINT32 addr;
+ UINT32 id;
+ UINT32 reset_delay_us; /* in usec */
+ UINT32 revision;
+
+ enum e1000_media_type media_type;
+
+ UINT16 autoneg_advertised;
+ UINT16 autoneg_mask;
+ UINT16 cable_length;
+ UINT16 max_cable_length;
+ UINT16 min_cable_length;
+
+ UINT8 mdix;
+
+ BOOLEAN disable_polarity_correction;
+ BOOLEAN is_mdix;
+ BOOLEAN polarity_correction;
+#ifndef NO_PHY_RESET_DISABLE
+ BOOLEAN reset_disable;
+#endif
+ BOOLEAN speed_downgraded;
+ BOOLEAN autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+ struct e1000_nvm_operations ops;
+ enum e1000_nvm_type type;
+ enum e1000_nvm_override override;
+
+ UINT32 flash_bank_size;
+ UINT32 flash_base_addr;
+
+ UINT16 word_size;
+ UINT16 delay_usec;
+ UINT16 address_bits;
+ UINT16 opcode_bits;
+ UINT16 page_size;
+};
+
+struct e1000_bus_info {
+ enum e1000_bus_type type;
+ enum e1000_bus_speed speed;
+ enum e1000_bus_width width;
+
+ UINT16 func;
+ UINT16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+ UINT32 high_water; /* Flow control high-water mark */
+ UINT32 low_water; /* Flow control low-water mark */
+ UINT16 pause_time; /* Flow control pause timer */
+ UINT16 refresh_time; /* Flow control refresh timer */
+ BOOLEAN send_xon; /* Flow control send XON */
+ BOOLEAN strict_ieee; /* Strict IEEE mode */
+ enum e1000_fc_mode current_mode; /* FC mode in effect */
+ enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
+};
+
+#ifndef NO_82571_SUPPORT
+struct e1000_dev_spec_82571 {
+ BOOLEAN laa_is_present;
+ UINT32 smb_counter;
+ E1000_MUTEX swflag_mutex;
+};
+
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_80003ES2LAN_SUPPORT
+struct e1000_dev_spec_80003es2lan {
+ BOOLEAN mdic_wa_enable;
+};
+
+#endif /* NO_80003ES2LAN_SUPPORT */
+#ifndef NO_ICH8LAN_SUPPORT
+struct e1000_shadow_ram {
+ UINT16 value;
+ BOOLEAN modified;
+};
+
+#define E1000_SHADOW_RAM_WORDS 2048
+
+struct e1000_dev_spec_ich8lan {
+ BOOLEAN kmrn_lock_loss_workaround_enabled;
+ struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS];
+ E1000_MUTEX nvm_mutex;
+ E1000_MUTEX swflag_mutex;
+ BOOLEAN nvm_k1_enabled;
+ BOOLEAN eee_disable;
+};
+
+#endif /* NO_ICH8LAN_SUPPORT */
+#ifndef NO_82575_SUPPORT
+struct e1000_dev_spec_82575 {
+ BOOLEAN sgmii_active;
+ BOOLEAN global_device_reset;
+};
+
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82576_SUPPORT
+struct e1000_dev_spec_vf {
+ UINT32 vf_number;
+ UINT32 v2p_mailbox;
+};
+
+#endif /* NO_82576_SUPPORT */
+struct e1000_hw {
+ void *back;
+
+ UINT8 *hw_addr;
+ UINT8 *flash_address;
+ unsigned long io_base;
+
+ struct e1000_mac_info mac;
+ struct e1000_fc_info fc;
+ struct e1000_phy_info phy;
+ struct e1000_nvm_info nvm;
+ struct e1000_bus_info bus;
+ struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+ union {
+#ifndef NO_82571_SUPPORT
+ struct e1000_dev_spec_82571 _82571;
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ struct e1000_dev_spec_80003es2lan _80003es2lan;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ struct e1000_dev_spec_ich8lan ich8lan;
+#endif
+#ifndef NO_82575_SUPPORT
+ struct e1000_dev_spec_82575 _82575;
+#endif
+#ifndef NO_82576_SUPPORT
+ struct e1000_dev_spec_vf vf;
+#endif
+ } dev_spec;
+
+ UINT16 device_id;
+ UINT16 subsystem_vendor_id;
+ UINT16 subsystem_device_id;
+ UINT16 vendor_id;
+
+ UINT8 revision_id;
+};
+
+#ifndef NO_82571_SUPPORT
+#include "e1000_82571.h"
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+#include "e1000_80003es2lan.h"
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+#include "e1000_ich8lan.h"
+#endif
+#ifndef NO_82575_SUPPORT
+#include "e1000_82575.h"
+#endif
+
+/* These functions must be implemented by drivers */
+INT32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#ifndef NO_PCIE_SUPPORT
+INT32 e1000_write_pcie_cap_reg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#endif
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+void e1000_read_pci_cfg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#endif
+#ifndef NO_PCIX_SUPPORT
+void e1000_write_pci_cfg(struct e1000_hw *hw, UINT32 reg, UINT16 *value);
+#endif
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c
new file mode 100755
index 0000000..d1bead3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.c
@@ -0,0 +1,4070 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*
+ * 82562G 10/100 Network Connection
+ * 82562G-2 10/100 Network Connection
+ * 82562GT 10/100 Network Connection
+ * 82562GT-2 10/100 Network Connection
+ * 82562V 10/100 Network Connection
+ * 82562V-2 10/100 Network Connection
+ * 82566DC-2 Gigabit Network Connection
+ * 82566DC Gigabit Network Connection
+ * 82566DM-2 Gigabit Network Connection
+ * 82566DM Gigabit Network Connection
+ * 82566MC Gigabit Network Connection
+ * 82566MM Gigabit Network Connection
+ * 82567LM Gigabit Network Connection
+ * 82567LF Gigabit Network Connection
+ * 82567V Gigabit Network Connection
+ * 82567LM-2 Gigabit Network Connection
+ * 82567LF-2 Gigabit Network Connection
+ * 82567V-2 Gigabit Network Connection
+ * 82567LM-4 Gigabit Network Connection
+ * 82577LM Gigabit Network Connection
+ * 82577LC Gigabit Network Connection
+ * 82578DM Gigabit Network Connection
+ * 82578DC Gigabit Network Connection
+ * 82579LM Gigabit Network Connection
+ * 82579V Gigabit Network Connection
+ */
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_phy_params_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
+STATIC void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
+STATIC void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
+STATIC BOOLEAN e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
+STATIC BOOLEAN e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
+STATIC void e1000_rar_set_pch2lan(struct e1000_hw *hw, UINT8 *addr, UINT32 index);
+STATIC INT32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, BOOLEAN active);
+STATIC INT32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
+ BOOLEAN active);
+STATIC INT32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+STATIC INT32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
+ UINT16 *data);
+STATIC INT32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_reset_hw_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_init_hw_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex);
+STATIC INT32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_on_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_off_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, BOOLEAN link);
+STATIC INT32 e1000_setup_led_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_cleanup_led_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_on_pchlan(struct e1000_hw *hw);
+STATIC INT32 e1000_led_off_pchlan(struct e1000_hw *hw);
+STATIC void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, UINT32 bank);
+static INT32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, UINT32 timeout);
+static INT32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
+static INT32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 *data);
+static INT32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 *data);
+STATIC INT32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT16 *data);
+static INT32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 byte);
+STATIC INT32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 data);
+static INT32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 data);
+STATIC INT32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
+STATIC void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
+static INT32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
+STATIC INT32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
+STATIC INT32 e1000_k1_workaround_lv(struct e1000_hw *hw);
+STATIC void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, BOOLEAN gate);
+
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+ struct ich8_hsfsts {
+ UINT16 flcdone :1; /* bit 0 Flash Cycle Done */
+ UINT16 flcerr :1; /* bit 1 Flash Cycle Error */
+ UINT16 dael :1; /* bit 2 Direct Access error Log */
+ UINT16 berasesz :2; /* bit 4:3 Sector Erase Size */
+ UINT16 flcinprog :1; /* bit 5 flash cycle in Progress */
+ UINT16 reserved1 :2; /* bit 13:6 Reserved */
+ UINT16 reserved2 :6; /* bit 13:6 Reserved */
+ UINT16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+ UINT16 flockdn :1; /* bit 15 Flash Config Lock-Down */
+ } hsf_status;
+ UINT16 regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+ struct ich8_hsflctl {
+ UINT16 flcgo :1; /* 0 Flash Cycle Go */
+ UINT16 flcycle :2; /* 2:1 Flash Cycle */
+ UINT16 reserved :5; /* 7:3 Reserved */
+ UINT16 fldbcount :2; /* 9:8 Flash Data Byte Count */
+ UINT16 flockdn :6; /* 15:10 Reserved */
+ } hsf_ctrl;
+ UINT16 regval;
+};
+
+/* ICH Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+ struct ich8_flracc {
+ UINT32 grra :8; /* 0:7 GbE region Read Access */
+ UINT32 grwa :8; /* 8:15 GbE region Write Access */
+ UINT32 gmrag :8; /* 23:16 GbE Master Read Access Grant */
+ UINT32 gmwag :8; /* 31:24 GbE Master Write Access Grant */
+ } hsf_flregacc;
+ UINT16 regval;
+};
+
+/**
+ * e1000_init_phy_params_pchlan - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific PHY parameters and function pointers.
+ **/
+STATIC INT32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 ctrl, fwsm;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_init_phy_params_pchlan");
+
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
+
+ phy->ops.acquire = e1000_acquire_swflag_ich8lan;
+ phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
+ phy->ops.read_reg = e1000_read_phy_reg_hv;
+ phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
+ phy->ops.release = e1000_release_swflag_ich8lan;
+ phy->ops.reset = e1000_phy_hw_reset_ich8lan;
+ phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
+ phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
+ phy->ops.write_reg = e1000_write_phy_reg_hv;
+ phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /*
+ * The MAC-PHY interconnect may still be in SMBus mode
+ * after Sx->S0. If the manageability engine (ME) is
+ * disabled, then toggle the LANPHYPC Value bit to force
+ * the interconnect to PCIe mode.
+ */
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+ if (!(fwsm & E1000_ICH_FWSM_FW_VALID)) {
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
+ ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ usec_delay(10);
+ ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ msec_delay(50);
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+ }
+
+ /*
+ * Reset the PHY before any acccess to it. Doing so, ensures that
+ * the PHY is in a known good state before we read/write PHY registers.
+ * The generic reset is sufficient here, because we haven't determined
+ * the PHY type yet.
+ */
+ ret_val = e1000_phy_hw_reset_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
+ msec_delay(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
+ }
+
+ phy->id = e1000_phy_unknown;
+ ret_val = e1000_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
+ /*
+ * In case the PHY needs to be in mdio slow mode (eg. 82577),
+ * set slow mode and try to get the PHY id again.
+ */
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ }
+ phy->type = e1000_get_phy_type_from_id(phy->id);
+
+ switch (phy->type) {
+ case e1000_phy_82577:
+ case e1000_phy_82579:
+ phy->ops.check_polarity = e1000_check_polarity_82577;
+ phy->ops.force_speed_duplex =
+ e1000_phy_force_speed_duplex_82577;
+ phy->ops.get_cable_length = e1000_get_cable_length_82577;
+ phy->ops.get_info = e1000_get_phy_info_82577;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ break;
+ case e1000_phy_82578:
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ break;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_phy_params_ich8lan - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific PHY parameters and function pointers.
+ **/
+STATIC INT32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i = 0;
+
+ DEBUGFUNC("e1000_init_phy_params_ich8lan");
+
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
+
+ phy->ops.acquire = e1000_acquire_swflag_ich8lan;
+ phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
+ phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
+ phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
+ phy->ops.read_reg = e1000_read_phy_reg_igp;
+ phy->ops.release = e1000_release_swflag_ich8lan;
+ phy->ops.reset = e1000_phy_hw_reset_ich8lan;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
+ phy->ops.write_reg = e1000_write_phy_reg_igp;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
+
+ /*
+ * We may need to do this twice - once for IGP and if that fails,
+ * we'll set BM func pointers and try again
+ */
+ ret_val = e1000_determine_phy_address(hw);
+ if (ret_val) {
+ phy->ops.write_reg = e1000_write_phy_reg_bm;
+ phy->ops.read_reg = e1000_read_phy_reg_bm;
+ ret_val = e1000_determine_phy_address(hw);
+ if (ret_val) {
+ DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
+ goto out;
+ }
+ }
+
+ phy->id = 0;
+ while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
+ (i++ < 100)) {
+ msec_delay(1);
+ ret_val = e1000_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Verify phy id */
+ switch (phy->id) {
+ case IGP03E1000_E_PHY_ID:
+ phy->type = e1000_phy_igp_3;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
+ phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
+ phy->ops.get_info = e1000_get_phy_info_igp;
+ phy->ops.check_polarity = e1000_check_polarity_igp;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy->type = e1000_phy_ife;
+ phy->autoneg_mask = E1000_ALL_NOT_GIG;
+ phy->ops.get_info = e1000_get_phy_info_ife;
+ phy->ops.check_polarity = e1000_check_polarity_ife;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
+ break;
+ case BME1000_E_PHY_ID:
+ phy->type = e1000_phy_bm;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->ops.read_reg = e1000_read_phy_reg_bm;
+ phy->ops.write_reg = e1000_write_phy_reg_bm;
+ phy->ops.commit = e1000_phy_sw_reset_generic;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific NVM parameters and function
+ * pointers.
+ **/
+STATIC INT32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 gfpreg, sector_base_addr, sector_end_addr;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_init_nvm_params_ich8lan");
+
+ /* Can't read flash registers if the register set isn't mapped. */
+ if (!hw->flash_address) {
+ DEBUGOUT("ERROR: Flash registers not mapped\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ nvm->type = e1000_nvm_flash_sw;
+
+ gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
+
+ /*
+ * sector_X_addr is a "sector"-aligned address (4096 bytes)
+ * Add 1 to sector_end_addr since this sector is included in
+ * the overall size.
+ */
+ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+ sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+
+ /* flash_base_addr is byte-aligned */
+ nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+
+ /*
+ * find total size of the NVM, then cut in half since the total
+ * size represents two separate NVM banks.
+ */
+ nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
+ << FLASH_SECTOR_ADDR_SHIFT;
+ nvm->flash_bank_size /= 2;
+ /* Adjust to word count */
+ nvm->flash_bank_size /= sizeof(UINT16);
+
+ nvm->word_size = E1000_SHADOW_RAM_WORDS;
+
+ /* Clear shadow ram */
+ for (i = 0; i < nvm->word_size; i++) {
+ dev_spec->shadow_ram[i].modified = FALSE;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+ //E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
+ //E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
+
+ /* Function Pointers */
+ nvm->ops.acquire = e1000_acquire_nvm_ich8lan;
+ nvm->ops.release = e1000_release_nvm_ich8lan;
+ nvm->ops.read = e1000_read_nvm_ich8lan;
+ nvm->ops.update = e1000_update_nvm_checksum_ich8lan;
+ nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
+ nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan;
+ nvm->ops.write = e1000_write_nvm_ich8lan;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_mac_params_ich8lan - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific MAC parameters and function
+ * pointers.
+ **/
+STATIC INT32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT16 pci_cfg;
+
+ DEBUGFUNC("e1000_init_mac_params_ich8lan");
+
+ /* Set media type function pointer */
+ hw->phy.media_type = e1000_media_type_copper;
+
+ /* Set mta register count */
+ mac->mta_reg_count = 32;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
+ if (mac->type == e1000_ich8lan)
+ mac->rar_entry_count--;
+#ifndef NO_ASF_FIRMWARE_CHECK
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = TRUE;
+#endif
+ /* FWSM register */
+ mac->has_fwsm = TRUE;
+ /* ARC subsystem not supported */
+ mac->arc_subsystem_valid = FALSE;
+ /* Adaptive IFS supported */
+ mac->adaptive_ifs = TRUE;
+
+ /* Function pointers */
+
+ /* bus type/speed/width */
+ mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
+ /* function id */
+ mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+ /* reset */
+ mac->ops.reset_hw = e1000_reset_hw_ich8lan;
+ /* hw initialization */
+ mac->ops.init_hw = e1000_init_hw_ich8lan;
+ /* link setup */
+ mac->ops.setup_link = e1000_setup_link_ich8lan;
+ /* physical interface setup */
+ mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
+ /* check for link */
+ mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
+ /* link info */
+ mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
+ /* multicast address update */
+ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+ /* clear hardware counters */
+ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
+
+ /* LED operations */
+ switch (mac->type) {
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_generic;
+ /* blink LED */
+ mac->ops.blink_led = e1000_blink_led_generic;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_generic;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_ich8lan;
+ mac->ops.led_off = e1000_led_off_ich8lan;
+ break;
+ case e1000_pch2lan:
+ mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
+ mac->ops.rar_set = e1000_rar_set_pch2lan;
+ /* fall-through */
+ case e1000_pchlan:
+ /* save PCH revision_id */
+ e1000_read_pci_cfg(hw, 0x2, &pci_cfg);
+ hw->revision_id = (UINT8)(pci_cfg &= 0x000F);
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
+ /* ID LED init */
+ mac->ops.id_led_init = e1000_id_led_init_pchlan;
+ /* setup LED */
+ mac->ops.setup_led = e1000_setup_led_pchlan;
+ /* cleanup LED */
+ mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
+ /* turn on/off LED */
+ mac->ops.led_on = e1000_led_on_pchlan;
+ mac->ops.led_off = e1000_led_off_pchlan;
+ break;
+ default:
+ break;
+ }
+
+ /* Enable PCS Lock-loss workaround for ICH8 */
+ if (mac->type == e1000_ich8lan)
+ e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
+
+ /* Gate automatic PHY configuration by hardware on managed 82579 */
+ if ((mac->type == e1000_pch2lan) &&
+ (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_eee_pchlan - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ *
+ * Enable/disable EEE based on setting in dev_spec structure. The bits in
+ * the LPI Control register will remain set only if/when link is up.
+ **/
+STATIC INT32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_reg;
+
+ DEBUGFUNC("e1000_set_eee_pchlan");
+
+ if (hw->phy.type != e1000_phy_82579)
+ goto out;
+
+ ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg);
+ if (ret_val)
+ goto out;
+
+ if (hw->dev_spec.ich8lan.eee_disable)
+ phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
+ else
+ phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
+
+ ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_copper_link_ich8lan - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed. If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ **/
+static INT32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
+
+ /*
+ * We only want to go out to the PHY registers to see if Auto-Neg
+ * has completed and/or if our link status has changed. The
+ * get_link_status flag is set upon receiving a Link Status
+ * Change or Rx Sequence Error interrupt.
+ */
+ if (!mac->get_link_status) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ /*
+ * First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (hw->mac.type == e1000_pchlan) {
+ ret_val = e1000_k1_gig_workaround_hv(hw, link);
+ if (ret_val)
+ goto out;
+ }
+
+ if (!link)
+ goto out; /* No link detected */
+
+ mac->get_link_status = FALSE;
+
+ if (hw->phy.type == e1000_phy_82578) {
+ ret_val = e1000_link_stall_workaround_hv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ if (hw->mac.type == e1000_pch2lan) {
+ ret_val = e1000_k1_workaround_lv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Check if there was DownShift, must be checked
+ * immediately after link-up
+ */
+ e1000_check_downshift_generic(hw);
+
+ /* Enable/Disable EEE after link up */
+ ret_val = e1000_set_eee_pchlan(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if (!mac->autoneg) {
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ /*
+ * Auto-Neg is enabled. Auto Speed Detection takes care
+ * of MAC speed/duplex configuration. So we only need to
+ * configure Collision Distance in the MAC.
+ */
+ e1000_config_collision_dist_generic(hw);
+
+ /*
+ * Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control
+ * settings because we may have had to re-autoneg with a
+ * different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val)
+ DEBUGOUT("Error configuring flow control\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific function pointers for PHY, MAC, and NVM.
+ **/
+void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_init_function_pointers_ich8lan");
+
+ hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
+ hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
+ break;
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * e1000_acquire_nvm_ich8lan - Acquire NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the mutex for performing NVM operations.
+ **/
+STATIC INT32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_acquire_nvm_ich8lan");
+
+ //E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_release_nvm_ich8lan - Release NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Releases the mutex used while performing NVM operations.
+ **/
+STATIC void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_ich8lan");
+
+ //E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
+
+ return;
+}
+
+/**
+ * e1000_acquire_swflag_ich8lan - Acquire software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the software control flag for performing PHY and select
+ * MAC CSR accesses.
+ **/
+STATIC INT32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_acquire_swflag_ich8lan");
+
+ //E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
+
+ while (timeout) {
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
+ break;
+
+ msec_delay_irq(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("SW/FW/HW has locked the resource for too long.\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ timeout = SW_FLAG_TIMEOUT;
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+ while (timeout) {
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ break;
+
+ msec_delay_irq(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Failed to acquire the semaphore.\n");
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+out:
+ /*if (ret_val)
+ E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);*/
+
+ return ret_val;
+}
+
+/**
+ * e1000_release_swflag_ich8lan - Release software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Releases the software control flag for performing PHY and select
+ * MAC CSR accesses.
+ **/
+STATIC void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_release_swflag_ich8lan");
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+ //E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
+
+ return;
+}
+
+/**
+ * e1000_check_mng_mode_ich8lan - Checks management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has any manageability enabled.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+STATIC BOOLEAN e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 fwsm;
+
+ DEBUGFUNC("e1000_check_mng_mode_ich8lan");
+
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ * e1000_check_mng_mode_pchlan - Checks management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has iAMT enabled.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+STATIC BOOLEAN e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
+{
+ UINT32 fwsm;
+
+ DEBUGFUNC("e1000_check_mng_mode_pchlan");
+
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ * e1000_rar_set_pch2lan - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr. For 82579, RAR[0] is the base address register that is to
+ * contain the MAC address but RAR[1-6] are reserved for manageability (ME).
+ * Use SHRA[0-3] in place of those reserved for ME.
+ **/
+STATIC void e1000_rar_set_pch2lan(struct e1000_hw *hw, UINT8 *addr, UINT32 index)
+{
+ UINT32 rar_low, rar_high;
+
+ DEBUGFUNC("e1000_rar_set_pch2lan");
+
+ /*
+ * HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((UINT32) addr[0] |
+ ((UINT32) addr[1] << 8) |
+ ((UINT32) addr[2] << 16) | ((UINT32) addr[3] << 24));
+
+ rar_high = ((UINT32) addr[4] | ((UINT32) addr[5] << 8));
+
+ /* If MAC address zero, no need to set the AV bit */
+ if (rar_low || rar_high)
+ rar_high |= E1000_RAH_AV;
+
+ if (index == 0) {
+ E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+ E1000_WRITE_FLUSH(hw);
+ return;
+ }
+
+ if (index < hw->mac.rar_entry_count) {
+ E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
+ E1000_WRITE_FLUSH(hw);
+
+ /* verify the register updates */
+ if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
+ (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
+ return;
+
+ DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
+ (index - 1), E1000_READ_REG(hw, E1000_FWSM));
+ }
+
+ DEBUGOUT1("Failed to write receive address at index %d\n", index);
+}
+
+/**
+ * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Checks if firmware is blocking the reset of the PHY.
+ * This is a function pointer entry point only called by
+ * reset routines.
+ **/
+STATIC INT32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 fwsm;
+
+ DEBUGFUNC("e1000_check_reset_block_ich8lan");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (hw->phy.reset_disable)
+ return E1000_BLK_PHY_RESET;
+
+#endif
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
+ : E1000_BLK_PHY_RESET;
+}
+
+/**
+ * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
+ * @hw: pointer to the HW structure
+ *
+ * Assumes semaphore already acquired.
+ *
+ **/
+STATIC INT32 e1000_write_smbus_addr(struct e1000_hw *hw)
+{
+ UINT16 phy_data;
+ UINT32 strap = E1000_READ_REG(hw, E1000_STRAP);
+ INT32 ret_val = E1000_SUCCESS;
+
+ strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+
+ ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~HV_SMB_ADDR_MASK;
+ phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
+ phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
+ * @hw: pointer to the HW structure
+ *
+ * SW should configure the LCD from the NVM extended configuration region
+ * as a workaround for certain parts.
+ **/
+STATIC INT32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+ DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
+
+ /*
+ * Initialize the PHY from the NVM on ICH platforms. This
+ * is needed due to an issue where the NVM configuration is
+ * not properly autoloaded after power transitions.
+ * Therefore, after each PHY reset, we will load the
+ * configuration data out of the NVM manually.
+ */
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ if (phy->type != e1000_phy_igp_3)
+ return ret_val;
+
+ if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
+ (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+ break;
+ }
+ /* Fall-thru */
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+ break;
+ default:
+ return ret_val;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ data = E1000_READ_REG(hw, E1000_FEXTNVM);
+ if (!(data & sw_cfg_mask))
+ goto out;
+
+ /*
+ * Make sure HW does not configure LCD from PHY
+ * extended configuration before SW configuration
+ */
+ data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+ goto out;
+ }
+
+ cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
+ cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+ cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+ if (!cnf_size)
+ goto out;
+
+ cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+ cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+ if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+ (hw->mac.type == e1000_pchlan)) ||
+ (hw->mac.type == e1000_pch2lan)) {
+ /*
+ * HW configures the SMBus address and LEDs when the
+ * OEM and LCD Write Enable bits are set in the NVM.
+ * When both NVM bits are cleared, SW will configure
+ * them instead.
+ */
+ ret_val = e1000_write_smbus_addr(hw);
+ if (ret_val)
+ goto out;
+
+ data = E1000_READ_REG(hw, E1000_LEDCTL);
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
+ (UINT16)data);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Configure LCD from extended configuration region. */
+
+ /* cnf_base_addr is in DWORD */
+ word_addr = (UINT16)(cnf_base_addr << 1);
+
+ for (i = 0; i < cnf_size; i++) {
+ ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
+ 1, ®_addr);
+ if (ret_val)
+ goto out;
+
+ /* Save off the PHY page for future writes. */
+ if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+ phy_page = reg_data;
+ continue;
+ }
+
+ reg_addr &= PHY_REG_MASK;
+ reg_addr |= phy_page;
+
+ ret_val = phy->ops.write_reg_locked(hw, (UINT32)reg_addr,
+ reg_data);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * e1000_k1_gig_workaround_hv - K1 Si workaround
+ * @hw: pointer to the HW structure
+ * @link: link up BOOLEAN flag
+ *
+ * If K1 is enabled for 1Gbps, the MAC might stall when transitioning
+ * from a lower speed. This workaround disables K1 whenever link is at 1Gig
+ * If link is down, the function will restore the default K1 setting located
+ * in the NVM.
+ **/
+STATIC INT32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, BOOLEAN link)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 status_reg = 0;
+ BOOLEAN k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
+
+ DEBUGFUNC("e1000_k1_gig_workaround_hv");
+
+ if (hw->mac.type != e1000_pchlan)
+ goto out;
+
+ /* Wrap the whole flow with the sw flag */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
+ if (link) {
+ if (hw->phy.type == e1000_phy_82578) {
+ ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
+ &status_reg);
+ if (ret_val)
+ goto release;
+
+ status_reg &= BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK;
+
+ if (status_reg == (BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_1000))
+ k1_enable = FALSE;
+ }
+
+ if (hw->phy.type == e1000_phy_82577) {
+ ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
+ &status_reg);
+ if (ret_val)
+ goto release;
+
+ status_reg &= HV_M_STATUS_LINK_UP |
+ HV_M_STATUS_AUTONEG_COMPLETE |
+ HV_M_STATUS_SPEED_MASK;
+
+ if (status_reg == (HV_M_STATUS_LINK_UP |
+ HV_M_STATUS_AUTONEG_COMPLETE |
+ HV_M_STATUS_SPEED_1000))
+ k1_enable = FALSE;
+ }
+
+ /* Link stall fix for link up */
+ ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+ 0x0100);
+ if (ret_val)
+ goto release;
+
+ } else {
+ /* Link stall fix for link down */
+ ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+ 0x4100);
+ if (ret_val)
+ goto release;
+ }
+
+ ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
+
+release:
+ hw->phy.ops.release(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_configure_k1_ich8lan - Configure K1 power state
+ * @hw: pointer to the HW structure
+ * @enable: K1 state to configure
+ *
+ * Configure the K1 power state based on the provided parameter.
+ * Assumes semaphore already acquired.
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ **/
+INT32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, BOOLEAN k1_enable)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 ctrl_reg = 0;
+ UINT32 ctrl_ext = 0;
+ UINT32 reg = 0;
+ UINT16 kmrn_reg = 0;
+
+ DEBUGFUNC("e1000_configure_k1_ich8lan");
+
+ ret_val = e1000_read_kmrn_reg_locked(hw,
+ E1000_KMRNCTRLSTA_K1_CONFIG,
+ &kmrn_reg);
+ if (ret_val)
+ goto out;
+
+ if (k1_enable)
+ kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
+ else
+ kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
+
+ ret_val = e1000_write_kmrn_reg_locked(hw,
+ E1000_KMRNCTRLSTA_K1_CONFIG,
+ kmrn_reg);
+ if (ret_val)
+ goto out;
+
+ usec_delay(20);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
+
+ reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ reg |= E1000_CTRL_FRCSPD;
+ E1000_WRITE_REG(hw, E1000_CTRL, reg);
+
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
+ usec_delay(20);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ usec_delay(20);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
+ * @hw: pointer to the HW structure
+ * @d0_state: BOOLEANean if entering d0 or d3 device state
+ *
+ * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
+ * collectively called OEM bits. The OEM Write Enable bit and SW Config bit
+ * in NVM determines whether HW should configure LPLU and Gbe Disable.
+ **/
+INT32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, BOOLEAN d0_state)
+{
+ INT32 ret_val = 0;
+ UINT32 mac_reg;
+ UINT16 oem_reg;
+
+ DEBUGFUNC("e1000_oem_bits_config_ich8lan");
+
+ if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
+ return ret_val;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+ if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+ goto out;
+ }
+
+ mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
+ if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
+ goto out;
+
+ mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+ ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
+ if (ret_val)
+ goto out;
+
+ oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
+
+ if (d0_state) {
+ if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
+ oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+ if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ } else {
+ if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
+ oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+ if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ }
+ /* Restart auto-neg to activate the bits */
+ if (!hw->phy.ops.check_reset_block(hw))
+ oem_reg |= HV_OEM_BITS_RESTART_AN;
+ ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
+
+out:
+ hw->phy.ops.release(hw);
+
+ return ret_val;
+}
+
+
+/**
+ * e1000_hv_phy_powerdown_workaround_ich8lan - Power down workaround on Sx
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_hv_phy_powerdown_workaround_ich8lan");
+
+ if ((hw->phy.type != e1000_phy_82577) || (hw->revision_id > 2))
+ return E1000_SUCCESS;
+
+ return hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0444);
+}
+
+/**
+ * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
+
+ ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= HV_KMRN_MDIO_SLOW;
+
+ ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ **/
+STATIC INT32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
+
+ if (hw->mac.type != e1000_pchlan)
+ goto out;
+
+ /* Set MDIO slow mode before any other MDIO access */
+ if (hw->phy.type == e1000_phy_82577) {
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Hanksville M Phy init for IEEE. */
+ if ((hw->revision_id == 2) &&
+ (hw->phy.type == e1000_phy_82577) &&
+ ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
+ hw->phy.ops.write_reg(hw, 0x10, 0x8823);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0018);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8824);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0016);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8825);
+ hw->phy.ops.write_reg(hw, 0x11, 0x001A);
+ hw->phy.ops.write_reg(hw, 0x10, 0x888C);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0007);
+ hw->phy.ops.write_reg(hw, 0x10, 0x888D);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0007);
+ hw->phy.ops.write_reg(hw, 0x10, 0x888E);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0007);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8827);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0001);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8835);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0001);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8834);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0001);
+ hw->phy.ops.write_reg(hw, 0x10, 0x8833);
+ hw->phy.ops.write_reg(hw, 0x11, 0x0002);
+ }
+
+ if (((hw->phy.type == e1000_phy_82577) &&
+ ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
+ ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
+ /* Disable generation of early preamble */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
+ if (ret_val)
+ goto out;
+
+ /* Preamble tuning for SSC */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
+ if (ret_val)
+ goto out;
+ }
+
+ if (hw->phy.type == e1000_phy_82578) {
+ if (hw->revision_id < 3) {
+ /* PHY config */
+ ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29,
+ 0x66C0);
+ if (ret_val)
+ goto out;
+
+ /* PHY config */
+ ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E,
+ 0xFFFF);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Return registers to default by doing a soft reset then
+ * writing 0x3140 to the control register.
+ */
+ if (hw->phy.revision < 2) {
+ e1000_phy_sw_reset_generic(hw);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
+ 0x3140);
+ }
+ }
+
+ if ((hw->revision_id == 2) &&
+ (hw->phy.type == e1000_phy_82577) &&
+ ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
+ /*
+ * Workaround for OEM (GbE) not operating after reset -
+ * restart AN (twice)
+ */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Select page 0 */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ hw->phy.addr = 1;
+ ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+ hw->phy.ops.release(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Configure the K1 Si workaround during phy reset assuming there is
+ * link so that it disables K1 if link is in 1Gbps.
+ */
+ ret_val = e1000_k1_gig_workaround_hv(hw, TRUE);
+ if (ret_val)
+ goto out;
+
+ /* Workaround for link disconnects on a busy hub in half duplex */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg_locked(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 17),
+ &phy_data);
+ if (ret_val)
+ goto release;
+ ret_val = hw->phy.ops.write_reg_locked(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 17),
+ phy_data & 0x00FF);
+release:
+ hw->phy.ops.release(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
+ * @hw: pointer to the HW structure
+ **/
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 mac_reg;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
+
+ /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
+ hw->phy.ops.write_reg(hw, BM_RAR_L(i), (UINT16)(mac_reg & 0xFFFF));
+ hw->phy.ops.write_reg(hw, BM_RAR_M(i), (UINT16)((mac_reg >> 16) & 0xFFFF));
+ mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
+ hw->phy.ops.write_reg(hw, BM_RAR_H(i), (UINT16)(mac_reg & 0xFFFF));
+ hw->phy.ops.write_reg(hw, BM_RAR_CTRL(i), (UINT16)((mac_reg >> 16) & 0x8000));
+ }
+}
+
+static UINT32 e1000_calc_rx_da_crc(UINT8 mac[])
+{
+ UINT32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */
+ UINT32 i, j, mask, crc;
+
+ DEBUGFUNC("e1000_calc_rx_da_crc");
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ crc = crc ^ mac[i];
+ for (j = 8; j > 0; j--) {
+ mask = (crc & 1) * (-1);
+ crc = (crc >> 1) ^ (poly & mask);
+ }
+ }
+ return ~crc;
+}
+
+/**
+ * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
+ * with 82579 PHY
+ * @hw: pointer to the HW structure
+ * @enable: flag to enable/disable workaround when enabling/disabling jumbos
+ **/
+INT32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, BOOLEAN enable)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_reg, data;
+ UINT32 mac_reg;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* disable Rx path while enabling/disabling workaround */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | (1 << 14));
+ if (ret_val)
+ goto out;
+
+ if (enable) {
+ /*
+ * Write Rx addresses (rar_entry_count for RAL/H, +4 for
+ * SHRAL/H) and initial CRC values to the MAC
+ */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ UINT8 mac_addr[ETH_ADDR_LEN] = {0};
+ UINT32 addr_high, addr_low;
+
+ addr_high = E1000_READ_REG(hw, E1000_RAH(i));
+ if (!(addr_high & E1000_RAH_AV))
+ continue;
+ addr_low = E1000_READ_REG(hw, E1000_RAL(i));
+ mac_addr[0] = (addr_low & 0xFF);
+ mac_addr[1] = ((addr_low >> 8) & 0xFF);
+ mac_addr[2] = ((addr_low >> 16) & 0xFF);
+ mac_addr[3] = ((addr_low >> 24) & 0xFF);
+ mac_addr[4] = (addr_high & 0xFF);
+ mac_addr[5] = ((addr_high >> 8) & 0xFF);
+
+ E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
+ e1000_calc_rx_da_crc(mac_addr));
+ }
+
+ /* Write Rx addresses to the PHY */
+ e1000_copy_rx_addrs_to_phy_ich8lan(hw);
+
+ /* Enable jumbo frame workaround in the MAC */
+ mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
+ mac_reg &= ~(1 << 14);
+ mac_reg |= (7 << 15);
+ E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
+
+ mac_reg = E1000_READ_REG(hw, E1000_RCTL);
+ mac_reg |= E1000_RCTL_SECRC;
+ E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
+
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data | (1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Enable jumbo frame workaround in the PHY */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ data |= (0x37 << 5);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
+ data &= ~(1 << 13);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x1A << 2);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xFE00);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
+ ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data | (1 << 10));
+ if (ret_val)
+ goto out;
+ } else {
+ /* Write MAC register values back to h/w defaults */
+ mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
+ mac_reg &= ~(0xF << 14);
+ E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
+
+ mac_reg = E1000_READ_REG(hw, E1000_RCTL);
+ mac_reg &= ~E1000_RCTL_SECRC;
+ E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
+
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data & ~(1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Write PHY register values back to h/w defaults */
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
+ data |= (1 << 13);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x8 << 2);
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
+ if (ret_val)
+ goto out;
+ hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
+ ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data & ~(1 << 10));
+ if (ret_val)
+ goto out;
+ }
+
+ /* re-enable Rx path after enabling/disabling workaround */
+ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg & ~(1 << 14));
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ **/
+STATIC INT32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set MDIO slow mode before any other MDIO access */
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_k1_gig_workaround_lv - K1 Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * Workaround to set the K1 beacon duration for 82579 parts
+ **/
+STATIC INT32 e1000_k1_workaround_lv(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 status_reg = 0;
+ UINT32 mac_reg;
+
+ DEBUGFUNC("e1000_k1_workaround_lv");
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set K1 beacon duration based on 1Gbps speed or otherwise */
+ ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
+ if (ret_val)
+ goto out;
+
+ if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
+ == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
+ mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
+ mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
+
+ if (status_reg & HV_M_STATUS_SPEED_1000)
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
+ else
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
+
+ E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
+ * @hw: pointer to the HW structure
+ * @gate: BOOLEANean set to TRUE to gate, FALSE to un-gate
+ *
+ * Gate/ungate the automatic PHY configuration via hardware; perform
+ * the configuration via software instead.
+ **/
+STATIC void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, BOOLEAN gate)
+{
+ UINT32 extcnf_ctrl;
+
+ DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
+
+ if (hw->mac.type != e1000_pch2lan)
+ return;
+
+ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+
+ if (gate)
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+ else
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+
+ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+ return;
+}
+
+/**
+ * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
+ * @hw: pointer to the HW structure
+ **/
+STATIC INT32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 reg;
+
+ DEBUGFUNC("e1000_post_phy_reset_ich8lan");
+
+ if (hw->phy.ops.check_reset_block(hw))
+ goto out;
+
+ /* Perform any necessary post-reset workarounds */
+ switch (hw->mac.type) {
+ case e1000_pchlan:
+ ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_pch2lan:
+ ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ break;
+ default:
+ break;
+ }
+
+ /* Dummy read to clear the phy wakeup bit after lcd reset */
+ if (hw->mac.type >= e1000_pchlan)
+ hw->phy.ops.read_reg(hw, BM_WUC, ®);
+
+ /* Configure the LCD with the extended configuration region in NVM */
+ ret_val = e1000_sw_lcd_config_ich8lan(hw);
+ if (ret_val)
+ goto out;
+
+ /* Configure the LCD with the OEM bits in NVM */
+ ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
+
+ /* Ungate automatic PHY configuration on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+ msec_delay(10);
+ e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Resets the PHY
+ * This is a function pointer entry point called by drivers
+ * or other shared routines.
+ **/
+STATIC INT32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
+
+ /* Gate automatic PHY configuration by hardware on non-managed 82579 */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+
+ ret_val = e1000_phy_hw_reset_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_post_phy_reset_ich8lan(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_lplu_state_pchlan - Set Low Power Link Up state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU state according to the active flag. For PCH, if OEM write
+ * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
+ * the phy speed. This function will manually set the LPLU bit and restart
+ * auto-neg as hw would do. D3 and D0 LPLU will call the same function
+ * since it configures the same bit.
+ **/
+STATIC INT32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, BOOLEAN active)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 oem_reg;
+
+ DEBUGFUNC("e1000_set_lplu_state_pchlan");
+
+ ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
+ if (ret_val)
+ goto out;
+
+ if (active)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ else
+ oem_reg &= ~HV_OEM_BITS_LPLU;
+
+ oem_reg |= HV_OEM_BITS_RESTART_AN;
+ ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 phy_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
+
+ if (phy->type == e1000_phy_ife)
+ goto out;
+
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+ if (active) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers
+ */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D3 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+STATIC INT32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 phy_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
+
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+ if (!active) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (phy->type != e1000_phy_igp_3)
+ goto out;
+
+ /*
+ * Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers
+ */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
+ * @hw: pointer to the HW structure
+ * @bank: pointer to the variable that returns the active bank
+ *
+ * Reads signature byte from the NVM using the flash access registers.
+ * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
+ **/
+STATIC INT32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, UINT32 *bank)
+{
+ UINT32 eecd;
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 bank1_offset = nvm->flash_bank_size * sizeof(UINT16);
+ UINT32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+ UINT8 sig_byte = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
+
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
+ E1000_EECD_SEC1VAL_VALID_MASK) {
+ if (eecd & E1000_EECD_SEC1VAL)
+ *bank = 1;
+ else
+ *bank = 0;
+
+ goto out;
+ }
+ DEBUGOUT("Unable to determine valid NVM bank via EEC - "
+ "reading flash signature\n");
+ /* fall-thru */
+ default:
+ /* set bank to 0 in case flash read fails */
+ *bank = 0;
+
+ /* Check bank 0 */
+ ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
+ &sig_byte);
+ if (ret_val)
+ goto out;
+ if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+ E1000_ICH_NVM_SIG_VALUE) {
+ *bank = 0;
+ goto out;
+ }
+
+ /* Check bank 1 */
+ ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
+ bank1_offset,
+ &sig_byte);
+ if (ret_val)
+ goto out;
+ if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+ E1000_ICH_NVM_SIG_VALUE) {
+ *bank = 1;
+ goto out;
+ }
+
+ DEBUGOUT("ERROR: No valid NVM bank present\n");
+ ret_val = -E1000_ERR_NVM;
+ break;
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_nvm_ich8lan - Read word(s) from the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to read.
+ * @words: Size of data to read in words
+ * @data: Pointer to the word(s) to read at offset.
+ *
+ * Reads a word(s) from the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 act_offset;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 bank = 0;
+ UINT16 i, word;
+
+ DEBUGFUNC("e1000_read_nvm_ich8lan");
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ nvm->ops.acquire(hw);
+
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+ bank = 0;
+ }
+
+ act_offset = (bank) ? nvm->flash_bank_size : 0;
+ act_offset += offset;
+
+ ret_val = E1000_SUCCESS;
+ for (i = 0; i < words; i++) {
+ if ((dev_spec->shadow_ram) &&
+ (dev_spec->shadow_ram[offset+i].modified)) {
+ data[i] = dev_spec->shadow_ram[offset+i].value;
+ } else {
+ ret_val = e1000_read_flash_word_ich8lan(hw,
+ act_offset + i,
+ &word);
+ if (ret_val)
+ break;
+ data[i] = word;
+ }
+ }
+
+ nvm->ops.release(hw);
+
+out:
+ if (ret_val)
+ DEBUGOUT1("NVM read error: %d\n", ret_val);
+
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_init_ich8lan - Initialize flash
+ * @hw: pointer to the HW structure
+ *
+ * This function does initial flash setup so that a new read/write/erase cycle
+ * can be started.
+ **/
+static INT32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
+{
+ union ich8_hws_flash_status hsfsts;
+ INT32 ret_val = -E1000_ERR_NVM;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
+
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+
+ /* Check if the flash descriptor is valid */
+ if (hsfsts.hsf_status.fldesvalid == 0) {
+ DEBUGOUT("Flash descriptor invalid. "
+ "SW Sequencing must be used.");
+ goto out;
+ }
+
+ /* Clear FCERR and DAEL in hw status by writing 1 */
+ hsfsts.hsf_status.flcerr = 1;
+ hsfsts.hsf_status.dael = 1;
+
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+
+ /*
+ * Either we should have a hardware SPI cycle in progress
+ * bit to check against, in order to start a new cycle or
+ * FDONE bit should be changed in the hardware so that it
+ * is 1 after hardware reset, which can then be used as an
+ * indication whether a cycle is in progress or has been
+ * completed.
+ */
+
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ /*
+ * There is no cycle running at present,
+ * so we can start a cycle.
+ * Begin by setting Flash Cycle Done.
+ */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+ ret_val = E1000_SUCCESS;
+ } else {
+ /*
+ * Otherwise poll for sometime so the current
+ * cycle has a chance to end before giving up.
+ */
+ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+ usec_delay(1);
+ }
+ if (ret_val == E1000_SUCCESS) {
+ /*
+ * Successful in waiting for previous cycle to timeout,
+ * now set the Flash Cycle Done.
+ */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
+ hsfsts.regval);
+ } else {
+ DEBUGOUT("Flash controller busy, cannot get access");
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
+ * @hw: pointer to the HW structure
+ * @timeout: maximum time to wait for completion
+ *
+ * This function starts a flash cycle and waits for its completion.
+ **/
+static INT32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, UINT32 timeout)
+{
+ union ich8_hws_flash_ctrl hsflctl;
+ union ich8_hws_flash_status hsfsts;
+ INT32 ret_val = -E1000_ERR_NVM;
+ UINT32 i = 0;
+
+ DEBUGFUNC("e1000_flash_cycle_ich8lan");
+
+ /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcgo = 1;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ /* wait till FDONE bit is set to 1 */
+ do {
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcdone == 1)
+ break;
+ usec_delay(1);
+ } while (i++ < timeout);
+
+ if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
+ ret_val = E1000_SUCCESS;
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_word_ich8lan - Read word from flash
+ * @hw: pointer to the HW structure
+ * @offset: offset to data location
+ * @data: pointer to the location for storing the data
+ *
+ * Reads the flash word at offset into data. Offset is converted
+ * to bytes before read.
+ **/
+STATIC INT32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_read_flash_word_ich8lan");
+
+ if (!data) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Must convert offset into bytes. */
+ offset <<= 1;
+
+ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_byte_ich8lan - Read byte from flash
+ * @hw: pointer to the HW structure
+ * @offset: The offset of the byte to read.
+ * @data: Pointer to a byte to store the value read.
+ *
+ * Reads a single byte from the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 *data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 word = 0;
+
+ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
+ if (ret_val)
+ goto out;
+
+ *data = (UINT8)word;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_data_ich8lan - Read byte or word from NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte or word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: Pointer to the word to store the value read.
+ *
+ * Reads a byte or word from the NVM using the flash access registers.
+ **/
+static INT32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 *data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ UINT32 flash_linear_addr;
+ UINT32 flash_data = 0;
+ INT32 ret_val = -E1000_ERR_NVM;
+ UINT8 count = 0;
+
+ DEBUGFUNC("e1000_read_flash_data_ich8lan");
+
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ goto out;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ usec_delay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+ /*
+ * Check if FCERR is set to 1, if set to 1, clear it
+ * and try the whole sequence a few more times, else
+ * read in (shift in) the Flash Data0, the order is
+ * least significant byte first msb to lsb
+ */
+ if (ret_val == E1000_SUCCESS) {
+ flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
+ if (size == 1)
+ *data = (UINT8)(flash_data & 0x000000FF);
+ else if (size == 2)
+ *data = (UINT16)(flash_data & 0x0000FFFF);
+ break;
+ } else {
+ /*
+ * If we've gotten here, then things are probably
+ * completely hosed, but if the error condition is
+ * detected, it won't hurt to give it another try...
+ * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_ich8lan - Write word(s) to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to write.
+ * @words: Size of data to write in words
+ * @data: Pointer to the word(s) to write at offset.
+ *
+ * Writes a byte or word to the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_write_nvm_ich8lan");
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ nvm->ops.acquire(hw);
+
+ for (i = 0; i < words; i++) {
+ dev_spec->shadow_ram[offset+i].modified = TRUE;
+ dev_spec->shadow_ram[offset+i].value = data[i];
+ }
+
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
+ * @hw: pointer to the HW structure
+ *
+ * The NVM checksum is updated by calling the generic update_nvm_checksum,
+ * which writes the checksum to the shadow ram. The changes in the shadow
+ * ram are then committed to the EEPROM by processing each bank at a time
+ * checking for the modified bit and writing only the pending changes.
+ * After a successful commit, the shadow ram is cleared and is ready for
+ * future writes.
+ **/
+STATIC INT32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 i, act_offset, new_bank_offset, old_bank_offset, bank;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
+
+ ret_val = e1000_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ goto out;
+
+ if (nvm->type != e1000_nvm_flash_sw)
+ goto out;
+
+ nvm->ops.acquire(hw);
+
+ /*
+ * We're writing to the opposite bank so if we're on bank 1,
+ * write to bank 0 etc. We also need to erase the segment that
+ * is going to be written
+ */
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+ bank = 0;
+ }
+
+ if (bank == 0) {
+ new_bank_offset = nvm->flash_bank_size;
+ old_bank_offset = 0;
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
+ if (ret_val)
+ goto release;
+ } else {
+ old_bank_offset = nvm->flash_bank_size;
+ new_bank_offset = 0;
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
+ if (ret_val)
+ goto release;
+ }
+
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ /*
+ * Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM
+ */
+ if (dev_spec->shadow_ram[i].modified) {
+ data = dev_spec->shadow_ram[i].value;
+ } else {
+ ret_val = e1000_read_flash_word_ich8lan(hw, i +
+ old_bank_offset,
+ &data);
+ if (ret_val)
+ break;
+ }
+
+ /*
+ * If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+ * signature is valid. We want to do this after the write
+ * has completed so that we don't mark the segment valid
+ * while the write is still in progress
+ */
+ if (i == E1000_ICH_NVM_SIG_WORD)
+ data |= E1000_ICH_NVM_SIG_MASK;
+
+ /* Convert offset to bytes. */
+ act_offset = (i + new_bank_offset) << 1;
+
+ usec_delay(100);
+ /* Write the bytes to the new bank. */
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset,
+ (UINT8)data);
+ if (ret_val)
+ break;
+
+ usec_delay(100);
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset + 1,
+ (UINT8)(data >> 8));
+ if (ret_val)
+ break;
+ }
+
+ /*
+ * Don't bother writing the segment valid bits if sector
+ * programming failed.
+ */
+ if (ret_val) {
+ DEBUGOUT("Flash commit failed.\n");
+ goto release;
+ }
+
+ /*
+ * Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b
+ */
+ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+ ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+ if (ret_val)
+ goto release;
+
+ data &= 0xBFFF;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset * 2 + 1,
+ (UINT8)(data >> 8));
+ if (ret_val)
+ goto release;
+
+ /*
+ * And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase
+ */
+ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
+ if (ret_val)
+ goto release;
+
+ /* Great! Everything worked, we can now clear the cached entries. */
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ dev_spec->shadow_ram[i].modified = FALSE;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+release:
+ nvm->ops.release(hw);
+
+ /*
+ * Reload the EEPROM, or else modifications will not appear
+ * until after the next adapter reset.
+ */
+ if (!ret_val) {
+ nvm->ops.reload(hw);
+ msec_delay(10);
+ }
+
+out:
+ if (ret_val)
+ DEBUGOUT1("NVM update error: %d\n", ret_val);
+
+ return ret_val;
+}
+
+/**
+ * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
+ * If the bit is 0, that the EEPROM had been modified, but the checksum was not
+ * calculated, in which case we need to calculate the checksum and set bit 6.
+ **/
+STATIC INT32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
+
+ /*
+ * Read 0x19 and check bit 6. If this bit is 0, the checksum
+ * needs to be fixed. This bit is an indication that the NVM
+ * was prepared by OEM software and did not calculate the
+ * checksum...a likely scenario.
+ */
+ ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data);
+ if (ret_val)
+ goto out;
+
+ if ((data & 0x40) == 0) {
+ data |= 0x40;
+ ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data);
+ if (ret_val)
+ goto out;
+ ret_val = hw->nvm.ops.update(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_validate_nvm_checksum_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_flash_data_ich8lan - Writes bytes to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte/word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: The byte(s) to write to the NVM.
+ *
+ * Writes one/two bytes to the NVM using the flash access registers.
+ **/
+static INT32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 size, UINT16 data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ UINT32 flash_linear_addr;
+ UINT32 flash_data = 0;
+ INT32 ret_val = -E1000_ERR_NVM;
+ UINT8 count = 0;
+
+ DEBUGFUNC("e1000_write_ich8_data");
+
+ if (size < 1 || size > 2 || data > size * 0xff ||
+ offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ goto out;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ usec_delay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+ if (size == 1)
+ flash_data = (UINT32)data & 0x00FF;
+ else
+ flash_data = (UINT32)data;
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
+
+ /*
+ * check if FCERR is set to 1 , if set to 1, clear it
+ * and try the whole sequence a few more times else done
+ */
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+ if (ret_val == E1000_SUCCESS)
+ break;
+
+ /*
+ * If we're here, then things are most likely
+ * completely hosed, but if the error condition
+ * is detected, it won't hurt to give it another
+ * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* Repeat for some time before giving up. */
+ continue;
+ if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_flash_byte_ich8lan - Write a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The index of the byte to read.
+ * @data: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ **/
+STATIC INT32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, UINT32 offset,
+ UINT8 data)
+{
+ UINT16 word = (UINT16)data;
+
+ DEBUGFUNC("e1000_write_flash_byte_ich8lan");
+
+ return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
+}
+
+/**
+ * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset of the byte to write.
+ * @byte: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ * Goes through a retry algorithm before giving up.
+ **/
+static INT32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ UINT32 offset, UINT8 byte)
+{
+ INT32 ret_val;
+ UINT16 program_retries;
+
+ DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
+
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (ret_val == E1000_SUCCESS)
+ goto out;
+
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
+ usec_delay(100);
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (ret_val == E1000_SUCCESS)
+ break;
+ }
+ if (program_retries == 100) {
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
+ * @hw: pointer to the HW structure
+ * @bank: 0 for first bank, 1 for second bank, etc.
+ *
+ * Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
+ * bank N is 4096 * N + flash_reg_addr.
+ **/
+STATIC INT32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, UINT32 bank)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ UINT32 flash_linear_addr;
+ /* bank size is in 16bit words - adjust to bytes */
+ UINT32 flash_bank_size = nvm->flash_bank_size * 2;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 count = 0;
+ INT32 j, iteration, sector_size;
+
+ DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
+
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+
+ /*
+ * Determine HW Sector size: Read BERASE bits of hw flash status
+ * register
+ * 00: The Hw sector is 256 bytes, hence we need to erase 16
+ * consecutive sectors. The start index for the nth Hw sector
+ * can be calculated as = bank * 4096 + n * 256
+ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+ * The start index for the nth Hw sector can be calculated
+ * as = bank * 4096
+ * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
+ * (ich9 only, otherwise error condition)
+ * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
+ */
+ switch (hsfsts.hsf_status.berasesz) {
+ case 0:
+ /* Hw sector size 256 */
+ sector_size = ICH_FLASH_SEG_SIZE_256;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
+ break;
+ case 1:
+ sector_size = ICH_FLASH_SEG_SIZE_4K;
+ iteration = 1;
+ break;
+ case 2:
+ sector_size = ICH_FLASH_SEG_SIZE_8K;
+ iteration = 1;
+ break;
+ case 3:
+ sector_size = ICH_FLASH_SEG_SIZE_64K;
+ iteration = 1;
+ break;
+ default:
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Start with the base address, then add the sector offset. */
+ flash_linear_addr = hw->nvm.flash_base_addr;
+ flash_linear_addr += (bank) ? flash_bank_size : 0;
+
+ for (j = 0; j < iteration ; j++) {
+ do {
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Write a value 11 (block Erase) in Flash
+ * Cycle field in hw flash control
+ */
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
+ hsflctl.regval);
+
+ /*
+ * Write the last 24 bits of an index within the
+ * block into Flash Linear address field in Flash
+ * Address.
+ */
+ flash_linear_addr += (j * sector_size);
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
+ flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+ if (ret_val == E1000_SUCCESS)
+ break;
+
+ /*
+ * Check if FCERR is set to 1. If 1,
+ * clear it and try the whole sequence
+ * a few more times else Done
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* repeat for some time before giving up */
+ continue;
+ else if (hsfsts.hsf_status.flcdone == 0)
+ goto out;
+ } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_valid_led_default_ich8lan - Set the default LED settings
+ * @hw: pointer to the HW structure
+ * @data: Pointer to the LED settings
+ *
+ * Reads the LED default settings from the NVM to data. If the NVM LED
+ * settings is all 0's or F's, set the LED default to a valid LED default
+ * setting.
+ **/
+STATIC INT32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_ich8lan");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT_ICH8LAN;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_id_led_init_pchlan - store LED configurations
+ * @hw: pointer to the HW structure
+ *
+ * PCH does not control LEDs via the LEDCTL register, rather it uses
+ * the PHY LED configuration register.
+ *
+ * PCH also does not have an "always on" or "always off" mode which
+ * complicates the ID feature. Instead of using the "on" mode to indicate
+ * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
+ * use "link_up" mode. The LEDs will still ID on request if there is no
+ * link based on logic in e1000_led_[on|off]_pchlan().
+ **/
+STATIC INT32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ const UINT32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
+ const UINT32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
+ UINT16 data, i, temp, shift;
+
+ DEBUGFUNC("e1000_id_led_init_pchlan");
+
+ /* Get default ID LED modes */
+ ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+ if (ret_val)
+ goto out;
+
+ mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+ mac->ledctl_mode1 = mac->ledctl_default;
+ mac->ledctl_mode2 = mac->ledctl_default;
+
+ for (i = 0; i < 4; i++) {
+ temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
+ shift = (i * 5);
+ switch (temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+ mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode1 |= (ledctl_on << shift);
+ break;
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode1 |= (ledctl_off << shift);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch (temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+ mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode2 |= (ledctl_on << shift);
+ break;
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+ mac->ledctl_mode2 |= (ledctl_off << shift);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_bus_info_ich8lan - Get/Set the bus type and width
+ * @hw: pointer to the HW structure
+ *
+ * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
+ * register, so the the bus width is hard coded.
+ **/
+STATIC INT32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_bus_info_ich8lan");
+
+ ret_val = e1000_get_bus_info_pcie_generic(hw);
+
+ /*
+ * ICH devices are "PCI Express"-ish. They have
+ * a configuration space, but do not contain
+ * PCI Express Capability registers, so bus width
+ * must be hardcoded.
+ */
+ if (bus->width == e1000_bus_width_unknown)
+ bus->width = e1000_bus_width_pcie_x1;
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_ich8lan - Reset the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Does a full reset of the hardware which includes a reset of the PHY and
+ * MAC.
+ **/
+STATIC INT32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT16 reg;
+ UINT32 ctrl, kab;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_reset_hw_ich8lan");
+
+ /*
+ * Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000_disable_pcie_master_generic(hw);
+ if (ret_val)
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+ /*
+ * Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC
+ * with the global reset.
+ */
+ E1000_WRITE_REG(hw, E1000_RCTL, 0);
+ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ msec_delay(10);
+
+ /* Workaround for ICH8 bit corruption issue in FIFO memory */
+ if (hw->mac.type == e1000_ich8lan) {
+ /* Set Tx and Rx buffer allocation to 8k apiece. */
+ E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
+ /* Set Packet Buffer Size to 16k. */
+ E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
+ }
+
+ if (hw->mac.type == e1000_pchlan) {
+ /* Save the NVM K1 bit setting*/
+ ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®);
+ if (ret_val)
+ return ret_val;
+
+ if (reg & E1000_NVM_K1_ENABLE)
+ dev_spec->nvm_k1_enabled = TRUE;
+ else
+ dev_spec->nvm_k1_enabled = FALSE;
+ }
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ if (!hw->phy.ops.check_reset_block(hw)) {
+ /*
+ * Full-chip reset requires MAC and PHY reset at the same
+ * time to make sure the interface between MAC and the
+ * external PHY is reset.
+ */
+ ctrl |= E1000_CTRL_PHY_RST;
+
+ /*
+ * Gate automatic PHY configuration by hardware on
+ * non-managed 82579
+ */
+ if ((hw->mac.type == e1000_pch2lan) &&
+ !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
+ e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
+ }
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ DEBUGOUT("Issuing a global reset to ich8lan\n");
+ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
+ msec_delay(20);
+
+ if (!ret_val)
+ e1000_release_swflag_ich8lan(hw);
+
+ if (ctrl & E1000_CTRL_PHY_RST) {
+ ret_val = hw->phy.ops.get_cfg_done(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_post_phy_reset_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * For PCH, this write will make sure that any noise
+ * will be detected as a CRC error and be dropped rather than show up
+ * as a bad packet to the DMA engine.
+ */
+ if (hw->mac.type == e1000_pchlan)
+ E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
+
+ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+ E1000_READ_REG(hw, E1000_ICR);
+
+ kab = E1000_READ_REG(hw, E1000_KABGTXD);
+ kab |= E1000_KABGTXD_BGSQLBIAS;
+ E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_ich8lan - Initialize the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Prepares the hardware for transmit and receive by doing the following:
+ * - initialize hardware bits
+ * - initialize LED identification
+ * - setup receive address registers
+ * - setup flow control
+ * - setup transmit descriptors
+ * - clear statistics
+ **/
+STATIC INT32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 ctrl_ext, txdctl, snoop;
+ INT32 ret_val;
+ UINT16 i;
+
+ DEBUGFUNC("e1000_init_hw_ich8lan");
+
+ e1000_initialize_hw_bits_ich8lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = mac->ops.id_led_init(hw);
+ if (ret_val)
+ DEBUGOUT("Error initializing identification LED\n");
+ /* This is not fatal and we should not stop init due to this */
+
+ /* Setup the receive address. */
+ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /*
+ * The 82578 Rx buffer will stall if wakeup is enabled in host and
+ * the ME. Reading the BM_WUC register will clear the host wakeup bit.
+ * Reset the phy after disabling host wakeup to reset the Rx buffer.
+ */
+ if (hw->phy.type == e1000_phy_82578) {
+ hw->phy.ops.read_reg(hw, BM_WUC, &i);
+ ret_val = e1000_phy_hw_reset_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Setup link and flow control */
+ ret_val = mac->ops.setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy for both queues */
+ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
+ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
+
+ /*
+ * ICH8 has opposite polarity of no_snoop bits.
+ * By default, we should use snoop behavior.
+ */
+ if (mac->type == e1000_ich8lan)
+ snoop = PCIE_ICH8_SNOOP_ALL;
+ else
+ snoop = (UINT32) ~(PCIE_NO_SNOOP_ALL);
+ e1000_set_pcie_no_snoop_generic(hw, snoop);
+
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+ /*
+ * Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_ich8lan(hw);
+
+ return ret_val;
+}
+/**
+ * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
+ * @hw: pointer to the HW structure
+ *
+ * Sets/Clears required hardware bits necessary for correctly setting up the
+ * hardware for transmit and receive.
+ **/
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 reg;
+
+ DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
+
+ /* Extended Device Control */
+ reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ reg |= (1 << 22);
+ /* Enable PHY low-power state when MAC is at D3 w/o WoL */
+ if (hw->mac.type >= e1000_pchlan)
+ reg |= E1000_CTRL_EXT_PHYPDEN;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+ /* Transmit Descriptor Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+ reg |= (1 << 22);
+ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = E1000_READ_REG(hw, E1000_TARC(0));
+ if (hw->mac.type == e1000_ich8lan)
+ reg |= (1 << 28) | (1 << 29);
+ reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
+ E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = E1000_READ_REG(hw, E1000_TARC(1));
+ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ reg |= (1 << 24) | (1 << 26) | (1 << 30);
+ E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+
+ /* Device Status */
+ if (hw->mac.type == e1000_ich8lan) {
+ reg = E1000_READ_REG(hw, E1000_STATUS);
+ reg &= ~(1 << 31);
+ E1000_WRITE_REG(hw, E1000_STATUS, reg);
+ }
+
+ /*
+ * work-around descriptor data corruption issue during nfs v2 udp
+ * traffic, just disable the nfs filtering capability
+ */
+ reg = E1000_READ_REG(hw, E1000_RFCTL);
+ reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
+ E1000_WRITE_REG(hw, E1000_RFCTL, reg);
+
+ return;
+}
+
+/**
+ * e1000_setup_link_ich8lan - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+STATIC INT32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_link_ich8lan");
+
+ if (hw->phy.ops.check_reset_block(hw))
+ goto out;
+
+ /*
+ * ICH parts do not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ if (hw->fc.requested_mode == e1000_fc_default)
+ hw->fc.requested_mode = e1000_fc_full;
+
+ /*
+ * Save off the requested flow control mode for use later. Depending
+ * on the link partner's capabilities, we may or may not use this mode.
+ */
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
+ hw->fc.current_mode);
+
+ /* Continue to configure the copper link. */
+ ret_val = hw->mac.ops.setup_physical_interface(hw);
+ if (ret_val)
+ goto out;
+
+ E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+ if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
+ (hw->phy.type == e1000_phy_82577)) {
+ E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
+
+ ret_val = hw->phy.ops.write_reg(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 27),
+ hw->fc.pause_time);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
+ * @hw: pointer to the HW structure
+ *
+ * Configures the kumeran interface to the PHY to wait the appropriate time
+ * when polling the PHY, then call the generic setup_copper_link to finish
+ * configuring the copper link.
+ **/
+STATIC INT32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val;
+ UINT16 reg_data;
+
+ DEBUGFUNC("e1000_setup_copper_link_ich8lan");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /*
+ * Set the mac to wait the maximum time between each iteration
+ * and increase the max iterations when polling the phy;
+ * this fixes erroneous timeouts at 10Mbps.
+ */
+ ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
+ 0xFFFF);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_read_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_INBAND_PARAM,
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_INBAND_PARAM,
+ reg_data);
+ if (ret_val)
+ goto out;
+
+ switch (hw->phy.type) {
+ case e1000_phy_igp_3:
+ ret_val = e1000_copper_link_setup_igp(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_phy_bm:
+ case e1000_phy_82578:
+ ret_val = e1000_copper_link_setup_m88(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_phy_82577:
+ case e1000_phy_82579:
+ ret_val = e1000_copper_link_setup_82577(hw);
+ if (ret_val)
+ goto out;
+ break;
+ case e1000_phy_ife:
+ ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
+ ®_data);
+ if (ret_val)
+ goto out;
+
+ reg_data &= ~IFE_PMC_AUTO_MDIX;
+
+ switch (hw->phy.mdix) {
+ case 1:
+ reg_data &= ~IFE_PMC_FORCE_MDIX;
+ break;
+ case 2:
+ reg_data |= IFE_PMC_FORCE_MDIX;
+ break;
+ case 0:
+ default:
+ reg_data |= IFE_PMC_AUTO_MDIX;
+ break;
+ }
+ ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
+ reg_data);
+ if (ret_val)
+ goto out;
+ break;
+ default:
+ break;
+ }
+ ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_link_up_info_ich8lan - Get current link speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to store current link speed
+ * @duplex: pointer to store the current link duplex
+ *
+ * Calls the generic get_speed_and_duplex to retrieve the current link
+ * information and then calls the Kumeran lock loss workaround for links at
+ * gigabit speeds.
+ **/
+STATIC INT32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_get_link_up_info_ich8lan");
+
+ ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
+ if (ret_val)
+ goto out;
+
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3) &&
+ (*speed == SPEED_1000)) {
+ ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
+ * @hw: pointer to the HW structure
+ *
+ * Work-around for 82566 Kumeran PCS lock loss:
+ * On link status change (i.e. PCI reset, speed change) and link is up and
+ * speed is gigabit-
+ * 0) if workaround is optionally disabled do nothing
+ * 1) wait 1ms for Kumeran link to come up
+ * 2) check Kumeran Diagnostic register PCS lock loss bit
+ * 3) if not set the link is locked (all is good), otherwise...
+ * 4) reset the PHY
+ * 5) repeat up to 10 times
+ * Note: this is only called for IGP3 copper when speed is 1gb.
+ **/
+static INT32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ UINT32 phy_ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i, data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
+
+ if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
+ goto out;
+
+ /*
+ * Make sure link is up before proceeding. If not just return.
+ * Attempting this while link is negotiating fouled up link
+ * stability
+ */
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (!link) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ for (i = 0; i < 10; i++) {
+ /* read once to clear */
+ ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ goto out;
+ /* and again to get new status */
+ ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ goto out;
+
+ /* check for PCS lock */
+ if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ /* Issue PHY reset */
+ hw->phy.ops.reset(hw);
+ msec_delay_irq(5);
+ }
+ /* Disable GigE link negotiation */
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+ phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ /*
+ * Call gig speed drop workaround on Gig disable before accessing
+ * any PHY registers
+ */
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* unable to acquire PCS lock */
+ ret_val = -E1000_ERR_PHY;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
+ * @hw: pointer to the HW structure
+ * @state: BOOLEANean value used to set the current Kumeran workaround state
+ *
+ * If ICH8, set the current Kumeran workaround state (enabled - TRUE
+ * /disabled - FALSE).
+ **/
+void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ BOOLEAN state)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+
+ DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
+
+ if (hw->mac.type != e1000_ich8lan) {
+ DEBUGOUT("Workaround applies to ICH8 only.\n");
+ return;
+ }
+
+ dev_spec->kmrn_lock_loss_workaround_enabled = state;
+
+ return;
+}
+
+/**
+ * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
+ * @hw: pointer to the HW structure
+ *
+ * Workaround for 82566 power-down on D3 entry:
+ * 1) disable gigabit link
+ * 2) write VR power-down enable
+ * 3) read it back
+ * Continue if successful, else issue LCD reset and repeat
+ **/
+void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 reg;
+ UINT16 data;
+ UINT8 retry = 0;
+
+ DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
+
+ if (hw->phy.type != e1000_phy_igp_3)
+ goto out;
+
+ /* Try the workaround twice (if needed) */
+ do {
+ /* Disable link */
+ reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
+ reg |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
+
+ /*
+ * Call gig speed drop workaround on Gig disable before
+ * accessing any PHY registers
+ */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000_gig_downshift_workaround_ich8lan(hw);
+
+ /* Write VR power-down enable */
+ hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
+ data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
+ data | IGP3_VR_CTRL_MODE_SHUTDOWN);
+
+ /* Read it back and test */
+ hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
+ data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
+ break;
+
+ /* Issue PHY reset and repeat at most one more time */
+ reg = E1000_READ_REG(hw, E1000_CTRL);
+ E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
+ retry++;
+ } while (retry);
+
+out:
+ return;
+}
+
+/**
+ * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ * @hw: pointer to the HW structure
+ *
+ * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ * LPLU, Gig disable, MDIC PHY reset):
+ * 1) Set Kumeran Near-end loopback
+ * 2) Clear Kumeran Near-end loopback
+ * Should only be called for ICH8[m] devices with IGP_3 Phy.
+ **/
+void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 reg_data;
+
+ DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
+
+ if ((hw->mac.type != e1000_ich8lan) ||
+ (hw->phy.type != e1000_phy_igp_3))
+ goto out;
+
+ ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ ®_data);
+ if (ret_val)
+ goto out;
+ reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+ if (ret_val)
+ goto out;
+ reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000_write_kmrn_reg_generic(hw,
+ E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+out:
+ return;
+}
+
+/**
+ * e1000_disable_gig_wol_ich8lan - disable gig during WoL
+ * @hw: pointer to the HW structure
+ *
+ * During S0 to Sx transition, it is possible the link remains at gig
+ * instead of negotiating to a lower speed. Before going to Sx, set
+ * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
+ * to a lower speed.
+ *
+ * Should only be called for applicable parts.
+ **/
+void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+ UINT32 phy_ctrl;
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_disable_gig_wol_ich8lan");
+
+ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
+ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+ if (hw->mac.type >= e1000_pchlan) {
+ e1000_oem_bits_config_ich8lan(hw, TRUE);
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return;
+ e1000_write_smbus_addr(hw);
+ hw->phy.ops.release(hw);
+ }
+
+ return;
+}
+
+/**
+ * e1000_cleanup_led_ich8lan - Restore the default LED operation
+ * @hw: pointer to the HW structure
+ *
+ * Return the LED back to the default configuration.
+ **/
+STATIC INT32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led_ich8lan");
+
+ if (hw->phy.type == e1000_phy_ife)
+ return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ 0);
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_on_ich8lan - Turn LEDs on
+ * @hw: pointer to the HW structure
+ *
+ * Turn on the LEDs.
+ **/
+STATIC INT32 e1000_led_on_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_led_on_ich8lan");
+
+ if (hw->phy.type == e1000_phy_ife)
+ return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_off_ich8lan - Turn LEDs off
+ * @hw: pointer to the HW structure
+ *
+ * Turn off the LEDs.
+ **/
+STATIC INT32 e1000_led_off_ich8lan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_led_off_ich8lan");
+
+ if (hw->phy.type == e1000_phy_ife)
+ return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_setup_led_pchlan - Configures SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This prepares the SW controllable LED for use.
+ **/
+STATIC INT32 e1000_setup_led_pchlan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_setup_led_pchlan");
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+ (UINT16)hw->mac.ledctl_mode1);
+}
+
+/**
+ * e1000_cleanup_led_pchlan - Restore the default LED operation
+ * @hw: pointer to the HW structure
+ *
+ * Return the LED back to the default configuration.
+ **/
+STATIC INT32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led_pchlan");
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+ (UINT16)hw->mac.ledctl_default);
+}
+
+/**
+ * e1000_led_on_pchlan - Turn LEDs on
+ * @hw: pointer to the HW structure
+ *
+ * Turn on the LEDs.
+ **/
+STATIC INT32 e1000_led_on_pchlan(struct e1000_hw *hw)
+{
+ UINT16 data = (UINT16)hw->mac.ledctl_mode2;
+ UINT32 i, led;
+
+ DEBUGFUNC("e1000_led_on_pchlan");
+
+ /*
+ * If no link, then turn LED on by setting the invert bit
+ * for each LED that's mode is "link_up" in ledctl_mode2.
+ */
+ if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+ for (i = 0; i < 3; i++) {
+ led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+ if ((led & E1000_PHY_LED0_MODE_MASK) !=
+ E1000_LEDCTL_MODE_LINK_UP)
+ continue;
+ if (led & E1000_PHY_LED0_IVRT)
+ data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+ else
+ data |= (E1000_PHY_LED0_IVRT << (i * 5));
+ }
+ }
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ * e1000_led_off_pchlan - Turn LEDs off
+ * @hw: pointer to the HW structure
+ *
+ * Turn off the LEDs.
+ **/
+STATIC INT32 e1000_led_off_pchlan(struct e1000_hw *hw)
+{
+ UINT16 data = (UINT16)hw->mac.ledctl_mode1;
+ UINT32 i, led;
+
+ DEBUGFUNC("e1000_led_off_pchlan");
+
+ /*
+ * If no link, then turn LED off by clearing the invert bit
+ * for each LED that's mode is "link_up" in ledctl_mode1.
+ */
+ if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+ for (i = 0; i < 3; i++) {
+ led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+ if ((led & E1000_PHY_LED0_MODE_MASK) !=
+ E1000_LEDCTL_MODE_LINK_UP)
+ continue;
+ if (led & E1000_PHY_LED0_IVRT)
+ data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+ else
+ data |= (E1000_PHY_LED0_IVRT << (i * 5));
+ }
+ }
+
+ return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Read appropriate register for the config done bit for completion status
+ * and configure the PHY through s/w for EEPROM-less parts.
+ *
+ * NOTE: some silicon which is EEPROM-less will fail trying to read the
+ * config done bit, so only an error is logged and continues. If we were
+ * to return with error, EEPROM-less silicon would not be able to be reset
+ * or change link.
+ **/
+STATIC INT32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 bank = 0;
+ UINT32 status;
+
+ DEBUGFUNC("e1000_get_cfg_done_ich8lan");
+
+ e1000_get_cfg_done_generic(hw);
+
+ /* Wait for indication from h/w that it has completed basic config */
+ ret_val = e1000_get_auto_rd_done_generic(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ DEBUGOUT("Auto Read Done did not complete\n");
+ ret_val = E1000_SUCCESS;
+ }
+
+ /* Clear PHY Reset Asserted bit */
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_PHYRA)
+ E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
+ else
+ DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
+
+ /* If EEPROM is not marked present, init the IGP 3 PHY manually */
+ if (hw->mac.type <= e1000_ich9lan) {
+ if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+ (hw->phy.type == e1000_phy_igp_3)) {
+ e1000_phy_init_script_igp3(hw);
+ }
+ } else {
+ if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
+ /* Maybe we should do a basic PHY config */
+ DEBUGOUT("EEPROM not present\n");
+ ret_val = -E1000_ERR_CONFIG;
+ }
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+STATIC void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
+{
+ /* If the management interface is not enabled, then power down */
+ if (!(hw->mac.ops.check_mng_mode(hw) ||
+ hw->phy.ops.check_reset_block(hw)))
+ e1000_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
+ * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears hardware counters specific to the silicon family and calls
+ * clear_hw_cntrs_generic to clear all general purpose counters.
+ **/
+STATIC void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
+{
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
+
+ e1000_clear_hw_cntrs_base_generic(hw);
+
+ E1000_READ_REG(hw, E1000_ALGNERRC);
+ E1000_READ_REG(hw, E1000_RXERRC);
+ E1000_READ_REG(hw, E1000_TNCRS);
+ E1000_READ_REG(hw, E1000_CEXTERR);
+ E1000_READ_REG(hw, E1000_TSCTC);
+ E1000_READ_REG(hw, E1000_TSCTFC);
+
+ E1000_READ_REG(hw, E1000_MGTPRC);
+ E1000_READ_REG(hw, E1000_MGTPDC);
+ E1000_READ_REG(hw, E1000_MGTPTC);
+
+ E1000_READ_REG(hw, E1000_IAC);
+ E1000_READ_REG(hw, E1000_ICRXOC);
+
+ /* Clear PHY statistics registers */
+ if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
+ (hw->phy.type == e1000_phy_82577)) {
+ hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
+ hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
+ }
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h
new file mode 100755
index 0000000..e90f400
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_ich8lan.h
@@ -0,0 +1,233 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_ICH8LAN_H_
+#define _E1000_ICH8LAN_H_
+
+#define ICH_FLASH_GFPREG 0x0000
+#define ICH_FLASH_HSFSTS 0x0004
+#define ICH_FLASH_HSFCTL 0x0006
+#define ICH_FLASH_FADDR 0x0008
+#define ICH_FLASH_FDATA0 0x0010
+
+/* Requires up to 10 seconds when MNG might be accessing part. */
+#define ICH_FLASH_READ_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT 10
+
+#define ICH_CYCLE_READ 0
+#define ICH_CYCLE_WRITE 2
+#define ICH_CYCLE_ERASE 3
+
+#define FLASH_GFPREG_BASE_MASK 0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT 12
+
+#define ICH_FLASH_SEG_SIZE_256 256
+#define ICH_FLASH_SEG_SIZE_4K 4096
+#define ICH_FLASH_SEG_SIZE_8K 8192
+#define ICH_FLASH_SEG_SIZE_64K 65536
+#define ICH_FLASH_SECTOR_SIZE 4096
+
+#define ICH_FLASH_REG_MAPSIZE 0x00A0
+
+#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
+#define E1000_ICH_FWSM_DISSW 0x10000000 /* FW Disables SW Writes */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID 0x00008000
+
+#define E1000_ICH_MNG_IAMT_MODE 0x2
+
+#define E1000_FWSM_PROXY_MODE 0x00000008 /* FW is in proxy mode */
+
+/* Shared Receive Address Registers */
+#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8))
+#define E1000_SHRAH_AV 0x80000000 /* Addr Valid bit */
+#define E1000_SHRAH_MAV 0x40000000 /* Multicast Addr Valid bit */
+
+#define E1000_H2ME 0x05B50 /* Host to ME */
+#define E1000_H2ME_LSECREQ 0x00000001 /* Linksec Request */
+#define E1000_H2ME_LSECA 0x00000002 /* Linksec Active */
+#define E1000_H2ME_LSECSF 0x00000004 /* Linksec Failed */
+#define E1000_H2ME_LSECD 0x00000008 /* Linksec Disabled */
+#define E1000_H2ME_SLCAPD 0x00000010 /* Start LCAPD */
+#define E1000_H2ME_IPV4_ARP_EN 0x00000020 /* Arp Offload enable bit */
+#define E1000_H2ME_IPV6_NS_EN 0x00000040 /* NS Offload enable bit */
+
+#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_OFF1_ON2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD 0x13
+#define E1000_ICH_NVM_SIG_MASK 0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0
+#define E1000_ICH_NVM_SIG_VALUE 0x80
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
+
+#define E1000_FEXTNVM_SW_CONFIG 1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */
+
+#define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3
+
+#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES 7
+#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+ ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
+#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */
+#define IGP3_PM_CTRL PHY_REG(769, 20) /* Power Management Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200
+#define IGP3_PM_CTRL_FORCE_PWR_DOWN 0x0020
+
+/* PHY Wakeup Registers and defines */
+#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0)
+#define BM_WUC PHY_REG(BM_WUC_PAGE, 1)
+#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
+#define BM_WUS PHY_REG(BM_WUC_PAGE, 3)
+#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+#define BM_IPAV (BM_PHY_REG(BM_WUC_PAGE, 64))
+#define BM_IP4AT_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 82 + ((_i) * 2)))
+#define BM_IP4AT_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 83 + ((_i) * 2)))
+
+#define BM_SHRAL_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 44 + ((_i) * 4)))
+#define BM_SHRAL_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 45 + ((_i) * 4)))
+#define BM_SHRAH_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 46 + ((_i) * 4)))
+#define BM_SHRAH_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 47 + ((_i) * 4)))
+
+#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */
+#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */
+#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */
+#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */
+#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */
+#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */
+#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */
+
+#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */
+#define HV_MUX_DATA_CTRL PHY_REG(776, 16)
+#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400
+#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004
+#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */
+#define HV_SCC_LOWER PHY_REG(778, 17)
+#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */
+#define HV_ECOL_LOWER PHY_REG(778, 19)
+#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */
+#define HV_MCC_LOWER PHY_REG(778, 21)
+#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */
+#define HV_LATECOL_LOWER PHY_REG(778, 24)
+#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */
+#define HV_COLC_LOWER PHY_REG(778, 26)
+#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */
+#define HV_DC_LOWER PHY_REG(778, 28)
+#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */
+#define HV_TNCRS_LOWER PHY_REG(778, 30)
+
+#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */
+
+#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
+#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */
+
+/* SMBus Address Phy Register */
+#define HV_SMB_ADDR PHY_REG(768, 26)
+#define HV_SMB_ADDR_MASK 0x007F
+#define HV_SMB_ADDR_PEC_EN 0x0200
+#define HV_SMB_ADDR_VALID 0x0080
+
+/* Strapping Option Register - RO */
+#define E1000_STRAP 0x0000C
+#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000
+#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */
+#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */
+#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
+
+#define LCD_CFG_PHY_ADDR_BIT 0x0020 /* Phy address bit from LCD Config word */
+
+/* KMRN Mode Control */
+#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
+#define HV_KMRN_MDIO_SLOW 0x0400
+
+/* PHY Power Management Control */
+#define HV_PM_CTRL PHY_REG(770, 17)
+
+#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */
+
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+
+/*
+ * Additional interrupts need to be handled for ICH family:
+ * DSW = The FW changed the status of the DISSW bit in FWSM
+ * PHYINT = The LAN connected device generates an interrupt
+ * EPRST = Manageability reset event
+ */
+#define IMS_ICH_ENABLE_MASK (\
+ E1000_IMS_DSW | \
+ E1000_IMS_PHYINT | \
+ E1000_IMS_EPRST)
+
+/* Receive Address Initial CRC Calculation */
+#define E1000_PCH_RAICC(_n) (0x05F50 + ((_n) * 4))
+
+void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ BOOLEAN state);
+void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw);
+INT32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, BOOLEAN k1_enable);
+INT32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, BOOLEAN d0_config);
+INT32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
+INT32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, BOOLEAN enable);
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c
new file mode 100755
index 0000000..a29288e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.c
@@ -0,0 +1,2203 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+#include <Library/BaseMemoryLib.h>
+
+STATIC INT32 e1000_set_default_fc_generic(struct e1000_hw *hw);
+STATIC INT32 e1000_commit_fc_settings_generic(struct e1000_hw *hw);
+STATIC INT32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
+STATIC INT32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
+STATIC void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+
+/**
+ * e1000_init_mac_ops_generic - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Setups up the function pointers to no-op functions
+ **/
+void e1000_init_mac_ops_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ DEBUGFUNC("e1000_init_mac_ops_generic");
+
+ /* General Setup */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.init_params = e1000_null_ops_generic;
+ mac->ops.init_hw = e1000_null_ops_generic;
+ mac->ops.reset_hw = e1000_null_ops_generic;
+ mac->ops.setup_physical_interface = e1000_null_ops_generic;
+ mac->ops.get_bus_info = e1000_null_ops_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie;
+ mac->ops.read_mac_addr = e1000_read_mac_addr_generic;
+ mac->ops.config_collision_dist = e1000_config_collision_dist_generic;
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.clear_hw_cntrs = e1000_null_mac_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+#ifndef NO_NULL_OPS_SUPPORT
+ /* LED */
+ mac->ops.cleanup_led = e1000_null_ops_generic;
+ mac->ops.setup_led = e1000_null_ops_generic;
+ mac->ops.blink_led = e1000_null_ops_generic;
+ mac->ops.led_on = e1000_null_ops_generic;
+ mac->ops.led_off = e1000_null_ops_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ /* LINK */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.setup_link = e1000_null_ops_generic;
+ mac->ops.get_link_up_info = e1000_null_link_info;
+ mac->ops.check_for_link = e1000_null_ops_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.wait_autoneg = e1000_wait_autoneg_generic;
+ /* Management */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.check_mng_mode = e1000_null_mng_mode;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic;
+ mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic;
+ mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic;
+ /* VLAN, MC, etc. */
+#ifndef NO_NULL_OPS_SUPPORT
+ mac->ops.update_mc_addr_list = e1000_null_update_mc;
+ mac->ops.clear_vfta = e1000_null_mac_generic;
+ mac->ops.write_vfta = e1000_null_write_vfta;
+#endif /* NO_NULL_OPS_SUPPORT */
+ mac->ops.rar_set = e1000_rar_set_generic;
+ mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic;
+}
+
+#ifndef NO_NULL_OPS_SUPPORT
+/**
+ * e1000_null_ops_generic - No-op function, returns 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_ops_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_ops_generic");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_mac_generic - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_mac_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_mac_generic");
+ return;
+}
+
+/**
+ * e1000_null_link_info - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_link_info(struct e1000_hw *hw, UINT16 *s, UINT16 *d)
+{
+ DEBUGFUNC("e1000_null_link_info");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_mng_mode - No-op function, return FALSE
+ * @hw: pointer to the HW structure
+ **/
+BOOLEAN e1000_null_mng_mode(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_mng_mode");
+ return FALSE;
+}
+
+/**
+ * e1000_null_update_mc - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_update_mc(struct e1000_hw *hw, UINT8 *h, UINT32 a)
+{
+ DEBUGFUNC("e1000_null_update_mc");
+ return;
+}
+
+/**
+ * e1000_null_write_vfta - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_write_vfta(struct e1000_hw *hw, UINT32 a, UINT32 b)
+{
+ DEBUGFUNC("e1000_null_write_vfta");
+ return;
+}
+
+/**
+ * e1000_null_rar_set - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_rar_set(struct e1000_hw *hw, UINT8 *h, UINT32 a)
+{
+ DEBUGFUNC("e1000_null_rar_set");
+ return;
+}
+
+#endif /* NO_NULL_OPS_SUPPORT */
+#ifndef NO_PCI_SUPPORT
+/**
+ * e1000_get_bus_info_pci_generic - Get PCI(x) bus information
+ * @hw: pointer to the HW structure
+ *
+ * Determines and stores the system bus information for a particular
+ * network interface. The following bus information is determined and stored:
+ * bus speed, bus width, type (PCI/PCIx), and PCI(-x) function.
+ **/
+INT32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_bus_info *bus = &hw->bus;
+ UINT32 status = E1000_READ_REG(hw, E1000_STATUS);
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_get_bus_info_pci_generic");
+
+ /* PCI or PCI-X? */
+ bus->type = (status & E1000_STATUS_PCIX_MODE)
+ ? e1000_bus_type_pcix
+ : e1000_bus_type_pci;
+
+ /* Bus speed */
+ if (bus->type == e1000_bus_type_pci) {
+ bus->speed = (status & E1000_STATUS_PCI66)
+ ? e1000_bus_speed_66
+ : e1000_bus_speed_33;
+ } else {
+ switch (status & E1000_STATUS_PCIX_SPEED) {
+ case E1000_STATUS_PCIX_SPEED_66:
+ bus->speed = e1000_bus_speed_66;
+ break;
+ case E1000_STATUS_PCIX_SPEED_100:
+ bus->speed = e1000_bus_speed_100;
+ break;
+ case E1000_STATUS_PCIX_SPEED_133:
+ bus->speed = e1000_bus_speed_133;
+ break;
+ default:
+ bus->speed = e1000_bus_speed_reserved;
+ break;
+ }
+ }
+
+ /* Bus width */
+ bus->width = (status & E1000_STATUS_BUS64)
+ ? e1000_bus_width_64
+ : e1000_bus_width_32;
+
+ /* Which PCI(-X) function? */
+ mac->ops.set_lan_id(hw);
+
+ return ret_val;
+}
+
+#endif /* NO_PCI_SUPPORT */
+/**
+ * e1000_get_bus_info_pcie_generic - Get PCIe bus information
+ * @hw: pointer to the HW structure
+ *
+ * Determines and stores the system bus information for a particular
+ * network interface. The following bus information is determined and stored:
+ * bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+INT32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_bus_info *bus = &hw->bus;
+ INT32 ret_val;
+ UINT16 pcie_link_status;
+
+ DEBUGFUNC("e1000_get_bus_info_pcie_generic");
+
+ bus->type = e1000_bus_type_pci_express;
+
+ ret_val = e1000_read_pcie_cap_reg(hw,
+ PCIE_LINK_STATUS,
+ &pcie_link_status);
+ if (ret_val) {
+ bus->width = e1000_bus_width_unknown;
+ bus->speed = e1000_bus_speed_unknown;
+ } else {
+ switch (pcie_link_status & PCIE_LINK_SPEED_MASK) {
+ case PCIE_LINK_SPEED_2500:
+ bus->speed = e1000_bus_speed_2500;
+ break;
+ case PCIE_LINK_SPEED_5000:
+ bus->speed = e1000_bus_speed_5000;
+ break;
+ default:
+ bus->speed = e1000_bus_speed_unknown;
+ break;
+ }
+
+ bus->width = (enum e1000_bus_width)((pcie_link_status &
+ PCIE_LINK_WIDTH_MASK) >>
+ PCIE_LINK_WIDTH_SHIFT);
+ }
+
+ mac->ops.set_lan_id(hw);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ * @hw: pointer to the HW structure
+ *
+ * Determines the LAN function id by reading memory-mapped registers
+ * and swaps the port value if requested.
+ **/
+STATIC void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ UINT32 reg;
+
+ /*
+ * The status register reports the correct function number
+ * for the device regardless of function swap state.
+ */
+ reg = E1000_READ_REG(hw, E1000_STATUS);
+ bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+#ifndef NO_PCI_SUPPORT
+/**
+ * e1000_set_lan_id_multi_port_pci - Set LAN id for PCI multiple port devices
+ * @hw: pointer to the HW structure
+ *
+ * Determines the LAN function id by reading PCI config space.
+ **/
+void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ UINT16 pci_header_type;
+ UINT32 status;
+
+ e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
+ if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ bus->func = (status & E1000_STATUS_FUNC_MASK)
+ >> E1000_STATUS_FUNC_SHIFT;
+ } else {
+ bus->func = 0;
+ }
+}
+
+#endif /* NO_PCI_SUPPORT */
+/**
+ * e1000_set_lan_id_single_port - Set LAN id for a single port device
+ * @hw: pointer to the HW structure
+ *
+ * Sets the LAN function id to zero for a single port device.
+ **/
+void e1000_set_lan_id_single_port(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+
+ bus->func = 0;
+}
+
+/**
+ * e1000_clear_vfta_generic - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * Clears the register array which contains the VLAN filter table by
+ * setting all the values to 0.
+ **/
+void e1000_clear_vfta_generic(struct e1000_hw *hw)
+{
+ UINT32 offset;
+
+ DEBUGFUNC("e1000_clear_vfta_generic");
+
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
+ E1000_WRITE_FLUSH(hw);
+ }
+}
+
+/**
+ * e1000_write_vfta_generic - Write value to VLAN filter table
+ * @hw: pointer to the HW structure
+ * @offset: register offset in VLAN filter table
+ * @value: register value written to VLAN filter table
+ *
+ * Writes value at the given offset in the register array which stores
+ * the VLAN filter table.
+ **/
+void e1000_write_vfta_generic(struct e1000_hw *hw, UINT32 offset, UINT32 value)
+{
+ DEBUGFUNC("e1000_write_vfta_generic");
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_init_rx_addrs_generic - Initialize receive address's
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setups the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ **/
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, UINT16 rar_count)
+{
+ UINT32 i;
+ UINT8 mac_addr[ETH_ADDR_LEN] = {0};
+
+ DEBUGFUNC("e1000_init_rx_addrs_generic");
+
+ /* Setup the receive address */
+ DEBUGOUT("Programming MAC Address into RAR[0]\n");
+
+ hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
+ for (i = 1; i < rar_count; i++)
+ hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
+ * e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
+ * @hw: pointer to the HW structure
+ *
+ * Checks the nvm for an alternate MAC address. An alternate MAC address
+ * can be setup by pre-boot software and must be treated like a permanent
+ * address and must override the actual permanent MAC address. If an
+ * alternate MAC address is found it is programmed into RAR0, replacing
+ * the permanent address that was installed into RAR0 by the Si on reset.
+ * This function will return SUCCESS unless it encounters an error while
+ * reading the EEPROM.
+ **/
+INT32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+ UINT32 i;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 offset, nvm_alt_mac_addr_offset, nvm_data;
+ UINT8 alt_mac_addr[ETH_ADDR_LEN];
+
+ DEBUGFUNC("e1000_check_alt_mac_addr_generic");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &nvm_data);
+ if (ret_val)
+ goto out;
+
+ if (!(nvm_data & NVM_COMPAT_LOM))
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+ &nvm_alt_mac_addr_offset);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (nvm_alt_mac_addr_offset == 0xFFFF) {
+ /* There is no Alternate MAC Address */
+ goto out;
+ }
+
+ if (hw->bus.func == E1000_FUNC_1)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+#ifndef NO_82580_SUPPORT
+ if (hw->bus.func == E1000_FUNC_2)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN2;
+
+ if (hw->bus.func == E1000_FUNC_3)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN3;
+#endif /* Barton Hills HW */
+ for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+ offset = nvm_alt_mac_addr_offset + (i >> 1);
+ ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ alt_mac_addr[i] = (UINT8)(nvm_data & 0xFF);
+ alt_mac_addr[i + 1] = (UINT8)(nvm_data >> 8);
+ }
+
+ /* if multicast bit is set, the alternate address will not be used */
+ if (alt_mac_addr[0] & 0x01) {
+ DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
+ goto out;
+ }
+
+ /*
+ * We have a valid alternate MAC address, and we want to treat it the
+ * same as the normal permanent MAC address stored by the HW into the
+ * RAR. Do this by mapping this address into RAR0.
+ */
+ hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_rar_set_generic - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr.
+ **/
+void e1000_rar_set_generic(struct e1000_hw *hw, UINT8 *addr, UINT32 index)
+{
+ UINT32 rar_low, rar_high;
+
+ DEBUGFUNC("e1000_rar_set_generic");
+
+ /*
+ * HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((UINT32) addr[0] |
+ ((UINT32) addr[1] << 8) |
+ ((UINT32) addr[2] << 16) | ((UINT32) addr[3] << 24));
+
+ rar_high = ((UINT32) addr[4] | ((UINT32) addr[5] << 8));
+
+ /* If MAC address zero, no need to set the AV bit */
+ if (rar_low || rar_high)
+ rar_high |= E1000_RAH_AV;
+
+ /*
+ * Some bridges will combine consecutive 32-bit writes into
+ * a single burst write, which will malfunction on some parts.
+ * The flushes avoid this.
+ */
+ E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+ E1000_WRITE_FLUSH(hw);
+ E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_update_mc_addr_list_generic - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ *
+ * Updates entire Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+ UINT8 *mc_addr_list, UINT32 mc_addr_count)
+{
+ UINT32 hash_value, hash_bit, hash_reg;
+ int i;
+
+ DEBUGFUNC("e1000_update_mc_addr_list_generic");
+
+ /* clear mta_shadow */
+ SetMem (&hw->mac.mta_shadow, sizeof(hw->mac.mta_shadow), 0);
+
+ /* update mta_shadow from mc_addr_list */
+ for (i = 0; (UINT32) i < mc_addr_count; i++) {
+ hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
+
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+ mc_addr_list += (ETH_ADDR_LEN);
+ }
+
+ /* replace the entire MTA table */
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_hash_mc_addr_generic - Generate a multicast hash value
+ * @hw: pointer to the HW structure
+ * @mc_addr: pointer to a multicast address
+ *
+ * Generates a multicast address hash value which is used to determine
+ * the multicast filter table array address and new table value.
+ **/
+UINT32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, UINT8 *mc_addr)
+{
+ UINT32 hash_value, hash_mask;
+ UINT8 bit_shift = 0;
+
+ DEBUGFUNC("e1000_hash_mc_addr_generic");
+
+ /* Register count multiplied by bits per register */
+ hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+ /*
+ * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+ * where 0xFF would still fall within the hash mask.
+ */
+ while (hash_mask >> bit_shift != 0xFF)
+ bit_shift++;
+
+ /*
+ * The portion of the address that is used for the hash table
+ * is determined by the mc_filter_type setting.
+ * The algorithm is such that there is a total of 8 bits of shifting.
+ * The bit_shift for a mc_filter_type of 0 represents the number of
+ * left-shifts where the MSB of mc_addr[5] would still fall within
+ * the hash_mask. Case 0 does this exactly. Since there are a total
+ * of 8 bits of shifting, then mc_addr[4] will shift right the
+ * remaining number of bits. Thus 8 - bit_shift. The rest of the
+ * cases are a variation of this algorithm...essentially raising the
+ * number of bits to shift mc_addr[5] left, while still keeping the
+ * 8-bit shifting total.
+ *
+ * For example, given the following Destination MAC Address and an
+ * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+ * we can see that the bit_shift for case 0 is 4. These are the hash
+ * values resulting from each mc_filter_type...
+ * [0] [1] [2] [3] [4] [5]
+ * 01 AA 00 12 34 56
+ * LSB MSB
+ *
+ * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+ * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+ * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+ * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+ */
+ switch (hw->mac.mc_filter_type) {
+ default:
+ case 0:
+ break;
+ case 1:
+ bit_shift += 1;
+ break;
+ case 2:
+ bit_shift += 2;
+ break;
+ case 3:
+ bit_shift += 4;
+ break;
+ }
+
+ hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+ (((UINT16) mc_addr[5]) << bit_shift)));
+
+ return hash_value;
+}
+
+#ifndef NO_PCIX_SUPPORT
+/**
+ * e1000_pcix_mmrbc_workaround_generic - Fix incorrect MMRBC value
+ * @hw: pointer to the HW structure
+ *
+ * In certain situations, a system BIOS may report that the PCIx maximum
+ * memory read byte count (MMRBC) value is higher than than the actual
+ * value. We check the PCIx command register with the current PCIx status
+ * register.
+ **/
+void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw)
+{
+ UINT16 cmd_mmrbc;
+ UINT16 pcix_cmd;
+ UINT16 pcix_stat_hi_word;
+ UINT16 stat_mmrbc;
+
+ DEBUGFUNC("e1000_pcix_mmrbc_workaround_generic");
+
+ /* Workaround for PCI-X issue when BIOS sets MMRBC incorrectly */
+ if (hw->bus.type != e1000_bus_type_pcix)
+ return;
+
+ e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
+ e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
+ cmd_mmrbc = (pcix_cmd & PCIX_COMMAND_MMRBC_MASK) >>
+ PCIX_COMMAND_MMRBC_SHIFT;
+ stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+ PCIX_STATUS_HI_MMRBC_SHIFT;
+ if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+ stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+ if (cmd_mmrbc > stat_mmrbc) {
+ pcix_cmd &= ~PCIX_COMMAND_MMRBC_MASK;
+ pcix_cmd |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+ e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
+ }
+}
+
+#endif /* NO_PCIX_SUPPORT */
+/**
+ * e1000_clear_hw_cntrs_base_generic - Clear base hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_clear_hw_cntrs_base_generic");
+
+ E1000_READ_REG(hw, E1000_CRCERRS);
+ E1000_READ_REG(hw, E1000_SYMERRS);
+ E1000_READ_REG(hw, E1000_MPC);
+ E1000_READ_REG(hw, E1000_SCC);
+ E1000_READ_REG(hw, E1000_ECOL);
+ E1000_READ_REG(hw, E1000_MCC);
+ E1000_READ_REG(hw, E1000_LATECOL);
+ E1000_READ_REG(hw, E1000_COLC);
+ E1000_READ_REG(hw, E1000_DC);
+ E1000_READ_REG(hw, E1000_SEC);
+ E1000_READ_REG(hw, E1000_RLEC);
+ E1000_READ_REG(hw, E1000_XONRXC);
+ E1000_READ_REG(hw, E1000_XONTXC);
+ E1000_READ_REG(hw, E1000_XOFFRXC);
+ E1000_READ_REG(hw, E1000_XOFFTXC);
+ E1000_READ_REG(hw, E1000_FCRUC);
+ E1000_READ_REG(hw, E1000_GPRC);
+ E1000_READ_REG(hw, E1000_BPRC);
+ E1000_READ_REG(hw, E1000_MPRC);
+ E1000_READ_REG(hw, E1000_GPTC);
+ E1000_READ_REG(hw, E1000_GORCL);
+ E1000_READ_REG(hw, E1000_GORCH);
+ E1000_READ_REG(hw, E1000_GOTCL);
+ E1000_READ_REG(hw, E1000_GOTCH);
+ E1000_READ_REG(hw, E1000_RNBC);
+ E1000_READ_REG(hw, E1000_RUC);
+ E1000_READ_REG(hw, E1000_RFC);
+ E1000_READ_REG(hw, E1000_ROC);
+ E1000_READ_REG(hw, E1000_RJC);
+ E1000_READ_REG(hw, E1000_TORL);
+ E1000_READ_REG(hw, E1000_TORH);
+ E1000_READ_REG(hw, E1000_TOTL);
+ E1000_READ_REG(hw, E1000_TOTH);
+ E1000_READ_REG(hw, E1000_TPR);
+ E1000_READ_REG(hw, E1000_TPT);
+ E1000_READ_REG(hw, E1000_MPTC);
+ E1000_READ_REG(hw, E1000_BPTC);
+}
+
+/**
+ * e1000_check_for_copper_link_generic - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed. If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ **/
+INT32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_check_for_copper_link");
+
+ /*
+ * We only want to go out to the PHY registers to see if Auto-Neg
+ * has completed and/or if our link status has changed. The
+ * get_link_status flag is set upon receiving a Link Status
+ * Change or Rx Sequence Error interrupt.
+ */
+ if (!mac->get_link_status) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ /*
+ * First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ goto out; /* No link detected */
+
+ mac->get_link_status = FALSE;
+
+ /*
+ * Check if there was DownShift, must be checked
+ * immediately after link-up
+ */
+ e1000_check_downshift_generic(hw);
+
+ /*
+ * If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if (!mac->autoneg) {
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ /*
+ * Auto-Neg is enabled. Auto Speed Detection takes care
+ * of MAC speed/duplex configuration. So we only need to
+ * configure Collision Distance in the MAC.
+ */
+ mac->ops.config_collision_dist(hw);
+
+ /*
+ * Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control
+ * settings because we may have had to re-autoneg with a
+ * different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val)
+ DEBUGOUT("Error configuring flow control\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_fiber_link_generic - Check for link (Fiber)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+INT32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 rxcw;
+ UINT32 ctrl;
+ UINT32 status;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_for_fiber_link_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+ /*
+ * If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), the cable is plugged in (we have signal),
+ * and our link partner is not trying to auto-negotiate with us (we
+ * are receiving idles or data), we need to force link up. We also
+ * need to give auto-negotiation time to complete, in case the cable
+ * was just plugged in. The autoneg_failed flag does this.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ goto out;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ goto out;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /*
+ * If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = TRUE;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_for_serdes_link_generic - Check for link (Serdes)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+INT32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 rxcw;
+ UINT32 ctrl;
+ UINT32 status;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_check_for_serdes_link_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+ /*
+ * If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), and our link partner is not trying to
+ * auto-negotiate with us (we are receiving idles or data),
+ * we need to force link up. We also need to give auto-negotiation
+ * time to complete.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ goto out;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ goto out;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /*
+ * If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = TRUE;
+ } else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
+ /*
+ * If we force link for non-auto-negotiation switch, check
+ * link status based on MAC synchronization for internal
+ * serdes media type.
+ */
+ /* SYNCH bit and IV bit are sticky. */
+ usec_delay(10);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+ if (rxcw & E1000_RXCW_SYNCH) {
+ if (!(rxcw & E1000_RXCW_IV)) {
+ mac->serdes_has_link = TRUE;
+ DEBUGOUT("SERDES: Link up - forced.\n");
+ }
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - force failed.\n");
+ }
+ }
+
+ if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_LU) {
+ /* SYNCH bit and IV bit are sticky, so reread rxcw. */
+ usec_delay(10);
+ rxcw = E1000_READ_REG(hw, E1000_RXCW);
+ if (rxcw & E1000_RXCW_SYNCH) {
+ if (!(rxcw & E1000_RXCW_IV)) {
+ mac->serdes_has_link = TRUE;
+ DEBUGOUT("SERDES: Link up - autoneg "
+ "completed sucessfully.\n");
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - invalid"
+ "codewords detected in autoneg.\n");
+ }
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - no sync.\n");
+ }
+ } else {
+ mac->serdes_has_link = FALSE;
+ DEBUGOUT("SERDES: Link down - autoneg failed\n");
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_link_generic - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+INT32 e1000_setup_link_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_link_generic");
+
+ /*
+ * In the case of the phy reset being blocked, we already have a link.
+ * We do not need to set it up again.
+ */
+ if (e1000_check_reset_block(hw))
+ goto out;
+
+ /*
+ * If requested flow control is set to default, set flow control
+ * based on the EEPROM flow control settings.
+ */
+ if (hw->fc.requested_mode == e1000_fc_default) {
+ ret_val = e1000_set_default_fc_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Save off the requested flow control mode for use later. Depending
+ * on the link partner's capabilities, we may or may not use this mode.
+ */
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
+ hw->fc.current_mode);
+
+ /* Call the necessary media_type subroutine to configure the link. */
+ ret_val = hw->mac.ops.setup_physical_interface(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+ E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+ E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+
+ ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes
+ * links. Upon successful setup, poll for link.
+ **/
+INT32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ /* Take the link out of reset */
+ ctrl &= ~E1000_CTRL_LRST;
+
+ mac->ops.config_collision_dist(hw);
+
+ ret_val = e1000_commit_fc_settings_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Since auto-negotiation is enabled, take the link out of reset (the
+ * link will be in reset, because we previously reset the chip). This
+ * will restart auto-negotiation. If auto-negotiation is successful
+ * then the link-up status bit will be set and the flow control enable
+ * bits (RFCE and TFCE) will be set according to their negotiated value.
+ */
+ DEBUGOUT("Auto-negotiation enabled\n");
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+
+ /*
+ * For these adapters, the SW definable pin 1 is set when the optics
+ * detect a signal. If we have a signal, then poll for a "Link-Up"
+ * indication.
+ */
+ if (hw->phy.media_type == e1000_media_type_internal_serdes ||
+ (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
+ ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+ } else {
+ DEBUGOUT("No signal detected\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_config_collision_dist_generic - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup.
+ **/
+void e1000_config_collision_dist_generic(struct e1000_hw *hw)
+{
+ UINT32 tctl;
+
+ DEBUGFUNC("e1000_config_collision_dist_generic");
+
+ tctl = E1000_READ_REG(hw, E1000_TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * e1000_poll_fiber_serdes_link_generic - Poll for link up
+ * @hw: pointer to the HW structure
+ *
+ * Polls for link up by reading the status register, if link fails to come
+ * up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+STATIC INT32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 i, status;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_poll_fiber_serdes_link_generic");
+
+ /*
+ * If we have a signal (the cable is plugged in, or assumed TRUE for
+ * serdes media) then poll for a "Link-Up" indication in the Device
+ * Status Register. Time-out if a link isn't seen in 500 milliseconds
+ * seconds (Auto-negotiation should complete in less than 500
+ * milliseconds even if the other end is doing it in SW).
+ */
+ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+ msec_delay(10);
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_LU)
+ break;
+ }
+ if (i == FIBER_LINK_UP_LIMIT) {
+ DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+ mac->autoneg_failed = 1;
+ /*
+ * AutoNeg failed to achieve a link, so we'll call
+ * mac->check_for_link. This routine will force the
+ * link up if we detect a signal. This will allow us to
+ * communicate with non-autonegotiating link partners.
+ */
+ ret_val = mac->ops.check_for_link(hw);
+ if (ret_val) {
+ DEBUGOUT("Error while checking for link\n");
+ goto out;
+ }
+ mac->autoneg_failed = 0;
+ } else {
+ mac->autoneg_failed = 0;
+ DEBUGOUT("Valid Link Found\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_commit_fc_settings_generic - Configure flow control
+ * @hw: pointer to the HW structure
+ *
+ * Write the flow control settings to the Transmit Config Word Register (TXCW)
+ * base on the flow control settings in e1000_mac_info.
+ **/
+STATIC INT32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 txcw;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_commit_fc_settings_generic");
+
+ /*
+ * Check for a software override of the flow control settings, and
+ * setup the device accordingly. If auto-negotiation is enabled, then
+ * software will have to set the "PAUSE" bits to the correct value in
+ * the Transmit Config Word Register (TXCW) and re-start auto-
+ * negotiation. However, if auto-negotiation is disabled, then
+ * software will have to manually configure the two flow control enable
+ * bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames,
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we
+ * do not support receiving pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) are enabled.
+ */
+ switch (hw->fc.current_mode) {
+ case e1000_fc_none:
+ /* Flow control completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /*
+ * Rx Flow control is enabled and Tx Flow control is disabled
+ * by a software over-ride. Since there really isn't a way to
+ * advertise that we are capable of Rx Pause ONLY, we will
+ * advertise that we support both symmetric and asymmetric Rx
+ * PAUSE. Later, we will disable the adapter's ability to send
+ * PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /*
+ * Tx Flow control is enabled, and Rx Flow control is disabled,
+ * by a software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /*
+ * Flow control (both Rx and Tx) is enabled by a software
+ * over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ break;
+ }
+
+ E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+ mac->txcw = txcw;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_set_fc_watermarks_generic - Set flow control high/low watermarks
+ * @hw: pointer to the HW structure
+ *
+ * Sets the flow control high/low threshold (watermark) registers. If
+ * flow control XON frame transmission is enabled, then set XON frame
+ * transmission as well.
+ **/
+INT32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw)
+{
+ UINT32 fcrtl = 0, fcrth = 0;
+
+ DEBUGFUNC("e1000_set_fc_watermarks_generic");
+
+ /*
+ * Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames is not enabled, then these
+ * registers will be set to 0.
+ */
+ if (hw->fc.current_mode & e1000_fc_tx_pause) {
+ /*
+ * We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
+ */
+ fcrtl = hw->fc.low_water;
+ if (hw->fc.send_xon)
+ fcrtl |= E1000_FCRTL_XONE;
+
+ fcrth = hw->fc.high_water;
+ }
+ E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
+ E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_default_fc_generic - Set flow control default values
+ * @hw: pointer to the HW structure
+ *
+ * Read the EEPROM for the default values for flow control and store the
+ * values.
+ **/
+STATIC INT32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 nvm_data;
+
+ DEBUGFUNC("e1000_set_default_fc_generic");
+
+ /*
+ * Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+ hw->fc.requested_mode = e1000_fc_none;
+ else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+ NVM_WORD0F_ASM_DIR)
+ hw->fc.requested_mode = e1000_fc_tx_pause;
+ else
+ hw->fc.requested_mode = e1000_fc_full;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_force_mac_fc_generic - Force the MAC's flow control settings
+ * @hw: pointer to the HW structure
+ *
+ * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
+ * device control register to reflect the adapter settings. TFCE and RFCE
+ * need to be explicitly set by software when a copper PHY is used because
+ * autonegotiation is managed by the PHY rather than the MAC. Software must
+ * also configure these bits when link is forced on a fiber connection.
+ **/
+INT32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_force_mac_fc_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ /*
+ * Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "hw->fc.current_mode" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+ DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
+
+ switch (hw->fc.current_mode) {
+ case e1000_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case e1000_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case e1000_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case e1000_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_config_fc_after_link_up_generic - Configures flow control after link
+ * @hw: pointer to the HW structure
+ *
+ * Checks the status of auto-negotiation after link up to ensure that the
+ * speed and duplex were not forced. If the link needed to be forced, then
+ * flow control needs to be forced also. If auto-negotiation is enabled
+ * and did not fail, then we configure flow control based on our link
+ * partner.
+ **/
+INT32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+ UINT16 speed, duplex;
+
+ DEBUGFUNC("e1000_config_fc_after_link_up_generic");
+
+ /*
+ * Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if (mac->autoneg_failed) {
+ if (hw->phy.media_type == e1000_media_type_fiber ||
+ hw->phy.media_type == e1000_media_type_internal_serdes)
+ ret_val = e1000_force_mac_fc_generic(hw);
+ } else {
+ if (hw->phy.media_type == e1000_media_type_copper)
+ ret_val = e1000_force_mac_fc_generic(hw);
+ }
+
+ if (ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ goto out;
+ }
+
+ /*
+ * Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+ /*
+ * Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ goto out;
+
+ if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+ DEBUGOUT("Copper PHY and Auto Neg "
+ "has not completed.\n");
+ goto out;
+ }
+
+ /*
+ * The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement
+ * Register (Address 4) and the Auto_Negotiation Base
+ * Page Ability Register (Address 5) to determine how
+ * flow control was negotiated.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
+ &mii_nway_adv_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
+ &mii_nway_lp_ability_reg);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ * Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | E1000_fc_full
+ *
+ */
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /*
+ * Now we need to check if the user selected Rx ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise Rx
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if (hw->fc.requested_mode == e1000_fc_full) {
+ hw->fc.current_mode = e1000_fc_full;
+ DEBUGOUT("Flow Control = FULL.\r\n");
+ } else {
+ hw->fc.current_mode = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = "
+ "Rx PAUSE frames only.\r\n");
+ }
+ }
+ /*
+ * For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ */
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = e1000_fc_tx_pause;
+ DEBUGOUT("Flow Control = Tx PAUSE frames only.\r\n");
+ }
+ /*
+ * For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ */
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = Rx PAUSE frames only.\r\n");
+ } else {
+ /*
+ * Per the IEEE spec, at this point flow control
+ * should be disabled.
+ */
+ hw->fc.current_mode = e1000_fc_none;
+ DEBUGOUT("Flow Control = NONE.\r\n");
+ }
+
+ /*
+ * Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+ if (ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ goto out;
+ }
+
+ if (duplex == HALF_DUPLEX)
+ hw->fc.current_mode = e1000_fc_none;
+
+ /*
+ * Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000_force_mac_fc_generic(hw);
+ if (ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Read the status register for the current speed/duplex and store the current
+ * speed and duplex for copper connections.
+ **/
+INT32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex)
+{
+ UINT32 status;
+
+ DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic");
+
+ status = E1000_READ_REG(hw, E1000_STATUS);
+ if (status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ DEBUGOUT("1000 Mbs, ");
+ } else if (status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ DEBUGOUT("100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ DEBUGOUT("10 Mbs, ");
+ }
+
+ if (status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ DEBUGOUT("Half Duplex\n");
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Sets the speed and duplex to gigabit full duplex (the only possible option)
+ * for fiber/serdes links.
+ **/
+INT32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex)
+{
+ DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
+
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_hw_semaphore_generic - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+INT32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+ INT32 ret_val = E1000_SUCCESS;
+ INT32 timeout = hw->nvm.word_size + 1;
+ INT32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_generic");
+
+ /* Get the SW semaphore */
+ while (i < timeout) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ usec_delay(50);
+ i++;
+ }
+
+ if (i == timeout) {
+ DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ usec_delay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_generic(hw);
+ DEBUGOUT("Driver can't access the NVM\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_generic - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw)
+{
+ UINT32 swsm;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_generic");
+
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ * e1000_get_auto_rd_done_generic - Check for auto read completion
+ * @hw: pointer to the HW structure
+ *
+ * Check EEPROM for Auto Read done bit.
+ **/
+INT32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
+{
+ INT32 i = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_get_auto_rd_done_generic");
+
+ while (i < AUTO_READ_DONE_TIMEOUT) {
+ if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
+ break;
+ msec_delay(1);
+ i++;
+ }
+
+ if (i == AUTO_READ_DONE_TIMEOUT) {
+ DEBUGOUT("Auto read by HW from NVM has not completed.\n");
+ ret_val = -E1000_ERR_RESET;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_valid_led_default_generic - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+INT32 e1000_valid_led_default_generic(struct e1000_hw *hw, UINT16 *data)
+{
+ INT32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_generic");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_id_led_init_generic -
+ * @hw: pointer to the HW structure
+ *
+ **/
+INT32 e1000_id_led_init_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ INT32 ret_val;
+ const UINT32 ledctl_mask = 0x000000FF;
+ const UINT32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+ const UINT32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+ UINT16 data, i, temp;
+ const UINT16 led_mask = 0x0F;
+
+ DEBUGFUNC("e1000_id_led_init_generic");
+
+ ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+ if (ret_val)
+ goto out;
+
+ mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+ mac->ledctl_mode1 = mac->ledctl_default;
+ mac->ledctl_mode2 = mac->ledctl_default;
+
+ for (i = 0; i < 4; i++) {
+ temp = (data >> (i << 2)) & led_mask;
+ switch (temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch (temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_led_generic - Configures SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This prepares the SW controllable LED for use and saves the current state
+ * of the LED so it can be later restored.
+ **/
+INT32 e1000_setup_led_generic(struct e1000_hw *hw)
+{
+ UINT32 ledctl;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_setup_led_generic");
+
+ if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ if (hw->phy.media_type == e1000_media_type_fiber) {
+ ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+ hw->mac.ledctl_default = ledctl;
+ /* Turn off LED0 */
+ ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+ E1000_LEDCTL_LED0_BLINK |
+ E1000_LEDCTL_LED0_MODE_MASK);
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+ E1000_LEDCTL_LED0_MODE_SHIFT);
+ E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+ } else if (hw->phy.media_type == e1000_media_type_copper) {
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_cleanup_led_generic - Set LED config to default operation
+ * @hw: pointer to the HW structure
+ *
+ * Remove the current LED configuration and set the LED configuration
+ * to the default value, saved from the EEPROM.
+ **/
+INT32 e1000_cleanup_led_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led_generic");
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_blink_led_generic - Blink LED
+ * @hw: pointer to the HW structure
+ *
+ * Blink the LEDs which are set to be on.
+ **/
+INT32 e1000_blink_led_generic(struct e1000_hw *hw)
+{
+ UINT32 ledctl_blink = 0;
+ UINT32 i;
+
+ DEBUGFUNC("e1000_blink_led_generic");
+
+ if (hw->phy.media_type == e1000_media_type_fiber) {
+ /* always blink LED0 for PCI-E fiber */
+ ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+ } else {
+ /*
+ * set the blink bit for each LED that's "on" (0x0E)
+ * in ledctl_mode2
+ */
+ ledctl_blink = hw->mac.ledctl_mode2;
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+ (i * 8));
+ }
+
+ E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_on_generic - Turn LED on
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED on.
+ **/
+INT32 e1000_led_on_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_led_on_generic");
+
+ switch (hw->phy.media_type) {
+ case e1000_media_type_fiber:
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+ break;
+ default:
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_led_off_generic - Turn LED off
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED off.
+ **/
+INT32 e1000_led_off_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_led_off_generic");
+
+ switch (hw->phy.media_type) {
+ case e1000_media_type_fiber:
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+ break;
+ default:
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities
+ * @hw: pointer to the HW structure
+ * @no_snoop: bitmap of snoop events
+ *
+ * Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, UINT32 no_snoop)
+{
+ UINT32 gcr;
+
+ DEBUGFUNC("e1000_set_pcie_no_snoop_generic");
+
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+ if (hw->bus.type != e1000_bus_type_pci_express)
+ goto out;
+
+#endif
+ if (no_snoop) {
+ gcr = E1000_READ_REG(hw, E1000_GCR);
+ gcr &= ~(PCIE_NO_SNOOP_ALL);
+ gcr |= no_snoop;
+ E1000_WRITE_REG(hw, E1000_GCR, gcr);
+ }
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+out:
+#endif
+ return;
+}
+
+/**
+ * e1000_disable_pcie_master_generic - Disables PCI-express master access
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_SUCCESS if successful, else returns -10
+ * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ * the master requests to be disabled.
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests.
+ **/
+INT32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl;
+ INT32 timeout = MASTER_DISABLE_TIMEOUT;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_disable_pcie_master_generic");
+
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+ if (hw->bus.type != e1000_bus_type_pci_express)
+ goto out;
+
+#endif
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ while (timeout) {
+ if (!(E1000_READ_REG(hw, E1000_STATUS) &
+ E1000_STATUS_GIO_MASTER_ENABLE))
+ break;
+ usec_delay(100);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("Master requests are pending.\n");
+ ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+ }
+
+#if !defined(NO_PCI_SUPPORT) || !defined(NO_PCIX_SUPPORT)
+out:
+#endif
+ return ret_val;
+}
+
+/**
+ * e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing
+ * @hw: pointer to the HW structure
+ *
+ * Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000_reset_adaptive_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ DEBUGFUNC("e1000_reset_adaptive_generic");
+
+ if (!mac->adaptive_ifs) {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ goto out;
+ }
+
+ 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;
+ E1000_WRITE_REG(hw, E1000_AIT, 0);
+out:
+ return;
+}
+
+/**
+ * e1000_update_adaptive_generic - 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 e1000_update_adaptive_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ DEBUGFUNC("e1000_update_adaptive_generic");
+
+ if (!mac->adaptive_ifs) {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ goto out;
+ }
+
+ 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;
+ E1000_WRITE_REG(hw, 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;
+ E1000_WRITE_REG(hw, E1000_AIT, 0);
+ }
+ }
+out:
+ return;
+}
+
+/**
+ * e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings
+ * @hw: pointer to the HW structure
+ *
+ * Verify that when not using auto-negotiation that MDI/MDIx is correctly
+ * set, which is forced to MDI mode only.
+ **/
+STATIC INT32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_validate_mdi_setting_generic");
+
+ if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+ DEBUGOUT("Invalid MDI setting detected\n");
+ hw->phy.mdix = 1;
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+#ifndef NO_82575_SUPPORT
+
+/**
+ * e1000_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register
+ * @hw: pointer to the HW structure
+ * @reg: 32bit register offset such as E1000_SCTL
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes an address/data control type register. There are several of these
+ * and they all have the format address << 8 | data and bit 31 is polled for
+ * completion.
+ **/
+INT32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, UINT32 reg,
+ UINT32 offset, UINT8 data)
+{
+ UINT32 i, regvalue = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_8bit_ctrl_reg_generic");
+
+ /* Set up the address and data */
+ regvalue = ((UINT32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
+ E1000_WRITE_REG(hw, reg, regvalue);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+ usec_delay(5);
+ regvalue = E1000_READ_REG(hw, reg);
+ if (regvalue & E1000_GEN_CTL_READY)
+ break;
+ }
+ if (!(regvalue & E1000_GEN_CTL_READY)) {
+ DEBUGOUT1("Reg %08x did not indicate ready\n", reg);
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+#endif /* NO_82575_SUPPORT */
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h
new file mode 100755
index 0000000..db43611
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_mac.h
@@ -0,0 +1,102 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_MAC_H_
+#define _E1000_MAC_H_
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+void e1000_init_mac_ops_generic(struct e1000_hw *hw);
+#ifndef NO_NULL_OPS_SUPPORT
+void e1000_null_mac_generic(struct e1000_hw *hw);
+INT32 e1000_null_ops_generic(struct e1000_hw *hw);
+INT32 e1000_null_link_info(struct e1000_hw *hw, UINT16 *s, UINT16 *d);
+BOOLEAN e1000_null_mng_mode(struct e1000_hw *hw);
+void e1000_null_update_mc(struct e1000_hw *hw, UINT8 *h, UINT32 a);
+void e1000_null_write_vfta(struct e1000_hw *hw, UINT32 a, UINT32 b);
+void e1000_null_rar_set(struct e1000_hw *hw, UINT8 *h, UINT32 a);
+#endif /* NO_NULL_OPS_SUPPORT */
+INT32 e1000_blink_led_generic(struct e1000_hw *hw);
+INT32 e1000_check_for_copper_link_generic(struct e1000_hw *hw);
+INT32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw);
+INT32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw);
+INT32 e1000_cleanup_led_generic(struct e1000_hw *hw);
+INT32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw);
+INT32 e1000_disable_pcie_master_generic(struct e1000_hw *hw);
+INT32 e1000_force_mac_fc_generic(struct e1000_hw *hw);
+INT32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw);
+#ifndef NO_PCI_SUPPORT
+INT32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw);
+#endif
+INT32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw);
+void e1000_set_lan_id_single_port(struct e1000_hw *hw);
+#ifndef NO_PCI_SUPPORT
+void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw);
+#endif
+INT32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
+INT32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, UINT16 *speed,
+ UINT16 *duplex);
+INT32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+ UINT16 *speed, UINT16 *duplex);
+INT32 e1000_id_led_init_generic(struct e1000_hw *hw);
+INT32 e1000_led_on_generic(struct e1000_hw *hw);
+INT32 e1000_led_off_generic(struct e1000_hw *hw);
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+ UINT8 *mc_addr_list, UINT32 mc_addr_count);
+INT32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw);
+INT32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
+INT32 e1000_setup_led_generic(struct e1000_hw *hw);
+INT32 e1000_setup_link_generic(struct e1000_hw *hw);
+#ifndef NO_82575_SUPPORT
+INT32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, UINT32 reg,
+ UINT32 offset, UINT8 data);
+#endif
+
+UINT32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, UINT8 *mc_addr);
+
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
+void e1000_clear_vfta_generic(struct e1000_hw *hw);
+void e1000_config_collision_dist_generic(struct e1000_hw *hw);
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, UINT16 rar_count);
+void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw);
+void e1000_rar_set_generic(struct e1000_hw *hw, UINT8 *addr, UINT32 index);
+INT32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void e1000_reset_adaptive_generic(struct e1000_hw *hw);
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, UINT32 no_snoop);
+void e1000_update_adaptive_generic(struct e1000_hw *hw);
+void e1000_write_vfta_generic(struct e1000_hw *hw, UINT32 offset, UINT32 value);
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c
new file mode 100755
index 0000000..8e6f787
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.c
@@ -0,0 +1,409 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+STATIC UINT8 e1000_calculate_checksum(UINT8 *buffer, UINT32 length);
+
+/**
+ * e1000_calculate_checksum - Calculate checksum for buffer
+ * @buffer: pointer to EEPROM
+ * @length: size of EEPROM to calculate a checksum for
+ *
+ * Calculates the checksum for some buffer on a specified length. The
+ * checksum calculated is returned.
+ **/
+STATIC UINT8 e1000_calculate_checksum(UINT8 *buffer, UINT32 length)
+{
+ UINT32 i;
+ UINT8 sum = 0;
+
+ DEBUGFUNC("e1000_calculate_checksum");
+
+ if (!buffer)
+ return 0;
+
+ for (i = 0; i < length; i++)
+ sum += buffer[i];
+
+ return (UINT8) (0 - sum);
+}
+
+/**
+ * e1000_mng_enable_host_if_generic - Checks host interface is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ * This function checks whether the HOST IF is enabled for command operation
+ * and also checks whether the previous command is completed. It busy waits
+ * in case of previous command is not completed.
+ **/
+INT32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
+{
+ UINT32 hicr;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT8 i;
+
+ DEBUGFUNC("e1000_mng_enable_host_if_generic");
+
+ if (!(hw->mac.arc_subsystem_valid)) {
+ DEBUGOUT("ARC subsystem not valid.\n");
+ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+ goto out;
+ }
+
+ /* Check that the host interface is enabled. */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ if ((hicr & E1000_HICR_EN) == 0) {
+ DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+ goto out;
+ }
+ /* check the previous command is completed */
+ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+ msec_delay_irq(1);
+ }
+
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+ DEBUGOUT("Previous command timeout failed .\n");
+ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_mng_mode_generic - Generic check management mode
+ * @hw: pointer to the HW structure
+ *
+ * Reads the firmware semaphore register and returns TRUE (>0) if
+ * manageability is enabled, else FALSE (0).
+ **/
+BOOLEAN e1000_check_mng_mode_generic(struct e1000_hw *hw)
+{
+ UINT32 fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+ DEBUGFUNC("e1000_check_mng_mode_generic");
+
+
+ return (fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+}
+
+/**
+ * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on Tx
+ * @hw: pointer to the HW structure
+ *
+ * Enables packet filtering on transmit packets if manageability is enabled
+ * and host interface is enabled.
+ **/
+BOOLEAN e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
+{
+ struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+ UINT32 *buffer = (UINT32 *)&hw->mng_cookie;
+ UINT32 offset;
+ INT32 ret_val, hdr_csum, csum;
+ UINT8 i, len;
+
+ DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
+
+ hw->mac.tx_pkt_filtering = TRUE;
+
+ /* No manageability, no filtering */
+ if (!hw->mac.ops.check_mng_mode(hw)) {
+ hw->mac.tx_pkt_filtering = FALSE;
+ goto out;
+ }
+
+ /*
+ * If we can't read from the host interface for whatever
+ * reason, disable filtering.
+ */
+ ret_val = hw->mac.ops.mng_enable_host_if(hw);
+ if (ret_val != E1000_SUCCESS) {
+ hw->mac.tx_pkt_filtering = FALSE;
+ goto out;
+ }
+
+ /* Read in the header. Length and offset are in dwords. */
+ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+ offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+ for (i = 0; i < len; i++)
+ *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
+ offset + i);
+ hdr_csum = hdr->checksum;
+ hdr->checksum = 0;
+ csum = e1000_calculate_checksum((UINT8 *)hdr,
+ E1000_MNG_DHCP_COOKIE_LENGTH);
+ /*
+ * If either the checksums or signature don't match, then
+ * the cookie area isn't considered valid, in which case we
+ * take the safe route of assuming Tx filtering is enabled.
+ */
+ if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
+ hw->mac.tx_pkt_filtering = TRUE;
+ goto out;
+ }
+
+ /* Cookie area is valid, make the final check for filtering. */
+ if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
+ hw->mac.tx_pkt_filtering = FALSE;
+ goto out;
+ }
+
+out:
+ return hw->mac.tx_pkt_filtering;
+}
+
+/**
+ * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface
+ * @length: size of the buffer
+ *
+ * Writes the DHCP information to the host interface.
+ **/
+INT32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, UINT8 *buffer,
+ UINT16 length)
+{
+ struct e1000_host_mng_command_header hdr;
+ INT32 ret_val;
+ UINT32 hicr;
+
+ DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
+
+ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+ hdr.command_length = length;
+ hdr.reserved1 = 0;
+ hdr.reserved2 = 0;
+ hdr.checksum = 0;
+
+ /* Enable the host interface */
+ ret_val = hw->mac.ops.mng_enable_host_if(hw);
+ if (ret_val)
+ goto out;
+
+ /* Populate the host interface with the contents of "buffer". */
+ ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
+ sizeof(hdr), &(hdr.checksum));
+ if (ret_val)
+ goto out;
+
+ /* Write the manageability command header */
+ ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
+ if (ret_val)
+ goto out;
+
+ /* Tell the ARC a new command is pending. */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_mng_write_cmd_header_generic - Writes manageability command header
+ * @hw: pointer to the HW structure
+ * @hdr: pointer to the host interface command header
+ *
+ * Writes the command header after does the checksum calculation.
+ **/
+INT32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr)
+{
+ UINT16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+ DEBUGFUNC("e1000_mng_write_cmd_header_generic");
+
+ /* Write the whole command header structure with new checksum. */
+
+ hdr->checksum = e1000_calculate_checksum((UINT8 *)hdr, length);
+
+ length >>= 2;
+ /* Write the relevant command block into the ram area. */
+ for (i = 0; i < length; i++) {
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
+ *((UINT32 *) hdr + i));
+ E1000_WRITE_FLUSH(hw);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_mng_host_if_write_generic - Write to the manageability host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface buffer
+ * @length: size of the buffer
+ * @offset: location in the buffer to write to
+ * @sum: sum of the data (not checksum)
+ *
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient
+ * way. Also fills up the sum of the buffer in *buffer parameter.
+ **/
+INT32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, UINT8 *buffer,
+ UINT16 length, UINT16 offset, UINT8 *sum)
+{
+ UINT8 *tmp;
+ UINT8 *bufptr = buffer;
+ UINT32 data = 0;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 remaining, i, j, prev_bytes;
+
+ DEBUGFUNC("e1000_mng_host_if_write_generic");
+
+ /* sum = only sum of the data and it is not checksum */
+
+ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+ ret_val = -E1000_ERR_PARAM;
+ goto out;
+ }
+
+ tmp = (UINT8 *)&data;
+ prev_bytes = offset & 0x3;
+ offset >>= 2;
+
+ if (prev_bytes) {
+ data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
+ for (j = prev_bytes; j < sizeof(UINT32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
+ length -= j - prev_bytes;
+ offset++;
+ }
+
+ remaining = length & 0x3;
+ length -= remaining;
+
+ /* Calculate length in DWORDs */
+ length >>= 2;
+
+ /*
+ * The device driver writes the relevant command block into the
+ * ram area.
+ */
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < sizeof(UINT32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
+ data);
+ }
+ if (remaining) {
+ for (j = 0; j < sizeof(UINT32); j++) {
+ if (j < remaining)
+ *(tmp + j) = *bufptr++;
+ else
+ *(tmp + j) = 0;
+
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_enable_mng_pass_thru - 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.
+ **/
+BOOLEAN e1000_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+ UINT32 manc;
+ UINT32 fwsm, factps;
+ BOOLEAN ret_val = FALSE;
+
+ DEBUGFUNC("e1000_enable_mng_pass_thru");
+
+#ifndef NO_ASF_FIRMWARE_CHECK
+ if (!hw->mac.asf_firmware_present)
+ goto out;
+#endif
+
+ manc = E1000_READ_REG(hw, E1000_MANC);
+
+ if (!(manc & E1000_MANC_RCV_TCO_EN))
+ goto out;
+
+ if (hw->mac.has_fwsm) {
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+ factps = E1000_READ_REG(hw, E1000_FACTPS);
+
+ if (!(factps & E1000_FACTPS_MNGCG) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+ ret_val = TRUE;
+ goto out;
+ }
+#ifndef NO_82574_SUPPORT
+ } else if ((hw->mac.type == e1000_82574) ||
+ (hw->mac.type == e1000_82583)) {
+ UINT16 data;
+
+ factps = E1000_READ_REG(hw, E1000_FACTPS);
+ e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+
+ if (!(factps & E1000_FACTPS_MNGCG) &&
+ ((data & E1000_NVM_INIT_CTRL2_MNGM) ==
+ (e1000_mng_mode_pt << 13))) {
+ ret_val = TRUE;
+ goto out;
+ }
+#endif /* NO_82574_SUPPORT */
+ } else if ((manc & E1000_MANC_SMBUS_EN) &&
+ !(manc & E1000_MANC_ASF_EN)) {
+ ret_val = TRUE;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h
new file mode 100755
index 0000000..09e6867
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_manage.h
@@ -0,0 +1,87 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_MANAGE_H_
+#define _E1000_MANAGE_H_
+
+BOOLEAN e1000_check_mng_mode_generic(struct e1000_hw *hw);
+BOOLEAN e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
+INT32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
+INT32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, UINT8 *buffer,
+ UINT16 length, UINT16 offset, UINT8 *sum);
+INT32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr);
+INT32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
+ UINT8 *buffer, UINT16 length);
+BOOLEAN e1000_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+ e1000_mng_mode_none = 0,
+ e1000_mng_mode_asf,
+ e1000_mng_mode_pt,
+ e1000_mng_mode_ipmi,
+ e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG 0x20000000
+
+#define E1000_FWSM_MODE_MASK 0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
+
+#define E1000_VFTA_ENTRY_SHIFT 5
+#define E1000_VFTA_ENTRY_MASK 0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */
+
+#define E1000_HICR_EN 0x01 /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C 0x02
+#define E1000_HICR_SV 0x04 /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET 0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE 0x544D4149
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c
new file mode 100755
index 0000000..319e060
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.c
@@ -0,0 +1,1063 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+STATIC void e1000_stop_nvm(struct e1000_hw *hw);
+STATIC void e1000_reload_nvm_generic(struct e1000_hw *hw);
+
+/**
+ * e1000_init_nvm_ops_generic - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Setups up the function pointers to no-op functions
+ **/
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ DEBUGFUNC("e1000_init_nvm_ops_generic");
+
+ /* Initialize function pointers */
+#ifndef NO_NULL_OPS_SUPPORT
+ nvm->ops.init_params = e1000_null_ops_generic;
+ nvm->ops.acquire = e1000_null_ops_generic;
+ nvm->ops.read = e1000_null_read_nvm;
+ nvm->ops.release = e1000_null_nvm_generic;
+#endif /* NO_NULL_OPS_SUPPORT */
+ nvm->ops.reload = e1000_reload_nvm_generic;
+#ifndef NO_NULL_OPS_SUPPORT
+ nvm->ops.update = e1000_null_ops_generic;
+ nvm->ops.valid_led_default = e1000_null_led_default;
+ nvm->ops.validate = e1000_null_ops_generic;
+ nvm->ops.write = e1000_null_write_nvm;
+#endif /* NO_NULL_OPS_SUPPORT */
+}
+
+#ifndef NO_NULL_OPS_SUPPORT
+/**
+ * e1000_null_nvm_read - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_read_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c)
+{
+ DEBUGFUNC("e1000_null_read_nvm");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_nvm_generic - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_nvm_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_nvm_generic");
+ return;
+}
+
+/**
+ * e1000_null_led_default - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_led_default(struct e1000_hw *hw, UINT16 *data)
+{
+ DEBUGFUNC("e1000_null_led_default");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_write_nvm - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_write_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c)
+{
+ DEBUGFUNC("e1000_null_write_nvm");
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_NULL_OPS_SUPPORT */
+/**
+ * e1000_raise_eec_clk - Raise EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000_raise_eec_clk(struct e1000_hw *hw, UINT32 *eecd)
+{
+ *eecd = *eecd | E1000_EECD_SK;
+ E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_lower_eec_clk - Lower EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000_lower_eec_clk(struct e1000_hw *hw, UINT32 *eecd)
+{
+ *eecd = *eecd & ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ * @hw: pointer to the HW structure
+ * @data: data to send to the EEPROM
+ * @count: number of bits to shift out
+ *
+ * We need to shift 'count' bits out to the EEPROM. So, the value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_eec_bits(struct e1000_hw *hw, UINT16 data, UINT16 count)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ UINT32 mask;
+
+ DEBUGFUNC("e1000_shift_out_eec_bits");
+
+ mask = 0x01 << (count - 1);
+#ifndef NO_MICROWIRE_SUPPORT
+ if (nvm->type == e1000_nvm_eeprom_microwire)
+ eecd &= ~E1000_EECD_DO;
+ else
+#endif /* NO_MICROWIRE_SUPPORT */
+ if (nvm->type == e1000_nvm_eeprom_spi)
+ eecd |= E1000_EECD_DO;
+
+ do {
+ eecd &= ~E1000_EECD_DI;
+
+ if (data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(nvm->delay_usec);
+
+ e1000_raise_eec_clk(hw, &eecd);
+ e1000_lower_eec_clk(hw, &eecd);
+
+ mask >>= 1;
+ } while (mask);
+
+ eecd &= ~E1000_EECD_DI;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ * @hw: pointer to the HW structure
+ * @count: number of bits to shift in
+ *
+ * In order to read a register from the EEPROM, we need to shift 'count' bits
+ * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+ * the EEPROM (setting the SK bit), and then reading the value of the data out
+ * "DO" bit. During this "shifting in" process the data in "DI" bit should
+ * always be clear.
+ **/
+static UINT16 e1000_shift_in_eec_bits(struct e1000_hw *hw, UINT16 count)
+{
+ UINT32 eecd;
+ UINT32 i;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_shift_in_eec_bits");
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for (i = 0; i < count; i++) {
+ data <<= 1;
+ e1000_raise_eec_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ eecd &= ~E1000_EECD_DI;
+ if (eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_eec_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/**
+ * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ * @hw: pointer to the HW structure
+ * @ee_reg: EEPROM flag for polling
+ *
+ * Polls the EEPROM status bit for either read or write completion based
+ * upon the value of 'ee_reg'.
+ **/
+INT32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+ UINT32 attempts = 100000;
+ UINT32 i, reg = 0;
+ INT32 ret_val = -E1000_ERR_NVM;
+
+ DEBUGFUNC("e1000_poll_eerd_eewr_done");
+
+ for (i = 0; i < attempts; i++) {
+ if (ee_reg == E1000_NVM_POLL_READ)
+ reg = E1000_READ_REG(hw, E1000_EERD);
+ else
+ reg = E1000_READ_REG(hw, E1000_EEWR);
+
+ if (reg & E1000_NVM_RW_REG_DONE) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+
+ usec_delay(5);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_acquire_nvm_generic - Generic request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+INT32 e1000_acquire_nvm_generic(struct e1000_hw *hw)
+{
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ INT32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_acquire_nvm_generic");
+
+ E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ while (timeout) {
+ if (eecd & E1000_EECD_GNT)
+ break;
+ usec_delay(5);
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ timeout--;
+ }
+
+ if (!timeout) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ DEBUGOUT("Could not acquire NVM grant\n");
+ ret_val = -E1000_ERR_NVM;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_standby_nvm - Return EEPROM to standby state
+ * @hw: pointer to the HW structure
+ *
+ * Return the EEPROM to a standby state.
+ **/
+static void e1000_standby_nvm(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+
+ DEBUGFUNC("e1000_standby_nvm");
+
+#ifndef NO_MICROWIRE_SUPPORT
+ if (nvm->type == e1000_nvm_eeprom_microwire) {
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+
+ e1000_raise_eec_clk(hw, &eecd);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+
+ e1000_lower_eec_clk(hw, &eecd);
+ } else
+#endif /* NO_MICROWIRE_SUPPORT */
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(nvm->delay_usec);
+ }
+}
+
+/**
+ * e1000_stop_nvm - Terminate EEPROM command
+ * @hw: pointer to the HW structure
+ *
+ * Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+STATIC void e1000_stop_nvm(struct e1000_hw *hw)
+{
+ UINT32 eecd;
+
+ DEBUGFUNC("e1000_stop_nvm");
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+ /* Pull CS high */
+ eecd |= E1000_EECD_CS;
+ e1000_lower_eec_clk(hw, &eecd);
+#ifndef NO_MICROWIRE_SUPPORT
+ } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ e1000_raise_eec_clk(hw, &eecd);
+ e1000_lower_eec_clk(hw, &eecd);
+#endif /* NO_MICROWIRE_SUPPORT */
+ }
+}
+
+/**
+ * e1000_release_nvm_generic - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000_release_nvm_generic(struct e1000_hw *hw)
+{
+ UINT32 eecd;
+
+ DEBUGFUNC("e1000_release_nvm_generic");
+
+ e1000_stop_nvm(hw);
+
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ * @hw: pointer to the HW structure
+ *
+ * Setups the EEPROM for reading and writing.
+ **/
+static INT32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 eecd = E1000_READ_REG(hw, E1000_EECD);
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 timeout = 0;
+ UINT8 spi_stat_reg;
+
+ DEBUGFUNC("e1000_ready_nvm_eeprom");
+
+#ifndef NO_MICROWIRE_SUPPORT
+ if (nvm->type == e1000_nvm_eeprom_microwire) {
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ } else
+#endif /* NO_MICROWIRE_SUPPORT */
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, E1000_EECD, eecd);
+ usec_delay(1);
+ timeout = NVM_MAX_RETRY_SPI;
+
+ /*
+ * Read "Status Register" repeatedly until the LSB is cleared.
+ * The EEPROM will signal that the command has been completed
+ * by clearing bit 0 of the internal status register. If it's
+ * not cleared within 'timeout', then error out.
+ */
+ while (timeout) {
+ e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+ hw->nvm.opcode_bits);
+ spi_stat_reg = (UINT8)e1000_shift_in_eec_bits(hw, 8);
+ if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+ break;
+
+ usec_delay(5);
+ e1000_standby_nvm(hw);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("SPI NVM Status error\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_MICROWIRE_SUPPORT
+/**
+ * e1000_read_nvm_microwire - Reads EEPROM's using microwire
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM.
+ **/
+INT32 e1000_read_nvm_microwire(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 i = 0;
+ INT32 ret_val;
+ UINT8 read_opcode = NVM_READ_OPCODE_MICROWIRE;
+
+ DEBUGFUNC("e1000_read_nvm_microwire");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ ret_val = nvm->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val)
+ goto release;
+
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (UINT16)(offset + i),
+ nvm->address_bits);
+
+ /*
+ * Read the data. For microwire, each word requires the
+ * overhead of setup and tear-down.
+ */
+ data[i] = e1000_shift_in_eec_bits(hw, 16);
+ e1000_standby_nvm(hw);
+ }
+
+release:
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+#endif /* NO_MICROWIRE_SUPPORT */
+/**
+ * e1000_read_nvm_eerd - Reads EEPROM using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+INT32 e1000_read_nvm_eerd(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ UINT32 i, eerd = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_nvm_eerd");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * too many words for the offset, and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+ E1000_NVM_RW_REG_START;
+
+ E1000_WRITE_REG(hw, E1000_EERD, eerd);
+ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+ if (ret_val)
+ break;
+
+ data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
+ E1000_NVM_RW_REG_DATA);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_spi - Write to EEPROM using SPI
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * Writes data to EEPROM at offset using SPI interface.
+ *
+ * If e1000_update_nvm_checksum is not called after this function , the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+INT32 e1000_write_nvm_spi(struct e1000_hw *hw, UINT16 offset, UINT16 words, UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ INT32 ret_val;
+ UINT16 widx = 0;
+
+ DEBUGFUNC("e1000_write_nvm_spi");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ ret_val = nvm->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ while (widx < words) {
+ UINT8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val)
+ goto release;
+
+ e1000_standby_nvm(hw);
+
+ /* Send the WRITE ENABLE command (8 bit opcode) */
+ e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+ nvm->opcode_bits);
+
+ e1000_standby_nvm(hw);
+
+ /*
+ * Some SPI eeproms use the 8th address bit embedded in the
+ * opcode
+ */
+ if ((nvm->address_bits == 8) && (offset >= 128))
+ write_opcode |= NVM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+ e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (UINT16)((offset + widx) * 2),
+ nvm->address_bits);
+
+ /* Loop to allow for up to whole page write of eeprom */
+ while (widx < words) {
+ UINT16 word_out = data[widx];
+ word_out = (word_out >> 8) | (word_out << 8);
+ e1000_shift_out_eec_bits(hw, word_out, 16);
+ widx++;
+
+ if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+ e1000_standby_nvm(hw);
+ break;
+ }
+ }
+ }
+
+ msec_delay(10);
+release:
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_MICROWIRE_SUPPORT
+/**
+ * e1000_write_nvm_microwire - Writes EEPROM using microwire
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * Writes data to EEPROM at offset using microwire interface.
+ *
+ * If e1000_update_nvm_checksum is not called after this function , the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+INT32 e1000_write_nvm_microwire(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ INT32 ret_val;
+ UINT32 eecd;
+ UINT16 words_written = 0;
+ UINT16 widx = 0;
+
+ DEBUGFUNC("e1000_write_nvm_microwire");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ ret_val = nvm->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val)
+ goto release;
+
+ e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE,
+ (UINT16)(nvm->opcode_bits + 2));
+
+ e1000_shift_out_eec_bits(hw, 0, (UINT16)(nvm->address_bits - 2));
+
+ e1000_standby_nvm(hw);
+
+ while (words_written < words) {
+ e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE,
+ nvm->opcode_bits);
+
+ e1000_shift_out_eec_bits(hw, (UINT16)(offset + words_written),
+ nvm->address_bits);
+
+ e1000_shift_out_eec_bits(hw, data[words_written], 16);
+
+ e1000_standby_nvm(hw);
+
+ for (widx = 0; widx < 200; widx++) {
+ eecd = E1000_READ_REG(hw, E1000_EECD);
+ if (eecd & E1000_EECD_DO)
+ break;
+ usec_delay(50);
+ }
+
+ if (widx == 200) {
+ DEBUGOUT("NVM Write did not complete\n");
+ ret_val = -E1000_ERR_NVM;
+ goto release;
+ }
+
+ e1000_standby_nvm(hw);
+
+ words_written++;
+ }
+
+ e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE,
+ (UINT16)(nvm->opcode_bits + 2));
+
+ e1000_shift_out_eec_bits(hw, 0, (UINT16)(nvm->address_bits - 2));
+
+release:
+ nvm->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+#endif /* NO_MICROWIRE_SUPPORT */
+/**
+ * e1000_read_pba_string_generic - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ **/
+INT32 e1000_read_pba_string_generic(struct e1000_hw *hw, UINT8 *pba_num,
+ UINT32 pba_num_size)
+{
+ INT32 ret_val;
+ UINT16 nvm_data;
+ UINT16 pba_ptr;
+ UINT16 offset;
+ UINT16 length;
+
+ DEBUGFUNC("e1000_read_pba_string_generic");
+
+ if (pba_num == NULL) {
+ DEBUGOUT("PBA string buffer was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ /*
+ * if nvm_data is not ptr guard the PBA must be in legacy format which
+ * means pba_ptr is actually our second data word for the PBA number
+ * and we can decode it into an ascii string
+ */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ DEBUGOUT("NVM PBA number is not stored as string\n");
+
+ /* we will need 11 characters to store the PBA */
+ if (pba_num_size < 11) {
+ DEBUGOUT("PBA string buffer too small\n");
+ return E1000_ERR_NO_SPACE;
+ }
+
+ /* extract hex string from data and pba_ptr */
+ pba_num[0] = (nvm_data >> 12) & 0xF;
+ pba_num[1] = (nvm_data >> 8) & 0xF;
+ pba_num[2] = (nvm_data >> 4) & 0xF;
+ pba_num[3] = nvm_data & 0xF;
+ pba_num[4] = (pba_ptr >> 12) & 0xF;
+ pba_num[5] = (pba_ptr >> 8) & 0xF;
+ pba_num[6] = '-';
+ pba_num[7] = 0;
+ pba_num[8] = (pba_ptr >> 4) & 0xF;
+ pba_num[9] = pba_ptr & 0xF;
+
+ /* put a null character on the end of our string */
+ pba_num[10] = '\0';
+
+ /* switch all the data but the '-' to hex char */
+ for (offset = 0; offset < 10; offset++) {
+ if (pba_num[offset] < 0xA)
+ pba_num[offset] += '0';
+ else if (pba_num[offset] < 0x10)
+ pba_num[offset] += 'A' - 0xA;
+ }
+
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ DEBUGOUT("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+ /* check if pba_num buffer is big enough */
+ if (pba_num_size < (((UINT32)length * 2) - 1)) {
+ DEBUGOUT("PBA string buffer too small\n");
+ ret_val = E1000_ERR_NO_SPACE;
+ goto out;
+ }
+
+ /* trim pba length from start of string */
+ pba_ptr++;
+ length--;
+
+ for (offset = 0; offset < length; offset++) {
+ ret_val = hw->nvm.ops.read(hw, pba_ptr + offset, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+ pba_num[offset * 2] = (UINT8)(nvm_data >> 8);
+ pba_num[(offset * 2) + 1] = (UINT8)(nvm_data & 0xFF);
+ }
+ pba_num[offset * 2] = '\0';
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_pba_length_generic - Read device part number length
+ * @hw: pointer to the HW structure
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number length from the EEPROM and
+ * stores the value in pba_num_size.
+ **/
+INT32 e1000_read_pba_length_generic(struct e1000_hw *hw, UINT32 *pba_num_size)
+{
+ INT32 ret_val;
+ UINT16 nvm_data;
+ UINT16 pba_ptr;
+ UINT16 length;
+
+ DEBUGFUNC("e1000_read_pba_length_generic");
+
+ if (pba_num_size == NULL) {
+ DEBUGOUT("PBA buffer size was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ /* if data is not ptr guard the PBA must be in legacy format */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ *pba_num_size = 11;
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ DEBUGOUT("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+
+ /*
+ * Convert from length in UINT16 values to UINT8 chars, add 1 for NULL,
+ * and subtract 2 because length field is included in length.
+ */
+ *pba_num_size = ((UINT32)length * 2) - 1;
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+/**
+ * e1000_read_pba_num_generic - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ **/
+INT32 e1000_read_pba_num_generic(struct e1000_hw *hw, UINT32 *pba_num)
+{
+ INT32 ret_val;
+ UINT16 nvm_data;
+
+ DEBUGFUNC("e1000_read_pba_num_generic");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ } else if (nvm_data == NVM_PBA_PTR_GUARD) {
+ DEBUGOUT("NVM Not Supported\n");
+ ret_val = E1000_NOT_IMPLEMENTED;
+ goto out;
+ }
+ *pba_num = (UINT32)(nvm_data << 16);
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+ *pba_num |= nvm_data;
+
+out:
+ return ret_val;
+}
+
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+/**
+ * e1000_read_mac_addr_generic - Read device MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the device MAC address from the EEPROM and stores the value.
+ * Since devices with two ports use the same EEPROM, we increment the
+ * last bit in the MAC address for the second port.
+ **/
+INT32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
+{
+ UINT32 rar_high;
+ UINT32 rar_low;
+ UINT16 i;
+
+ rar_high = E1000_READ_REG(hw, E1000_RAH(0));
+ rar_low = E1000_READ_REG(hw, E1000_RAL(0));
+
+ for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i] = (UINT8)(rar_low >> (i*8));
+
+ for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i+4] = (UINT8)(rar_high >> (i*8));
+
+ for (i = 0; i < ETH_ADDR_LEN; i++)
+ hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_validate_nvm_checksum_generic - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+INT32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 checksum = 0;
+ UINT16 i, nvm_data;
+
+ DEBUGFUNC("e1000_validate_nvm_checksum_generic");
+
+ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+
+ if (checksum != (UINT16) NVM_SUM) {
+ DEBUGOUT("NVM Checksum Invalid\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_generic - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+INT32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 checksum = 0;
+ UINT16 i, nvm_data;
+
+ DEBUGFUNC("e1000_update_nvm_checksum");
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error while updating checksum.\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (UINT16) NVM_SUM - checksum;
+ ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
+ if (ret_val)
+ DEBUGOUT("NVM Write Error while updating checksum.\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_reload_nvm_generic - Reloads EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ * extended control register.
+ **/
+STATIC void e1000_reload_nvm_generic(struct e1000_hw *hw)
+{
+ UINT32 ctrl_ext;
+
+ DEBUGFUNC("e1000_reload_nvm_generic");
+
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h
new file mode 100755
index 0000000..56f497b
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_nvm.h
@@ -0,0 +1,75 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_NVM_H_
+#define _E1000_NVM_H_
+
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw);
+#ifndef NO_NULL_OPS_SUPPORT
+INT32 e1000_null_read_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c);
+void e1000_null_nvm_generic(struct e1000_hw *hw);
+INT32 e1000_null_led_default(struct e1000_hw *hw, UINT16 *data);
+INT32 e1000_null_write_nvm(struct e1000_hw *hw, UINT16 a, UINT16 b, UINT16 *c);
+#endif /* NO_NULL_OPS_SUPPORT */
+INT32 e1000_acquire_nvm_generic(struct e1000_hw *hw);
+
+INT32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+INT32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+#ifndef NO_PBA_NUM_ONLY_SUPPORT
+INT32 e1000_read_pba_num_generic(struct e1000_hw *hw, UINT32 *pba_num);
+#endif /* NO_PBA_NUM_ONLY_SUPPORT */
+INT32 e1000_read_pba_string_generic(struct e1000_hw *hw, UINT8 *pba_num,
+ UINT32 pba_num_size);
+INT32 e1000_read_pba_length_generic(struct e1000_hw *hw, UINT32 *pba_num_size);
+#ifndef NO_MICROWIRE_SUPPORT
+INT32 e1000_read_nvm_microwire(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+#endif
+INT32 e1000_read_nvm_eerd(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data);
+INT32 e1000_valid_led_default_generic(struct e1000_hw *hw, UINT16 *data);
+INT32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw);
+INT32 e1000_write_nvm_eewr(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+#ifndef NO_MICROWIRE_SUPPORT
+INT32 e1000_write_nvm_microwire(struct e1000_hw *hw, UINT16 offset,
+ UINT16 words, UINT16 *data);
+#endif
+INT32 e1000_write_nvm_spi(struct e1000_hw *hw, UINT16 offset, UINT16 words,
+ UINT16 *data);
+INT32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw);
+void e1000_release_nvm_generic(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE 0xDB00
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c
new file mode 100755
index 0000000..b81eab2
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.c
@@ -0,0 +1,693 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+
+INT32
+e1000_read_pcie_cap_reg(
+ struct e1000_hw *hw,
+ UINT32 reg,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ Reads from the PCI capabality region.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ reg - The register offset within the cap region.
+ value - The value at the register offset.
+
+Returns:
+ Error code
+
+--*/
+{
+ // Start at the first cap pointer of PCI space
+ UINT16 next_ptr_offset = PCI_CAP_PTR;
+ UINT16 next_ptr_value = 0;
+
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Keep only the first byte of the returned value
+ next_ptr_value &= 0xFF;
+ // Traverse the capabilities linked regions until the end
+ while (next_ptr_value != PCI_CAP_PTR_ENDPOINT)
+ {
+ next_ptr_offset = next_ptr_value;
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Check if we found the requested capabilities region
+ if ((next_ptr_value & 0xFF) != PCI_EX_CAP_ID)
+ {
+ // Jump to the next capabilities region
+ next_ptr_value &= 0xFF00;
+ next_ptr_value = next_ptr_value >> 8;
+ next_ptr_value &= 0xFF;
+ }
+ else
+ {
+ // Read the value from the request offset
+ e1000_read_pci_cfg(hw, next_ptr_offset + reg, &next_ptr_value);
+ *value = next_ptr_value;
+ return E1000_SUCCESS;
+ }
+ }
+ // The requested region was not found in PCI space
+ DEBUGPRINT(IO, ("Cap ID 0x10 was not found in PCI space.\n"));
+ return E1000_ERR_CONFIG;
+}
+
+#ifndef NO_PCIE_SUPPORT
+INT32
+e1000_write_pcie_cap_reg(
+ struct e1000_hw *hw,
+ UINT32 reg,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ Writes into the PCI capabality region.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ reg - The register offset within the cap region.
+ value - The value at the register offset.
+
+Returns:
+ Error code
+
+--*/
+{
+ // Start at the first cap pointer of PCI space
+ UINT16 next_ptr_offset = PCI_CAP_PTR;
+ UINT16 next_ptr_value = 0;
+
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Keep only the first byte of the returned value
+ next_ptr_value &= 0xFF;
+ // Traverse the capabilities linked regions until the end
+ while (next_ptr_value != PCI_CAP_PTR_ENDPOINT)
+ {
+ next_ptr_offset = next_ptr_value;
+ e1000_read_pci_cfg(hw, next_ptr_offset, &next_ptr_value);
+ // Check if we found the requested capabilities region
+ if ((next_ptr_value & 0xFF) != PCI_EX_CAP_ID)
+ {
+ // Jump to the next capabilities region
+ next_ptr_value &= 0xFF00;
+ next_ptr_value = next_ptr_value >> 8;
+ next_ptr_value &= 0xFF;
+ }
+ else
+ {
+ // Write the value from the request offset
+ e1000_write_pci_cfg(hw, next_ptr_offset + reg, value);
+ return E1000_SUCCESS;
+ }
+ }
+ // The requested region was not found in PCI space
+ DEBUGPRINT(IO, ("Cap ID 0x10 was not found in PCI space.\n"));
+ return E1000_ERR_CONFIG;
+}
+#endif
+
+VOID
+e1000_write_reg_io(
+ struct e1000_hw *hw,
+ UINT32 offset,
+ UINT32 value
+ )
+/*++
+
+Routine Description:
+ Writes a value to one of the devices registers using port I/O (as opposed to
+ memory mapped I/O). Only 82544 and newer devices support port I/O.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ offset - The register offset to write.
+ value - The value to write to the register.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+
+ DEBUGPRINT(IO, ("e1000_write_reg_io\n"));
+ DEBUGPRINT(IO, ("IO bAR INDEX = %d\n", Adapter->IoBarIndex));
+ DEBUGWAIT(IO);
+
+ MemoryFence ();
+ Adapter->PciIo->Io.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ Adapter->IoBarIndex,
+ 0, // IO location offset
+ 1,
+ (VOID *) (&offset)
+ );
+ MemoryFence ();
+ Adapter->PciIo->Io.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ Adapter->IoBarIndex,
+ 4, // IO data offset
+ 1,
+ (VOID *) (&value)
+ );
+ MemoryFence ();
+ return;
+}
+
+VOID
+e1000_read_pci_cfg (
+ struct e1000_hw *hw,
+ UINT32 port,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ This function calls the EFI PCI IO protocol to read a value from the device's PCI
+ register space.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ Port - Which register to read from.
+ value - Returns the value read from the PCI register.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Pci.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ port,
+ 1,
+ (VOID *) value
+ );
+ MemoryFence ();
+ return ;
+}
+
+VOID
+e1000_write_pci_cfg (
+ struct e1000_hw *hw,
+ UINT32 port,
+ UINT16 *value
+ )
+/*++
+
+Routine Description:
+ This function calls the EFI PCI IO protocol to write a value to the device's PCI
+ register space.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+ Port - Which register to write to.
+ value - Value to write to the PCI register.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Pci.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ port,
+ 1,
+ (VOID *) value
+ );
+ MemoryFence ();
+
+ return ;
+}
+
+VOID
+DelayInMicroseconds (
+ IN GIG_DRIVER_DATA *Adapter,
+ UINTN MicroSeconds
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+ AdapterInfo - Pointer to the NIC data structure information
+ which the UNDI driver is layering on..
+ MicroSeconds - Time to delay in Microseconds.
+
+Returns:
+
+--*/
+{
+ if (Adapter->Delay != NULL) {
+ (*Adapter->Delay) (Adapter->Unique_ID, MicroSeconds);
+ } else {
+ gBS->Stall(MicroSeconds);
+ }
+}
+
+VOID
+uSecDelay (
+ struct e1000_hw *hw,
+ UINTN usecs
+ )
+/*++
+
+Routine Description:
+ Delay a specified number of microseconds.
+
+Arguments:
+ hw - Pointer to hardware instance.
+ usecs - Number of microseconds to delay
+
+--*/
+{
+ DelayInMicroseconds(hw->back, usecs);
+}
+
+UINT32
+e1000_InDword (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+{
+ UINT32 Results;
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Mem.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ Port,
+ 1,
+ (VOID *) (&Results)
+ );
+ MemoryFence ();
+ return Results;
+}
+
+VOID
+e1000_OutDword (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+{
+ UINT32 Value;
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+ Value = Data;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Mem.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ Port,
+ 1,
+ (VOID *) (&Value)
+ );
+
+ MemoryFence ();
+ return ;
+}
+
+UINT32
+e1000_FlashRead (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+{
+ UINT32 Results;
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Mem.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Results)
+ );
+ MemoryFence ();
+ return Results;
+}
+
+
+UINT16
+e1000_FlashRead16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to read a dword from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Port - Which port to read from.
+
+Returns:
+ Results - The data read from the port.
+
+--*/
+{
+ UINT16 Results;
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Mem.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Results)
+ );
+ MemoryFence ();
+ return Results;
+}
+
+
+VOID
+e1000_FlashWrite (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ hw - Pointer to hardware instance.
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+{
+ UINT32 Value;
+ GIG_DRIVER_DATA *Adapter;
+
+ Adapter = hw->back;
+ Value = Data;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Mem.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint32,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Value)
+ );
+
+ MemoryFence ();
+ return ;
+}
+
+VOID
+e1000_FlashWrite16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT16 Data
+ )
+/*++
+
+Routine Description:
+ This function calls the MemIo callback to write a word from the device's
+ address space
+ Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
+ which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
+ to make undi3.0 a special case
+
+Arguments:
+ Data - Data to write to Port.
+ Port - Which port to write to.
+
+Returns:
+ none
+
+--*/
+{
+ GIG_DRIVER_DATA *GigAdapter;
+
+ GigAdapter = hw->back;
+
+ MemoryFence ();
+
+ GigAdapter->PciIo->Mem.Write (
+ GigAdapter->PciIo,
+ EfiPciIoWidthUint16,
+ 1,
+ Port,
+ 1,
+ (VOID *) (&Data)
+ );
+
+ MemoryFence ();
+ return ;
+}
+
+VOID
+e1000_PciFlush (
+ IN struct e1000_hw *hw
+ )
+/*++
+
+Routine Description:
+ Flushes a PCI write transaction to system memory.
+
+Arguments:
+ hw - Pointer to hardware structure.
+
+Returns:
+ none
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ Adapter = hw->back;
+
+ MemoryFence ();
+
+ Adapter->PciIo->Flush (Adapter->PciIo);
+
+ MemoryFence ();
+
+ return ;
+}
+
+VOID
+e1000_pci_set_mwi (
+ struct e1000_hw *hw
+ )
+/*++
+
+Routine Description:
+ Sets the memory write and invalidate bit in the device's PCI command register.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ UINT32 CommandReg;
+
+ Adapter = hw->back;
+
+ MemoryFence ();
+ Adapter->PciIo->Pci.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+
+ CommandReg |= PCI_COMMAND_MWI;
+
+ Adapter->PciIo->Pci.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+ MemoryFence ();
+
+ return ;
+}
+
+VOID
+e1000_pci_clear_mwi (
+ struct e1000_hw *hw
+ )
+/*++
+
+Routine Description:
+ Clears the memory write and invalidate bit in the device's PCI command register.
+
+Arguments:
+ hw - Pointer to the shared code hw structure.
+
+Returns:
+ VOID
+
+--*/
+{
+ GIG_DRIVER_DATA *Adapter;
+ UINT32 CommandReg;
+
+ Adapter = hw->back;
+
+ Adapter->PciIo->Pci.Read (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+
+ CommandReg &= ~PCI_COMMAND_MWI;
+
+ Adapter->PciIo->Pci.Write (
+ Adapter->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ (VOID *) (&CommandReg)
+ );
+
+ return ;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h
new file mode 100755
index 0000000..39cda7e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_osdep.h
@@ -0,0 +1,180 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_OSDEP_H_
+#define _E1000_OSDEP_H_
+
+#ifndef EFI_SPECIFICATION_VERSION
+#define EFI_SPECIFICATION_VERSION 0x00020000
+#endif
+
+#ifndef TIANO_RELEASE_VERSION
+#define TIANO_RELEASE_VERSION 0x00080005
+#endif
+
+struct e1000_hw;
+
+UINT32
+e1000_InDword (
+ struct e1000_hw *hw,
+ UINT32 Port
+ );
+
+VOID
+e1000_OutDword (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ );
+
+UINT32
+e1000_FlashRead (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ );
+
+UINT16
+e1000_FlashRead16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port
+ );
+
+VOID
+e1000_FlashWrite (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT32 Data
+ );
+
+VOID
+e1000_FlashWrite16 (
+ IN struct e1000_hw *hw,
+ IN UINT32 Port,
+ IN UINT16 Data
+ );
+
+VOID
+e1000_PciFlush (
+ struct e1000_hw *hw
+ );
+
+VOID
+uSecDelay (
+ struct e1000_hw *hw,
+ UINTN usecs
+ );
+
+VOID
+e1000_write_reg_io(
+ struct e1000_hw *hw,
+ UINT32 offset,
+ UINT32 value
+ );
+
+
+#define usec_delay(x) uSecDelay(hw, x)
+#define msec_delay(x) uSecDelay(hw, x*1000)
+#define msec_delay_irq(x) uSecDelay(hw, x*1000)
+#define memset(Buffer, Value, BufferLength) SetMem (Buffer, BufferLength, Value)
+
+#define CMD_MEM_WRT_INVALIDATE EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE
+
+typedef BOOLEAN BOOLEANean_t;
+
+
+#if (0)
+#define DEBUGFUNC(F)
+#define DEBUGOUT(s) Aprint(s);
+#define DEBUGOUT1(s,a) Aprint(s,a);
+#define DEBUGOUT2(s,a,b) Aprint(s,a,b);
+#define DEBUGOUT3(s,a,b,c) Aprint(s,a,b,c);
+#define DEBUGOUT7(s,a,b,c,d,e,f,g) Aprint(s,a,b,c,d,e,f,g);
+#else
+#define DEBUGFUNC(F)
+#define DEBUGOUT(s)
+#define DEBUGOUT1(s,a)
+#define DEBUGOUT2(s,a,b)
+#define DEBUGOUT3(s,a,b,c)
+#define DEBUGOUT7(s,a,b,c,d,e,f,g)
+#endif
+
+
+#define E1000_WRITE_REG(a, reg, value) \
+ e1000_OutDword(a, (UINT32)(reg), value)
+
+#define E1000_READ_REG(a, reg) \
+ e1000_InDword(a, (UINT32)(reg)) \
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+ e1000_OutDword(a, (UINT32)(reg + ((offset) << 2)), value)
+
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) \
+ e1000_OutDword(a, (UINT32)(reg + ((offset) << 2)), value) \
+
+#define E1000_WRITE_REG_ARRAY_DWORD(a, reg, offset, value) \
+ e1000_OutDword(a, (UINT32)(reg + ((offset) << 2)), value) \
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
+ e1000_InDword(a, (UINT32)(reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) \
+ e1000_InDword(a, (UINT32)(reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_DWORD(a, reg, offset) \
+ e1000_InDword(a, (UINT32)(reg + ((offset) << 2)))
+
+#define E1000_WRITE_FLUSH(a) e1000_PciFlush(a);
+
+#define E1000_WRITE_REG_IO(a, reg, value) \
+ e1000_write_reg_io(a, (UINT32) (reg), value)
+
+#define E1000_READ_FLASH_REG(a, reg) \
+ e1000_FlashRead(a, (UINT32)(reg))
+
+#define E1000_WRITE_FLASH_REG(a, reg, data) \
+ e1000_FlashWrite(a, (UINT32)(reg), data)
+
+#define E1000_READ_FLASH_REG16(a, reg) \
+ e1000_FlashRead16(a, (UINT32)(reg))
+
+#define E1000_WRITE_FLASH_REG16(a, reg, data) \
+ e1000_FlashWrite16(a, (UINT32)(reg), data)
+
+#define E1000_MUTEX UINT8
+#define E1000_MUTEX_INIT(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_DESTROY(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_LOCK(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_TRYLOCK(mutex) UNREFERENCED_1PARAMETER(mutex)
+#define E1000_MUTEX_UNLOCK(mutex) UNREFERENCED_1PARAMETER(mutex)
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c
new file mode 100755
index 0000000..272fc3c
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.c
@@ -0,0 +1,3579 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000_api.h"
+
+STATIC INT32 e1000_copper_link_autoneg(struct e1000_hw *hw);
+STATIC INT32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
+static UINT32 e1000_get_phy_addr_for_bm_page(UINT32 page, UINT32 reg);
+STATIC INT32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read);
+STATIC UINT32 e1000_get_phy_addr_for_hv_page(UINT32 page);
+STATIC INT32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read);
+
+/* Cable length tables */
+static const UINT16 e1000_m88_cable_length_table[] =
+ { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_m88_cable_length_table) / \
+ sizeof(e1000_m88_cable_length_table[0]))
+
+static const UINT16 e1000_igp_2_cable_length_table[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+ 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+ 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+ 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+ 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+ 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+ 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+ 104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_igp_2_cable_length_table) / \
+ sizeof(e1000_igp_2_cable_length_table[0]))
+
+#ifndef NO_NULL_OPS_SUPPORT
+/**
+ * e1000_init_phy_ops_generic - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Setups up the function pointers to no-op functions
+ **/
+void e1000_init_phy_ops_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ DEBUGFUNC("e1000_init_phy_ops_generic");
+
+ /* Initialize function pointers */
+ phy->ops.init_params = e1000_null_ops_generic;
+ phy->ops.acquire = e1000_null_ops_generic;
+ phy->ops.check_polarity = e1000_null_ops_generic;
+ phy->ops.check_reset_block = e1000_null_ops_generic;
+ phy->ops.commit = e1000_null_ops_generic;
+ phy->ops.force_speed_duplex = e1000_null_ops_generic;
+ phy->ops.get_cfg_done = e1000_null_ops_generic;
+ phy->ops.get_cable_length = e1000_null_ops_generic;
+ phy->ops.get_info = e1000_null_ops_generic;
+ phy->ops.read_reg = e1000_null_read_reg;
+ phy->ops.read_reg_locked = e1000_null_read_reg;
+ phy->ops.release = e1000_null_phy_generic;
+ phy->ops.reset = e1000_null_ops_generic;
+ phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
+ phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
+ phy->ops.write_reg = e1000_null_write_reg;
+ phy->ops.write_reg_locked = e1000_null_write_reg;
+ phy->ops.power_up = e1000_null_phy_generic;
+ phy->ops.power_down = e1000_null_phy_generic;
+#ifndef NO_80003ES2LAN_SUPPORT
+ phy->ops.cfg_on_link_up = e1000_null_ops_generic;
+#endif
+}
+
+/**
+ * e1000_null_read_reg - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_read_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ DEBUGFUNC("e1000_null_read_reg");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_phy_generic - No-op function, return void
+ * @hw: pointer to the HW structure
+ **/
+void e1000_null_phy_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_null_phy_generic");
+ return;
+}
+
+/**
+ * e1000_null_lplu_state - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_lplu_state(struct e1000_hw *hw, BOOLEAN active)
+{
+ DEBUGFUNC("e1000_null_lplu_state");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_null_write_reg - No-op function, return 0
+ * @hw: pointer to the HW structure
+ **/
+INT32 e1000_null_write_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ DEBUGFUNC("e1000_null_write_reg");
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_NULL_OPS_SUPPORT */
+/**
+ * e1000_check_reset_block_generic - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Read the PHY management control register and check whether a PHY reset
+ * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise
+ * return E1000_BLK_PHY_RESET (12).
+ **/
+INT32 e1000_check_reset_block_generic(struct e1000_hw *hw)
+{
+ UINT32 manc;
+
+ DEBUGFUNC("e1000_check_reset_block");
+
+ manc = E1000_READ_REG(hw, E1000_MANC);
+
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_phy_id - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+INT32 e1000_get_phy_id(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_id;
+ UINT16 retry_count = 0;
+
+ DEBUGFUNC("e1000_get_phy_id");
+
+ if (!(phy->ops.read_reg))
+ goto out;
+
+ while (retry_count < 2) {
+ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id = (UINT32)(phy_id << 16);
+ usec_delay(20);
+ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id |= (UINT32)(phy_id & PHY_REVISION_MASK);
+ phy->revision = (UINT32)(phy_id & ~PHY_REVISION_MASK);
+
+ if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
+ goto out;
+
+ retry_count++;
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_reset_dsp_generic - Reset PHY DSP
+ * @hw: pointer to the HW structure
+ *
+ * Reset the digital signal processor.
+ **/
+INT32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_phy_reset_dsp_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.write_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_mdic - Read MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control register in the PHY at offset and stores the
+ * information read to data.
+ **/
+INT32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, mdic = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_phy_reg_mdic");
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /*
+ * Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+ /* Workaround for Si errata */
+ if ((hw->phy.type == e1000_phy_82577) && (hw->revision_id <= 2))
+ msec_delay(10);
+
+ /*
+ * Poll the ready bit to see if the MDI read completed
+ * Increasing the time out as testing showed failures with
+ * the lower time out
+ */
+ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+ usec_delay(50);
+ mdic = E1000_READ_REG(hw, E1000_MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Read did not complete\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+ *data = (UINT16) mdic;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_mdic - Write MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ **/
+INT32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, mdic = 0;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_phy_reg_mdic");
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /*
+ * Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = (((UINT32)data) |
+ (offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+ /* Workaround for Si errata */
+ if ((hw->phy.type == e1000_phy_82577) && (hw->revision_id <= 2))
+ msec_delay(10);
+
+ /*
+ * Poll the ready bit to see if the MDI read completed
+ * Increasing the time out as testing showed failures with
+ * the lower time out
+ */
+ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+ usec_delay(50);
+ mdic = E1000_READ_REG(hw, E1000_MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Write did not complete\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+#ifndef NO_82575_SUPPORT
+/**
+ * e1000_read_phy_reg_i2c - Read PHY register using i2c
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the i2c interface and stores the
+ * retrieved information in data.
+ **/
+INT32 e1000_read_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, i2ccmd = 0;
+
+ DEBUGFUNC("e1000_read_phy_reg_i2c");
+
+ /*
+ * Set up Op-code, Phy Address, and register address in the I2CCMD
+ * register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ (E1000_I2CCMD_OPCODE_READ));
+
+ E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit to see if the I2C read completed */
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ usec_delay(50);
+ i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+ if (i2ccmd & E1000_I2CCMD_READY)
+ break;
+ }
+ if (!(i2ccmd & E1000_I2CCMD_READY)) {
+ DEBUGOUT("I2CCMD Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (i2ccmd & E1000_I2CCMD_ERROR) {
+ DEBUGOUT("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Need to byte-swap the 16-bit value. */
+ *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_write_phy_reg_i2c - Write PHY register using i2c
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset using the i2c interface.
+ **/
+INT32 e1000_write_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ UINT32 i, i2ccmd = 0;
+ UINT16 phy_data_swapped;
+
+ DEBUGFUNC("e1000_write_phy_reg_i2c");
+
+ /* Swap the data bytes for the I2C interface */
+ phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+
+ /*
+ * Set up Op-code, Phy Address, and register address in the I2CCMD
+ * register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ E1000_I2CCMD_OPCODE_WRITE |
+ phy_data_swapped);
+
+ E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit to see if the I2C read completed */
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ usec_delay(50);
+ i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+ if (i2ccmd & E1000_I2CCMD_READY)
+ break;
+ }
+ if (!(i2ccmd & E1000_I2CCMD_READY)) {
+ DEBUGOUT("I2CCMD Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (i2ccmd & E1000_I2CCMD_ERROR) {
+ DEBUGOUT("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+
+ return E1000_SUCCESS;
+}
+
+#endif /* NO_82575_SUPPORT */
+/**
+ * e1000_read_phy_reg_m88 - Read m88 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+INT32 e1000_read_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_phy_reg_m88");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_m88 - Write m88 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_phy_reg_m88");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * __e1000_read_phy_reg_igp - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and stores the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+static INT32 __e1000_read_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 *data,
+ BOOLEAN locked)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("__e1000_read_phy_reg_igp");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (UINT16)offset);
+ if (ret_val)
+ goto release;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+release:
+ if (!locked)
+ hw->phy.ops.release(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_igp - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset and stores the
+ * retrieved information in data.
+ * Release the acquired semaphore before exiting.
+ **/
+INT32 e1000_read_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_igp(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_read_phy_reg_igp_locked - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data. Assumes semaphore already acquired.
+ **/
+INT32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_igp(hw, offset, data, TRUE);
+}
+
+/**
+ * e1000_write_phy_reg_igp - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+static INT32 __e1000_write_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 data,
+ BOOLEAN locked)
+{
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_phy_reg_igp");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (UINT16)offset);
+ if (ret_val)
+ goto release;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+release:
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_igp - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_igp(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_write_phy_reg_igp_locked - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset.
+ * Assumes semaphore already acquired.
+ **/
+INT32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_igp(hw, offset, data, TRUE);
+}
+
+/**
+ * __e1000_read_kmrn_reg - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary. Then reads the PHY register at offset
+ * using the kumeran interface. The information retrieved is stored in data.
+ * Release any acquired semaphores before exiting.
+ **/
+static INT32 __e1000_read_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data,
+ BOOLEAN locked)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("__e1000_read_kmrn_reg");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
+ *data = (UINT16)kmrnctrlsta;
+
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_kmrn_reg_generic - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset using the
+ * kumeran interface. The information retrieved is stored in data.
+ * Release the acquired semaphore before exiting.
+ **/
+INT32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_kmrn_reg(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_read_kmrn_reg_locked - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the kumeran interface. The
+ * information retrieved is stored in data.
+ * Assumes semaphore already acquired.
+ **/
+INT32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_kmrn_reg(hw, offset, data, TRUE);
+}
+
+/**
+ * __e1000_write_kmrn_reg - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary. Then write the data to PHY register
+ * at the offset using the kumeran interface. Release any acquired semaphores
+ * before exiting.
+ **/
+static INT32 __e1000_write_kmrn_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data,
+ BOOLEAN locked)
+{
+ UINT32 kmrnctrlsta;
+ INT32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_kmrn_reg_generic");
+
+ if (!locked) {
+ if (!(hw->phy.ops.acquire))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | data;
+ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+ usec_delay(2);
+
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_write_kmrn_reg_generic - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to the PHY register at the offset
+ * using the kumeran interface. Release the acquired semaphore before exiting.
+ **/
+INT32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_kmrn_reg(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_write_kmrn_reg_locked - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Write the data to PHY register at the offset using the kumeran interface.
+ * Assumes semaphore already acquired.
+ **/
+INT32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_kmrn_reg(hw, offset, data, TRUE);
+}
+
+/**
+ * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up Carrier-sense on Transmit and downshift values.
+ **/
+INT32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_copper_link_setup_82577");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (hw->phy.reset_disable) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+#endif /* NO_PHY_RESET_DISABLE */
+#ifndef NO_82580_SUPPORT
+ if (hw->phy.type == e1000_phy_82580) {
+ ret_val = hw->phy.ops.reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error resetting the PHY.\n");
+ goto out;
+ }
+ }
+
+#endif /* NO_82580_SUPPORT */
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = hw->phy.ops.read_reg(hw, I82577_CFG_REG, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
+
+ /* Enable downshift */
+ phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
+
+ ret_val = hw->phy.ops.write_reg(hw, I82577_CFG_REG, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock
+ * and downshift values are set also.
+ **/
+INT32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+
+ DEBUGFUNC("e1000_copper_link_setup_m88");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (phy->reset_disable) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+#endif /* NO_PHY_RESET_DISABLE */
+
+ /* Enable CRS on Tx. This must be set for half-duplex operation. */
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ /* For BM PHY this bit is downshift enable */
+ if (phy->type == e1000_phy_bm)
+ phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /*
+ * Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (phy->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if (phy->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+ /* Enable downshift on BM (disabled by default) */
+ if (phy->type == e1000_phy_bm)
+ phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
+
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+#ifndef NO_82574_SUPPORT
+ if ((phy->type == e1000_phy_m88) &&
+ (phy->revision < E1000_REVISION_4) &&
+ (phy->id != BME1000_E_PHY_ID_R2)) {
+#else
+ if ((phy->type == e1000_phy_m88) && (phy->revision < E1000_REVISION_4)) {
+#endif /* NO_82574_SUPPORT */
+ /*
+ * Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((phy->revision == E1000_REVISION_2) &&
+ (phy->id == M88E1111_I_PHY_ID)) {
+ /* 82573L PHY - set the downshift counter to 5x. */
+ phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ }
+ ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val)
+ goto out;
+ }
+
+#ifndef NO_82574_SUPPORT
+ if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
+ /* Set PHY page 0, register 29 to 0x0003 */
+ ret_val = phy->ops.write_reg(hw, 29, 0x0003);
+ if (ret_val)
+ goto out;
+
+ /* Set PHY page 0, register 30 to 0x0000 */
+ ret_val = phy->ops.write_reg(hw, 30, 0x0000);
+ if (ret_val)
+ goto out;
+ }
+
+#endif /* NO_82574_SUPPORT */
+ /* Commit the changes. */
+ ret_val = phy->ops.commit(hw);
+ if (ret_val) {
+ DEBUGOUT("Error committing the PHY changes\n");
+ goto out;
+ }
+
+ if (phy->type == e1000_phy_82578) {
+ ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ /* 82578 PHY - set the downshift count to 1x. */
+ phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
+ phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
+ ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_setup_igp - Setup igp PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ * igp PHY's.
+ **/
+INT32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_copper_link_setup_igp");
+
+#ifndef NO_PHY_RESET_DISABLE
+ if (phy->reset_disable) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+#endif /* NO_PHY_RESET_DISABLE */
+
+ ret_val = hw->phy.ops.reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error resetting the PHY.\n");
+ goto out;
+ }
+
+ /*
+ * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+ * timeout issues when LFS is enabled.
+ */
+ msec_delay(100);
+
+ /* disable lplu d0 during driver init */
+ if (hw->phy.ops.set_d0_lplu_state) {
+ ret_val = hw->phy.ops.set_d0_lplu_state(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D0\n");
+ goto out;
+ }
+ }
+ /* Configure mdi-mdix settings */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+ switch (phy->mdix) {
+ case 1:
+ data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 2:
+ data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 0:
+ default:
+ data |= IGP01E1000_PSCR_AUTO_MDIX;
+ break;
+ }
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
+ if (ret_val)
+ goto out;
+
+ /* set auto-master slave resolution settings */
+ if (hw->mac.autoneg) {
+ /*
+ * when autonegotiation advertisement is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default.
+ */
+ if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Set auto Master/Slave resolution process */
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~CR_1000T_MS_ENABLE;
+ ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ goto out;
+
+ /* load defaults for future use */
+ phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+ ((data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) :
+ e1000_ms_auto;
+
+ switch (phy->ms_type) {
+ case e1000_ms_force_master:
+ data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ data |= CR_1000T_MS_ENABLE;
+ data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ data &= ~CR_1000T_MS_ENABLE;
+ default:
+ break;
+ }
+ ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Performs initial bounds checking on autoneg advertisement parameter, then
+ * configure to advertise the full capability. Setup the PHY to autoneg
+ * and restart the negotiation process between the link partner. If
+ * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+STATIC INT32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_ctrl;
+
+ DEBUGFUNC("e1000_copper_link_autoneg");
+
+ /*
+ * Perform some bounds checking on the autoneg advertisement
+ * parameter.
+ */
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /*
+ * If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if (phy->autoneg_advertised == 0)
+ phy->autoneg_advertised = phy->autoneg_mask;
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ goto out;
+ }
+ DEBUGOUT("Restarting Auto-Neg\n");
+
+ /*
+ * Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if (phy->autoneg_wait_to_complete) {
+ ret_val = hw->mac.ops.wait_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error while waiting for "
+ "autoneg to complete\n");
+ goto out;
+ }
+ }
+
+ hw->mac.get_link_status = TRUE;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ * @hw: pointer to the HW structure
+ *
+ * Reads the MII auto-neg advertisement register and/or the 1000T control
+ * register and if the PHY is already setup for auto-negotiation, then
+ * return successful. Otherwise, setup advertisement and flow control to
+ * the appropriate values for the wanted auto-negotiation.
+ **/
+STATIC INT32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 mii_autoneg_adv_reg;
+ UINT16 mii_1000t_ctrl_reg = 0;
+
+ DEBUGFUNC("e1000_phy_setup_autoneg");
+
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if (ret_val)
+ goto out;
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
+ &mii_1000t_ctrl_reg);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /*
+ * First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+ NWAY_AR_100TX_HD_CAPS |
+ NWAY_AR_10T_FD_CAPS |
+ NWAY_AR_10T_HD_CAPS);
+ mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+ DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+ DEBUGOUT("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+ DEBUGOUT("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+ DEBUGOUT("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+ DEBUGOUT("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+ DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+ DEBUGOUT("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /*
+ * Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+ * negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->fc.current_mode) {
+ case e1000_fc_none:
+ /*
+ * Flow control (Rx & Tx) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_rx_pause:
+ /*
+ * Rx Flow control is enabled, and Tx Flow control is
+ * disabled, by a software over-ride.
+ *
+ * Since there really isn't a way to advertise that we are
+ * capable of Rx Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric Rx PAUSE. Later
+ * (in e1000_config_fc_after_link_up) we will disable the
+ * hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_tx_pause:
+ /*
+ * Tx Flow control is enabled, and Rx Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case e1000_fc_full:
+ /*
+ * Flow control (both Rx and Tx) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ ret_val = phy->ops.write_reg(hw,
+ PHY_1000T_CTRL,
+ mii_1000t_ctrl_reg);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_setup_copper_link_generic - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Calls the appropriate function to configure the link for auto-neg or forced
+ * speed and duplex. Then we check for link, once link is established calls
+ * to configure collision distance and flow control are called. If link is
+ * not established, we return -E1000_ERR_PHY (-2).
+ **/
+INT32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_setup_copper_link_generic");
+
+ if (hw->mac.autoneg) {
+ /*
+ * Setup autoneg and flow control advertisement and perform
+ * autonegotiation.
+ */
+ ret_val = e1000_copper_link_autoneg(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ /*
+ * PHY will be set to 10H, 10F, 100H or 100F
+ * depending on user settings.
+ */
+ DEBUGOUT("Forcing Speed and Duplex\n");
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Forcing Speed and Duplex\n");
+ goto out;
+ }
+ }
+
+ /*
+ * Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ ret_val = e1000_phy_has_link_generic(hw,
+ COPPER_LINK_UP_LIMIT,
+ 10,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (link) {
+ DEBUGOUT("Valid link established!!!\n");
+ e1000_config_collision_dist_generic(hw);
+ ret_val = e1000_config_fc_after_link_up_generic(hw);
+ } else {
+ DEBUGOUT("Unable to establish link!!!\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Waits for link and returns
+ * successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+INT32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("IGP PSCR: %X\n", phy_data);
+
+ usec_delay(1);
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ DEBUGOUT("Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Resets the PHY to commit the
+ * changes. If time expires while waiting for link up, we reset the DSP.
+ * After reset, TX_CLK and CRS on Tx must be set. Return successful upon
+ * successful completion, else return corresponding error code.
+ **/
+INT32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
+
+ /*
+ * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ /* Reset the phy to commit changes. */
+ ret_val = hw->phy.ops.commit(hw);
+ if (ret_val)
+ goto out;
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ if (hw->phy.type != e1000_phy_m88) {
+ DEBUGOUT("Link taking longer than expected.\n");
+ } else {
+ /*
+ * We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = phy->ops.write_reg(hw,
+ M88E1000_PHY_PAGE_SELECT,
+ 0x001d);
+ if (ret_val)
+ goto out;
+ ret_val = e1000_phy_reset_dsp_generic(hw);
+ if (ret_val)
+ goto out;
+ }
+ }
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ goto out;
+ }
+
+ if (hw->phy.type != e1000_phy_m88)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Resetting the phy means we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock from
+ * the reset value of 2.5MHz.
+ */
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
+ * @hw: pointer to the HW structure
+ *
+ * Forces the speed and duplex settings of the PHY.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+INT32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
+ if (ret_val)
+ goto out;
+
+ /* Disable MDI-X support for 10/100 */
+ ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IFE_PMC_AUTO_MDIX;
+ data &= ~IFE_PMC_FORCE_MDIX;
+
+ ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
+ if (ret_val)
+ goto out;
+
+ DEBUGOUT1("IFE PMC: %X\n", data);
+
+ usec_delay(1);
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
+
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ DEBUGOUT("Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ * @hw: pointer to the HW structure
+ * @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ * Forces speed and duplex on the PHY by doing the following: disable flow
+ * control, force speed/duplex on the MAC, disable auto speed detection,
+ * disable auto-negotiation, configure duplex, configure speed, configure
+ * the collision distance, write configuration to CTRL register. The
+ * caller must write to the PHY_CONTROL register for these settings to
+ * take affect.
+ **/
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, UINT16 *phy_ctrl)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
+
+ /* Turn off flow control when forcing speed/duplex */
+ hw->fc.current_mode = e1000_fc_none;
+
+ /* Force speed/duplex on the mac */
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~E1000_CTRL_SPD_SEL;
+
+ /* Disable Auto Speed Detection */
+ ctrl &= ~E1000_CTRL_ASDE;
+
+ /* Disable autoneg on the phy */
+ *phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Forcing Full or Half Duplex? */
+ if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+ ctrl &= ~E1000_CTRL_FD;
+ *phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Half Duplex\n");
+ } else {
+ ctrl |= E1000_CTRL_FD;
+ *phy_ctrl |= MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ }
+
+ /* Forcing 10mb or 100mb? */
+ if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+ ctrl |= E1000_CTRL_SPD_100;
+ *phy_ctrl |= MII_CR_SPEED_100;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ DEBUGOUT("Forcing 100mb\n");
+ } else {
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ *phy_ctrl |= MII_CR_SPEED_10;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ DEBUGOUT("Forcing 10mb\n");
+ }
+
+ e1000_config_collision_dist_generic(hw);
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+}
+
+/**
+ * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: BOOLEANean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained.
+ **/
+INT32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, BOOLEAN active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_set_d3_lplu_state_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ goto out;
+
+ if (!active) {
+ data &= ~IGP02E1000_PM_D3_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = phy->ops.read_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ goto out;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ data |= IGP02E1000_PM_D3_LPLU;
+ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ goto out;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_downshift_generic - Checks whether a downshift in speed occurred
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * A downshift is detected by querying the PHY link health.
+ **/
+INT32 e1000_check_downshift_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, offset, mask;
+
+ DEBUGFUNC("e1000_check_downshift_generic");
+
+ switch (phy->type) {
+ case e1000_phy_m88:
+ case e1000_phy_gg82563:
+ case e1000_phy_bm:
+ case e1000_phy_82578:
+ offset = M88E1000_PHY_SPEC_STATUS;
+ mask = M88E1000_PSSR_DOWNSHIFT;
+ break;
+ case e1000_phy_igp_2:
+ case e1000_phy_igp_3:
+ offset = IGP01E1000_PHY_LINK_HEALTH;
+ mask = IGP01E1000_PLHR_SS_DOWNGRADE;
+ break;
+ default:
+ /* speed downshift not supported */
+ phy->speed_downgraded = FALSE;
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->speed_downgraded = (phy_data & mask) ? TRUE : FALSE;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_m88 - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY specific status register.
+ **/
+INT32 e1000_check_polarity_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_check_polarity_m88");
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_igp - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY port status register, and the
+ * current speed (since there is no polarity at 100Mbps).
+ **/
+INT32 e1000_check_polarity_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data, offset, mask;
+
+ DEBUGFUNC("e1000_check_polarity_igp");
+
+ /*
+ * Polarity is determined based on the speed of
+ * our connection.
+ */
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ offset = IGP01E1000_PHY_PCS_INIT_REG;
+ mask = IGP01E1000_PHY_POLARITY_MASK;
+ } else {
+ /*
+ * This really only applies to 10Mbps since
+ * there is no polarity for 100Mbps (always 0).
+ */
+ offset = IGP01E1000_PHY_PORT_STATUS;
+ mask = IGP01E1000_PSSR_POLARITY_REVERSED;
+ }
+
+ ret_val = phy->ops.read_reg(hw, offset, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_ife - Check cable polarity for IFE PHY
+ * @hw: pointer to the HW structure
+ *
+ * Polarity is determined on the polarity reversal feature being enabled.
+ **/
+INT32 e1000_check_polarity_ife(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, offset, mask;
+
+ DEBUGFUNC("e1000_check_polarity_ife");
+
+ /*
+ * Polarity is determined based on the reversal feature being enabled.
+ */
+ if (phy->polarity_correction) {
+ offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+ mask = IFE_PESC_POLARITY_REVERSED;
+ } else {
+ offset = IFE_PHY_SPECIAL_CONTROL;
+ mask = IFE_PSC_FORCE_POLARITY;
+ }
+
+ ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->cable_polarity = (phy_data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_wait_autoneg_generic - Wait for auto-neg completion
+ * @hw: pointer to the HW structure
+ *
+ * Waits for auto-negotiation to complete or for the auto-negotiation time
+ * limit to expire, which ever happens first.
+ **/
+INT32 e1000_wait_autoneg_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i, phy_status;
+
+ DEBUGFUNC("e1000_wait_autoneg_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ return E1000_SUCCESS;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+ for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_AUTONEG_COMPLETE)
+ break;
+ msec_delay(100);
+ }
+
+ /*
+ * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+ * has completed.
+ */
+ return ret_val;
+}
+
+/**
+ * e1000_phy_has_link_generic - Polls PHY for link
+ * @hw: pointer to the HW structure
+ * @iterations: number of times to poll for link
+ * @usec_interval: delay between polling attempts
+ * @success: pointer to whether polling was successful or not
+ *
+ * Polls the PHY status register for link, 'iterations' number of times.
+ **/
+INT32 e1000_phy_has_link_generic(struct e1000_hw *hw, UINT32 iterations,
+ UINT32 usec_interval, BOOLEAN *success)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 i, phy_status;
+
+ DEBUGFUNC("e1000_phy_has_link_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ return E1000_SUCCESS;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ for (i = 0; i < iterations; i++) {
+ /*
+ * Some PHYs require the PHY_STATUS register to be read
+ * twice due to the link bit being sticky. No harm doing
+ * it across the board.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ /*
+ * If the first read fails, another entity may have
+ * ownership of the resources, wait and try again to
+ * see if they have relinquished the resources yet.
+ */
+ usec_delay(usec_interval);
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_LINK_STATUS)
+ break;
+ if (usec_interval >= 1000)
+ msec_delay_irq(usec_interval/1000);
+ else
+ usec_delay(usec_interval);
+ }
+
+ *success = (i < iterations) ? TRUE : FALSE;
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_m88 - Determine cable length for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY specific status register to retrieve the cable length
+ * information. The cable length is determined by averaging the minimum and
+ * maximum values to get the "average" cable length. The m88 PHY has four
+ * possible cable length values, which are:
+ * Register Value Cable Length
+ * 0 < 50 meters
+ * 1 50 - 80 meters
+ * 2 80 - 110 meters
+ * 3 110 - 140 meters
+ * 4 > 140 meters
+ **/
+INT32 e1000_get_cable_length_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, index;
+
+ DEBUGFUNC("e1000_get_cable_length_m88");
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ phy->min_cable_length = e1000_m88_cable_length_table[index];
+ phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ * @hw: pointer to the HW structure
+ *
+ * The automatic gain control (agc) normalizes the amplitude of the
+ * received signal, adjusting for the attenuation produced by the
+ * cable. By reading the AGC registers, which represent the
+ * combination of coarse and fine gain value, the value can be put
+ * into a lookup table to obtain the approximate cable length
+ * for each channel.
+ **/
+INT32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_data, i, agc_value = 0;
+ UINT16 cur_agc_index, max_agc_index = 0;
+ UINT16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+ UINT16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+ {IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D};
+
+ DEBUGFUNC("e1000_get_cable_length_igp_2");
+
+ /* Read the AGC registers for all channels */
+ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Getting bits 15:9, which represent the combination of
+ * coarse and fine gain values. The result is a number
+ * that can be put into the lookup table to obtain the
+ * approximate cable length.
+ */
+ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
+
+ /* Array index bound check. */
+ if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+ (cur_agc_index == 0)) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc_index] >
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ min_agc_index = cur_agc_index;
+ if (e1000_igp_2_cable_length_table[max_agc_index] <
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ max_agc_index = cur_agc_index;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+ }
+
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+ e1000_igp_2_cable_length_table[max_agc_index]);
+ agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+ /* Calculate cable length with the error range of +/- 10 meters. */
+ phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_m88 - Retrieve PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Valid for only copper links. Read the PHY status register (sticky read)
+ * to verify that link is up. Read the PHY special control register to
+ * determine the polarity and 10base-T extended distance. Read the PHY
+ * special status register to determine MDI/MDIx and current speed. If
+ * speed is 1000, then determine cable length, local and remote receiver.
+ **/
+INT32 e1000_get_phy_info_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_m88");
+
+ if (phy->media_type != e1000_media_type_copper) {
+ DEBUGOUT("Phy info is only valid for copper media\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+ ? TRUE : FALSE;
+
+ ret_val = e1000_check_polarity_m88(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? TRUE : FALSE;
+
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+ ret_val = hw->phy.ops.get_cable_length(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ /* Set values to "undefined" */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_igp - Retrieve igp PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up. If link is up, then
+ * set/determine 10base-T extended distance and polarity correction. Read
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ **/
+INT32 e1000_get_phy_info_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_igp");
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ phy->polarity_correction = TRUE;
+
+ ret_val = e1000_check_polarity_igp(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? TRUE : FALSE;
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ ret_val = phy->ops.get_cable_length(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_ife - Retrieves various IFE PHY states
+ * @hw: pointer to the HW structure
+ *
+ * Populates "phy" structure with various feature states.
+ **/
+INT32 e1000_get_phy_info_ife(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_ife");
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+ if (ret_val)
+ goto out;
+ phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
+ ? FALSE : TRUE;
+
+ if (phy->polarity_correction) {
+ ret_val = e1000_check_polarity_ife(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ /* Polarity is forced */
+ phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+ }
+
+ ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? TRUE : FALSE;
+
+ /* The following parameters are undefined for 10/100 operation. */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_sw_reset_generic - PHY software reset
+ * @hw: pointer to the HW structure
+ *
+ * Does a software reset of the PHY by reading the PHY control register and
+ * setting/write the control register reset bit to the PHY.
+ **/
+INT32 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 phy_ctrl;
+
+ DEBUGFUNC("e1000_phy_sw_reset_generic");
+
+#ifndef NO_NULL_OPS_SUPPORT
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
+#endif /* NO_NULL_OPS_SUPPORT */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ phy_ctrl |= MII_CR_RESET;
+ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ usec_delay(1);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_phy_hw_reset_generic - PHY hardware reset
+ * @hw: pointer to the HW structure
+ *
+ * Verify the reset block is not blocking us from resetting. Acquire
+ * semaphore (if necessary) and read/set/write the device control reset
+ * bit in the PHY. Wait the appropriate delay time for the device to
+ * reset and release the semaphore (if necessary).
+ **/
+INT32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val = E1000_SUCCESS;
+ UINT32 ctrl;
+
+ DEBUGFUNC("e1000_phy_hw_reset_generic");
+
+ ret_val = phy->ops.check_reset_block(hw);
+ if (ret_val) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+
+ ret_val = phy->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(phy->reset_delay_us);
+
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(150);
+
+ phy->ops.release(hw);
+
+ ret_val = phy->ops.get_cfg_done(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cfg_done_generic - Generic configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Generic function to wait 10 milli-seconds for configuration to complete
+ * and return success.
+ **/
+INT32 e1000_get_cfg_done_generic(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_get_cfg_done_generic");
+
+ msec_delay_irq(10);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_phy_init_script_igp3 - Inits the IGP3 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+INT32 e1000_phy_init_script_igp3(struct e1000_hw *hw)
+{
+ DEBUGOUT("Running IGP 3 PHY init script\n");
+
+ /* PHY init IGP 3 */
+ /* Enable rise/fall, 10-mode work in class-A */
+ hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
+ /* Remove all caps from Replica path filter */
+ hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
+ /* Bias trimming for ADC, AFE and Driver (Default) */
+ hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
+ /* Increase Hybrid poly bias */
+ hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
+ /* Add 4% to Tx amplitude in Gig mode */
+ hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
+ /* Disable trimming (TTT) */
+ hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
+ /* Poly DC correction to 94.6% + 2% for all channels */
+ hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
+ /* ABS DC correction to 95.9% */
+ hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
+ /* BG temp curve trim */
+ hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
+ /* Increasing ADC OPAMP stage 1 currents to max */
+ hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
+ /* Force 1000 ( required for enabling PHY regs configuration) */
+ hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
+ /* Set upd_freq to 6 */
+ hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
+ /* Disable NPDFE */
+ hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
+ /* Disable adaptive fixed FFE (Default) */
+ hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
+ /* Enable FFE hysteresis */
+ hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
+ /* Fixed FFE for short cable lengths */
+ hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
+ /* Fixed FFE for medium cable lengths */
+ hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
+ /* Fixed FFE for long cable lengths */
+ hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
+ /* Enable Adaptive Clip Threshold */
+ hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
+ /* AHT reset limit to 1 */
+ hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
+ /* Set AHT master delay to 127 msec */
+ hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
+ /* Set scan bits for AHT */
+ hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
+ /* Set AHT Preset bits */
+ hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
+ /* Change integ_factor of channel A to 3 */
+ hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
+ /* Change prop_factor of channels BCD to 8 */
+ hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
+ /* Change cg_icount + enable integbp for channels BCD */
+ hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
+ /*
+ * Change cg_icount + enable integbp + change prop_factor_master
+ * to 8 for channel A
+ */
+ hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
+ /* Disable AHT in Slave mode on channel A */
+ hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
+ /*
+ * Enable LPLU and disable AN to 1000 in non-D0a states,
+ * Enable SPD+B2B
+ */
+ hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
+ /* Enable restart AN on an1000_dis change */
+ hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
+ /* Enable wh_fifo read clock in 10/100 modes */
+ hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
+ /* Restart AN, Speed selection is 1000 */
+ hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_get_phy_type_from_id - Get PHY type from id
+ * @phy_id: phy_id read from the phy
+ *
+ * Returns the phy type from the id.
+ **/
+enum e1000_phy_type e1000_get_phy_type_from_id(UINT32 phy_id)
+{
+ enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+ switch (phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1000_E_PHY_ID:
+ case M88E1111_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+ phy_type = e1000_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+ phy_type = e1000_phy_igp_2;
+ break;
+ case GG82563_E_PHY_ID:
+ phy_type = e1000_phy_gg82563;
+ break;
+ case IGP03E1000_E_PHY_ID:
+ phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy_type = e1000_phy_ife;
+ break;
+ case BME1000_E_PHY_ID:
+ case BME1000_E_PHY_ID_R2:
+ phy_type = e1000_phy_bm;
+ break;
+ case I82578_E_PHY_ID:
+ phy_type = e1000_phy_82578;
+ break;
+ case I82577_E_PHY_ID:
+ phy_type = e1000_phy_82577;
+ break;
+ case I82579_E_PHY_ID:
+ phy_type = e1000_phy_82579;
+ break;
+#ifndef NO_82580_SUPPORT
+ case I82580_I_PHY_ID:
+ phy_type = e1000_phy_82580;
+ break;
+#endif /* NO_82580_SUPPORT */
+ default:
+ phy_type = e1000_phy_unknown;
+ break;
+ }
+ return phy_type;
+}
+
+/**
+ * e1000_determine_phy_address - Determines PHY address.
+ * @hw: pointer to the HW structure
+ *
+ * This uses a trial and error method to loop through possible PHY
+ * addresses. It tests each by reading the PHY ID registers and
+ * checking for a match.
+ **/
+INT32 e1000_determine_phy_address(struct e1000_hw *hw)
+{
+ INT32 ret_val = -E1000_ERR_PHY_TYPE;
+ UINT32 phy_addr = 0;
+ UINT32 i;
+ enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+ hw->phy.id = phy_type;
+
+ for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
+ hw->phy.addr = phy_addr;
+ i = 0;
+
+ do {
+ e1000_get_phy_id(hw);
+ phy_type = e1000_get_phy_type_from_id(hw->phy.id);
+
+ /*
+ * If phy_type is valid, break - we found our
+ * PHY address
+ */
+ if (phy_type != e1000_phy_unknown) {
+ ret_val = E1000_SUCCESS;
+ goto out;
+ }
+ msec_delay(1);
+ i++;
+ } while (i < 10);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_addr_for_bm_page - Retrieve PHY page address
+ * @page: page to access
+ *
+ * Returns the phy address for the page requested.
+ **/
+static UINT32 e1000_get_phy_addr_for_bm_page(UINT32 page, UINT32 reg)
+{
+ UINT32 phy_addr = 2;
+
+ if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))
+ phy_addr = 1;
+
+ return phy_addr;
+}
+
+/**
+ * e1000_write_phy_reg_bm - Write BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+ UINT32 page_select = 0;
+ UINT32 page = offset >> IGP_PAGE_SHIFT;
+ UINT32 page_shift = 0;
+
+ DEBUGFUNC("e1000_write_phy_reg_bm");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+ FALSE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /*
+ * Page select is register 31 for phy address 1 and 22 for
+ * phy address 2 and 3. Page select is shifted only for
+ * phy address 1.
+ */
+ if (hw->phy.addr == 1) {
+ page_shift = IGP_PAGE_SHIFT;
+ page_select = IGP01E1000_PHY_PAGE_SELECT;
+ } else {
+ page_shift = 0;
+ page_select = BM_PHY_PAGE_SELECT;
+ }
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select,
+ (page << page_shift));
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_bm - Read BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+INT32 e1000_read_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+ UINT32 page_select = 0;
+ UINT32 page = offset >> IGP_PAGE_SHIFT;
+ UINT32 page_shift = 0;
+
+ DEBUGFUNC("e1000_read_phy_reg_bm");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+ TRUE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /*
+ * Page select is register 31 for phy address 1 and 22 for
+ * phy address 2 and 3. Page select is shifted only for
+ * phy address 1.
+ */
+ if (hw->phy.addr == 1) {
+ page_shift = IGP_PAGE_SHIFT;
+ page_select = IGP01E1000_PHY_PAGE_SELECT;
+ } else {
+ page_shift = 0;
+ page_select = BM_PHY_PAGE_SELECT;
+ }
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, page_select,
+ (page << page_shift));
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+#ifndef NO_82574_SUPPORT
+/**
+ * e1000_read_phy_reg_bm2 - Read BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+INT32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ INT32 ret_val;
+ UINT16 page = (UINT16)(offset >> IGP_PAGE_SHIFT);
+
+ DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+ TRUE);
+ goto out;
+ }
+
+ hw->phy.addr = 1;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+ page);
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_bm2 - Write BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ INT32 ret_val;
+ UINT16 page = (UINT16)(offset >> IGP_PAGE_SHIFT);
+
+ DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+ FALSE);
+ goto out;
+ }
+
+ hw->phy.addr = 1;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+ page);
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+out:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+#endif /* NO_82574_SUPPORT */
+/**
+ * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read or written
+ * @data: pointer to the data to read or write
+ * @read: determines if operation is read or write
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting. Note that procedure to read the wakeup
+ * registers are different. It works as such:
+ * 1) Set page 769, register 17, bit 2 = 1
+ * 2) Set page to 800 for host (801 if we were manageability)
+ * 3) Write the address using the address opcode (0x11)
+ * 4) Read or write the data using the data opcode (0x12)
+ * 5) Restore 769_17.2 to its original value
+ *
+ * Assumes semaphore already acquired.
+ **/
+STATIC INT32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read)
+{
+ INT32 ret_val;
+ UINT16 reg = BM_PHY_REG_NUM(offset);
+ UINT16 phy_reg = 0;
+
+ DEBUGFUNC("e1000_access_phy_wakeup_reg_bm");
+
+ /* Gig must be disabled for MDIO accesses to page 800 */
+ if ((hw->mac.type == e1000_pchlan) &&
+ (!(E1000_READ_REG(hw, E1000_PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
+ DEBUGOUT("Attempting to access page 800 while gig enabled.\n");
+
+ /* All operations in this function are phy address 1 */
+ hw->phy.addr = 1;
+
+ /* Set page 769 */
+ e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+ ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
+ if (ret_val) {
+ DEBUGOUT("Could not read PHY page 769\n");
+ goto out;
+ }
+
+ /* First clear bit 4 to avoid a power state change */
+ phy_reg &= ~(BM_WUC_HOST_WU_BIT);
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+ if (ret_val) {
+ DEBUGOUT("Could not clear PHY page 769 bit 4\n");
+ goto out;
+ }
+
+ /* Write bit 2 = 1, and clear bit 4 to 769_17 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
+ phy_reg | BM_WUC_ENABLE_BIT);
+ if (ret_val) {
+ DEBUGOUT("Could not write PHY page 769 bit 2\n");
+ goto out;
+ }
+
+ /* Select page 800 */
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_PAGE << IGP_PAGE_SHIFT));
+
+ /* Write the page 800 offset value using opcode 0x11 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
+ if (ret_val) {
+ DEBUGOUT("Could not write address opcode to page 800\n");
+ goto out;
+ }
+
+ if (read) {
+ /* Read the page 800 value using opcode 0x12 */
+ ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+ data);
+ } else {
+ /* Write the page 800 value using opcode 0x12 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+ *data);
+ }
+
+ if (ret_val) {
+ DEBUGOUT("Could not access data value from page 800\n");
+ goto out;
+ }
+
+ /*
+ * Restore 769_17.2 to its original value
+ * Set page 769
+ */
+ e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+ /* Clear 769_17.2 */
+ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+ if (ret_val) {
+ DEBUGOUT("Could not clear PHY page 769 bit 2\n");
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_up_phy_copper(struct e1000_hw *hw)
+{
+ UINT16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_down_phy_copper(struct e1000_hw *hw)
+{
+ UINT16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+ msec_delay(1);
+}
+
+/**
+ * __e1000_read_phy_reg_hv - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and stores the retrieved information in data. Release any acquired
+ * semaphore before exiting.
+ **/
+static INT32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 *data,
+ BOOLEAN locked)
+{
+ INT32 ret_val;
+ UINT16 page = BM_PHY_REG_PAGE(offset);
+ UINT16 reg = BM_PHY_REG_NUM(offset);
+
+ DEBUGFUNC("__e1000_read_phy_reg_hv");
+
+ if (!locked) {
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+ data, TRUE);
+ goto out;
+ }
+
+ if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+ ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+ data, TRUE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+ if (page == HV_INTC_FC_PAGE_START)
+ page = 0;
+
+ if (reg > MAX_PHY_MULTI_PAGE_REG) {
+ UINT32 phy_addr = hw->phy.addr;
+
+ hw->phy.addr = 1;
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (page << IGP_PAGE_SHIFT));
+ hw->phy.addr = phy_addr;
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+ data);
+out:
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_hv - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset and stores
+ * the retrieved information in data. Release the acquired semaphore
+ * before exiting.
+ **/
+INT32 e1000_read_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_hv(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_read_phy_reg_hv_locked - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data. Assumes semaphore already acquired.
+ **/
+INT32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data)
+{
+ return __e1000_read_phy_reg_hv(hw, offset, data, TRUE);
+}
+
+/**
+ * __e1000_write_phy_reg_hv - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+static INT32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 data,
+ BOOLEAN locked)
+{
+ INT32 ret_val;
+ UINT16 page = BM_PHY_REG_PAGE(offset);
+ UINT16 reg = BM_PHY_REG_NUM(offset);
+
+ DEBUGFUNC("__e1000_write_phy_reg_hv");
+
+ if (!locked) {
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+ &data, FALSE);
+ goto out;
+ }
+
+ if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+ ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+ &data, FALSE);
+ goto out;
+ }
+
+ hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+ if (page == HV_INTC_FC_PAGE_START)
+ page = 0;
+
+ /*
+ * Workaround MDIO accesses being disabled after entering IEEE Power
+ * Down (whenever bit 11 of the PHY Control register is set)
+ */
+ if ((hw->phy.type == e1000_phy_82578) &&
+ (hw->phy.revision >= 1) &&
+ (hw->phy.addr == 2) &&
+ ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
+ (data & (1 << 11))) {
+ UINT16 data2 = 0x7EFF;
+ ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
+ &data2, FALSE);
+ if (ret_val)
+ goto out;
+ }
+
+ if (reg > MAX_PHY_MULTI_PAGE_REG) {
+ UINT32 phy_addr = hw->phy.addr;
+
+ hw->phy.addr = 1;
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (page << IGP_PAGE_SHIFT));
+ hw->phy.addr = phy_addr;
+
+ if (ret_val)
+ goto out;
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+ data);
+
+out:
+ if (!locked)
+ hw->phy.ops.release(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_hv - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to PHY register at the offset.
+ * Release the acquired semaphores before exiting.
+ **/
+INT32 e1000_write_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_hv(hw, offset, data, FALSE);
+}
+
+/**
+ * e1000_write_phy_reg_hv_locked - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset. Assumes semaphore
+ * already acquired.
+ **/
+INT32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data)
+{
+ return __e1000_write_phy_reg_hv(hw, offset, data, TRUE);
+}
+
+/**
+ * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
+ * @page: page to be accessed
+ **/
+STATIC UINT32 e1000_get_phy_addr_for_hv_page(UINT32 page)
+{
+ UINT32 phy_addr = 2;
+
+ if (page >= HV_INTC_FC_PAGE_START)
+ phy_addr = 1;
+
+ return phy_addr;
+}
+
+/**
+ * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read or written
+ * @data: pointer to the data to be read or written
+ * @read: determines if operation is read or written
+ *
+ * Reads the PHY register at offset and stores the retreived information
+ * in data. Assumes semaphore already acquired. Note that the procedure
+ * to read these regs uses the address port and data port to read/write.
+ **/
+STATIC INT32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, UINT32 offset,
+ UINT16 *data, BOOLEAN read)
+{
+ INT32 ret_val;
+ UINT32 addr_reg = 0;
+ UINT32 data_reg = 0;
+
+ DEBUGFUNC("e1000_access_phy_debug_regs_hv");
+
+ /* This takes care of the difference with desktop vs mobile phy */
+ addr_reg = (hw->phy.type == e1000_phy_82578) ?
+ I82578_ADDR_REG : I82577_ADDR_REG;
+ data_reg = addr_reg + 1;
+
+ /* All operations in this function are phy address 2 */
+ hw->phy.addr = 2;
+
+ /* masking with 0x3F to remove the page from offset */
+ ret_val = e1000_write_phy_reg_mdic(hw, addr_reg, (UINT16)offset & 0x3F);
+ if (ret_val) {
+ DEBUGOUT("Could not write PHY the HV address register\n");
+ goto out;
+ }
+
+ /* Read or write the data value next */
+ if (read)
+ ret_val = e1000_read_phy_reg_mdic(hw, data_reg, data);
+ else
+ ret_val = e1000_write_phy_reg_mdic(hw, data_reg, *data);
+
+ if (ret_val) {
+ DEBUGOUT("Could not read data value from HV data register\n");
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_link_stall_workaround_hv - Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * This function works around a Si bug where the link partner can get
+ * a link up indication before the PHY does. If small packets are sent
+ * by the link partner they can be placed in the packet buffer without
+ * being properly accounted for by the PHY and will stall preventing
+ * further packets from being received. The workaround is to clear the
+ * packet buffer after the PHY detects link up.
+ **/
+INT32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
+{
+ INT32 ret_val = E1000_SUCCESS;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_link_stall_workaround_hv");
+
+ if (hw->phy.type != e1000_phy_82578)
+ goto out;
+
+ /* Do not apply workaround if in PHY loopback bit 14 set */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &data);
+ if (data & PHY_CONTROL_LB)
+ goto out;
+
+ /* check if link is up and at 1Gbps */
+ ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ data &= BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK;
+
+ if (data != (BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_1000))
+ goto out;
+
+ msec_delay(200);
+
+ /* flush the packets in the fifo buffer */
+ ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC |
+ HV_MUX_DATA_CTRL_FORCE_SPEED);
+ if (ret_val)
+ goto out;
+
+ ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_82577 - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY specific status register.
+ **/
+INT32 e1000_check_polarity_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+
+ DEBUGFUNC("e1000_check_polarity_82577");
+
+ ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex.
+ **/
+INT32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex_82577");
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ usec_delay(1);
+
+ if (phy->autoneg_wait_to_complete) {
+ DEBUGOUT("Waiting for forced speed/duplex link on 82577 phy\n");
+
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ DEBUGOUT("Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_info_82577 - Retrieve I82577 PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up. If link is up, then
+ * set/determine 10base-T extended distance and polarity correction. Read
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ **/
+INT32 e1000_get_phy_info_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 data;
+ BOOLEAN link;
+
+ DEBUGFUNC("e1000_get_phy_info_82577");
+
+ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ DEBUGOUT("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ phy->polarity_correction = TRUE;
+
+ ret_val = e1000_check_polarity_82577(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+ if (ret_val)
+ goto out;
+
+ phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? TRUE : FALSE;
+
+ if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
+ I82577_PHY_STATUS2_SPEED_1000MBPS) {
+ ret_val = hw->phy.ops.get_cable_length(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+ if (ret_val)
+ goto out;
+
+ phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Reads the diagnostic status register and verifies result is valid before
+ * placing it in the phy_cable_length field.
+ **/
+INT32 e1000_get_cable_length_82577(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ INT32 ret_val;
+ UINT16 phy_data, length;
+
+ DEBUGFUNC("e1000_get_cable_length_82577");
+
+ ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
+ I82577_DSTATUS_CABLE_LENGTH_SHIFT;
+
+ if (length == E1000_CABLE_LENGTH_UNDEFINED)
+ ret_val = -E1000_ERR_PHY;
+
+ phy->cable_length = length;
+
+out:
+ return ret_val;
+}
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h
new file mode 100755
index 0000000..ec4661d
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_phy.h
@@ -0,0 +1,268 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_PHY_H_
+#define _E1000_PHY_H_
+
+void e1000_init_phy_ops_generic(struct e1000_hw *hw);
+#ifndef NO_NULL_OPS_SUPPORT
+INT32 e1000_null_read_reg(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+void e1000_null_phy_generic(struct e1000_hw *hw);
+INT32 e1000_null_lplu_state(struct e1000_hw *hw, BOOLEAN active);
+INT32 e1000_null_write_reg(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#endif /* NO_NULL_OPS_SUPPORT */
+INT32 e1000_check_downshift_generic(struct e1000_hw *hw);
+INT32 e1000_check_polarity_m88(struct e1000_hw *hw);
+INT32 e1000_check_polarity_igp(struct e1000_hw *hw);
+INT32 e1000_check_polarity_ife(struct e1000_hw *hw);
+INT32 e1000_check_reset_block_generic(struct e1000_hw *hw);
+INT32 e1000_copper_link_setup_igp(struct e1000_hw *hw);
+INT32 e1000_copper_link_setup_m88(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
+INT32 e1000_get_cable_length_m88(struct e1000_hw *hw);
+INT32 e1000_get_cable_length_igp_2(struct e1000_hw *hw);
+INT32 e1000_get_cfg_done_generic(struct e1000_hw *hw);
+INT32 e1000_get_phy_id(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_igp(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_m88(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_ife(struct e1000_hw *hw);
+INT32 e1000_phy_sw_reset_generic(struct e1000_hw *hw);
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, UINT16 *phy_ctrl);
+INT32 e1000_phy_hw_reset_generic(struct e1000_hw *hw);
+INT32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw);
+INT32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, BOOLEAN active);
+INT32 e1000_setup_copper_link_generic(struct e1000_hw *hw);
+INT32 e1000_wait_autoneg_generic(struct e1000_hw *hw);
+INT32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_igp(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_m88(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_phy_reset_dsp(struct e1000_hw *hw);
+INT32 e1000_phy_has_link_generic(struct e1000_hw *hw, UINT32 iterations,
+ UINT32 usec_interval, BOOLEAN *success);
+INT32 e1000_phy_init_script_igp3(struct e1000_hw *hw);
+enum e1000_phy_type e1000_get_phy_type_from_id(UINT32 phy_id);
+INT32 e1000_determine_phy_address(struct e1000_hw *hw);
+INT32 e1000_write_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_read_phy_reg_bm(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+#ifndef NO_82574_SUPPORT
+INT32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#endif /* NO_82574_SUPPORT */
+void e1000_power_up_phy_copper(struct e1000_hw *hw);
+void e1000_power_down_phy_copper(struct e1000_hw *hw);
+INT32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#ifndef NO_82575_SUPPORT
+INT32 e1000_read_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_i2c(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+#endif /* *NO_82575_SUPPORT */
+INT32 e1000_read_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 *data);
+INT32 e1000_write_phy_reg_hv(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, UINT32 offset, UINT16 data);
+INT32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
+INT32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
+INT32 e1000_check_polarity_82577(struct e1000_hw *hw);
+INT32 e1000_get_phy_info_82577(struct e1000_hw *hw);
+INT32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
+INT32 e1000_get_cable_length_82577(struct e1000_hw *hw);
+
+#define E1000_MAX_PHY_ADDR 4
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
+#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality */
+#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */
+#define IGP_PAGE_SHIFT 5
+#define PHY_REG_MASK 0x1F
+
+/* BM/HV Specific Registers */
+#define BM_PORT_CTRL_PAGE 769
+#define BM_PCIE_PAGE 770
+#define BM_WUC_PAGE 800
+#define BM_WUC_ADDRESS_OPCODE 0x11
+#define BM_WUC_DATA_OPCODE 0x12
+#define BM_WUC_ENABLE_PAGE BM_PORT_CTRL_PAGE
+#define BM_WUC_ENABLE_REG 17
+#define BM_WUC_ENABLE_BIT (1 << 2)
+#define BM_WUC_HOST_WU_BIT (1 << 4)
+
+#define PHY_UPPER_SHIFT 21
+#define BM_PHY_REG(page, reg) \
+ (((reg) & MAX_PHY_REG_ADDRESS) |\
+ (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+ (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+#define BM_PHY_REG_PAGE(offset) \
+ ((UINT16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define BM_PHY_REG_NUM(offset) \
+ ((UINT16)(((offset) & MAX_PHY_REG_ADDRESS) |\
+ (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+ ~MAX_PHY_REG_ADDRESS)))
+
+#define HV_INTC_FC_PAGE_START 768
+#define I82578_ADDR_REG 29
+#define I82577_ADDR_REG 16
+#define I82577_CFG_REG 22
+#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15)
+#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */
+#define I82577_CTRL_REG 23
+
+/* 82577 specific PHY registers */
+#define I82577_PHY_CTRL_2 18
+#define I82577_PHY_LBK_CTRL 19
+#define I82577_PHY_STATUS_2 26
+#define I82577_PHY_DIAG_STATUS 31
+
+/* I82577 PHY Status 2 */
+#define I82577_PHY_STATUS2_REV_POLARITY 0x0400
+#define I82577_PHY_STATUS2_MDIX 0x0800
+#define I82577_PHY_STATUS2_SPEED_MASK 0x0300
+#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
+#define I82577_PHY_STATUS2_SPEED_100MBPS 0x0100
+
+/* I82577 PHY Control 2 */
+#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400
+#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200
+
+/* I82577 PHY Diagnostics Status */
+#define I82577_DSTATUS_CABLE_LENGTH 0x03FC
+#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
+
+/* BM PHY Copper Specific Control 1 */
+#define BM_CS_CTRL1 16
+#define BM_CS_CTRL1_ENERGY_DETECT 0x0300 /* Enable Energy Detect */
+
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS 17
+#define BM_CS_STATUS_ENERGY_DETECT 0x0010 /* Energy Detect Status */
+#define BM_CS_STATUS_LINK_UP 0x0400
+#define BM_CS_STATUS_RESOLVED 0x0800
+#define BM_CS_STATUS_SPEED_MASK 0xC000
+#define BM_CS_STATUS_SPEED_1000 0x8000
+
+/* 82577 Mobile Phy Status Register */
+#define HV_M_STATUS 26
+#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000
+#define HV_M_STATUS_SPEED_MASK 0x0300
+#define HV_M_STATUS_SPEED_1000 0x0200
+#define HV_M_STATUS_LINK_UP 0x0040
+
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK 0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP01E1000_GMII_FLEX_SPD 0x0010
+#define IGP01E1000_GMII_SPD 0x0020 /* Enable SPD */
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX 0x0800
+#define IGP01E1000_PSSR_SPEED_MASK 0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK 0x7F
+#define IGP02E1000_AGC_RANGE 15
+
+#define IGP03E1000_PHY_MISC_CTRL 0x1B
+#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Manually Set Duplex */
+
+#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET 0x1 /* Kumeran Control */
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
+#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
+#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002
+#define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED 0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010
+#define IFE_PSC_FORCE_POLARITY 0x0020
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE 0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h
new file mode 100755
index 0000000..880905b
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/e1000_regs.h
@@ -0,0 +1,576 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _E1000_REGS_H_
+#define _E1000_REGS_H_
+
+#define E1000_CTRL 0x00000 /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS 0x00008 /* Device Status - RO */
+#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
+#define E1000_EERD 0x00014 /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
+#define E1000_FLA 0x0001C /* Flash Access - RW */
+#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#ifndef NO_82580_SUPPORT
+#define E1000_MDICNFG 0x00E04 /* MDI Config - RW */
+#define E1000_REGISTER_SET_SIZE 0x20000 /* CSR Size */
+#define E1000_EEPROM_INIT_CTRL_WORD_2 0x0F /* EEPROM Init Ctrl Word 2 */
+#define E1000_BARCTRL 0x5BBC /* BAR ctrl reg */
+#define E1000_BARCTRL_FLSIZE 0x0700 /* BAR ctrl Flsize */
+#define E1000_BARCTRL_CSRSIZE 0x2000 /* BAR ctrl CSR size */
+#endif
+#define E1000_SCTL 0x00024 /* SerDes Control - RW */
+#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
+#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
+#define E1000_FEXT 0x0002C /* Future Extended - RW */
+#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
+#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */
+#define E1000_FCT 0x00030 /* Flow Control Type - RW */
+#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
+#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
+#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
+#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
+#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
+#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
+#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
+#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
+#ifndef NO_82574_SUPPORT
+#define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */
+#endif /* NO_82574_SUPPORT */
+#define E1000_SVCR 0x000F0
+#define E1000_SVT 0x000F4
+#define E1000_RCTL 0x00100 /* Rx Control - RW */
+#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */
+#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */
+#ifndef NO_82571_SUPPORT
+#define E1000_PBA_ECC 0x01100 /* PBA ECC Register */
+#endif /* NO_82571_SUPPORT */
+#ifndef NO_82575_SUPPORT
+#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
+#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#endif /* NO_82575_SUPPORT */
+#ifndef NO_82576_SUPPORT
+#define E1000_GPIE 0x01514 /* General Purpose Interrupt Enable - RW */
+#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */
+#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
+#endif /* NO_82576_SUPPORT */
+#define E1000_TCTL 0x00400 /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */
+#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */
+#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */
+#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
+#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
+#define E1000_PBS 0x01008 /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
+#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT 0x01028 /* FLASH Timer Register */
+#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL 0x01030 /* FLASH control register */
+#define E1000_FLSWDATA 0x01034 /* FLASH data register */
+#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
+#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
+#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */
+#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */
+#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */
+#ifndef NO_82575_SUPPORT
+#define E1000_TCPTIMER 0x0104C /* TCP Timer - RW */
+#endif
+#ifndef NO_82576_SUPPORT
+#define E1000_VPDDIAG 0x01060 /* VPD Diagnostic - RO */
+#define E1000_ICR_V2 0x01500 /* Interrupt Cause - new location - RC */
+#define E1000_ICS_V2 0x01504 /* Interrupt Cause Set - new location - WO */
+#define E1000_IMS_V2 0x01508 /* Interrupt Mask Set/Read - new location - RW */
+#define E1000_IMC_V2 0x0150C /* Interrupt Mask Clear - new location - WO */
+#define E1000_IAM_V2 0x01510 /* Interrupt Ack Auto Mask - new location - RW */
+#endif
+#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
+#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
+#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n)))
+#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */
+#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */
+#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */
+#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */
+#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */
+#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */
+#ifndef NO_82576_SUPPORT
+#define E1000_PBDIAG 0x02458 /* Packet Buffer Diagnostic - RW */
+#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
+#endif
+#ifndef NO_82580_SUPPORT
+#define E1000_IRPBS 0x02404 /* Same as RXPBS, renamed for newer adapters - RW */
+#endif
+#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */
+#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+ (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+ (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+ (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
+ (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+ (0x0C010 + ((_n) * 0x40)))
+#define E1000_RXCTL(_n) ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
+ (0x0C014 + ((_n) * 0x40)))
+#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n)
+#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+ (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+ (0x0C028 + ((_n) * 0x40)))
+#define E1000_RQDPC(_n) ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \
+ (0x0C030 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+ (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+ (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+ (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+ (0x0E010 + ((_n) * 0x40)))
+#define E1000_TXCTL(_n) ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
+ (0x0E014 + ((_n) * 0x40)))
+#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
+#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+ (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+ (0x0E028 + ((_n) * 0x40)))
+#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
+ (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
+ (0x0E03C + ((_n) * 0x40)))
+#define E1000_TARC(_n) (0x03840 + ((_n) * 0x100))
+#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */
+#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */
+#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
+#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
+#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+ (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+ (0x054E4 + ((_i - 16) * 8)))
+#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8))
+#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8))
+#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4))
+#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
+#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8))
+#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8))
+#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8))
+#ifndef NO_82576_SUPPORT
+#define E1000_PBSLAC 0x03100 /* Packet Buffer Slave Access Control */
+#define E1000_PBSLAD(_n) (0x03110 + (0x4 * (_n))) /* Packet Buffer DWORD (_n) */
+#define E1000_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
+#endif
+#ifndef NO_82580_SUPPORT
+#define E1000_ITPBS 0x03404 /* Same as TXPBS, renamed for newer adpaters - RW */
+#endif
+#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */
+#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */
+#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */
+#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */
+#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */
+#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */
+#ifndef NO_82576_SUPPORT
+#define E1000_DTXTCPFLGL 0x0359C /* DMA Tx Control flag low - RW */
+#define E1000_DTXTCPFLGH 0x035A0 /* DMA Tx Control flag high - RW */
+#define E1000_DTXMXSZRQ 0x03540 /* DMA Tx Max Total Allow Size Requests - RW */
+#endif
+#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
+#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
+#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
+#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
+#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
+#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
+#define E1000_COLC 0x04028 /* Collision Count - R/clr */
+#define E1000_DC 0x04030 /* Defer Count - R/clr */
+#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */
+#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */
+#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */
+#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */
+#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */
+#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */
+#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */
+#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */
+#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */
+#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */
+#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */
+#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */
+#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
+#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
+#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset register */
+
+#ifndef NO_82576_SUPPORT
+/* Virtualization statistical counters */
+#define E1000_PFVFGPRC(_n) (0x010010 + (0x100 * (_n)))
+#define E1000_PFVFGPTC(_n) (0x010014 + (0x100 * (_n)))
+#define E1000_PFVFGORC(_n) (0x010018 + (0x100 * (_n)))
+#define E1000_PFVFGOTC(_n) (0x010034 + (0x100 * (_n)))
+#define E1000_PFVFMPRC(_n) (0x010038 + (0x100 * (_n)))
+#define E1000_PFVFGPRLBC(_n) (0x010040 + (0x100 * (_n)))
+#define E1000_PFVFGPTLBC(_n) (0x010044 + (0x100 * (_n)))
+#define E1000_PFVFGORLBC(_n) (0x010048 + (0x100 * (_n)))
+#define E1000_PFVFGOTLBC(_n) (0x010050 + (0x100 * (_n)))
+
+#define E1000_LSECTXUT 0x04300 /* LinkSec Tx Untagged Packet Count - OutPktsUntagged */
+#define E1000_LSECTXPKTE 0x04304 /* LinkSec Encrypted Tx Packets Count - OutPktsEncrypted */
+#define E1000_LSECTXPKTP 0x04308 /* LinkSec Protected Tx Packet Count - OutPktsProtected */
+#define E1000_LSECTXOCTE 0x0430C /* LinkSec Encrypted Tx Octets Count - OutOctetsEncrypted */
+#define E1000_LSECTXOCTP 0x04310 /* LinkSec Protected Tx Octets Count - OutOctetsProtected */
+#define E1000_LSECRXUT 0x04314 /* LinkSec Untagged non-Strict Rx Packet Count - InPktsUntagged/InPktsNoTag */
+#define E1000_LSECRXOCTD 0x0431C /* LinkSec Rx Octets Decrypted Count - InOctetsDecrypted */
+#define E1000_LSECRXOCTV 0x04320 /* LinkSec Rx Octets Validated - InOctetsValidated */
+#define E1000_LSECRXBAD 0x04324 /* LinkSec Rx Bad Tag - InPktsBadTag */
+#define E1000_LSECRXNOSCI 0x04328 /* LinkSec Rx Packet No SCI Count - InPktsNoSci */
+#define E1000_LSECRXUNSCI 0x0432C /* LinkSec Rx Packet Unknown SCI Count - InPktsUnknownSci */
+#define E1000_LSECRXUNCH 0x04330 /* LinkSec Rx Unchecked Packets Count - InPktsUnchecked */
+#define E1000_LSECRXDELAY 0x04340 /* LinkSec Rx Delayed Packet Count - InPktsDelayed */
+#define E1000_LSECRXLATE 0x04350 /* LinkSec Rx Late Packets Count - InPktsLate */
+#define E1000_LSECRXOK(_n) (0x04360 + (0x04 * (_n))) /* LinkSec Rx Packet OK Count - InPktsOk */
+#define E1000_LSECRXINV(_n) (0x04380 + (0x04 * (_n))) /* LinkSec Rx Invalid Count - InPktsInvalid */
+#define E1000_LSECRXNV(_n) (0x043A0 + (0x04 * (_n))) /* LinkSec Rx Not Valid Count - InPktsNotValid */
+#define E1000_LSECRXUNSA 0x043C0 /* LinkSec Rx Unused SA Count - InPktsUnusedSa */
+#define E1000_LSECRXNUSA 0x043D0 /* LinkSec Rx Not Using SA Count - InPktsNotUsingSa */
+#define E1000_LSECTXCAP 0x0B000 /* LinkSec Tx Capabilities Register - RO */
+#define E1000_LSECRXCAP 0x0B300 /* LinkSec Rx Capabilities Register - RO */
+#define E1000_LSECTXCTRL 0x0B004 /* LinkSec Tx Control - RW */
+#define E1000_LSECRXCTRL 0x0B304 /* LinkSec Rx Control - RW */
+#define E1000_LSECTXSCL 0x0B008 /* LinkSec Tx SCI Low - RW */
+#define E1000_LSECTXSCH 0x0B00C /* LinkSec Tx SCI High - RW */
+#define E1000_LSECTXSA 0x0B010 /* LinkSec Tx SA0 - RW */
+#define E1000_LSECTXPN0 0x0B018 /* LinkSec Tx SA PN 0 - RW */
+#define E1000_LSECTXPN1 0x0B01C /* LinkSec Tx SA PN 1 - RW */
+#define E1000_LSECRXSCL 0x0B3D0 /* LinkSec Rx SCI Low - RW */
+#define E1000_LSECRXSCH 0x0B3E0 /* LinkSec Rx SCI High - RW */
+#define E1000_LSECTXKEY0(_n) (0x0B020 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 0 - WO */
+#define E1000_LSECTXKEY1(_n) (0x0B030 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 1 - WO */
+#define E1000_LSECRXSA(_n) (0x0B310 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
+#define E1000_LSECRXPN(_n) (0x0B330 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
+/*
+ * LinkSec Rx Keys - where _n is the SA no. and _m the 4 dwords of the 128 bit
+ * key - RW.
+ */
+#define E1000_LSECRXKEY(_n, _m) (0x0B350 + (0x10 * (_n)) + (0x04 * (_m)))
+
+#define E1000_SSVPC 0x041A0 /* Switch Security Violation Packet Count */
+#define E1000_IPSCTRL 0xB430 /* IpSec Control Register */
+#define E1000_IPSRXCMD 0x0B408 /* IPSec Rx Command Register - RW */
+#define E1000_IPSRXIDX 0x0B400 /* IPSec Rx Index - RW */
+#define E1000_IPSRXIPADDR(_n) (0x0B420+ (0x04 * (_n))) /* IPSec Rx IPv4/v6 Address - RW */
+#define E1000_IPSRXKEY(_n) (0x0B410 + (0x04 * (_n))) /* IPSec Rx 128-bit Key - RW */
+#define E1000_IPSRXSALT 0x0B404 /* IPSec Rx Salt - RW */
+#define E1000_IPSRXSPI 0x0B40C /* IPSec Rx SPI - RW */
+#define E1000_IPSTXKEY(_n) (0x0B460 + (0x04 * (_n))) /* IPSec Tx 128-bit Key - RW */
+#define E1000_IPSTXSALT 0x0B454 /* IPSec Tx Salt - RW */
+#define E1000_IPSTXIDX 0x0B450 /* IPSec Tx SA IDX - RW */
+#endif /* NO_82576_SUPPORT */
+#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */
+#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */
+#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */
+#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */
+#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */
+#define E1000_RPTHC 0x04104 /* Rx Packets To Host */
+#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */
+#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */
+#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */
+#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */
+#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS 0x04138 /* Length Errors Count */
+#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */
+#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */
+#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */
+#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */
+#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */
+#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */
+#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
+#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
+#define E1000_RA 0x05400 /* Receive Address - RW Array */
+#ifndef NO_82576_SUPPORT
+#define E1000_RA2 0x054E0 /* 2nd half of receive address array - RW Array */
+#endif
+#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
+#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */
+#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */
+#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */
+#define E1000_WUC 0x05800 /* Wakeup Control - RW */
+#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
+#define E1000_WUS 0x05810 /* Wakeup Status - RO */
+#define E1000_MANC 0x05820 /* Management Control - RW */
+#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
+#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
+#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
+#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
+#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */
+#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF 0x08800 /* Host Interface */
+#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
+#ifndef NO_82576_SUPPORT
+#define E1000_FHFT(_n) (0x09000 + (_n * 0x100)) /* Flexible Host Filter Table */
+#define E1000_FHFT_EXT(_n) (0x09A00 + (_n * 0x100)) /* Ext Flexible Host Filter Table */
+
+#endif /* NO_82576_SUPPORT */
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA 0x0003C /* PHY address - RW */
+#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */
+#define E1000_MDEF(_n) (0x05890 + (4 * (_n))) /* Mngmt Decision Filters */
+#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL 0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
+#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */
+#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM 0x05B50 /* SW Semaphore */
+#define E1000_FWSM 0x05B54 /* FW Semaphore */
+#define E1000_SWSM2 0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */
+#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */
+#ifndef NO_82580_SUPPORT
+#define E1000_UFUSE 0x05B78 /* UFUSE - RO */
+#endif
+#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
+#define E1000_HICR 0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
+#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
+#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
+ * (_i) - RW */
+#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
+ * low reg - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
+ * upper reg - RW */
+#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
+ * message reg - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
+ * vector ctrl reg - RW */
+#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */
+#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
+#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */
+#ifndef NO_82576_SUPPORT
+/* VT Registers */
+#define E1000_SWPBS 0x03004 /* Switch Packet Buffer Size - RW */
+#define E1000_MBVFICR 0x00C80 /* Mailbox VF Cause - RWC */
+#define E1000_MBVFIMR 0x00C84 /* Mailbox VF int Mask - RW */
+#define E1000_VFLRE 0x00C88 /* VF Register Events - RWC */
+#define E1000_VFRE 0x00C8C /* VF Receive Enables */
+#define E1000_VFTE 0x00C90 /* VF Transmit Enables */
+#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */
+#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_WVBR 0x03554 /* VM Wrong Behavior - RWS */
+#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
+#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
+#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
+#define E1000_VMRCTL 0X05D80 /* Virtual Mirror Rule Control */
+/* These act per VF so an array friendly macro is used */
+#define E1000_V2PMAILBOX(_n) (0x00C40 + (4 * (_n)))
+#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n)))
+#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
+#define E1000_VFVMBMEM(_n) (0x00800 + (_n))
+#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n)))
+#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
+ * Filter - RW */
+#define E1000_VMVIR(_n) (0x03700 + (4 * (_n)))
+#endif /* NO_82576_SUPPORT */
+/* Time Sync */
+#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
+#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
+#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
+#define E1000_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */
+#define E1000_RXSTMPH 0x0B628 /* Rx timestamp High - RO */
+#define E1000_RXSATRL 0x0B62C /* Rx timestamp attribute low - RO */
+#define E1000_RXSATRH 0x0B630 /* Rx timestamp attribute high - RO */
+#define E1000_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
+#define E1000_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
+#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */
+#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */
+#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
+#ifndef NO_82580_SUPPORT
+#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
+#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */
+#endif /* NO_82580_SUPPORT */
+#ifndef NO_82576_SUPPORT
+
+/* Filtering Registers */
+#define E1000_SAQF(_n) (0x05980 + (4 * (_n))) /* Source Address Queue Fltr */
+#define E1000_DAQF(_n) (0x059A0 + (4 * (_n))) /* Dest Address Queue Fltr */
+#define E1000_SPQF(_n) (0x059C0 + (4 * (_n))) /* Source Port Queue Fltr */
+#define E1000_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
+#define E1000_TTQF(_n) (0x059E0 + (4 * (_n))) /* 2-tuple Queue Fltr */
+#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
+#define E1000_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
+
+#define E1000_RTTDCS 0x3600 /* Reedtown Tx Desc plane control and status */
+#define E1000_RTTPCS 0x3474 /* Reedtown Tx Packet Plane control and status */
+#define E1000_RTRPCS 0x2474 /* Rx packet plane control and status */
+#define E1000_RTRUP2TC 0x05AC4 /* Rx User Priority to Traffic Class */
+#define E1000_RTTUP2TC 0x0418 /* Transmit User Priority to Traffic Class */
+#define E1000_RTTDTCRC(_n) (0x3610 + ((_n) * 4)) /* Tx Desc plane TC Rate-scheduler config */
+#define E1000_RTTPTCRC(_n) (0x3480 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Config */
+#define E1000_RTRPTCRC(_n) (0x2480 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Config */
+#define E1000_RTTDTCRS(_n) (0x3630 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler Status */
+#define E1000_RTTDTCRM(_n) (0x3650 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler MMW */
+#define E1000_RTTPTCRS(_n) (0x34A0 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Status */
+#define E1000_RTTPTCRM(_n) (0x34C0 + ((_n) * 4)) /* Tx Packet plane TC Rate-scheduler MMW */
+#define E1000_RTRPTCRS(_n) (0x24A0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Status */
+#define E1000_RTRPTCRM(_n) (0x24C0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler MMW */
+#define E1000_RTTDVMRM(_n) (0x3670 + ((_n) * 4)) /* Tx Desc plane VM Rate-Scheduler MMW*/
+#define E1000_RTTBCNRM(_n) (0x3690 + ((_n) * 4)) /* Tx BCN Rate-Scheduler MMW */
+#define E1000_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select */
+#define E1000_RTTDVMRC 0x3608 /* Tx Desc Plane VM Rate-Scheduler Config */
+#define E1000_RTTDVMRS 0x360C /* Tx Desc Plane VM Rate-Scheduler Status */
+#define E1000_RTTBCNRC 0x36B0 /* Tx BCN Rate-Scheduler Config */
+#define E1000_RTTBCNRS 0x36B4 /* Tx BCN Rate-Scheduler Status */
+#define E1000_RTTBCNCR 0xB200 /* Tx BCN Control Register */
+#define E1000_RTTBCNTG 0x35A4 /* Tx BCN Tagging */
+#define E1000_RTTBCNCP 0xB208 /* Tx BCN Congestion point */
+#define E1000_RTRBCNCR 0xB20C /* Rx BCN Control Register */
+#define E1000_RTTBCNRD 0x36B8 /* Tx BCN Rate Drift */
+#define E1000_PFCTOP 0x1080 /* Priority Flow Control Type and Opcode */
+#define E1000_RTTBCNIDX 0xB204 /* Tx BCN Congestion Point */
+#define E1000_RTTBCNACH 0x0B214 /* Tx BCN Control High */
+#define E1000_RTTBCNACL 0x0B210 /* Tx BCN Control Low */
+#endif /* NO_82576_SUPPORT */
+
+#ifndef NO_82580_SUPPORT
+/* DMA Coalescing registers */
+#define E1000_DMACR 0x02508 /* Control Register */
+#define E1000_DMCTXTH 0x03550 /* Transmit Threshold */
+#define E1000_DMCTLX 0x02514 /* Time to Lx Request */
+#define E1000_DMCRTRH 0x05DD0 /* Receive Packet Rate Threshold */
+#define E1000_DMCCNT 0x05DD4 /* Current RX Count */
+#define E1000_FCRTC 0x02170 /* Flow Control Rx high watermark */
+#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
+
+/* PCIe Parity Status Register */
+#define E1000_PCIEERRSTS 0x05BA8
+#endif
+
+
+#endif
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf
new file mode 100755
index 0000000..5311e82
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_82575_edk1.inf
@@ -0,0 +1,97 @@
+#/*++
+#
+# Copyright (c) 2008, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+# Module Name:
+#
+# gig_82575_edk1.inf
+#
+# Abstract:
+#
+# Component description file for the Intel gigabit ethernet driver. This make file
+# includes only support from 82575 controllers to reduce driver size.
+#
+#--*/
+
+[defines]
+BASE_NAME = GigUndi
+FILE_GUID = BB801A52-C90F-4EDE-91B2-82520888CBC3
+COMPONENT_TYPE = RT_DRIVER
+
+[sources.common]
+ inventorystrings.uni
+ inventory.vfr
+ brand.h
+ clp.h
+ clp.c
+ componentname.c
+ decode.c
+ driverconfiguration.c
+ driverdiagnostics.c
+ e1000.h
+ e1000.c
+ e1000_80003es2lan.h
+ e1000_82571.h
+ e1000_82575.h
+ e1000_82575.c
+ e1000_api.h
+ e1000_api.c
+ e1000_defines.h
+ e1000_hw.h
+ e1000_ich8lan.h
+ e1000_mac.h
+ e1000_mac.c
+ e1000_manage.h
+ e1000_manage.c
+ e1000_nvm.h
+ e1000_nvm.c
+ e1000_osdep.h
+ e1000_osdep.c
+ e1000_phy.h
+ e1000_phy.c
+ e1000_regs.h
+ FirmwareManagement.h
+ FirmwareManagement.c
+ hii.h
+ hii.c
+ ieee_define.h
+ init.c
+ nvdatastruc.h
+ startstop.h
+ startstop.c
+ vlan.h
+ vlan.c
+
+[includes.common]
+ $(EDK_SOURCE)\Foundation
+ $(EDK_SOURCE)\Foundation\Include
+ $(EDK_SOURCE)\Foundation\Include\$(ARCH)
+ $(EDK_SOURCE)\Foundation\Include\IndustryStandard
+ $(EDK_SOURCE)\Foundation\Efi\Include
+ $(EDK_SOURCE)\Foundation\Efi
+ $(EDK_SOURCE)\Foundation\Framework
+ $(EDK_SOURCE)\Foundation\Framework\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\UefiEfiIfrSupportLib
+ $(DEST_DIR)
+ .
+
+[libraries.common]
+ EfiDriverLib
+ PrintLib
+ UefiEfiIfrSupportLib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT=InitializeGigUNDIDriver
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_82571_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_80003ES2LAN_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_ICH8LAN_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_BRANDING_SUPPORT
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf
new file mode 100755
index 0000000..aebb475
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/gig_ich_edk1.inf
@@ -0,0 +1,98 @@
+#/*++
+#
+# Copyright (c) 2008, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+# Module Name:
+#
+# gig_ich_edk1.inf
+#
+# Abstract:
+#
+# Component description file for the Intel gigabit ethernet driver. This make file
+# includes only support from ICH8 and ICH9 controllers to reduce driver size.
+#
+#--*/
+
+[defines]
+BASE_NAME = GigUndi
+FILE_GUID = BB801A52-C90F-4EDE-91B2-82520888CBC3
+COMPONENT_TYPE = RT_DRIVER
+
+[sources.common]
+ inventorystrings.uni
+ inventory.vfr
+ brand.h
+ clp.h
+ clp.c
+ componentname.c
+ decode.c
+ driverconfiguration.c
+ driverdiagnostics.c
+ e1000.h
+ e1000.c
+ e1000_80003es2lan.h
+ e1000_82571.h
+ e1000_82575.h
+ e1000_api.h
+ e1000_api.c
+ e1000_defines.h
+ e1000_hw.h
+ e1000_ich8lan.h
+ e1000_ich8lan.c
+ e1000_mac.h
+ e1000_mac.c
+ e1000_manage.h
+ e1000_manage.c
+ e1000_nvm.h
+ e1000_nvm.c
+ e1000_osdep.h
+ e1000_osdep.c
+ e1000_phy.h
+ e1000_phy.c
+ e1000_regs.h
+ FirmwareManagement.h
+ FirmwareManagement.c
+ hii.h
+ hii.c
+ ieee_define.h
+ init.c
+ nvdatastruc.h
+ startstop.h
+ startstop.c
+ vlan.h
+ vlan.c
+
+[includes.common]
+ $(EDK_SOURCE)\Foundation
+ $(EDK_SOURCE)\Foundation\Include
+ $(EDK_SOURCE)\Foundation\Include\$(ARCH)
+ $(EDK_SOURCE)\Foundation\Include\IndustryStandard
+ $(EDK_SOURCE)\Foundation\Efi\Include
+ $(EDK_SOURCE)\Foundation\Efi
+ $(EDK_SOURCE)\Foundation\Framework
+ $(EDK_SOURCE)\Foundation\Framework\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\Include
+ $(EDK_SOURCE)\Foundation\Library\Dxe\UefiEfiIfrSupportLib
+ $(DEST_DIR)
+ .
+
+[libraries.common]
+ EfiDriverLib
+ PrintLib
+ UefiEfiIfrSupportLib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT=InitializeGigUNDIDriver
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_80003ES2LAN_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_82571_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_82575_SUPPORT
+ C_STD_FLAGS = $(C_STD_FLAGS) /DNO_BRANDING_SUPPORT
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c
new file mode 100755
index 0000000..b9b941e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.c
@@ -0,0 +1,1973 @@
+/*++
+Copyright (c) 2004-2010, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ Hii.c
+
+Abstract:
+
+ This is an example of how a driver might export data to the HII protocol to be
+ later utilized by the Setup Protocol
+
+--*/
+
+#include "e1000.h"
+#include "hii.h"
+
+EFI_GUID mHiiFormGuid = E1000_HII_FORM_GUID;
+EFI_GUID mE1000DataGuid = E1000_HII_DATA_GUID;
+
+#if 0
+STRING_TOKEN (STR_TERMINATION_STRING);
+#endif
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+
+CHAR16 VariableName[] = L"GigNVData";
+
+UINT32 gGuidInstance = 0;
+
+EFI_STATUS
+GigUndiComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+VOID
+SetWakeOnLan (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINT8 Enable
+ );
+
+VOID
+GetWakeOnLanStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+VOID
+GetWakeOnLanSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+BOOLEAN
+GetFlashEnableStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+);
+
+EFI_STATUS
+GetFlashEnableSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+);
+
+EFI_STATUS
+SetFlashEnable (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ BOOLEAN Enable
+);
+
+
+
+VOID
+e1000_MemCopy (
+ IN UINT8* Dest,
+ IN UINT8* Source,
+ IN UINT32 Count
+ );
+
+UINTN
+GetLanSpeedStatus(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+ UINTN Active;
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // For media other than copper we do not support speed settings
+ //
+
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type != e1000_media_type_copper)
+ return LINK_SPEED_AUTO_NEG;
+
+ // If the device is a dual port device then we need to use the EEPROM settings
+ // for the second adapter port
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ }
+
+ e1000_read_nvm(hw, SetupOffset, 1, &SetupWord);
+
+ //
+ // Save the original setup word value so we can tell if the user changed it
+ //
+ GigUndiPrivateData->NicInfo.BackupSetupWord = SetupWord;
+
+ //
+ // If the boot agent EEPROM signature is not set properly then we will initialize
+ // the words to default values and assume a default autonegotiation setting
+ //
+ e1000_read_nvm(hw, ConfigOffset, 1, &CustomConfigWord);
+
+
+ if ((CustomConfigWord & SIG_MASK) != SIG) {
+ CustomConfigWord = SIG;
+ SetupWord = DISPLAY_SETUP_MESSAGE;
+ Active = LINK_SPEED_AUTO_NEG;
+ } else {
+ //
+ // The signature bits are set so get the speed duplex settings
+ // Mask of the speed and duplex setting bits so that we can determine
+ // what the settings are
+ //
+ switch (SetupWord & (FSP_MASK | FDP_FULL_DUPLEX_BIT))
+ {
+ case (FDP_FULL_DUPLEX_BIT | FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ Active = LINK_SPEED_100FULL;
+ break;
+ case (FDP_FULL_DUPLEX_BIT | FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ Active = LINK_SPEED_10FULL;
+ break;
+ case (FSP_100MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ Active = LINK_SPEED_100HALF;
+ break;
+ case (FSP_10MBS):
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ Active = LINK_SPEED_10HALF;
+ break;
+ default:
+ hw->mac.autoneg = 1;
+ Active = LINK_SPEED_AUTO_NEG;
+ }
+ }
+
+ GigUndiPrivateData->NicInfo.SetupWord = SetupWord;
+ GigUndiPrivateData->NicInfo.CustomConfigWord = CustomConfigWord;
+
+ return Active;
+}
+
+VOID
+SetLanSpeed(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ UINT8 LanSpeed
+)
+{
+ UINT16 SetupOffset;
+ UINT16 ConfigOffset;
+ UINT16 SetupWord;
+ UINT16 CustomConfigWord;
+ UINT8 ReceiveStarted;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // Configure offsets depending on function number
+ //
+ switch(GigUndiPrivateData->NicInfo.Function) {
+ case 0:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ break;
+ case 1:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANB;
+ SetupOffset = SETUP_OPTIONS_WORD_LANB;
+ break;
+ case 2:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LANC;
+ SetupOffset = SETUP_OPTIONS_WORD_LANC;
+ break;
+ case 3:
+ ConfigOffset = CONFIG_CUSTOM_WORD_LAND;
+ SetupOffset = SETUP_OPTIONS_WORD_LAND;
+ break;
+ default:
+ ConfigOffset = CONFIG_CUSTOM_WORD;
+ SetupOffset = SETUP_OPTIONS_WORD;
+ }
+
+ SetupWord = GigUndiPrivateData->NicInfo.SetupWord;
+ CustomConfigWord = GigUndiPrivateData->NicInfo.CustomConfigWord;
+
+ switch (LanSpeed)
+ {
+ case LINK_SPEED_AUTO_NEG:
+ //
+ // Speed mask has already been cleared
+ //
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FSP_AUTONEG);
+ hw->mac.autoneg = 1;
+ break;
+ case LINK_SPEED_100FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_100MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
+ break;
+ case LINK_SPEED_100HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_100MBS;
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_100_HALF;
+ break;
+ case LINK_SPEED_10FULL:
+ SetupWord &= ~FSP_MASK;
+ SetupWord |= (FDP_FULL_DUPLEX_BIT | FSP_10MBS);
+ hw->mac.autoneg = 0;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_FULL;
+ break;
+ case LINK_SPEED_10HALF:
+ SetupWord &= ~(FSP_MASK | FDP_FULL_DUPLEX_BIT);
+ SetupWord |= FSP_10MBS;
+ hw->mac.forced_speed_duplex = ADVERTISE_10_HALF;
+ hw->mac.autoneg = 0;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Only write the EEPROM if the speed/duplex value has changed
+ //
+ if (SetupWord != GigUndiPrivateData->NicInfo.BackupSetupWord) {
+ if (e1000_write_nvm (hw, ConfigOffset, 1, &CustomConfigWord) == E1000_SUCCESS) {
+ if (e1000_write_nvm (hw, SetupOffset, 1, &SetupWord) == E1000_SUCCESS) {
+ //
+ // Success
+ //
+ e1000_update_nvm_checksum (hw);
+ GigUndiPrivateData->NicInfo.BackupSetupWord = SetupWord;
+ }
+ }
+ //
+ // After speed/duplex setting completes we need to perform a full reset of the adapter.
+ // If the adapter was initialized on entry then force a full reset of the adapter.
+ // Also reenable the receive unit if it was enabled before we started the PHY loopback test.
+ //
+
+ ReceiveStarted = GigUndiPrivateData->NicInfo.ReceiveStarted;
+
+ e1000_reset_hw(&GigUndiPrivateData->NicInfo.hw);
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+ if (GigUndiPrivateData->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigUndiPrivateData->NicInfo);
+ DEBUGPRINT(HII, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(HII, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigUndiPrivateData->NicInfo);
+ }
+ }
+ DEBUGPRINT(HII, ("ADAPTER RESET COMPLETE\n"));
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+/*++
+
+ Routine Description:
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Request - A null-terminated Unicode string in <ConfigRequest> format.
+ Progress - On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ Results - A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ Returns:
+ EFI_SUCCESS - The Results is filled with the requested values.
+ EFI_OUT_OF_RESOURCES - Not enough memory to store the results.
+ EFI_INVALID_PARAMETER - Request is NULL, illegal syntax, or unknown name.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+
+ DEBUGPRINT(HII, ("ExtractConfig\n"));
+ GigUndiPrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mE1000DataGuid,
+ NULL,
+ &BufferSize,
+ &GigUndiPrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("GetVariable failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ // Get Wake on LAN settings
+
+ GetWakeOnLanSupport(GigUndiPrivateData);
+ GetWakeOnLanStatus(GigUndiPrivateData);
+
+ DEBUGPRINT(HII, ("GetWakeOnLan %d\n", GigUndiPrivateData->Configuration.WolEnable));
+
+ // Get Option ROM Enable status
+
+ GigUndiPrivateData->Configuration.OptionRomEnable = GetFlashEnableStatus(GigUndiPrivateData);
+
+ DEBUGPRINT(HII, ("GetFlashEnable %d\n", GigUndiPrivateData->Configuration.OptionRomEnable));
+
+ //
+ // Get link speed settings
+ //
+ GigUndiPrivateData->Configuration.LinkSpeed = GetLanSpeedStatus(GigUndiPrivateData);
+
+ DEBUGPRINT(HII, ("GetLinkSpeed %d\n", GigUndiPrivateData->Configuration.LinkSpeed));
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = GigUndiPrivateData->HiiConfigRouting->BlockToConfig (
+ GigUndiPrivateData->HiiConfigRouting,
+ Request,
+ (UINT8 *) &GigUndiPrivateData->Configuration,
+ sizeof(GIG_DRIVER_CONFIGURATION),
+ Results,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("BlockToConfig failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ DEBUGWAIT(HII);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Configuration - A null-terminated Unicode string in <ConfigResp> format.
+ Progress - A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ Returns:
+ EFI_SUCCESS - The Results is processed successfully.
+ EFI_INVALID_PARAMETER - Configuration is NULL.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+
+ DEBUGPRINT(HII, ("RouteConfig\n"));
+ GigUndiPrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mE1000DataGuid,
+ NULL,
+ &BufferSize,
+ &GigUndiPrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("GetVariable failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = GigUndiPrivateData->HiiConfigRouting->ConfigToBlock (
+ GigUndiPrivateData->HiiConfigRouting,
+ Configuration,
+ (UINT8 *) &GigUndiPrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("ConfigToBlock returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+ DEBUGPRINT(HII, ("Set WakeOnLan %d\n", GigUndiPrivateData->Configuration.WolEnable));
+
+ SetFlashEnable (
+ GigUndiPrivateData,
+ GigUndiPrivateData->Configuration.OptionRomEnable
+ );
+
+ SetWakeOnLan (
+ GigUndiPrivateData,
+ GigUndiPrivateData->Configuration.WolEnable
+ );
+
+ SetLanSpeed(
+ GigUndiPrivateData,
+ GigUndiPrivateData->Configuration.LinkSpeed
+ );
+
+ //
+ // Store Buffer Storage back to EFI variable
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &mE1000DataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (GIG_DRIVER_CONFIGURATION),
+ &GigUndiPrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("SetVariable failed with %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ DEBUGWAIT(HII);
+ return Status;
+}
+
+EFI_STATUS
+GetFlashEnableInformation (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ UINT32 *EepromWord,
+ UINT16 *EepromBitMask
+ )
+/*++
+
+ Routine Description:
+ This initializes eeprom addresss and bit mask for flash enable/disable operations.
+
+ Arguments:
+
+ Returns:
+ EFI_SUCCESS - The Results is processed successfully.
+ EFI_UNSUPPORTED - flash enable/disable operations not supported on current port.
+
+--*/
+{
+ UINT16 SetupWord;
+ UINT32 Result;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ //
+ // Check for LOM
+ //
+ Result = e1000_read_nvm(hw, COMPATIBILITY_WORD, 1, &SetupWord);
+
+ if (Result != E1000_SUCCESS) return EFI_DEVICE_ERROR;
+
+ if (SetupWord & COMPATABILITY_LOM_BIT) {
+ DEBUGPRINT(HII, ("LOM - unsupported\n"));
+ DEBUGWAIT(HII);
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUGPRINT(HII, ("\n\nGetFlashEnableInformation\n"));
+ DEBUGPRINT(HII, ("Device ID: %x\n", GigUndiPrivateData->NicInfo.hw.device_id));
+ DEBUGPRINT(HII, ("Function: %x\n", GigUndiPrivateData->NicInfo.Function));
+ DEBUGWAIT(HII);
+
+ switch (GigUndiPrivateData->NicInfo.hw.mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ case e1000_82572:
+ if (GigUndiPrivateData->NicInfo.Function == 0x1)
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3_LANB;
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT;
+ }
+ else
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3;
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT;
+ }
+ break;
+ case e1000_82574:
+ /* Read word containing NVM type bit out of NVM */
+ Result = e1000_read_nvm(hw, E1000_FLASH_SIZE_WORD_HARTW, 1, &SetupWord);
+
+ if (Result != E1000_SUCCESS) return EFI_DEVICE_ERROR;
+
+ if ((GigUndiPrivateData->NicInfo.hw.device_id != E1000_DEV_ID_82574L &&
+ GigUndiPrivateData->NicInfo.hw.device_id != E1000_DEV_ID_82574LA) ||
+ ((SetupWord & E1000_NVM_TYPE_BIT_HARTW) != E1000_NVM_TYPE_BIT_HARTW))
+ {
+ return EFI_UNSUPPORTED;
+ }
+ *EepromWord = E1000_HARTW_FLASH_LAN_ADDRESS;
+ *EepromBitMask = E1000_HARTW_EXP_ROM_DISABLE;
+ break;
+ case e1000_82583:
+ break;
+#endif
+ case e1000_82573:
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+#endif
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ return EFI_UNSUPPORTED;
+ break;
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+ case e1000_82576:
+
+ if (GigUndiPrivateData->NicInfo.hw.subsystem_vendor_id == 0x1734) // FSC
+ {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function == 0x01)
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3_LANB;
+ }
+ else
+ {
+ *EepromWord = E1000_INIT_CONTROL_WORD3;
+ }
+
+ if ((GigUndiPrivateData->NicInfo.hw.revision_id == 0) &&
+ (GigUndiPrivateData->NicInfo.hw.device_id != E1000_DEV_ID_82576))
+ {
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT;
+ }
+ else
+ {
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT_ZOAR;
+ }
+
+ break;
+#endif /* NO_82575_SUPPORT */
+ case e1000_82580:
+ *EepromBitMask = E1000_FLASH_DISABLE_BIT_ZOAR;
+
+ switch(GigUndiPrivateData->NicInfo.Function)
+ {
+ case 0x1:
+ *EepromWord = (LAN1_BASE_ADDRESS_82580 + E1000_INIT_CONTROL_WORD3);
+ break;
+
+ case 0x2:
+ *EepromWord = (LAN2_BASE_ADDRESS_82580 + E1000_INIT_CONTROL_WORD3);
+ break;
+
+ case 0x3:
+ *EepromWord = (LAN3_BASE_ADDRESS_82580 + E1000_INIT_CONTROL_WORD3);
+ break;
+
+ default: //0x0
+ *EepromWord = E1000_INIT_CONTROL_WORD3;
+ break;
+ }
+
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+ DEBUGPRINT(HII, ("EEPROM Word: %x\n", *EepromWord));
+ DEBUGPRINT(HII, ("EepromBitMask: %x\n", *EepromBitMask));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetFlashEnableSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+ UINT32 EepromWord;
+ UINT16 EepromBitMask;
+
+ return GetFlashEnableInformation(GigUndiPrivateData, &EepromWord, &EepromBitMask);
+}
+
+BOOLEAN
+GetFlashEnableStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+ UINT32 EepromWord;
+ UINT16 EepromBitMask;
+
+ UINT16 ReadWord;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ DEBUGPRINT(HII, ("GetFlashEnableStatus\n"));
+
+ if (GetFlashEnableInformation(GigUndiPrivateData, &EepromWord, &EepromBitMask) != EFI_SUCCESS) {
+ return FALSE;
+ }
+
+ e1000_read_nvm(hw, EepromWord, 1, &ReadWord);
+
+ DEBUGPRINT(HII, ("EEPROM Word: %x\n", EepromWord));
+ DEBUGPRINT(HII, ("EepromBitMask: %x\n", EepromBitMask));
+ DEBUGPRINT(HII, ("ReadWord: %x\n", ReadWord));
+
+ if (ReadWord & EepromBitMask){
+ return FALSE; // Flash disabled
+ } else {
+ return TRUE; // Flash enabled
+ }
+}
+
+EFI_STATUS
+SetFlashEnable (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ BOOLEAN Enable
+)
+{
+ UINT32 EepromWord;
+ UINT16 EepromBitMask;
+
+ UINT16 ConfWord, ConfWordTmp;
+
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ GetFlashEnableInformation(GigUndiPrivateData, &EepromWord, &EepromBitMask);
+
+ e1000_read_nvm(hw, EepromWord, 1, &ConfWord);
+
+ if (Enable){
+ ConfWordTmp = ConfWord & ~EepromBitMask;
+ } else {
+ ConfWordTmp = ConfWord | EepromBitMask;
+ }
+
+ if (ConfWordTmp != ConfWord) {
+ if (e1000_write_nvm (hw, EepromWord, 1, &ConfWordTmp) == E1000_SUCCESS)
+ return EFI_SUCCESS;
+ else return EFI_DEVICE_ERROR;
+ }
+ else return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+HiiOpenProtocol(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize the Hii Database handle to NULL so we can check later
+ // to see whether it was installed.
+ //
+ GigUndiPrivateData->HiiDatabase = NULL;
+ GigUndiPrivateData->HiiString = NULL;
+ GigUndiPrivateData->FormBrowser2 = NULL;
+ GigUndiPrivateData->HiiConfigRouting = NULL;
+
+ DEBUGPRINT(HII, ("Locate HII Protocol\n"));
+ //
+ // Locate Hii Database protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->HiiDatabase
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Locate HiiString protocol
+ //
+ DEBUGPRINT(HII, ("Locate HII String Protocol\n"));
+ Status = gBS->LocateProtocol (
+ &gEfiHiiStringProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->HiiString
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII String protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Locate Formbrowser2 protocol
+ //
+ DEBUGPRINT(HII, ("Locate HII Form Browser Protocol\n"));
+ Status = gBS->LocateProtocol (
+ &gEfiFormBrowser2ProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->FormBrowser2
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII form browser protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ DEBUGPRINT(HII, ("Locate HII ConfigRouting Protocol\n"));
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID**)&GigUndiPrivateData->HiiConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Error finding HII ConfigRouting protocol: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ DEBUGWAIT(HII);
+ return Status;
+}
+
+VOID
+SetMacIdString (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ OUT CHAR16 *String
+ )
+{
+ switch (GigUndiPrivateData->NicInfo.hw.mac.type) {
+#ifndef NO_82571_SUPPORT
+ case e1000_82571:
+ UnicodeSPrint(String, 80, L"Intel 82571");
+ break;
+ case e1000_82572:
+ UnicodeSPrint(String, 80, L"Intel 82572");
+ break;
+ case e1000_82573:
+ UnicodeSPrint(String, 80, L"Intel 82573");
+ break;
+#ifndef NO_82574_SUPPORT
+ case e1000_82574:
+ UnicodeSPrint(String, 80, L"Intel 82574");
+ break;
+ case e1000_82583:
+ UnicodeSPrint(String, 80, L"Intel 82583V");
+ break;
+#endif
+#endif
+#ifndef NO_80003ES2LAN_SUPPORT
+ case e1000_80003es2lan:
+ UnicodeSPrint(String, 80, L"Intel 80003ES2LAN");
+ break;
+#endif
+#ifndef NO_ICH8LAN_SUPPORT
+ case e1000_ich8lan:
+ UnicodeSPrint(String, 80, L"Intel ICH8");
+ break;
+ case e1000_ich9lan:
+ UnicodeSPrint(String, 80, L"Intel ICH9");
+ break;
+ case e1000_pchlan:
+ UnicodeSPrint(String, 80, L"Intel PCH");
+ break;
+#endif
+#ifndef NO_82575_SUPPORT
+ case e1000_82575:
+ UnicodeSPrint(String, 80, L"Intel 82575");
+ break;
+ case e1000_82576:
+ UnicodeSPrint(String, 80, L"Intel 82576");
+ break;
+#endif /* NO_82575_SUPPORT */
+ case e1000_82580:
+ UnicodeSPrint(String, 80, L"Intel 82580");
+ break;
+
+ default:
+ UnicodeSPrint(String, 80, L"unknown");
+ break;
+ }
+}
+
+
+VOID
+SetWakeOnLan (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ IN UINT8 Enable
+ )
+{
+ UINT16 Reg;
+ UINT16 Offset;
+
+ DEBUGPRINT(HII, ("SetWakeOnLan\n"));
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ DEBUGPRINT(HII, ("WOL not supported on this port\n"));
+ return;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function == 0) {
+ Offset = E1000_INIT_CONTROL_WORD3;
+ } else {
+ Offset = E1000_INIT_CONTROL_WORD3_LANB;
+ }
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+ if (Enable == WOL_ENABLE) {
+ Reg |= E1000_APM_ENABLE_BIT;
+ } else {
+ Reg &= ~E1000_APM_ENABLE_BIT;
+ }
+ e1000_write_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+
+ Offset = E1000_INIT_CONTROL_WORD2;
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+ if (Enable == WOL_ENABLE) {
+ Reg |= E1000_APM_PME_ENABLE_BIT;
+ } else {
+ Reg &= ~E1000_APM_PME_ENABLE_BIT;
+ }
+ e1000_write_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+
+ e1000_update_nvm_checksum(&GigUndiPrivateData->NicInfo.hw);
+
+ return;
+}
+
+VOID
+GetWakeOnLanSupport (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumHandles = 0;
+ EFI_HANDLE *HandleBuf;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Seg, Bus, Device, Function;
+ UINT16 DeviceId;
+ UINTN i = 0;
+ BOOLEAN LomBit;
+
+ UINT16 SetupWord;
+ UINT32 Result;
+ struct e1000_hw *hw = &GigUndiPrivateData->NicInfo.hw;
+
+ LomBit = FALSE; // Default LomBit to FALSE
+
+ DEBUGPRINT(HII, ("GetWakeOnLanSupport\n"));
+ DEBUGWAIT(HII);
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Check for LOM
+ //
+ Result = e1000_read_nvm(hw, COMPATIBILITY_WORD, 1, &SetupWord);
+
+ if (Result == E1000_SUCCESS){
+ if (SetupWord & COMPATABILITY_LOM_BIT){
+ LomBit = TRUE;
+ }
+ }
+
+ GigUndiPrivateData->Configuration.WolEnable = WOL_DISABLE;
+
+ //
+ // Check for WOL special cases.
+ //
+ switch (GigUndiPrivateData->NicInfo.hw.device_id) {
+ case E1000_DEV_ID_82571EB_COPPER:
+ if (GigUndiPrivateData->NicInfo.hw.subsystem_device_id != 0x135E) {
+ break;
+ }
+ case E1000_DEV_ID_82576: // WOL supported on each port of 82576 LOM device
+ DEBUGPRINT(HII, ("WOL supported on LOM device with ID: %X with subdevice ID: %X\n",
+ GigUndiPrivateData->NicInfo.hw.device_id, GigUndiPrivateData->NicInfo.hw.subsystem_device_id));
+ DEBUGWAIT(HII);
+ if (LomBit == FALSE) break;
+ case E1000_DEV_ID_82576_SERDES_QUAD:
+ DEBUGPRINT(HII, ("WOL supported on this device ID: %X with subdevice ID: %X\n",
+ GigUndiPrivateData->NicInfo.hw.device_id, GigUndiPrivateData->NicInfo.hw.subsystem_device_id));
+ DEBUGWAIT(HII);
+ return;
+ case E1000_DEV_ID_82575GB_QUAD_COPPER:
+ GigUndiPrivateData->Configuration.WolEnable = WOL_NA;
+ DEBUGPRINT(HII, ("WOL not supported on this device ID: %X\n", GigUndiPrivateData->NicInfo.hw.device_id));
+ DEBUGWAIT(HII);
+ return;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function != 0) {
+ GigUndiPrivateData->Configuration.WolEnable = WOL_NA;
+ DEBUGPRINT(HII, ("WOL not supported on non-primary port!\n"));
+ DEBUGWAIT(HII);
+ return;
+ }
+
+ //
+ // Check for quad-port device WOL support
+ //
+ if (GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571EB_QUAD_COPPER ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571EB_QUAD_COPPER_LP ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571EB_QUAD_FIBER ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82576_QUAD_COPPER ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82576_QUAD_COPPER_ET2 ||
+ GigUndiPrivateData->NicInfo.hw.device_id == E1000_DEV_ID_82571PT_QUAD_COPPER
+ ) {
+
+ DEBUGPRINT(HII, ("Quad port card detected, device ID: %x\n", GigUndiPrivateData->NicInfo.hw.device_id));
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuf
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("LocateHandleBuffer returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return;
+ }
+
+ for (i = 0; i < NumHandles; i++) {
+ Status = gBS->OpenProtocol (
+ HandleBuf[i],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ GigUndiPrivateData->ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns status %r for handle[%d] %X\n", Status, i, HandleBuf[i]));
+ continue;
+ }
+
+ PciIo->GetLocation (
+ PciIo,
+ &Seg,
+ &Bus,
+ &Device,
+ &Function
+ );
+
+ //
+ // Only PCI function 0 on the first device supports WOL. On PCIe
+ // cards each device will be on its own secondary bus as device 0.
+ // If we can read device 0 at the next lower bus number and it's
+ // the same ID, then we are looking at the second device on the
+ // card and WOL is not supported. Otherwise it must be the PCIe
+ // switch and therefore this is the first device.
+ //
+ if (Bus == (GigUndiPrivateData->NicInfo.Bus - 1)) {
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 2,
+ 1,
+ &DeviceId
+ );
+ DEBUGPRINT(HII, ("GetWakeOnLanSupport: Read device ID %X on Bus %d\n", DeviceId, Bus));
+ if (DeviceId == GigUndiPrivateData->NicInfo.hw.device_id) {
+ DEBUGPRINT(HII, ("WOL not supported on non-primary port!\n"));
+ GigUndiPrivateData->Configuration.WolEnable = WOL_NA;
+ }
+
+ Status = gBS->CloseProtocol(
+ HandleBuf[i],
+ &gEfiPciIoProtocolGuid,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ GigUndiPrivateData->ControllerHandle
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CloseProtocol returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ break;
+ }
+
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ DEBUGPRINT(HII, ("WOL not supported on this port!\n"));
+ } else {
+ DEBUGPRINT(HII, ("WOL supported on this port!\n"));
+ }
+
+ DEBUGWAIT(HII);
+}
+
+VOID
+GetWakeOnLanStatus (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+{
+ UINT16 Reg;
+ UINT16 Offset;
+
+ DEBUGPRINT(HII, ("GetWakeOnLanStatus\n"));
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ DEBUGPRINT(HII, ("WOL not supported on this port\n"));
+ return;
+ }
+
+ if (GigUndiPrivateData->NicInfo.Function == 0) {
+ Offset = E1000_INIT_CONTROL_WORD3;
+ DEBUGPRINT(HII, ("Port A WoL status\n"));
+ } else {
+ Offset = E1000_INIT_CONTROL_WORD3_LANB;
+ DEBUGPRINT(HII, ("Port B WoL status\n"));
+ }
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, Offset, 1, (UINT16*) &Reg);
+ if ((Reg & E1000_APM_ENABLE_BIT) == E1000_APM_ENABLE_BIT) {
+ GigUndiPrivateData->Configuration.WolEnable = WOL_ENABLE;
+ DEBUGPRINT(HII, ("WOL is enabled on this port\n"));
+ } else {
+ GigUndiPrivateData->Configuration.WolEnable = WOL_DISABLE;
+ DEBUGPRINT(HII, ("WOL is disabled on this port\n"));
+ }
+
+}
+
+EFI_STATUS
+SetMenuStrings(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData,
+ CHAR8 *Lang
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *BrandString;
+ CHAR16 String[HII_STRING_LEN];
+ CHAR16 SubString[HII_STRING_LEN];
+ CHAR8 MacAddr[6];
+ UINTN i, Size;
+ CHAR8 PBAString8[MAX_PBA_STR_LENGTH];
+ CHAR16 PBAString[MAX_PBA_STR_LENGTH];
+
+
+ BrandString = GigUndiPrivateData->Brand;
+
+ //
+ // Branding strings are not localized, use the English branding
+ // string.
+ //
+ UnicodeSPrint(SubString, 85, L"%s", BrandString);
+ UnicodeSPrint(String, 0, L"%s - %02x:%02x:%02x:%02x:%02x:%02x",
+ SubString,
+ GigUndiPrivateData->NicInfo.hw.mac.addr[0],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[1],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[2],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[3],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[4],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[5]);
+
+ Status = HiiSetString (
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_INV_FORM_SET_TITLE),
+ String,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set Factory Default MAC address
+ //
+ DEBUGPRINT(HII, ("Setting MAC address\n"));
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, 0, 3, (UINT16*) MacAddr);
+
+ DEBUGPRINT(HII, ("Adjusting MAC address for PCI function %d\n", (CHAR8) GigUndiPrivateData->NicInfo.Function));
+ MacAddr[5] ^= (CHAR8) GigUndiPrivateData->NicInfo.Function;
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_MAC_ADDR_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("1:GetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ UnicodeSPrint(String, 0, SubString, MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]);
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_MAC_ADDR_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("1:SetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set Alternate MAC address
+ //
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ALT_MAC_ADDR_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("2:GetString error: %r, Size = %d\n", Status, Size));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ UnicodeSPrint(String, 0, SubString,
+ GigUndiPrivateData->NicInfo.hw.mac.addr[0],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[1],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[2],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[3],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[4],
+ GigUndiPrivateData->NicInfo.hw.mac.addr[5]);
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ALT_MAC_ADDR_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("1:SetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set PCI Bus/Device/Function
+ //
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_PCI_BUS_DEV_FUNC_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ UnicodeSPrint(String, 0, SubString,
+ GigUndiPrivateData->NicInfo.Bus,
+ GigUndiPrivateData->NicInfo.Device,
+ GigUndiPrivateData->NicInfo.Function
+ );
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_PCI_BUS_DEV_FUNC_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("4:SetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+
+ //
+ // Set UEFI Driver Branding String
+ //
+ GigUndiComponentNameGetDriverName ( NULL, "eng", &BrandString);
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_EFI_DRIVER_VER_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+ UnicodeSPrint(String, 0, SubString, BrandString);
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_EFI_DRIVER_VER_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("4:IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set MAC ID String, not localized, use English string.
+ //
+ SetMacIdString(GigUndiPrivateData, String);
+ Status = HiiSetString (
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_CONTROLER_ID_TEXT),
+ String,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("6:IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Set PBA number
+ //
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetString (
+ GigUndiPrivateData->HiiString,
+ Lang,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ADAPTER_PBA_TEXT),
+ SubString,
+ &Size,
+ NULL
+ );
+
+
+ if (e1000_read_pba_string(
+ &GigUndiPrivateData->NicInfo.hw,
+ (UINT8*)PBAString8,
+ MAX_PBA_STR_LENGTH) == E1000_SUCCESS) {
+
+ //
+ // Convert CHAR8 to CHAR16 for use with UnicodeSPrint
+ //
+ i = 0;
+ while((PBAString8[i] != '\0') && (i < MAX_PBA_STR_LENGTH)) {
+ PBAString[i] = (CHAR16)PBAString8[i];
+ i++;
+ }
+ PBAString[i] = '\0';
+
+ UnicodeSPrint(String, 0, SubString, PBAString);
+ }
+
+ Status = GigUndiPrivateData->HiiString->SetString (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ STRING_TOKEN (STR_ADAPTER_PBA_TEXT),
+ Lang,
+ String,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("4:IfrLibSetString error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AddDynamicContents(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+/*++
+
+ Routine Description:
+ This function adds some OneOfOpcodes to port configuration form. These Opcodes are dynamically configured
+ depending of current adapter and port capabilities.
+
+ Arguments:
+ GigUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if opcodes were added correctly, otherwise EFI error code
+ is returned.
+
+--*/
+{
+#if 0 //TODO: Port Me
+ EFI_STATUS Status;
+ UINTN CapCnt;
+ IFR_OPTION *IfrOptionList;
+
+ UINT8 QuestionFlags;
+
+ //
+ // Initialize the container for dynamic opcodes.
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ //
+ // Allocate space for creation of Option List
+ //
+ IfrOptionList = AllocatePool (5 * sizeof (IFR_OPTION));
+ if (IfrOptionList == NULL){
+ DEBUGPRINT(CRITICAL, ("Allocate memory for IfrOptionList, out of resource.\n"));
+ DEBUGWAIT(CRITICAL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Create Flash Enable/Disable options
+ //
+
+ if (GetFlashEnableSupport (GigUndiPrivateData) == EFI_SUCCESS) {
+ IfrOptionList[0].Flags = 0;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_DISABLED_TEXT);
+ IfrOptionList[0].Value.UINT8 = OROM_DISABLE;
+ IfrOptionList[1].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_ENABLED_TEXT);
+ IfrOptionList[1].Value.UINT8 = OROM_ENABLE;
+
+ CapCnt = 2;
+
+ QuestionFlags = EFI_IFR_FLAG_RESET_REQUIRED;
+ } else {
+ IfrOptionList[0].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_NA_TEXT);
+ IfrOptionList[0].Value.UINT8 = OROM_DISABLE;
+
+ CapCnt = 1;
+
+ QuestionFlags = EFI_IFR_FLAG_READ_ONLY;
+ }
+
+ //
+ // Create OneOfOpcode
+ //
+ Status = HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ 0x8001, // Question ID
+ 0x1234, // Variable ID
+ 0, // Offset for Enable OROM field
+ STRING_TOKEN (STR_OPTION_ROM_EN_PROMPT), // Prompt Token
+ STRING_TOKEN (STR_OPTION_ROM_EN_HELP), // Help Token
+ QuestionFlags,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ CapCnt, // Number of Options
+ NULL
+ );
+
+ //
+ // Create link speed options depending on link capabilities of adapter
+ //
+
+ CapCnt=0;
+
+ IfrOptionList[0].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_AUTONEG_TEXT);
+ IfrOptionList[0].Value.UINT8 = LINK_SPEED_AUTO_NEG;
+ CapCnt++;
+
+ QuestionFlags = EFI_IFR_FLAG_READ_ONLY;
+
+ // Other options are only available for copper media type
+
+ if (GigUndiPrivateData->NicInfo.hw.phy.media_type == e1000_media_type_copper) {
+
+ IfrOptionList[1].Flags = 0;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_10HALF_TEXT);
+ IfrOptionList[1].Value.UINT8 = LINK_SPEED_10HALF;
+ IfrOptionList[2].Flags = 0;
+ IfrOptionList[2].StringToken = STRING_TOKEN (STR_10FULL_TEXT);
+ IfrOptionList[2].Value.UINT8 = LINK_SPEED_10FULL;
+ IfrOptionList[3].Flags = 0;
+ IfrOptionList[3].StringToken = STRING_TOKEN (STR_100HALF_TEXT);
+ IfrOptionList[3].Value.UINT8 = LINK_SPEED_100HALF;
+ IfrOptionList[4].Flags = 0;
+ IfrOptionList[4].StringToken = STRING_TOKEN (STR_100FULL_TEXT);
+ IfrOptionList[4].Value.UINT8 = LINK_SPEED_100FULL;
+ CapCnt+=4;
+
+ QuestionFlags = 0;
+
+ }
+
+ //
+ // Create OneOfOpcode
+ //
+ Status = HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ 0x8001, // Question ID
+ 0x1234, // Variable ID
+ 1, // Offset for LinkSpeed field
+ STRING_TOKEN (STR_LINK_SPEED_PROMPT), // Prompt Token
+ STRING_TOKEN (STR_LINK_SPEED_HELP), // Help Token
+ QuestionFlags,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ CapCnt, // Number of Options
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CreateOneOfOpcode %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Create WOL options depending on port capabilities
+ //
+
+ GetWakeOnLanSupport(GigUndiPrivateData);
+ GetWakeOnLanStatus(GigUndiPrivateData);
+
+ if (GigUndiPrivateData->Configuration.WolEnable == WOL_NA) {
+ IfrOptionList[0].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_NA_TEXT);
+ IfrOptionList[0].Value.UINT8 = WOL_NA;
+
+ CapCnt = 1;
+
+ QuestionFlags = EFI_IFR_FLAG_READ_ONLY;
+
+ } else {
+ IfrOptionList[0].Flags = 0;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_DISABLED_TEXT);
+ IfrOptionList[0].Value.UINT8 = WOL_DISABLE;
+ IfrOptionList[1].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_ENABLED_TEXT);
+ IfrOptionList[1].Value.UINT8 = WOL_ENABLE;
+
+ CapCnt = 2;
+
+ QuestionFlags = 0;
+
+ }
+
+ //
+ // Create OneOfOpcode
+ //
+ Status = HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ 0x8001, // Question ID
+ 0x1234, // Variable ID
+ 2, // Offset for LegacyBoot field
+ STRING_TOKEN (STR_WOL_TEXT), // Prompt Token
+ STRING_TOKEN (STR_WOL_HELP), // Help Token
+ QuestionFlags,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ CapCnt, // Number of Options
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CreateOneOfOpcode %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+
+ //
+ // Update Form ID 0x1235 with newly created element
+ //
+
+ Status = HiiUpdateForm (
+ GigUndiPrivateData->HiiHandle,
+ &mHiiFormGuid,
+ FORM_2, // Destination form ID
+ TRUE,
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("IfrLibUpdateForm %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ gBS->FreePool (IfrOptionList);
+
+ return Status;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+
+EFI_STATUS
+InventoryPackage(
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+)
+{
+#if 0 //TODO: PortMe
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList = NULL;
+ CHAR8 Lang[HII_STRING_LEN];
+ CHAR8 SubLang[HII_STRING_LEN];
+ UINTN Size;
+ UINTN i, j;
+
+ DEBUGPRINT(HII, ("InventoryPackage\n"));
+
+ PackageList = PreparePackageList (
+ 2,
+ &GigUndiPrivateData->HiiFormGuid,
+ GigUndiStrings,
+ inventoryBin
+ );
+ if (PackageList == NULL) {
+ DEBUGPRINT(CRITICAL, ("PreparePackageList, out of resource.\n"));
+ DEBUGWAIT(CRITICAL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUGPRINT(HII, ("Calling NewPackageList: %X %X\n", GigUndiPrivateData->HiiDatabase, PackageList));
+ Status = GigUndiPrivateData->HiiDatabase->NewPackageList (
+ GigUndiPrivateData->HiiDatabase,
+ PackageList,
+ GigUndiPrivateData->ControllerHandle,
+ &GigUndiPrivateData->HiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PackageList);
+ DEBUGPRINT(CRITICAL, ("NewPackageList error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ Size = HII_STRING_LEN;
+ Status = GigUndiPrivateData->HiiString->GetLanguages (
+ GigUndiPrivateData->HiiString,
+ GigUndiPrivateData->HiiHandle,
+ Lang,
+ &Size
+ );
+
+ for (i = 0; i < Size; i++) {
+ DEBUGPRINT(HII, ("%c", Lang[i]));
+ }
+ DEBUGPRINT (HII, ("Languages: %a, Size: %d\n", Lang, Size));
+ DEBUGPRINT (HII, ("GetLanguages returns %r\n", Status));
+
+ i = 0;
+ while (i < Size) {
+ j=0;
+ do {
+ if (Lang[i] == ';') {
+ SubLang[j]='\0';
+ i++;
+ j++;
+ break;
+ }else{
+ SubLang[j]=Lang[i];
+ i++;
+ j++;
+ }
+
+ } while (Lang[i] != '\0');
+
+ //
+ //Set strings for all languages except x-UEFI
+ //
+ if (SubLang[0] != 'x') Status = SetMenuStrings(GigUndiPrivateData, SubLang);
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("SetMenuStrings returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ break;
+ }
+
+ // This was the last supported language so we can leave the loop
+ if (Lang[i] == '\0')
+ break;
+ }
+
+ Status = AddDynamicContents(GigUndiPrivateData);
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("AddDynamicContents returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ return Status;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+EFI_STATUS
+EFIAPI
+DriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ DEBUGPRINT(HII, ("DriverCallback\n"));
+ DEBUGWAIT(HII);
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+
+ switch (QuestionId) {
+ case 0x1236:
+ DEBUGPRINT(HII, ("Save key press\n"));
+ DEBUGWAIT(HII);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ break;
+
+ case 0x1237:
+ //
+ // User press "Exit now", request Browser to exit
+ //
+ DEBUGPRINT(HII, ("Exit key press\n"));
+ DEBUGWAIT(HII);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+HiiInit (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ Installs the HII user interface screen in the UEFI device manager.
+
+ Arguments:
+ GigUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if HII interface installed correctly, otherwise EFI error code
+ is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_SCREEN_DESCRIPTOR Screen;
+ UINTN BufferSize;
+ BOOLEAN ExtractIfrDefault;
+ UINT8 MacAddr[6];
+
+ DEBUGPRINT(HII, ("HiiInit\n"));
+
+ //
+ // Try to open the HII protocols first. If they are not present in the system
+ // get out.
+ //
+ Status = HiiOpenProtocol(GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("HiiOpenProtocol returns: %x\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Initialize screen dimensions for SendForm().
+ // Remove 3 characters from top and bottom
+ //
+ ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow);
+
+ Screen.TopRow = 3;
+ Screen.BottomRow = Screen.BottomRow - 3;
+
+ e1000_MemCopy ((UINT8 *) (UINTN) &GigUndiPrivateData->HiiFormGuid, (UINT8 *) (UINTN) &mHiiFormGuid, sizeof(EFI_GUID));
+ //
+ // Copy the factory default MAC address into the last 6 bytes of the GUID to ensure the GUID is unique.
+ //
+ e1000_read_nvm(&GigUndiPrivateData->NicInfo.hw, 0, 3, (UINT16*) MacAddr);
+ MacAddr[5] ^= (CHAR8) GigUndiPrivateData->NicInfo.Function;
+
+ GigUndiPrivateData->HiiFormGuid.Data4[0] = MacAddr[0];
+ GigUndiPrivateData->HiiFormGuid.Data4[1] = MacAddr[1];
+ GigUndiPrivateData->HiiFormGuid.Data4[2] = MacAddr[2];
+ GigUndiPrivateData->HiiFormGuid.Data4[3] = MacAddr[3];
+ GigUndiPrivateData->HiiFormGuid.Data4[4] = MacAddr[4];
+ GigUndiPrivateData->HiiFormGuid.Data4[5] = MacAddr[5];
+
+
+ GigUndiPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ GigUndiPrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ GigUndiPrivateData->ConfigAccess.Callback = DriverCallback;
+
+ Status = gBS->InstallProtocolInterface (
+ &GigUndiPrivateData->ControllerHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &GigUndiPrivateData->ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InstallProtocolInterface error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = InventoryPackage(GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InventoryPackage returns: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ //
+ // Initialize configuration data
+ //
+ DEBUGPRINT(HII, ("initialize configuration data\n"));
+ ZeroMem (&GigUndiPrivateData->Configuration, sizeof (GIG_DRIVER_CONFIGURATION));
+
+ //
+ // Try to read NV config EFI variable first
+ //
+ ExtractIfrDefault = TRUE;
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mE1000DataGuid,
+ NULL,
+ &BufferSize,
+ &GigUndiPrivateData->Configuration
+ );
+ if (!EFI_ERROR (Status) && (BufferSize == sizeof (GIG_DRIVER_CONFIGURATION))) {
+ DEBUGPRINT(HII, ("E1000 NV variable already created\n"));
+ ExtractIfrDefault = FALSE;
+ }
+
+ if (ExtractIfrDefault) {
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ DEBUGPRINT(HII, ("Creating E1000 variable.\n"));
+ BufferSize = sizeof (GIG_DRIVER_CONFIGURATION);
+
+ GigUndiPrivateData->Configuration.OptionRomEnable = GetFlashEnableStatus(GigUndiPrivateData);
+ GigUndiPrivateData->Configuration.LinkSpeed = GetLanSpeedStatus(GigUndiPrivateData);
+
+ GetWakeOnLanSupport (GigUndiPrivateData);
+ GetWakeOnLanStatus (GigUndiPrivateData);
+
+ gRT->SetVariable(
+ VariableName,
+ &mE1000DataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (GIG_DRIVER_CONFIGURATION),
+ &GigUndiPrivateData->Configuration
+ );
+ }
+
+
+ DEBUGPRINT(HII, ("HiiInit is complete\n"));
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+HiiUnload (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ )
+/*++
+
+ Routine Description:
+ HII uninstalls the HII user interface screen in the UEFI device manager.
+
+ Arguments:
+ GigUndiPrivateData - Points to the driver instance private data.
+
+ Returns:
+ EFI_SUCCESS if HII interface uninstalled correctly, otherwise EFI error code
+ is returned.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ if (GigUndiPrivateData->HiiDatabase == NULL ||
+ GigUndiPrivateData->HiiString == NULL ||
+ GigUndiPrivateData->FormBrowser2 == NULL ||
+ GigUndiPrivateData->HiiConfigRouting == NULL
+ ) {
+ DEBUGPRINT(HII, ("HII Not initialized, returning.\n"));
+ return EFI_SUCCESS;
+ }
+
+ DEBUGPRINT(HII, ("Calling RemovePackageList: %X\n", GigUndiPrivateData->HiiDatabase));
+ Status = GigUndiPrivateData->HiiDatabase->RemovePackageList (
+ GigUndiPrivateData->HiiDatabase,
+ GigUndiPrivateData->HiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("RemovePackageList error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+
+ Status = gBS->UninstallProtocolInterface (
+ GigUndiPrivateData->ControllerHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &GigUndiPrivateData->ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallProtocolInterface error: %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ }
+
+ return Status;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h
new file mode 100755
index 0000000..bf582ab
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/hii.h
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 2004-2010, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Hii.h
+
+Abstract:
+
+
+Revision History
+
+--*/
+
+#ifndef _HII_H_
+#define _HII_H_
+
+#include "NVDataStruc.h"
+
+//
+// This is the generated header file which includes whatever needs to be exported (strings + IFR)
+//
+#include "LanIntelE1000DxeStrDefs.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of PreparePackageList() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 vfrBin[];
+extern UINT8 inventoryBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of PreparePackageList() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 GigUndiStrings[];
+
+#define SAMPLE_STRING L"This is an error!"
+
+#define DRIVER_SAMPLE_PRIVATE_SIGNATURE SIGNATURE_32 ('D', 'S', 'p', 's')
+
+//
+// EEPROM power management bit definitions
+//
+#define E1000_INIT_CONTROL_WORD1 0x0A
+#define E1000_PME_ENABLE_BIT 0x0008
+
+#define E1000_INIT_CONTROL_WORD2 0x0F
+#define E1000_APM_PME_ENABLE_BIT 0x8000
+
+#define E1000_LEGACY_APM_ENABLE_BIT 0x0004
+#define E1000_LEGACY_FLASH_DISABLE_BIT 0x0100
+
+#define E1000_INIT_CONTROL_WORD3 0x24
+#define E1000_INIT_CONTROL_WORD3_LANB 0x14
+#define E1000_FLASH_DISABLE_BIT 0x0800
+#define E1000_FLASH_DISABLE_BIT_ZOAR 0x0080
+#define E1000_APM_ENABLE_BIT 0x0400
+
+#define E1000_FLASH_SIZE_WORD_HARTW 0xf
+#define E1000_NVM_TYPE_BIT_HARTW 0x1000
+
+#define E1000_HARTW_FLASH_LAN_ADDRESS 0x21
+#define E1000_HARTW_EXP_ROM_DISABLE 0x80 /* bit 7 */
+
+#define LAN1_BASE_ADDRESS_82580 0x80
+#define LAN2_BASE_ADDRESS_82580 0xC0
+#define LAN3_BASE_ADDRESS_82580 0x100
+
+
+#define HII_STRING_LEN 200
+#define MAX_PBA_STR_LENGTH 15 // normally it is 10 chars string
+
+#define DRIVER_SAMPLE_PRIVATE_FROM_THIS(a) CR (a, GIG_UNDI_PRIVATE_DATA, ConfigAccess, GIG_UNDI_DEV_SIGNATURE)
+
+#endif
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h
new file mode 100755
index 0000000..7be86a5
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/ieee_define.h
@@ -0,0 +1,33 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c
new file mode 100755
index 0000000..6979034
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/init.c
@@ -0,0 +1,1505 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+#include "clp.h"
+
+
+//
+// Global Variables
+//
+VOID *e1000_pxe_memptr = NULL;
+PXE_SW_UNDI *e1000_pxe_31 = NULL; // 3.1 entry
+GIG_UNDI_PRIVATE_DATA *e1000_UNDI32DeviceList[MAX_NIC_INTERFACES];
+NII_TABLE e1000_UndiData;
+UINT8 ActiveInterfaces = 0;
+EFI_EVENT EventNotifyExitBs;
+EFI_EVENT EventNotifyVirtual;
+
+//
+// external Global Variables
+//
+extern UNDI_CALL_TABLE e1000_api_table[];
+extern EFI_COMPONENT_NAME_PROTOCOL gGigUndiComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gGigUndiComponentName2;
+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gGigUndiSupportedEFIVersion;
+extern EFI_DRIVER_CONFIGURATION_PROTOCOL gGigUndiDriverConfiguration;
+extern EFI_DRIVER_DIAGNOSTICS_PROTOCOL gGigUndiDriverDiagnostics;
+extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gGigUndiDriverDiagnostics2;
+
+extern EFI_GUID gEfiStartStopProtocolGuid;
+
+#define EFI_PRO1000_COM_GUID \
+ { \
+ 0xE3161450, 0xAD0F, 0x11D9, \
+ { \
+ 0x96, 0x69, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 \
+ } \
+ }
+
+EFI_GUID gEfiPro1000ComGuid = EFI_PRO1000_COM_GUID;
+
+//
+// function prototypes
+//
+EFI_STATUS
+EFIAPI
+InitializeGigUNDIDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+VOID
+EFIAPI
+GigUndiNotifyExitBs (
+ EFI_EVENT Event,
+ VOID *Context
+ );
+
+EFI_STATUS
+InitializePxeStruct(VOID);
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+GigAppendMac2DevPath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ );
+
+VOID
+GigUndiPxeStructInit (
+ PXE_SW_UNDI *PxePtr,
+ UINTN VersionFlag
+ );
+
+VOID
+GigUndiPxeUpdate (
+ IN GIG_DRIVER_DATA *NicPtr,
+ IN PXE_SW_UNDI *PxePtr
+ );
+
+EFI_STATUS
+EFIAPI
+GigUndiUnload (
+ IN EFI_HANDLE ImageHandle
+ );
+
+UINT8
+e1000_ChkSum (
+ IN VOID *Buffer,
+ IN UINT16 Len
+ );
+
+EFI_STATUS
+EFIAPI
+HiiInit (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+EFI_STATUS
+EFIAPI
+HiiUnload (
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+EFI_STATUS
+InitFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+
+EFI_STATUS
+UninstallFirmwareManagementProtocol (
+ IN GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData
+ );
+
+//
+// end function prototypes
+//
+//
+// This is a macro to convert the preprocessor defined version number into a hex value
+// that can be registered with EFI.
+//
+#define VERSION_TO_HEX ((MAJORVERSION << 24) + (MINORVERSION << 16) + (BUILDNUMBER / 10 << 12) + (BUILDNUMBER % 10 << 8))
+
+//
+// UNDI Class Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding = {
+ GigUndiDriverSupported, // Supported
+ GigUndiDriverStart, // Start
+ GigUndiDriverStop, // Stop
+ VERSION_TO_HEX, // Driver Version
+ NULL, // ImageHandle
+ NULL // Driver Binding Handle
+};
+
+EFI_STATUS
+EFIAPI
+InitializeGigUNDIDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+ Register Driver Binding protocol for this driver.
+
+Arguments:
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
+
+Returns:
+ EFI_SUCCESS - Driver loaded.
+ other - Driver not loaded.
+
+--*/
+// GC_TODO: ImageHandle - add argument and description to function comment
+// GC_TODO: SystemTable - add argument and description to function comment
+{
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImageInterface;
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBinding (ImageHandle, SystemTable, &mGigUndiDriverBinding, ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUGPRINT (INIT, ("SystemTable->Hdr.Revision = %x\n", SystemTable->Hdr.Revision));
+
+ DEBUGPRINT (INIT, ("Installing UEFI 1.10/2.10 Driver Diags and Component Name protocols.\n"));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mGigUndiDriverBinding.DriverBindingHandle,
+ &gEfiComponentNameProtocolGuid,
+ &gGigUndiComponentName,
+ &gEfiDriverDiagnosticsProtocolGuid,
+ &gGigUndiDriverDiagnostics,
+ &gEfiComponentName2ProtocolGuid,
+ &gGigUndiComponentName2,
+ &gEfiDriverDiagnostics2ProtocolGuid,
+ &gGigUndiDriverDiagnostics2,
+ &gEfiDriverConfigurationProtocolGuid,
+ &gGigUndiDriverConfiguration,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("InstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+ if (SystemTable->Hdr.Revision >= EFI_2_10_SYSTEM_TABLE_REVISION) {
+ DEBUGPRINT (INIT, ("Installing UEFI 2.1 Supported EFI Version Protocol.\n"));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gGigUndiSupportedEFIVersion,
+ NULL
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("InstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+
+ //
+ // This protocol does not need to be closed because it uses the GET_PROTOCOL attribute
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID *) &LoadedImageInterface,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ return Status;
+ }
+
+ LoadedImageInterface->Unload = GigUndiUnload;
+
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_NOTIFY,
+ GigUndiNotifyExitBs,
+ NULL,
+ &EventNotifyExitBs
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("CreateEvent returns %r\n", Status));
+ return Status;
+ }
+
+ Status = InitializePxeStruct();
+
+ return Status;
+}
+
+
+EFI_STATUS
+InitializePxeStruct(VOID)
+/*++
+
+Routine Description:
+ Allocate and initialize both (old and new) the !pxe structures here,
+ there should only be one copy of each of these structure for any number
+ of NICs this undi supports. Also, these structures need to be on a
+ paragraph boundary as per the spec. so, while allocating space for these,
+ make sure that there is space for 2 !pxe structures (old and new) and a
+ 32 bytes padding for alignment adjustment (in case)
+
+Arguments:
+ VOID
+
+Returns:
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData, //EfiRuntimeServicesData,
+ (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),
+ &e1000_pxe_memptr
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("AllocatePool returns %r\n", Status));
+ return Status;
+ }
+
+ ZeroMem (
+ e1000_pxe_memptr,
+ sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32
+ );
+
+ //
+ // check for paragraph alignment here, assuming that the pointer is
+ // already 8 byte aligned.
+ //
+ if (((UINTN) e1000_pxe_memptr & 0x0F) != 0) {
+ e1000_pxe_31 = (PXE_SW_UNDI *) ((UINTN)( (((UINTN)e1000_pxe_memptr) & (0xFFFFFFFFFFFFFFF0)) + 0x10 ));
+ } else {
+ e1000_pxe_31 = (PXE_SW_UNDI *) e1000_pxe_memptr;
+ }
+
+ //
+ // assuming that the sizeof pxe_31 is a 16 byte multiple
+ //
+ //e1000_pxe = (PXE_SW_UNDI*)((UINT8 *)(e1000_pxe_31) + sizeof (PXE_SW_UNDI));
+
+ // GigUndiPxeStructInit (e1000_pxe, 0x30); // 3.0 entry point
+ GigUndiPxeStructInit (e1000_pxe_31, 0x31); // 3.1 entry
+
+ return Status;
+}
+
+VOID
+EFIAPI
+GigUndiNotifyExitBs (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+/*++
+
+Routine Description:
+ When EFI is shuting down the boot services, we need to install a
+ configuration table for UNDI to work at runtime!
+
+Arguments:
+ (Standard Event handler)
+
+Returns:
+ None
+
+--*/
+// GC_TODO: Context - add argument and description to function comment
+{
+ UINT32 i;
+
+ //
+ // Divide Active interfaces by two because it tracks both the controller and
+ // child handle, then shutdown the receive unit in case it did not get done
+ // by the SNP, and release the software semaphore aquired by the shared code
+ //
+ for (i = 0; i < ActiveInterfaces; i++) {
+ if (e1000_UNDI32DeviceList[i]->NicInfo.hw.device_id != 0) {
+ E1000_WRITE_REG (&(e1000_UNDI32DeviceList[i]->NicInfo.hw), E1000_RCTL, 0);
+ E1000_WRITE_REG (&(e1000_UNDI32DeviceList[i]->NicInfo.hw), E1000_SWSM, 0);
+ e1000_PciFlush (&e1000_UNDI32DeviceList[i]->NicInfo.hw);
+ //
+ // Delay for 10ms to allow in progress DMA to complete
+ //
+ gBS->Stall(10000);
+ }
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+GigUndiUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+ Callback to unload the GigUndi from memory.
+
+Arguments:
+ ImageHandle to driver.
+
+Returns:
+ EFI_SUCCESS - This driver was unloaded successfully.
+ EFI_INVALID_PARAMETER - This driver was not unloaded.
+
+--*/
+{
+ EFI_HANDLE *DeviceHandleBuffer;
+ UINTN DeviceHandleCount;
+ UINTN Index;
+
+ EFI_STATUS Status;
+
+ DEBUGPRINT(INIT, ("GigUndiUnload e1000_pxe->IFcnt = %d\n", e1000_pxe_31->IFcnt));
+ DEBUGWAIT (INIT);
+
+ //
+ // Get the list of all the handles in the handle database.
+ // If there is an error getting the list, then the unload operation fails.
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &DeviceHandleCount,
+ &DeviceHandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("LocateHandleBuffer returns %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Disconnect the driver specified by ImageHandle from all the devices in the
+ // handle database.
+ //
+ DEBUGPRINT(INIT, ("Active interfaces = %d\n", ActiveInterfaces));
+ for (Index = 0; Index < DeviceHandleCount; Index++) {
+ Status = gBS->DisconnectController (
+ DeviceHandleBuffer[Index],
+ ImageHandle,
+ NULL
+ );
+ }
+ DEBUGPRINT(INIT, ("Active interfaces = %d\n", ActiveInterfaces));
+
+ //
+ // Free the buffer containing the list of handles from the handle database
+ //
+ if (DeviceHandleBuffer != NULL) {
+ gBS->FreePool (DeviceHandleBuffer);
+ }
+
+ if (ActiveInterfaces == 0) {
+ //
+ // Free PXE structures since they will no longer be needed
+ //
+ Status = gBS->FreePool (e1000_pxe_memptr);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("FreePool returns %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Close both events before unloading
+ //
+ Status = gBS->CloseEvent (EventNotifyExitBs);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("CloseEvent returns %r\n", Status));
+ return Status;
+ }
+
+ DEBUGPRINT (INIT, ("Uninstalling UEFI 1.10/2.10 Driver Diags and Component Name protocols.\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &mGigUndiDriverBinding,
+ &gEfiComponentNameProtocolGuid,
+ &gGigUndiComponentName,
+ &gEfiDriverDiagnosticsProtocolGuid,
+ &gGigUndiDriverDiagnostics,
+ &gEfiComponentName2ProtocolGuid,
+ &gGigUndiComponentName2,
+ &gEfiDriverDiagnostics2ProtocolGuid,
+ &gGigUndiDriverDiagnostics2,
+ &gEfiDriverConfigurationProtocolGuid,
+ &gGigUndiDriverConfiguration,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("UninstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+
+ if (gST->Hdr.Revision >= EFI_2_10_SYSTEM_TABLE_REVISION) {
+ DEBUGPRINT (INIT, ("Uninstalling UEFI 2.1 Supported EFI Version Protocol.\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gGigUndiSupportedEFIVersion,
+ NULL
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("UninstallMultipleProtocolInterfaces returns %x\n", Status));
+ return Status;
+ }
+
+ } else {
+ DEBUGPRINT(INIT, ("Returning EFI_INVALID_PARAMETER\n"));
+ DEBUGWAIT (INIT);
+ return EFI_INVALID_PARAMETER;
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,
+ and DeviceId matching an Intel PRO/1000 adapter can be supported.
+
+Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to test.
+ RemainingDevicePath - Not used.
+
+Returns:
+ EFI_SUCCESS - This driver supports this device.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PCI_CONFIG_HEADER),
+ &Pci
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.VendorId == INTEL_VENDOR_ID) {
+ if (
+#ifndef NO_82571_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_QUAD_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571PT_QUAD_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_QUAD_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82571EB_QUAD_COPPER_LP ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82572EI ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82573E ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82573E_IAMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82573L ||
+#ifndef NO_82574_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82574L ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82574LA ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82583V ||
+#endif
+#endif /* NO_82571_SUPPORT */
+
+#ifndef NO_80003ES2LAN_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_COPPER_DPT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_SERDES_DPT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_COPPER_SPT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_80003ES2LAN_SERDES_SPT ||
+#endif /* NO_80003ES2LAN_SUPPORT */
+
+#ifndef NO_ICH8LAN_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_M_AMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_AMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_C ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IFE ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH8_IGP_M ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_M ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_M_AMT ||//
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_M_V ||//
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_AMT ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_BM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH9_IGP_C ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH10_R_BM_LM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH10_R_BM_LF ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_ICH10_R_BM_V ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_M_HV_LM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_M_HV_LC ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_D_HV_DM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH_D_HV_DC ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH2_LV_LM ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_PCH2_LV_V ||
+#endif /* NO_ICH8LAN_SUPPORT */
+
+#ifndef NO_82575_SUPPORT
+#ifndef NO_82576_SUPPORT
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576 ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_QUAD_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_QUAD_COPPER_ET2 ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_NS ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_NS_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82576_SERDES_QUAD ||
+#endif /* NO_82576_SUPPORT */
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82575EB_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82575EB_FIBER_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82575GB_QUAD_COPPER ||
+#endif /* NO_82575_SUPPORT */
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_COPPER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_FIBER ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_SERDES ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_SGMII ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_COPPER_DUAL ||
+ Pci.Hdr.DeviceId == E1000_DEV_ID_82580_QUAD_FIBER ||
+ Pci.Hdr.DeviceId == 0xDEAD
+ ) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ Start this driver on Controller by opening PciIo and DevicePath protocol.
+ Initialize PXE structures, create a copy of the Controller Device Path with the
+ NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol
+ on the newly created Device Path.
+
+Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to work with.
+ RemainingDevicePath - Not used, always produce all possible children.
+
+Returns:
+ EFI_SUCCESS - This driver is added to Controller.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PCI_IO_PROTOCOL *PciIoFncs;
+ UINT64 Result = 0;
+ EFI_STATUS Status;
+
+ DEBUGPRINT(INIT, ("GigUndiDriverStart\n"));
+ DEBUGWAIT(INIT);
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (GIG_UNDI_PRIVATE_DATA),
+ (VOID **) &GigUndiPrivateData
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("AllocatePool returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiError;
+ }
+
+ ZeroMem ((UINT8 *) GigUndiPrivateData, sizeof (GIG_UNDI_PRIVATE_DATA));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &GigUndiPrivateData->NicInfo.PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData->NIIProtocol_31.Id = (UINT64) (e1000_pxe_31);
+
+ //
+ // Get the PCI Command options that are supported by this controller.
+ //
+ Status = GigUndiPrivateData->NicInfo.PciIo->Attributes (
+ GigUndiPrivateData->NicInfo.PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Result
+ );
+
+ DEBUGPRINT(INIT, ("Attributes supported %x\n", Result));
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Attributes returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiError;
+ }
+
+ //
+ // Set the PCI Command options to enable device memory mapped IO,
+ // port IO, and bus mastering.
+ //
+ Status = GigUndiPrivateData->NicInfo.PciIo->Attributes (
+ GigUndiPrivateData->NicInfo.PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Result & (EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE),
+ NULL
+ );
+
+ DEBUGPRINT(INIT, ("Attributes enabled %x\n", Result));
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Attributes returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiError;
+ }
+
+ //
+ // the IfNum index for the current interface will be the total number
+ // of interfaces initialized so far
+ //
+ GigUndiPxeUpdate (&GigUndiPrivateData->NicInfo, e1000_pxe_31);
+ //
+ // IFcnt should be equal to the total number of physical ports - 1
+ //
+ DEBUGWAIT(INIT);
+ GigUndiPrivateData->NIIProtocol_31.IfNum = e1000_pxe_31->IFcnt;
+ e1000_UNDI32DeviceList[GigUndiPrivateData->NIIProtocol_31.IfNum] = GigUndiPrivateData;
+
+ ActiveInterfaces++;
+ GigUndiPrivateData->Undi32BaseDevPath = UndiDevicePath;
+
+ //
+ // Initialize the UNDI callback functions to 0 so that the default boot services
+ // callback is used instead of the SNP callback.
+ //
+ GigUndiPrivateData->NicInfo.Delay = (VOID *) 0;
+ GigUndiPrivateData->NicInfo.Virt2Phys = (VOID *) 0;
+ GigUndiPrivateData->NicInfo.Block = (VOID *) 0;
+ GigUndiPrivateData->NicInfo.MapMem = (void *) 0;
+ GigUndiPrivateData->NicInfo.UnMapMem = (void *) 0;
+ GigUndiPrivateData->NicInfo.SyncMem = (void *) 0;
+ GigUndiPrivateData->NicInfo.Unique_ID = (UINT64) &GigUndiPrivateData->NicInfo;
+ GigUndiPrivateData->NicInfo.VersionFlag = 0x31;
+
+ //
+ // Allocate memory for transmit and receive resources.
+ //
+ Status = GigUndiPrivateData->NicInfo.PciIo->AllocateBuffer (
+ GigUndiPrivateData->NicInfo.PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ UNDI_MEM_PAGES (MEMORY_NEEDED),
+ (VOID **) &GigUndiPrivateData->NicInfo.MemoryPtr,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("AllocateBuffer returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+
+ //
+ // Perform the first time initialization of the hardware
+ //
+ Status = e1000_FirstTimeInit (&GigUndiPrivateData->NicInfo);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("e1000_FirstTimeInit returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ Status = ClpEntry (
+ This,
+ Controller,
+ &GigUndiPrivateData->NicInfo
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("ClpEntry returns %r\n", Status));
+ }
+
+ //
+ // Re-read the MAC address after running CLP. This will also set the RAR0 address
+ // if the alternate MAC address is in effect.
+ //
+ if (e1000_read_mac_addr (&GigUndiPrivateData->NicInfo.hw) != E1000_SUCCESS) {
+ DEBUGPRINT(INIT, ("Could not read MAC address\n"));
+ }
+
+ Status = GigAppendMac2DevPath (
+ &GigUndiPrivateData->Undi32DevPath,
+ GigUndiPrivateData->Undi32BaseDevPath,
+ &GigUndiPrivateData->NicInfo
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("GigAppendMac2DevPath returns %r\n", Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ //
+ // Figure out the controllers name for the Component Naming protocol
+ // This must be performed after GigAppendMac2DevPath because we need the MAC
+ // address of the controller to name it properly
+ //
+ GetUndiControllerName (GigUndiPrivateData);
+
+ GigUndiPrivateData->Signature = GIG_UNDI_DEV_SIGNATURE;
+
+ GigUndiPrivateData->NIIProtocol_31.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
+ GigUndiPrivateData->NIIProtocol_31.Type = EfiNetworkInterfaceUndi;
+ GigUndiPrivateData->NIIProtocol_31.MajorVer = PXE_ROMID_MAJORVER;
+ GigUndiPrivateData->NIIProtocol_31.MinorVer = PXE_ROMID_MINORVER;
+ GigUndiPrivateData->NIIProtocol_31.ImageSize = 0;
+ GigUndiPrivateData->NIIProtocol_31.ImageAddr = 0;
+ GigUndiPrivateData->NIIProtocol_31.Ipv6Supported = TRUE;
+
+ GigUndiPrivateData->NIIProtocol_31.StringId[0] = 'U';
+ GigUndiPrivateData->NIIProtocol_31.StringId[1] = 'N';
+ GigUndiPrivateData->NIIProtocol_31.StringId[2] = 'D';
+ GigUndiPrivateData->NIIProtocol_31.StringId[3] = 'I';
+
+ GigUndiPrivateData->DeviceHandle = NULL;
+
+ GigUndiPrivateData->NicInfo.HwInitialized = FALSE;
+
+ //
+ // The PRO1000 COM protocol is used only by this driver. It is done so that
+ // we can get the NII protocol from either the parent or the child handle. This is convenient
+ // in the Diagnostic protocol because it allows the test to be run when called from either the
+ // parent or child handle which makes it more user friendly.
+ //
+ GigUndiPrivateData->EfiPro1000Com.NIIProtocol_31 = &GigUndiPrivateData->NIIProtocol_31;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ NULL
+ );
+
+ DEBUGPRINT(INIT, ("InstallMultipleProtocolInterfaces returns = %d %r\n", Status, Status));
+ DEBUGWAIT(INIT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InstallMultipleProtocolInterfaces returns Error = %d %r\n", Status, Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ GigUndiPrivateData->DriverStop.StartDriver = StartDriver;
+ GigUndiPrivateData->DriverStop.StopDriver = StopDriver;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &GigUndiPrivateData->DeviceHandle,
+ &gEfiDevicePathProtocolGuid, GigUndiPrivateData->Undi32DevPath,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &GigUndiPrivateData->NIIProtocol_31,
+ &gEfiVlanProtocolGuid, &gGigUndiVlanData,
+ &gEfiStartStopProtocolGuid, &GigUndiPrivateData->DriverStop,
+ NULL
+ );
+ DEBUGPRINT(INIT, ("InstallMultipleProtocolInterfaces returns = %d %r\n", Status, Status));
+ DEBUGWAIT(INIT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("InstallMultipleProtocolInterfaces returns Error = %d %r\n", Status, Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ Status = InitFirmwareManagementProtocol (GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT (CRITICAL, ("Could not install Firmware Management protocol interfaces. Error = %d %r\n", Status, Status));
+ DEBUGWAIT(CRITICAL);
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIoFncs,
+ This->DriverBindingHandle,
+ GigUndiPrivateData->DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ }
+
+ //
+ // Save off the controller handle so we can disconnect the driver later
+ //
+ GigUndiPrivateData->ControllerHandle = Controller;
+ DEBUGPRINT(INIT, ("ControllerHandle = %x, DeviceHandle = %x\n",
+ GigUndiPrivateData->ControllerHandle,
+ GigUndiPrivateData->DeviceHandle
+ ));
+
+ //
+ // HII may not install, so we do not want to return any errors
+ //
+ Status = HiiInit(GigUndiPrivateData);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("HiiInit returns %r\n", Status));
+ }
+
+ return EFI_SUCCESS;
+
+UndiErrorDeleteDevicePath:
+ e1000_UNDI32DeviceList[GigUndiPrivateData->NIIProtocol_31.IfNum] = NULL;
+ gBS->FreePool (GigUndiPrivateData->Undi32DevPath);
+ GigUndiPxeUpdate (NULL, e1000_pxe_31);
+ ActiveInterfaces--;
+
+UndiError:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+GigUndiDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+Routine Description:
+ Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
+ closing the DevicePath and PciIo protocols on Controller.
+
+Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to stop driver on.
+ NumberOfChildren - How many children need to be stopped.
+ ChildHandleBuffer - Child handle buffer to uninstall.
+
+Returns:
+ EFI_SUCCESS - This driver is removed Controller.
+ EFI_DEVICE_ERROR - The driver could not be successfully stopped.
+ other - This driver was not removed from this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
+
+ DEBUGPRINT(INIT, ("Number of children %d\n", NumberOfChildren));
+ //
+ // If we are called with less than one child handle it means that we already sucessfully
+ // uninstalled
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // Decrement the number of interfaces this driver is supporting
+ //
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate"));
+ ActiveInterfaces--;
+ // The below is commmented out because it causes a crash when SNP, MNP, and ARP drivers are loaded
+ // This has not been root caused but it is probably because some driver expects IFcnt not to change
+ // This should be okay because when ifCnt is set when the driver is started it is based on ActiveInterfaces
+ // GigUndiPxeUpdate (NULL, e1000_pxe);
+ // GigUndiPxeUpdate (NULL, e1000_pxe_31);
+
+ DEBUGPRINT(INIT, ("Removing gEfiDevicePathProtocolGuid\n"));
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Close of gEfiDevicePathProtocolGuid failed with %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Close of gEfiPciIoProtocolGuid failed with %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ return Status;
+ }
+
+ if (NumberOfChildren > 1) {
+ DEBUGPRINT(INIT, ("Unexpected number of child handles.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check to see
+ // if the interface has been shutdown. Does not need to be closed because we use the
+ // GET_PROTOCOL attribute to open it.
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[0],
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &NIIProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("OpenProtocol returns %r\n", Status));
+ return Status;
+ }
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (NIIProtocol);
+ DEBUGPRINT(INIT, ("State = %X\n", GigUndiPrivateData->NicInfo.State));
+ DEBUGWAIT (INIT);
+
+ //
+ // Call shutdown to clear DRV_LOAD bit and stop tx and rx
+ //
+ e1000_Shutdown (&GigUndiPrivateData->NicInfo);
+
+ e1000_ClearRegBits(&GigUndiPrivateData->NicInfo, E1000_CTRL_EXT, E1000_CTRL_EXT_DRV_LOAD);
+
+ Status = HiiUnload(GigUndiPrivateData);
+ if (EFI_ERROR(Status)) {
+ DEBUGPRINT(CRITICAL, ("HiiUnload returns %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Close the bus driver
+ //
+ DEBUGPRINT(INIT, ("Removing gEfiPciIoProtocolGuid\n"));
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[0]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("Close of gEfiPciIoProtocolGuid failed with %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ DEBUGPRINT(INIT, ("UninstallFirmwareManagementProtocol\n"));
+ Status = UninstallFirmwareManagementProtocol (GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallFirmwareManagementProtocol returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ DEBUGPRINT(INIT, ("UninstallMultipleProtocolInterfaces\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ GigUndiPrivateData->DeviceHandle,
+ &gEfiStartStopProtocolGuid, &GigUndiPrivateData->DriverStop,
+ &gEfiVlanProtocolGuid, &gGigUndiVlanData,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &GigUndiPrivateData->NIIProtocol_31,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ &gEfiDevicePathProtocolGuid, GigUndiPrivateData->Undi32DevPath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallMultipleProtocolInterfaces returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ //
+ // If we get the ACCESS_DENIED status code usually calling UninstallMultipleProtocolInterfaces a second
+ // time will uninstall the protocols successfully.
+ //
+ if (Status == EFI_ACCESS_DENIED)
+ {
+ DEBUGPRINT(INIT, ("UninstallMultipleProtocolInterfaces\n"));
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ GigUndiPrivateData->DeviceHandle,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &GigUndiPrivateData->NIIProtocol_31,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ &gEfiDevicePathProtocolGuid, GigUndiPrivateData->Undi32DevPath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallMultipleProtocolInterfaces returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+ }
+
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiPro1000ComGuid, &GigUndiPrivateData->EfiPro1000Com,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("UninstallMultipleProtocolInterfaces returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ DEBUGPRINT(INIT, ("FreeUnicodeStringTable"));
+ FreeUnicodeStringTable (GigUndiPrivateData->ControllerNameTable);
+
+ e1000_UNDI32DeviceList[GigUndiPrivateData->NIIProtocol_31.IfNum] = NULL;
+ DEBUGPRINT(INIT, ("FreePool(GigUndiPrivateData->Undi32DevPath)"));
+ Status = gBS->FreePool (GigUndiPrivateData->Undi32DevPath);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("FreePool(GigUndiPrivateData->Undi32DevPath) returns %r\n", Status));
+ }
+
+ Status = GigUndiPrivateData->NicInfo.PciIo->FreeBuffer (
+ GigUndiPrivateData->NicInfo.PciIo,
+ UNDI_MEM_PAGES (MEMORY_NEEDED),
+ (VOID*) (UINTN) GigUndiPrivateData->NicInfo.MemoryPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("PCI IO FreeBuffer returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+
+ DEBUGPRINT(INIT, ("Attributes"));
+ Status = GigUndiPrivateData->NicInfo.PciIo->Attributes (
+ GigUndiPrivateData->NicInfo.PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("PCI IO Attributes returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ Status = gBS->FreePool (GigUndiPrivateData);
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("FreePool(GigUndiPrivateData) returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ }
+
+ return Status;
+}
+
+VOID
+WaitForEnter (
+ VOID
+ )
+/*++
+
+Routine Description:
+ This is only for debugging, it will pause and wait for the user to press <ENTER>
+ Results AFTER this call are unpredicable. You can only be assured the code up to
+ this call is working.
+
+Arguments:
+ VOID
+
+Returns:
+ none
+
+--*/
+// GC_TODO: VOID - add argument and description to function comment
+{
+ EFI_INPUT_KEY Key;
+
+ DEBUGPRINT(0xFFFF, ("\nPress <Enter> to continue...\n"));
+
+ do {
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ } while (Key.UnicodeChar != 0xD);
+}
+
+EFI_STATUS
+GigAppendMac2DevPath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
+ IN GIG_DRIVER_DATA *GigAdapterInfo
+ )
+/*++
+
+Routine Description:
+ Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space
+ for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)
+ and an added MAC node.
+
+Arguments:
+ DevPtr - Pointer which will point to the newly created device path with the MAC node attached.
+ BaseDevPtr - Pointer to the device path which the UNDI device driver is latching on to.
+ AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
+
+Returns:
+ EFI_SUCCESS - A MAC address was successfully appended to the Base Device Path.
+ other - Not enough resources available to create new Device Path node.
+
+--*/
+// GC_TODO: GigAdapterInfo - add argument and description to function comment
+{
+ MAC_ADDR_DEVICE_PATH MacAddrNode;
+ EFI_DEVICE_PATH_PROTOCOL *EndNode;
+ UINT16 i;
+ UINT16 TotalPathLen;
+ UINT16 BasePathLen;
+ EFI_STATUS Status;
+ UINT8 *DevicePtr;
+
+ DEBUGPRINT(INIT, ("GigAppendMac2DevPath\n"));
+
+ ZeroMem (
+ (char *) &MacAddrNode,
+ sizeof (MacAddrNode)
+ );
+
+ E1000_COPY_MAC (MacAddrNode.MacAddress.Addr, GigAdapterInfo->hw.mac.perm_addr);
+
+ DEBUGPRINT(INIT, ("\n"));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(INIT, ("%2x ", MacAddrNode.MacAddress.Addr[i]));
+ }
+
+ DEBUGPRINT(INIT, ("\n"));
+ for (i = 0; i < 6; i++) {
+ DEBUGPRINT(INIT, ("%2x ", GigAdapterInfo->hw.mac.perm_addr[i]));
+ }
+
+ DEBUGPRINT(INIT, ("\n"));
+ DEBUGWAIT (INIT);
+
+ MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
+ MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
+ MacAddrNode.Header.Length[0] = sizeof (MacAddrNode);
+ MacAddrNode.Header.Length[1] = 0;
+
+ //
+ // find the size of the base dev path.
+ //
+ EndNode = BaseDevPtr;
+ while (!IsDevicePathEnd (EndNode)) {
+ EndNode = NextDevicePathNode (EndNode);
+ }
+
+ BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));
+
+ //
+ // create space for full dev path
+ //
+ TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData, //EfiRuntimeServicesData,
+ TotalPathLen,
+ (VOID**)&DevicePtr
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ //
+ // copy the base path, mac addr and end_dev_path nodes
+ //
+ *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;
+ CopyMem (DevicePtr, (char *) BaseDevPtr, BasePathLen);
+ DevicePtr += BasePathLen;
+ CopyMem (DevicePtr, (char *) &MacAddrNode, sizeof (MacAddrNode));
+ DevicePtr += sizeof (MacAddrNode);
+ CopyMem (DevicePtr, (char *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
+
+ return EFI_SUCCESS;
+}
+
+VOID
+GigUndiPxeUpdate (
+ IN GIG_DRIVER_DATA *NicPtr,
+ IN PXE_SW_UNDI *PxePtr
+ )
+/*++
+
+Routine Description:
+ When called with a null NicPtr, this routine decrements the number of NICs
+ this UNDI is supporting and removes the NIC_DATA_POINTER from the array.
+ Otherwise, it increments the number of NICs this UNDI is supported and
+ updates the pxe.Fudge to ensure a proper check sum results.
+
+Arguments:
+ NicPtr = contains bus, dev, function etc.
+ PxePtr = Pointer to the PXE structure
+
+Returns:
+ None
+
+--*/
+{
+ if (NicPtr == NULL) {
+ //
+ // IFcnt is equal to the number of NICs this undi supports - 1
+ //
+ if (PxePtr->IFcnt > 0) {
+ PxePtr->IFcnt--;
+ }
+
+ PxePtr->Fudge = (UINT8) (PxePtr->Fudge - e1000_ChkSum ((VOID *) PxePtr, PxePtr->Len));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: ActiveInterfaces = %d\n", ActiveInterfaces));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: PxePtr->IFcnt = %d\n", PxePtr->IFcnt));
+ return ;
+ }
+
+ //
+ // number of NICs this undi supports
+ //
+ PxePtr->IFcnt = ActiveInterfaces;
+ PxePtr->Fudge = (UINT8) (PxePtr->Fudge - e1000_ChkSum ((VOID *) PxePtr, PxePtr->Len));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: ActiveInterfaces = %d\n", ActiveInterfaces));
+ DEBUGPRINT(INIT, ("GigUndiPxeUpdate: PxePtr->IFcnt = %d\n", PxePtr->IFcnt));
+
+ return ;
+}
+
+VOID
+GigUndiPxeStructInit (
+ PXE_SW_UNDI *PxePtr,
+ UINTN VersionFlag
+ )
+/*++
+
+Routine Description:
+ Initialize the !PXE structure
+
+Arguments:
+ PxePtr = Pointer to the PXE structure to initialize
+ VersionFlag = Indicates PXE version 3.0 or 3.1
+
+Returns:
+ EFI_SUCCESS - This driver is added to Controller.
+ other - This driver does not support this device.
+
+--*/
+{
+ //
+ // initialize the !PXE structure
+ //
+ PxePtr->Signature = PXE_ROMID_SIGNATURE;
+ PxePtr->Len = sizeof (PXE_SW_UNDI);
+ PxePtr->Fudge = 0; // cksum
+ PxePtr->IFcnt = 0; // number of NICs this undi supports
+ PxePtr->Rev = PXE_ROMID_REV;
+ PxePtr->MajorVer = PXE_ROMID_MAJORVER;
+ PxePtr->MinorVer = PXE_ROMID_MINORVER;
+ PxePtr->reserved1 = 0;
+
+ PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
+ PXE_ROMID_IMP_FRAG_SUPPORTED |
+ PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
+ PXE_ROMID_IMP_NVDATA_READ_ONLY |
+ PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
+ PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
+ PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
+ PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
+ PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |
+ PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |
+ PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;
+
+ PxePtr->EntryPoint = (UINT64) e1000_UNDI_APIEntry;
+ PxePtr->MinorVer = PXE_ROMID_MINORVER;
+ PxePtr->reserved2[0] = 0;
+ PxePtr->reserved2[1] = 0;
+ PxePtr->reserved2[2] = 0;
+ PxePtr->BusCnt = 1;
+ PxePtr->BusType[0] = PXE_BUSTYPE_PCI;
+
+ // TODO: Check if this is correct.
+ PxePtr->Fudge = (UINT8) (PxePtr->Fudge - e1000_ChkSum ((VOID *) PxePtr, PxePtr->Len));
+
+ //
+ // return the !PXE structure
+ //
+}
+
+UINT8
+e1000_ChkSum (
+ IN VOID *Buffer,
+ IN UINT16 Len
+ )
+/*++
+
+Routine Description:
+ This does an 8 bit check sum of the passed in buffer for Len bytes.
+ This is primarily used to update the check sum in the SW UNDI header.
+
+Arguments:
+ Buffer - Pointer to the passed in buffer to check sum
+ Len - Length of buffer to be check summed in bytes.
+
+Returns:
+ The 8-bit checksum of the array pointed to by buf.
+
+--*/
+{
+ UINT8 Chksum;
+ INT8 *Bp;
+
+ Chksum = 0;
+
+ if ((Bp = Buffer) != NULL) {
+ while (Len--) {
+ Chksum = (UINT8) (Chksum + *Bp++);
+ }
+ }
+
+ return Chksum;
+}
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr
new file mode 100755
index 0000000..8846e32
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventory.vfr
@@ -0,0 +1,138 @@
+// *++
+//
+// Copyright (c) 2007, Intel Corporation
+// All rights reserved. This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// Module Name:
+//
+// Inventory.vfr
+//
+// Abstract:
+//
+// Sample Inventory Data.
+//
+// Revision History:
+//
+// --*/
+
+#include "LanIntelE1000DxeStrDefs.h"
+#include "NVDataStruc.h"
+
+//
+// Formset class used by Device Manager
+//
+#define EFI_NON_DEVICE_CLASS 0x00
+#define EFI_DISK_DEVICE_CLASS 0x01
+#define EFI_VIDEO_DEVICE_CLASS 0x02
+#define EFI_NETWORK_DEVICE_CLASS 0x04
+#define EFI_INPUT_DEVICE_CLASS 0x08
+#define EFI_ON_BOARD_DEVICE_CLASS 0x10
+#define EFI_OTHER_DEVICE_CLASS 0x20
+
+//
+// Formset subclass
+//
+#define EFI_SETUP_APPLICATION_SUBCLASS 0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01
+#define EFI_FRONT_PAGE_SUBCLASS 0x02
+#define EFI_SINGLE_USE_SUBCLASS 0x03
+
+//
+// EFI Variable attributes
+//
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+#define EFI_VARIABLE_READ_ONLY 0x00000008
+
+formset
+ guid = E1000_HII_FORM_GUID,
+ title = STRING_TOKEN(STR_INV_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ class = EFI_NETWORK_DEVICE_CLASS,
+ subclass = EFI_SETUP_APPLICATION_SUBCLASS,
+
+ //
+ // Define a Buffer Storage (EFI_IFR_VARSTORE)
+ //
+ varstore GIG_DRIVER_CONFIGURATION, // This is the data structure type
+ varid = 0x1234, // Optional VarStore ID
+ name = GigNVData, // Define referenced name in vfr
+ guid = E1000_HII_DATA_GUID; // GUID of this buffer storage
+
+ form formid = 1,
+ title = STRING_TOKEN(STR_INV_FORM1_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ goto 0x1235,
+ prompt = STRING_TOKEN(STR_PORT_CONFIG_MENU_REF),
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ subtitle text = STRING_TOKEN(STR_PORT_CONFIGURATION_INFO);
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ text
+ help = STRING_TOKEN(STR_MAC_ADDR_HELP),
+ text = STRING_TOKEN(STR_MAC_ADDR_PROMPT),
+ text = STRING_TOKEN(STR_MAC_ADDR_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_ALT_MAC_ADDR_HELP),
+ text = STRING_TOKEN(STR_ALT_MAC_ADDR_PROMPT),
+ text = STRING_TOKEN(STR_ALT_MAC_ADDR_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_EFI_DRIVER_VER_PROMPT),
+ text = STRING_TOKEN(STR_EFI_DRIVER_VER_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_PCI_BUS_DEV_FUNC_HELP),
+ text = STRING_TOKEN(STR_PCI_BUS_DEV_FUNC_PROMPT),
+ text = STRING_TOKEN(STR_PCI_BUS_DEV_FUNC_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_CONTROLER_ID_HELP),
+ text = STRING_TOKEN(STR_CONTROLER_ID_PROMPT),
+ text = STRING_TOKEN(STR_CONTROLER_ID_TEXT),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_ADAPTER_PBA_PROMPT),
+ text = STRING_TOKEN(STR_ADAPTER_PBA_TEXT),
+ flags = 0,
+ key = 0;
+
+ endform;
+
+ form formid = FORM_2,
+
+ title = STRING_TOKEN(STR_PORT_CONFIG_MENU);
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ label LABEL_START; // Placeholder for opcodes that are dynamically created during driver initialization
+
+ label LABEL_END;
+
+ endform;
+
+endformset;
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventorystrings.uni b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/inventorystrings.uni
new file mode 100755
index 0000000000000000000000000000000000000000..7d47c47b38cd4c8118dba136242265287ac85e1b
GIT binary patch
literal 47396
zcmeI5U5s7VRmV>w(PE&y!9!oTOsHx?ZhTTze7HjD#2!0NJ$***@4V~<Tpo%!};Ja?QK
zf5dKUm$VWh4$220qCB)EO89z-5D(NZ6x2czps0N)L8vXUiq)imB4|`3V`Bcly=Hr#
z`?be+Jm(`)***@5(Qx%b?C{(J4c{(G&x*52p(+dGmSNiDe}`33#GKlw48?YQw?OLiqI
z$%*7_vYIR=3(2wMq^{kb%p^ar_YWtj{(dQ`uOIz#a;HAsmo#<NTyk8;{CZWt=XFY-
zF6yYM&x`)^^{OR<!UeKWpEY+jm#hi%YI0hyv&mihY(lkN)TcG!Ulr~JSBGVtPpJ;G
zdOxWv=G^&=B(jn$>q@>mtKT(seNCTGYsy{J(Q#K=|8)=Or&JPmJg)L)bkuaH!QwG-
z$JupMr**ujYp0TFz4E(L4mo%Ndc(Kuu=!G`4Ru_+(PqeDC7I9s?w({k*{$>aEm%5h
z7to(^5}na2cw1$*D16)lnVQtO`<l*?-L#PV-b341>rkV4ePb<3Js#0j?KoRyWo>d+
zS4}&K%&S%=6)^GZ*1v$BzJF3Jywhn2T4D0%_p7co?owH+YWE#&?X#v&rd5|&X-***@a
zyHv_C{kPt8>&^oDtt+#*k^=gP<lbaRQW{Ohl96PuUI&w5o$pg0tf?3BKA}(dCHEu;
zbu{F9=E0<)_aS{wf3XrmuiYnh8qyWxuH+FN!4A9*=$&#YbwKa;xO2|nx10S7=qFVY
z_aAZCYRRO^8*_DN=<|KLKX)5(ILCBGE%^*|6S|gbz-L$O(Y4?_qW6#M8|nzIq4m31
zeTS06H_8d6?~~L<rLo*|w_~|pwF&6M(XjgWtkX9%uOWR|mJaN^F<OKxDV1>mHf1zG
zFU|_TX*1lorn{qei#L8<%Nz|***@_&;$-F?*{irqw#=GizIl~Nxt=f9bQM|-=XGM@
zJ2-Mqcmn=#G^TG(>xwn~+t_ulJM(o4wa+4}OVjUIA4e(6%KO#ic6Y?t?YbvyyReR#
zx*)5%`Uvecpcdj=_+m{QG2njL?N_jU-Su;RwOeO!<(lNiuPE0>_`UjO)***@K$o
zb=}z`SQ9r*CI6+GA8#pZ+<lIe!Pcuj^SWO>+2i{4fZl1%X7W9~@;***@GQOeiAnsMx
zL;6)cxlg^9T3(sEbK&!kS?#EyFX=vAWn-|7=e<fhr#sc9k>H_!3?!fV<***@tbp5
ziH!><V>)d>FTpavreTC?>I{pa*Bu^F`3EJ*J?e9mk0sP}r7XDdB5Mr|JJcs!saOsB
z9WJh$QV*DOlJYeSW!_4Opf==wgf)A`SoEkcH<CliQK5&GhIIrRP3Rpinh-+RIQ)fv
z=`pwV=5VDQ4LD8oR-&=`j^u7<Po^rjp<16z&N!`I(z(?YnZpLAiL?}TXfJ!S=iTa%
z)vfk&Z>|pKR15TO$#LPTc#XaTiz0E;>h_X1d)}=ES&eQl*Y`^7rp4q3LSzhzb!>gz
zEJ;|iS6k&@gDi{mssTNNIv7K*CT}?1oRXA{^UFh@<*iQiG0E1Fucco}***@h
zFU&mq>HKBg&Wl;Z8};`C7ru4=J5RhYlRwHVw{A<eNsIP4rdSqB!5fC4AAY;LC$pIZ
zx@%S#t+R6CctD)VD2GPHczQI$@a1wDW8o={btlDCy+*1vr&U;1j7fRpjWgG1a#{R|
zgr_89Jamp{^vd{;hi}}4l~vQ{?RDZx7%%^N#QDqj0FSp5sUPpU)v}0oh%?yb^!fA$
zX)UQg_U!%tBBuIMn!***@KenTr=FSq{rr)1GEr9BecNs=ju@|vI(rQ}ZI|;H
zu|D_84#i*gUZh!fSa!9H7jm<9+o)q&=1H<OWd<Z`(K4=?&t)@URk7Fxh08pn<6=Ab
ztS%qAog2Ky;q!H?2foVIwrThACHP{U<4dcAJ)3zJ*@*SRbt{qq%yLSczA9$tJpa1I
zIkB~FzBN4N7(-%LQyaW}ZwIu?ZnNjz+9=MA-***@oyfy`*8kpjWgq$=e|1*
zH(nlDc`$!0o!n^mjPcj7cxso}Yf$qTyTw{Z-5l14o3)xy%***@Ym@9OO8fO#iZ-KU
zGg38`%pI9go7EqF53I0LI#9NEIq5WVNoeN8L(Bu<<#@z(huGs~7B2r5jay{9g%Ui>
z>w9m~***@0%dD(2!x`x=rR3V7tJVToY33|!GGaqscg47uSka`jFjkC$s17|*a&wMlW
zGJP(6CH;@|Qt9^A)dP=?2ic{QADjHZ_5Ax{C%fQr&D_xA&2SBIgTu0u+F8TS`{$Yu
zYCh}3nwQv_^m|l3`}B)A)G`0IkMmHKk;nO{%E;r~RAuCGo2bgjJ2`GMtVY~(zl)o6
z<F)=-t=)***@ZkR5{Jhx^y3qG2w{BnQTZWVL)OHq8&|pBTkCgKz~&;FNK9x}ud8~k
zD^_c>_t;?gjy98w_sIM`9-7s+-e!-Pw?fRZy~cITQWEL17$uQ9UnVigve`3c#WBl9
zT!1-Nq_XT}LOV0Z*3HJVPnnI&dYGLuDWcwS?(***@GMh*%&MKy0y_`O4ekSL^o+U=&
zzwv##oSMeDy1hTv67Q#8dEg_5y_NY=`pxuD(tnr#8Z_EloVS&3b6#***@S{MpZ)
z#{T^0&p&@L;KT+k0^?@*c~D%;{G74I#-48f{7i<M=_hmJ90keH%L6A@!OQK%***@f@4
zQ<xGD__+9zytgTxao#M%Ba2&_F|H&Ak!^)V#eb{p^D=%DK_%CL$Q4Xq1+VwJjqCHi
z|K>k7#%;y-***@WI4qs)Vw&BrpWB;py8FBRGtRBp&}GlE-3s<{BcN4A9=Elsj67~T
zRT+7lyQ+-5lj%10b9=K|cYn8kR_kU*nf1ZEFtfsB1DgFp?s(R+dS`gMzos#txWXBY
z_gFgd2!r`@{d%-WW+O|k2=DJ!EIH!9w7B<lyW4gqpLc?<O9m^m9JD<)^@m)|x<x|p
zAHoWZH{A7>RrgNxaF^26vB%Q!qx0!+rH`ja)2wY-OT2emww0OnZLv7tJ2w1O;F&7>
zwxf!q?vroJ8jNwhv-ZNWh*^n2T-P#vS%Wa4p4UGo+Z|YuLH5Q@-NCZ+SqrsOv0Y~6
zLWXb^{***@zkztKkgg{GCav;#mvn6TF-61}<2-0`Wt|NziG0b_N7vy%aGut&NABai
zMc|HGl<l}jHCsoVnblQx^sxGd^%1gtTKh=ec6{8X^nLp4isgRbdM$Y={kn4M?D)Cg
zJ26*8G&OEJdW0W+@XP0SCVzSHeMfdCUl{wp&lJ(_owlL1byoA+^?qaP(P|W9s#f2)
zf2J~fdse#Ac~q6?ZZC9s>qDG_I^`8)nE%)u=b3V`#d)M$Y;guD7h5NXYz0HK`kDPR
zglARaW~?y8hQS(N(NV~ytwL1Pkk*w+>}?k`*hfk&*Rp&c?x6fk%PjMDN$|*K^-ZT8
z<L#Uxu*Z32Xnma_8BB9J#uLv*6T4e8MdFWhkMGOgc4?*`IsCEdB4TiH-toAwS%ycN
z7m7f%8MYzcb<lZ5tlq{?V$FHGzZCK}`ez#=***@tQm=rySJ5<3#>W!>iJH#XuIK*au
zkRV5}UJ>?hoHup}3z_bW93F2GsN!t!T>4k(tLc}OIbfK|_h4>&a`>rZhl<3rl`PQe
zi`)ted{Coc6}*ok)|hPMWfXxSuD#Y8d9z$xSBt?***@Iuo;cCRdnnuGvf9<U~Jx}
zvAWmD-2b?2yGgJE(1dnKVNandjL9BVeH~***@h0KC){***@hU5h?zgGmZxEA|%
z^T^0_G+(X=Y;o=WYwaMwNc_BB^PfA3Yx#?h?p^)lr!G$BkE2u5eSaQS?_nn!IG6w1
zogZs!$Ju$s?|;%;@4Ju1{p<Zfd3a0uUs3cm>=Hn%jlFi*k7%_5BQ+@5Cv8b~W>bIO
zd$6^??P&8J$>I#***@MuW!|5;l|^U0=idwCtP#+@<yxB+)HPuvHUZM6SR{Xp
zarStB<0t1IO8;Ez`(IA~Q)^***@D4j#@Sh#ZLk7j;x?AW3FWz)$bx568(vxVM<@1Hjs
z(#Gu0NY-0gHIZz4^9yUPA1yl_UUjPr%Feel{9#w5x+0DA_tqL<cd+6D9z+wC-JF=!
zpj?(|Bv;q51Y5*Q8!sH|gdC98c4=iJzrRxX^***@xtwOLGF7k;Y^>*+&XvRswj
zWvPgo#JMWFS5lU-n&~&hTwhHeI`u!}Ma=%iZ6NkYGX8q~$saa~L9`hjvwiEx;9yV9
zL(1d8^YQPkSsZX#|2!7<vD>ZQM_vIIPZfM0j|>hXCyL!?J+^YWr<ExKr+CCg_#1Jn
zX4G-^%KD6?$5n-O1Odw{vSXfCjz#&ik^$4h&;Ie)kDq(u6GdR!dOq+z5qq)q&jdF6
zQ?^}F%p6qQgDD0>T!V|j5Fg8n!4My*i@~rNUF^Qc7b^<cFZ!UyX?Bm^vngF1l^sYt
zDZabcu*O64Ps`R?***@c&&iU-gYMkntM`6}`TLM_nqTt!DSMyKzq3aqa=a?keohll
***@FQ09>J}d43-^Iz5Tj;f9PEgpW(_C)!U(q{kfXy<@E2<EAkcc?-g<***@w;?=>$3;P
z^T*Q3K%N84+O*#2cQPDPkDb4X`O}R!YIBx?***@l|***@DYx_wIJtyX@4uZ{@q}#7Nq@
zH-5H{4J1`&r;X=lN0gBg_CY18%ii|bO|22#&G<2+Znj`r78L$3&+{Nx$nQyR_bNa4
z;*hiOSd(WNoLGBUD64L_1>4(sRb#Z@-NxfCcjki~LCNi8Zvw15n~}8rAXsa8!hL5u
z*cXL3?niZNeXJkW+AX^_;5itqz{`J(k9%9Mrr%Hh$?a77r-~B)MfyFrpL0=CjI+(>
zp82Vx*Y4l;<***@FxE(c?{0BLozh?ocTnr$sRrZ!yOVl?PjuZVPvxqNJCb5_-mbPGPP
zCxqeu(ND>j4xe`K&Hkx6GtT!yMwYeAdNFwAE|oN?(S*<2%Vg~|@mOM2L?66#xh~8H
zqv=GR{nNV0j%VJ})?TB5v_kf&VgBCL%%tClXL%aYHPs3!nAD~edp{}p5>>KjST`S+
zRo1qSkd*|?R@<+6UK3|lUbkzkjkwy{Xs)BAlkVwKJ_DfURsj0;#J?q9y*s8QeMdyQ
zrpN(3qIJ|E;umJuYmN)q-^bV7o||H4MZ}llzWShgqOE_l5y;2O(2~|~Z13%EW0E}+
zhu6+k;#LZ~upf7N!?TBKPP****@pW8-<kFxf7?S3y}7JoG=`_p8BWGc#`3GK9YQ3J
zERzsHVE;***@j>dvs3JzAhq4;TK8`&qBY{9YiJE>&lC7S4D!$#e8bxI?%V}W*o=|!
zUf>Pi60{Q9VJ*>KI&0x+1!B}*PMq<)C|1j|Ue<FeeVBG()jcg^8i|dCTq(gvOuE?z
z))r)y!O2!9bdKjzfwgtLh~0@-U!x*gD{f)Dy|#U_nfhJkf|X%5MlE?d-L`OP?7UXw
***@TIY(bTU1k9!YO=XRIap(TVq@<Jw8x%J{g}?+2^J$8)ZwPrEFYSM<w^>BYuM
zx{wa5ocq(?QAzn*S#e8d$HewiKRx{$XSbgkKRP^SJJ)6Hn%lH50pI>`?kBGQ!SQVi
zX8HKI(3|5|8vodsU2@)+*0FqX?9)#***@Xk#CXrwcapR0W<HHY(48Ck?iHSDW##
z_N)JsGlxc!CyNbG1%C={ZhflPn$vN6&IEg_*ppNjgq`uOi02Z-$Ff7hVe1UZg<}*j
zjxi={-r$w|btca8hn%#ii;Z%|qkf0FHL+%Mi!JbOvt)5@`@X!T7t^14@((|ezqH~E
z^Y-t)FjEYUPFC3OG&8H0TRC44^NYH(P1YmY4A+n^***@M>jd`%R(Q7n^=VoC=
zJfgFWeWLO?i(Ngi5a5A+xywI8ny2oDdYhdeb~3j4BV!e8mYefp(Da)2MnSG1Yr2fZ
zt?WtN^gGU#tgs`0($74Zbx*cZJA?8}X|wF{6R^Il{=8nz^bqO>)3)x2?5$3-|MTaP
zIP+%vKi;FSwapL4_!t>5`)O8nt8O5Zo3Xj`uYH`;TkX}***@P9YHmcFDI;j4P?##hAp
zmt>J{JMz|i{&?fe|JMAk%mu5`j{}cS{KNQ_2g<Y(vyp>aIgauFpfVmN<l{ADXYQ4q
znaxGo4D%1Fhw>CG@|1Z#YuOnN?Rd&%!=ll|S*mC>an>jrO`H>oM$>5%=7}K22s}ml
z-h}-@_jK^VW*C9;*ne+YBR2L4Pf9)RvLMRlhJcK5c}E7_bc<D*|M(QQp#n~***@UC
z7T~+Z`6J+Jm!HpZxs_2X``d1IXPiv}Hj~+X<BvDK_Ei2Y8E2JFRM;5#qv~WAka(R8
z8o8CD<3=2_N0!Ha{k7X1Tfs5xXh*!KeETD`c+e4|IiSm0_xbmM{y2t6hs}}WkE~RJ
zYrg1uY>;DU<*n?ux6U=k4pfnAjvc51*W}Y?8*xo<i>6y^6V0u=J$SQYkR1;sXmph=
z8jmgLiSc{&Y#NWWdRC1`)-J<p*fkzq)hwHKTxIf2+15=***@2TCs>0}f8WGgr*@M;yj
zD&G@={#***@kmXVs%Z73NtNxMR{2%O@@dCqT+~***@3)3)~g78YD3*XHs*x
zSzoGGjr`~RbIzoTLJ{{Gk$qIt-3B$wo4?;eyr-^c*^utp{x_hkR`Pc&|A%LYwr279
zINCMMK3UdKQK;kI){rDf=8<JKup1_EpCY9ipV=8xE*LR7%g$O`k2)14yZFpbS^Y3R
zvtzQUB|mrY=>le%I(frO1>M{)P4$@_H^Uh|+TX5S?dSb-2K_u_LG$Ed%fTbNGpy}k
zexauI6GXY;7kk1n*_&te&***@Oi$dU=fH$=m0`***@I%)-(_aCi=^7$(b&H&ZnJ)OtZ;@
zq;}+n!w$xzSvjyz58v~YEV8t+wdYyE#Dy(Wz$C(x4806kVd!OGt9fmg9LpSFe-Q3!
zdCkZu?~yIee}lqm*}zDFYuOdJeI<(R3&iK(wg^8pvCLe{0w7P+_Yto2D_eYa=u~1)
zF0nm+mzCjb5?d)GHzLlmSt*=z*y+KBv{gew<ey!GJTsFcVA%yo(QC`=>P4KBi_G(1
zE#t(r#LFV+k9|@^kBGB6*{LD3)iPSiV|`Eho%BmCTi_e%pXvQ&WvN~m*?wv=o!45M
zOX=UHuj!LBzx~azgUVFBSdmQC*(GvQ$vOoq(XXJXC+3<***@xPz?*YjoO7sSQ}
z*7OZ(kMsTO`KLZFpnXj6=eIUCR3Q_!owdu)GY$M;D-H5z?Tz?qms|aLD0!uT5hTtR
zWW47ukGReE-w%+Lo<E9CYcFe8p*v`DOq+Krr+mB*eePeI$%zar-m0L_yPeJ8{Xs^`
z@--Sv*)=xR(CgjOXL?6<w3}5d`Rmn2+Rb{B{84mjcc(6Gq~DCyA&&0H<lgW7>vu!>
***@qKGt?C7gJaON}OM*7(E#dyY>DC_cvA761#7E$VWS!@)9dR9fbpExu{4sQDDEemi
zjg7i+Dtmq&RnFUxEa}k=bhKM9VD6xIEP8z1%k!%v?U}^***@v~pL-!vO3fBFX9T&3I
zEzH=kqMg+Vwl)-B)#gNM$yfC$^Syot4VyW^m&Yr{*Ui=_Zw-v|z+TOYG7|w_^7UD@
***@Q=w4T?k^=M5}JW>c62VcvveTWtV(X3}X3cCBI^w4bBnJDz^!*TlY|U-8*%
z?zhal6j{SKFR`NFX+1kBAgU!x>9<D?-_N?%{MjPTSnvIHRvUmO9m`_OA6F-fZOmY-
zMCA$8Lt+qi{yCy!d&UFb>{YwB{`JpbwF)p37|P|6A`rxRp$G(Vy)6PkTsMnAuo*36
z?rlsOh|UeV85q{<^wz}wwJ?i{Cn+)35^*4U<HrC-YsL#ct-{Kl&0sE9%d3bu&I(mT
i9A}X#B96086%l7Ku`AYq)@I{{*mDhTmLbqK{{J7+PdK9h
literal 0
HcmV?d00001
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c
new file mode 100755
index 0000000..ad3f565
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.c
@@ -0,0 +1,118 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+#include "e1000.h"
+#include "startstop.h"
+
+EFI_GUID gEfiStartStopProtocolGuid = EFI_DRIVER_STOP_PROTOCOL_GUID;
+
+EFI_STATUS
+StopDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+ Issues a call to stop the driver so diagnostic application can access the hardware.
+
+Arguments:
+ This - pointer to the EFI_DRIVER_STOP_PROTOCOL instance.
+
+Returns:
+ EFI_SUCCESS if driver is stopped successfully
+
+--*/
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ GIG_UNDI_PRIVATE_DATA *GigPrivate;
+
+ DEBUGPRINT (DIAG, ("Entering StopDriver\n"));
+ DEBUGWAIT(DIAG);
+
+ GigPrivate = GIG_UNDI_PRIVATE_DATA_FROM_DRIVER_STOP(This);
+
+ GigPrivate->NicInfo.DriverBusy = TRUE;
+
+ return Status;
+}
+
+EFI_STATUS
+StartDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+ Issues a call to start the driver after diagnostic application has completed.
+
+Arguments:
+ This - pointer to the EFI_DRIVER_STOP_PROTOCOL instance.
+
+Returns:
+ EFI_SUCCESS if driver has restarted successfully
+
+--*/
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ GIG_UNDI_PRIVATE_DATA *GigPrivate;
+ BOOLEAN ReceiveStarted;
+
+ DEBUGPRINT (DIAG, ("Entering StartDriver\n"));
+ DEBUGWAIT(DIAG);
+
+ GigPrivate = GIG_UNDI_PRIVATE_DATA_FROM_DRIVER_STOP(This);
+
+ //
+ // Save off the value of ReceiveStarted as it will be reset by XgbeInitialize
+ //
+ ReceiveStarted = GigPrivate->NicInfo.ReceiveStarted;
+
+ GigPrivate->NicInfo.HwInitialized = FALSE;
+ e1000_reset_hw(&GigPrivate->NicInfo.hw);
+ if (GigPrivate->NicInfo.State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
+ e1000_Inititialize (&GigPrivate->NicInfo);
+ DEBUGPRINT(DIAG, ("e1000_Inititialize complete\n"));
+ //
+ // Restart the receive unit if it was running on entry
+ //
+ if (ReceiveStarted) {
+ DEBUGPRINT(DIAG, ("RESTARTING RU\n"));
+ e1000_ReceiveEnable(&GigPrivate->NicInfo);
+ }
+ }
+
+ GigPrivate->NicInfo.DriverBusy = FALSE;
+
+ return Status;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h
new file mode 100755
index 0000000..b107db3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/startstop.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef _STARTSTOP_H_
+#define _STARTSTOP_H_
+
+#include "e1000.h"
+
+#define EFI_DRIVER_STOP_PROTOCOL_GUID \
+{ 0x34d59603, 0x1428, 0x4429, { 0xa4, 0x14, 0xe6, 0xb3, \
+0xb5, 0xfd, 0x7d, 0xc1 } }
+
+typedef struct _EFI_DRIVER_STOP_PROTOCOL EFI_DRIVER_STOP_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_STOP_PROTOCOL_STOP_DRIVER) (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_STOP_PROTOCOL_START_DRIVER) (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+typedef struct _EFI_DRIVER_STOP_PROTOCOL {
+ EFI_DRIVER_STOP_PROTOCOL_STOP_DRIVER StopDriver;
+ EFI_DRIVER_STOP_PROTOCOL_START_DRIVER StartDriver;
+} EFI_DRIVER_STOP_PROTOCOL;
+
+EFI_STATUS
+StopDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+EFI_STATUS
+StartDriver (
+ IN EFI_DRIVER_STOP_PROTOCOL *This
+ );
+
+
+#endif /* _STARTSTOP_H_ */
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c
new file mode 100755
index 0000000..4053495
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.c
@@ -0,0 +1,138 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "e1000.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL mGigUndiDriverBinding;
+extern EFI_GUID gEfiPro1000ComGuid;
+
+EFI_GUID gEfiVlanProtocolGuid = EFI_VLAN_GUID;
+
+EFI_VLAN_PROTOCOL gGigUndiVlanData = {
+ 1,
+ GigUndiSetVlanTag
+};
+
+EFI_STATUS
+GigUndiSetVlanTag (
+ IN EFI_HANDLE ControllerHandle,
+ IN BOOLEAN VlanEnable,
+ IN UINT16 VlanId,
+ IN UINT16 VlanPriority,
+ IN BOOLEAN VlanCfi
+ )
+/*++
+
+Routine Description:
+ Enables or disables 802.3Q VLAN tagging on the specified network interface.
+
+Arguments:
+ ControllerHandle - The handle to the network interface to configure VLAN tagging.
+ VlanEnable - Enable or disable 802.3Q ethernet header and VLAN tag insertion
+ VlanTag - Vlan tag to insert into each 802.3Q packet.
+
+Returns:
+ EFI_SUCCESS on success, appropriate EFI status code on failure
+
+--*/
+{
+ EFI_STATUS Status;
+ GIG_UNDI_PRIVATE_DATA *GigUndiPrivateData;
+ EFI_PRO1000_COM_PROTOCOL *EfiPro1000Com;
+ UINT32 Reg;
+
+ if (VlanId > 0x0FFF) {
+ DEBUGPRINT (VLAN, ("VlanId parameter out of range.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VlanPriority > 7) {
+ DEBUGPRINT (VLAN, ("VlanPriority parameter out of range.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VlanCfi > 1) {
+ DEBUGPRINT (VLAN, ("VlanCfi parameter out of range.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open an instance for the Network Interface Identifier Protocol so we can check
+ // if the child handle interface is actually valid.
+ //
+ DEBUGPRINT (VLAN, ("Open an instance for the Network Interface Identifier Protocol\n"));
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPro1000ComGuid,
+ (VOID **) &EfiPro1000Com,
+ mGigUndiDriverBinding.DriverBindingHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUGPRINT(CRITICAL, ("2. OpenProtocol returns %r\n", Status));
+ DEBUGWAIT (CRITICAL);
+ return Status;
+ }
+
+ GigUndiPrivateData = GIG_UNDI_PRIVATE_DATA_FROM_THIS (EfiPro1000Com->NIIProtocol_31);
+
+ DEBUGPRINT (VLAN, ("Subsystem Vendor ID = %X\n", GigUndiPrivateData->NicInfo.hw.subsystem_vendor_id));
+ DEBUGPRINT (VLAN, ("Vendor ID = %X\n", GigUndiPrivateData->NicInfo.hw.vendor_id));
+ DEBUGPRINT (VLAN, ("Device ID = %X\n", GigUndiPrivateData->NicInfo.hw.device_id));
+
+ Reg = E1000_READ_REG (&GigUndiPrivateData->NicInfo.hw, E1000_CTRL);
+ if (VlanEnable) {
+ GigUndiPrivateData->NicInfo.VlanEnable = TRUE;
+ GigUndiPrivateData->NicInfo.VlanTag = VlanId | (VlanCfi << 12) | (VlanPriority << 13);
+ DEBUGPRINT (VLAN, ("VlanTag = %X\n", GigUndiPrivateData->NicInfo.VlanTag));
+ Reg |= E1000_CTRL_VME;
+ DEBUGPRINT (VLAN, ("VME in CTRL register enabled\n"));
+ } else {
+ GigUndiPrivateData->NicInfo.VlanEnable = FALSE;
+ GigUndiPrivateData->NicInfo.VlanTag = 0;
+ Reg &= ~E1000_CTRL_VME;
+ DEBUGPRINT (VLAN, ("VME in CTRL register disabled\n"));
+ }
+ E1000_WRITE_REG (&GigUndiPrivateData->NicInfo.hw, E1000_CTRL, Reg);
+ DEBUGPRINT (VLAN, ("E1000_CTRL=%X\n", Reg));
+ DEBUGPRINT (VLAN, ("Vlan setting complete.\n"));
+
+ Reg = E1000_READ_REG (&GigUndiPrivateData->NicInfo.hw, E1000_VET);
+ DEBUGPRINT (VLAN, ("E1000_VET=%X\n", Reg));
+
+ return Status;
+}
+
+
diff --git a/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h
new file mode 100755
index 0000000..b78df64
--- /dev/null
+++ b/EmbeddedPkg/Drivers/LanIntelE1000Dxe/vlan.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+
+Copyright (c) 2001-2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+
+#ifndef _VLAN_H
+#define _VLAN_H
+
+#define EFI_VLAN_GUID \
+ { \
+ 0xe1ad94a, 0xdcf4, 0x11db, \
+ { \
+ 0x97, 0x5, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f \
+ } \
+ }
+
+typedef EFI_STATUS
+(EFIAPI *EFI_SET_VLAN_TAG) (
+ IN EFI_HANDLE ControllerHandle,
+ IN BOOLEAN VlanEnable,
+ IN UINT16 VlanId,
+ IN UINT16 VlanPriority,
+ IN BOOLEAN VlanCfi
+ );
+
+typedef struct _EFI_VLAN_PROTOCOL {
+ UINT16 Version;
+ EFI_SET_VLAN_TAG SetVlanTag;
+} EFI_VLAN_PROTOCOL;
+
+extern EFI_GUID gEfiVlanProtocolGuid;
+
+extern EFI_VLAN_PROTOCOL gGigUndiVlanData;
+
+EFI_STATUS
+GigUndiSetVlanTag (
+ IN EFI_HANDLE ControllerHandle,
+ IN BOOLEAN VlanEnable,
+ IN UINT16 VlanId,
+ IN UINT16 VlanPriority,
+ IN BOOLEAN VlanCfi
+ );
+
+#endif
--
2.1.1
------------------------------------------------------------------------------
2.1.1
------------------------------------------------------------------------------