summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/intel/Kconfig48
-rw-r--r--drivers/net/ethernet/intel/e1000/Makefile8
-rw-r--r--drivers/net/ethernet/intel/e1000/gcu.h102
-rw-r--r--drivers/net/ethernet/intel/e1000/gcu_if.c343
-rw-r--r--drivers/net/ethernet/intel/e1000/gcu_if.h51
-rw-r--r--drivers/net/ethernet/intel/e1000/gcu_main.c419
-rw-r--r--drivers/net/ethernet/intel/e1000/gcu_reg.h68
7 files changed, 1038 insertions, 1 deletions
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 76213162fbe..b1375813d59 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -70,6 +70,54 @@ config E1000
To compile this driver as a module, choose M here. The module
will be called e1000.
+config E1000_EP80579
+ bool "Intel(R) EP80579 Platform"
+ depends on E1000
+ ---help---
+ Select this option if you are using the E1000 driver on the EP80579 platform.
+
+config E1000_EP80579_MAC0_BASE_NAME
+ string "Base device name to use for MAC0"
+ depends on E1000_EP80579
+ default "eth"
+ ---help---
+ Base name to use for MAC0. By default, using eth which will translate to eth%d in the kernel.
+
+config E1000_EP80579_MAC1_BASE_NAME
+ string "Base device name to use for MAC1"
+ depends on E1000_EP80579
+ default "eth"
+ ---help---
+ Base name to use for MAC1. By default, using eth which will translate to eth%d in the kernel.
+
+config E1000_EP80579_MAC2_BASE_NAME
+ string "Base device name to use for MAC2"
+ depends on E1000_EP80579
+ default "eth"
+ ---help---
+ Base name to use for MAC2. By default, using eth which will translate to eth%d in the kernel.
+
+config E1000_EP80579_PHY0
+ bool "External PHY Connected to GIG Port 0"
+ depends on E1000_EP80579
+ ---help---
+ Select this option if you have an external PHY connected to port 0.
+ External PHYs supported: M88E1000, M88E1141, VSC8211, VSC8601.
+
+config E1000_EP80579_PHY1
+ bool "External PHY Connected to GIG Port 1"
+ depends on E1000_EP80579
+ ---help---
+ Select this option if you have an external PHY connected to port 1.
+ External PHYs supported: M88E1000, M88E1141, VSC8211, VSC8601.
+
+config E1000_EP80579_PHY2
+ bool "External PHY Connected to GIG Port 2"
+ depends on E1000_EP80579
+ ---help---
+ Select this option if you have an external PHY connected to port 2.
+ External PHYs supported: M88E1000, M88E1141, VSC8211, VSC8601.
+
config E1000E
tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
depends on PCI && (!SPARC32 || BROKEN)
diff --git a/drivers/net/ethernet/intel/e1000/Makefile b/drivers/net/ethernet/intel/e1000/Makefile
index 4a6ab152245..8a0f2c0ad22 100644
--- a/drivers/net/ethernet/intel/e1000/Makefile
+++ b/drivers/net/ethernet/intel/e1000/Makefile
@@ -30,6 +30,12 @@
# Makefile for the Intel(R) PRO/1000 ethernet driver
#
-obj-$(CONFIG_E1000) += e1000.o
+gcu-objs := gcu_main.o gcu_if.o
+
+ifeq ($(CONFIG_E1000_EP80579),y)
+ obj-$(CONFIG_E1000) += gcu.o
+endif
e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o
+
+obj-$(CONFIG_E1000) += e1000.o
diff --git a/drivers/net/ethernet/intel/e1000/gcu.h b/drivers/net/ethernet/intel/e1000/gcu.h
new file mode 100644
index 00000000000..b409a6ee136
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000/gcu.h
@@ -0,0 +1,102 @@
+/*****************************************************************************
+
+GPL LICENSE SUMMARY
+
+ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ Intel Corporation
+
+ version: Embedded.Release.Patch.L.1.0.7-5
+
+ Contact Information:
+
+ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+
+*****************************************************************************/
+
+/* Linux GCU Driver main header file */
+
+#ifndef _GCU_H_
+#define _GCU_H_
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define BAR_0 0
+
+#define INTEL_GCU_DEVICE(device_id) {\
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
+
+#define GCU_DEV_NAME_SIZE 16
+
+#ifdef DBG
+#define GCU_DBG(args...) printk(KERN_DEBUG "gcu: " args)
+#else
+#define GCU_DBG(args...)
+#endif
+
+#define GCU_ERR(args...) printk(KERN_ERR "gcu: " args)
+
+#define PFX "gcu: "
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+ (void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
+ printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->name, \
+ __func__ , ## args))
+
+struct gcu_adapter {
+ struct pci_dev *pdev;
+ uint32_t mem_start;
+ uint32_t mem_end;
+ uint32_t base_addr;
+ uint8_t *hw_addr;
+ char name[GCU_DEV_NAME_SIZE];
+ uint32_t pci_state[16];
+ int32_t msg_enable;
+ uint16_t device_id;
+ uint16_t vendor_id;
+ uint16_t subsystem_id;
+ uint16_t subsystem_vendor_id;
+ uint16_t pci_cmd_word;
+ uint8_t revision_id;
+ /* open/release and usage marking */
+ struct module *owner;
+
+};
+
+/*
+ * Exported interface functions need access to the modules
+ * gcu_adapter struct
+ */
+const struct gcu_adapter *gcu_get_adapter(void);
+void gcu_release_adapter(const struct gcu_adapter **adapter);
+
+#endif /* _GCU_H_ */
diff --git a/drivers/net/ethernet/intel/e1000/gcu_if.c b/drivers/net/ethernet/intel/e1000/gcu_if.c
new file mode 100644
index 00000000000..3b10dfa098b
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000/gcu_if.c
@@ -0,0 +1,343 @@
+/*****************************************************************************
+
+GPL LICENSE SUMMARY
+
+ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ Intel Corporation
+
+ version: Embedded.Release.Patch.L.1.0.7-5
+
+ Contact Information:
+
+ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+
+*****************************************************************************/
+
+/**************************************************************************
+ * @ingroup GCU_INTERFACE
+ *
+ * @file gcu_if.c
+ *
+ * @description
+ * This module contains shared functions for accessing and configuring
+ * the GCU.
+ *
+ **************************************************************************/
+
+#include "gcu.h"
+#include "gcu_reg.h"
+#include "gcu_if.h"
+
+/* forward declaration for write verify used in gcu_write_eth_phy */
+static int32_t gcu_write_verify(uint32_t phy_num,
+ uint32_t reg_addr,
+ uint16_t written_data,
+ const struct gcu_adapter *adapter);
+
+/**
+ * gcu_write_eth_phy
+ * @phy_num: phy we want to write to, either 0, 1, or 2
+ * @reg_addr: address in PHY's register space to write to
+ * @phy_data: data to be written
+ *
+ * interface function for other modules to access the GCU
+ **/
+int32_t
+gcu_write_eth_phy(uint32_t phy_num, uint32_t reg_addr, uint16_t phy_data)
+{
+ const struct gcu_adapter *adapter;
+ uint32_t data = 0;
+ uint32_t timeoutCounter = 0;
+ const uint32_t timeoutCounterMax = GCU_MAX_ATTEMPTS;
+ uint32_t pending;
+
+ GCU_DBG("%s\n", __func__);
+
+ if (phy_num > MDIO_COMMAND_PHY_ADDR_MAX) {
+ GCU_ERR("phy_num = %d, which is greater than "
+ "MDIO_COMMAND_PHY_ADDR_MAX\n", phy_num);
+
+ return -1;
+ }
+
+ if (reg_addr > MDIO_COMMAND_PHY_REG_MAX) {
+ GCU_ERR("reg_addr = %d, which is greater than "
+ "MDIO_COMMAND_PHY_REG_MAX\n", phy_num);
+
+ return -1;
+ }
+
+ /* format the data to be written to the MDIO_COMMAND_REG */
+ data = phy_data;
+ data |= (reg_addr << MDIO_COMMAND_PHY_REG_OFFSET);
+ data |= (phy_num << MDIO_COMMAND_PHY_ADDR_OFFSET);
+ data |= MDIO_COMMAND_OPER_MASK | MDIO_COMMAND_GO_MASK;
+
+ /*
+ * get_gcu_adapter contains a spinlock, this may pause for a bit
+ */
+ adapter = gcu_get_adapter();
+ if (!adapter) {
+ GCU_ERR("gcu_adapter not available, cannot access MMIO\n");
+ return -1;
+ }
+
+ /*
+ * We write to MDIO_COMMAND_REG initially, then read that
+ * same register until its MDIO_GO bit is cleared. When cleared,
+ * the transaction is complete
+ */
+ iowrite32(data, adapter->hw_addr + MDIO_COMMAND_REG);
+ do {
+ timeoutCounter++;
+ udelay(0x32); /* 50 microsecond delay */
+ data = ioread32(adapter->hw_addr + MDIO_COMMAND_REG);
+ pending =
+ (data & MDIO_COMMAND_GO_MASK) >> MDIO_COMMAND_GO_OFFSET;
+ } while (pending && timeoutCounter < timeoutCounterMax);
+
+ if (timeoutCounter == timeoutCounterMax && pending) {
+ GCU_ERR("Reached maximum number of retries"
+ " accessing MDIO_COMMAND_REG\n");
+
+ gcu_release_adapter(&adapter);
+
+ return -1;
+ }
+
+ /* validate the write during debug */
+#ifdef DBG2
+ if (!gcu_write_verify(phy_num, reg_addr, phy_data, adapter)) {
+ GCU_ERR("Write verification failed for PHY=%d and addr=%d\n",
+ phy_num, reg_addr);
+
+ gcu_release_adapter(&adapter);
+
+ return -1;
+ }
+#endif
+
+ gcu_release_adapter(&adapter);
+
+ return 0;
+}
+EXPORT_SYMBOL(gcu_write_eth_phy);
+
+/**
+ * gcu_read_eth_phy
+ * @phy_num: phy we want to write to, either 0, 1, or 2
+ * @reg_addr: address in PHY's register space to write to
+ * @phy_data: data to be written
+ *
+ * interface function for other modules to access the GCU
+ **/
+int32_t
+gcu_read_eth_phy(uint32_t phy_num, uint32_t reg_addr, uint16_t *phy_data)
+{
+ const struct gcu_adapter *adapter;
+ uint32_t data = 0;
+ uint32_t timeoutCounter = 0;
+ const uint32_t timeoutCounterMax = GCU_MAX_ATTEMPTS;
+ uint32_t pending = 0;
+
+ GCU_DBG("%s\n", __func__);
+
+ if (phy_num > MDIO_COMMAND_PHY_ADDR_MAX) {
+ GCU_ERR("phy_num = %d, which is greater than "
+ "MDIO_COMMAND_PHY_ADDR_MAX\n", phy_num);
+
+ return -1;
+ }
+
+ if (reg_addr > MDIO_COMMAND_PHY_REG_MAX) {
+ GCU_ERR("reg_addr = %d, which is greater than "
+ "MDIO_COMMAND_PHY_REG_MAX\n", phy_num);
+
+ return -1;
+ }
+
+ /* format the data to be written to MDIO_COMMAND_REG */
+ data |= (reg_addr << MDIO_COMMAND_PHY_REG_OFFSET);
+ data |= (phy_num << MDIO_COMMAND_PHY_ADDR_OFFSET);
+ data |= MDIO_COMMAND_GO_MASK;
+
+ /*
+ * this call contains a spinlock, so this may pause for a bit
+ */
+ adapter = gcu_get_adapter();
+ if (!adapter) {
+ GCU_ERR("gcu_adapter not available, cannot access MMIO\n");
+ return -1;
+ }
+
+ /*
+ * We write to MDIO_COMMAND_REG initially, then read that
+ * same register until its MDIO_GO bit is cleared. When cleared,
+ * the transaction is complete
+ */
+ iowrite32(data, adapter->hw_addr + MDIO_COMMAND_REG);
+ do {
+ timeoutCounter++;
+ udelay(0x32); /* 50 microsecond delay */
+ data = ioread32(adapter->hw_addr + MDIO_COMMAND_REG);
+ pending =
+ (data & MDIO_COMMAND_GO_MASK) >> MDIO_COMMAND_GO_OFFSET;
+ } while (pending && timeoutCounter < timeoutCounterMax);
+
+ if (timeoutCounter == timeoutCounterMax && pending) {
+ GCU_ERR("Reached maximum number of retries"
+ " accessing MDIO_COMMAND_REG\n");
+
+ gcu_release_adapter(&adapter);
+
+ return -1;
+ }
+
+ /* we retrieve the data from the MDIO_STATUS_REGISTER */
+ data = ioread32(adapter->hw_addr + MDIO_STATUS_REG);
+ if ((data & MDIO_STATUS_STATUS_MASK) != 0) {
+ GCU_ERR("Unable to retrieve data from MDIO_STATUS_REG\n");
+
+ gcu_release_adapter(&adapter);
+
+ return -1;
+ }
+
+ *phy_data = (uint16_t) (data & MDIO_STATUS_READ_DATA_MASK);
+
+ gcu_release_adapter(&adapter);
+
+ return 0;
+}
+EXPORT_SYMBOL(gcu_read_eth_phy);
+
+/**
+ * gcu_write_verify
+ * @phy_num: phy we want to write to, either 0, 1, or 2
+ * @reg_addr: address in PHY's register space to write to
+ * @phy_data: data to be checked
+ * @adapter: pointer to global adapter struct
+ *
+ * This f(n) assumes that the spinlock acquired for adapter is
+ * still in force.
+ **/
+int32_t
+gcu_write_verify(uint32_t phy_num, uint32_t reg_addr, uint16_t written_data,
+ const struct gcu_adapter *adapter)
+{
+ uint32_t data = 0;
+ uint32_t timeoutCounter = 0;
+ const uint32_t timeoutCounterMax = GCU_MAX_ATTEMPTS;
+ uint32_t pending = 0;
+
+ GCU_DBG("%s\n", __func__);
+
+ if (!adapter) {
+ GCU_ERR("Invalid adapter pointer\n");
+ return 0;
+ }
+
+ if (phy_num > MDIO_COMMAND_PHY_ADDR_MAX) {
+ GCU_ERR("phy_num = %d, which is greater than "
+ "MDIO_COMMAND_PHY_ADDR_MAX\n", phy_num);
+
+ return 0;
+ }
+
+ if (reg_addr > MDIO_COMMAND_PHY_REG_MAX) {
+ GCU_ERR("reg_addr = %d, which is greater than "
+ "MDIO_COMMAND_PHY_REG_MAX\n", phy_num);
+
+ return 0;
+ }
+
+ /* format the data to be written to MDIO_COMMAND_REG */
+ data |= (reg_addr << MDIO_COMMAND_PHY_REG_OFFSET);
+ data |= (phy_num << MDIO_COMMAND_PHY_ADDR_OFFSET);
+ data |= MDIO_COMMAND_GO_MASK;
+
+ /*
+ * We write to MDIO_COMMAND_REG initially, then read that
+ * same register until its MDIO_GO bit is cleared. When cleared,
+ * the transaction is complete
+ */
+ iowrite32(data, adapter->hw_addr + MDIO_COMMAND_REG);
+ do {
+ timeoutCounter++;
+ udelay(0x32); /* 50 microsecond delay */
+ data = ioread32(adapter->hw_addr + MDIO_COMMAND_REG);
+ pending =
+ (data & MDIO_COMMAND_GO_MASK) >> MDIO_COMMAND_GO_OFFSET;
+ } while (pending && timeoutCounter < timeoutCounterMax);
+
+ if (timeoutCounter == timeoutCounterMax && pending) {
+ GCU_ERR("Reached maximum number of retries"
+ " accessing MDIO_COMMAND_REG\n");
+
+ return 0;
+ }
+
+ /* we retrieve the data from the MDIO_STATUS_REGISTER */
+ data = ioread32(adapter->hw_addr + MDIO_STATUS_REG);
+ if ((data & MDIO_STATUS_STATUS_MASK) != 0) {
+ GCU_ERR("Unable to retrieve data from MDIO_STATUS_REG\n");
+
+ return 0;
+ }
+
+ return written_data == (uint16_t) (data & MDIO_STATUS_READ_DATA_MASK);
+}
+
+/*
+ * gcu_e1000_resume
+ * @pdev: gcu pci_dev
+ * purpose - exported PM resume function used by iegbe
+ * driver to enable the GCU device.
+ */
+void gcu_e1000_resume(struct pci_dev *pdev)
+{
+ GCU_DBG("%s\n", __func__);
+
+ pci_restore_state(pdev);
+ if (!pci_enable_device(pdev))
+ GCU_DBG("pci_enable_device failed!\n");
+
+ return;
+}
+EXPORT_SYMBOL(gcu_e1000_resume);
+
+/*
+ * gcu_e1000_suspend
+ * @pdev: gcu pci_dev
+ * @state: PM state
+ * purpose - exported PM suspend function used by iegbe
+ * driver to disable the GCU device.
+ */
+int gcu_e1000_suspend(struct pci_dev *pdev, uint32_t state)
+{
+ GCU_DBG("%s\n", __func__);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ state = (state > 0) ? 0 : 0;
+
+ return state;
+}
+EXPORT_SYMBOL(gcu_e1000_suspend);
diff --git a/drivers/net/ethernet/intel/e1000/gcu_if.h b/drivers/net/ethernet/intel/e1000/gcu_if.h
new file mode 100644
index 00000000000..84187f68e0e
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000/gcu_if.h
@@ -0,0 +1,51 @@
+/*****************************************************************************
+
+GPL LICENSE SUMMARY
+
+ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ Intel Corporation
+
+ version: Embedded.Release.Patch.L.1.0.7-5
+
+ Contact Information:
+
+ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+
+*****************************************************************************/
+
+/*
+ * gcu_if.h
+ * Shared functions for accessing and configuring the GCU
+ */
+
+#ifndef GCU_IF_H
+#define GCU_IF_H
+#define GCU_DEVID 0x503E
+#define GCU_MAX_ATTEMPTS 64
+
+int32_t gcu_write_eth_phy(uint32_t phy_num, uint32_t reg_addr,
+ uint16_t phy_data);
+
+int32_t gcu_read_eth_phy(uint32_t phy_num, uint32_t reg_addr,
+ uint16_t *phy_data);
+
+int gcu_e1000_suspend(struct pci_dev *pdev, uint32_t state);
+void gcu_e1000_resume(struct pci_dev *pdev);
+#endif /* ifndef GCU_IF_H */
diff --git a/drivers/net/ethernet/intel/e1000/gcu_main.c b/drivers/net/ethernet/intel/e1000/gcu_main.c
new file mode 100644
index 00000000000..4a4ccb7a4f0
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000/gcu_main.c
@@ -0,0 +1,419 @@
+/******************************************************************************
+
+GPL LICENSE SUMMARY
+
+ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ Intel Corporation
+
+ version: Embedded.Release.Patch.L.1.0.7-5
+
+ Contact Information:
+
+ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+
+******************************************************************************/
+/**************************************************************************
+ * @ingroup GCU_GENERAL
+ *
+ * @file gcu_main.c
+ *
+ * @description
+ * This module contains the upper-edge routines of the driver
+ * interface that handle initialization, resets, and shutdowns
+ * of the GCU.
+ *
+ **************************************************************************/
+
+#include "gcu.h"
+
+char gcu_driver_name[] = "GCU";
+char gcu_driver_string[] = "Global Configuration Unit Driver";
+#define DRV_VERSION "1.0.0"
+char gcu_driver_version[] = DRV_VERSION;
+char gcu_copyright[] = "Copyright (c) 1999-2007 Intel Corporation.";
+
+/* gcu_pci_tbl - PCI Device ID Table
+ *
+ * Last entry must be all 0s
+ *
+ * Macro expands to...
+ * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
+ */
+static DEFINE_PCI_DEVICE_TABLE(gcu_pci_tbl) = {
+ INTEL_GCU_DEVICE(0x503E),
+ /* required last entry */
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, gcu_pci_tbl);
+
+enum gcu_err_type { err_ioremap, err_alloc_gcu_adapter };
+
+static int gcu_init_module(void);
+static void gcu_exit_module(void);
+static int gcu_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void gcu_probe_err(enum gcu_err_type err, struct pci_dev *pdev,
+ struct gcu_adapter *adapter);
+static void __devexit gcu_remove(struct pci_dev *pdev);
+static int gcu_notify_reboot(struct notifier_block *, unsigned long event,
+ void *ptr);
+static int gcu_suspend(struct pci_dev *pdev, uint32_t state);
+static struct gcu_adapter *alloc_gcu_adapter(void);
+static void free_gcu_adapter(struct gcu_adapter *adapter);
+
+struct notifier_block gcu_notifier_reboot = {
+ .notifier_call = gcu_notify_reboot,
+ .next = NULL,
+ .priority = 0
+};
+
+static struct pci_driver gcu_driver = {
+ .name = gcu_driver_name,
+ .id_table = gcu_pci_tbl,
+ .probe = gcu_probe,
+ .remove = __devexit_p(gcu_remove),
+};
+
+static struct gcu_adapter *global_adapter;
+static DEFINE_SPINLOCK(global_adapter_spinlock);
+static unsigned long g_intflags;
+
+MODULE_AUTHOR("Intel(R) Corporation");
+MODULE_DESCRIPTION("Global Configuration Unit Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
+
+/*
+ * AFU: debug values are pulled originally from netdevice.h
+ * where in the orig iegbe driver, the enums were used.
+ * Probably want to come up with our own enum set
+ */
+static int debug = 0x1UL | 0x2UL;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+/**
+ * gcu_init_module - Driver Registration Routine
+ *
+ * gcu_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init gcu_init_module(void)
+{
+ int ret;
+ printk(KERN_INFO "%s - version %s\n",
+ gcu_driver_string, gcu_driver_version);
+
+ printk(KERN_INFO "%s\n", gcu_copyright);
+
+ ret = pci_register_driver(&gcu_driver);
+ if (ret >= 0)
+ register_reboot_notifier(&gcu_notifier_reboot);
+
+ return ret;
+}
+
+module_init(gcu_init_module);
+
+/**
+ * gcu_exit_module - Driver Exit Cleanup Routine
+ *
+ * gcu_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit gcu_exit_module(void)
+{
+ GCU_DBG("%s\n", __func__);
+
+ unregister_reboot_notifier(&gcu_notifier_reboot);
+ pci_unregister_driver(&gcu_driver);
+}
+
+module_exit(gcu_exit_module);
+
+/**
+ * gcu_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in gcu_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * gcu_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit
+gcu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct gcu_adapter *adapter = 0;
+ uint32_t mmio_start, mmio_len;
+ int err;
+
+ GCU_DBG("%s\n", __func__);
+
+ /** If we already have an adapter then we must already have been probed. */
+ if (global_adapter != 0)
+ return 0;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ GCU_DBG("Unable to enable PCI Device\n");
+ return err;
+ }
+
+ err = pci_request_regions(pdev, gcu_driver_name);
+ if (err) {
+ GCU_DBG("Unable to acquire requested memory regions\n");
+ return err;
+ }
+
+ /*
+ * acquire the adapter spinlock. Once the module is loaded, it is
+ * possible for someone to access the adapter struct via the interface
+ * functions exported in gcu_if.c
+ */
+ spin_lock(&global_adapter_spinlock);
+
+ adapter = alloc_gcu_adapter();
+ if (!adapter) {
+ gcu_probe_err(err_alloc_gcu_adapter, pdev, adapter);
+ spin_unlock(&global_adapter_spinlock);
+ return -ENOMEM;
+ }
+
+ pci_set_drvdata(pdev, adapter);
+
+ adapter->pdev = pdev;
+ adapter->msg_enable = (1 << debug) - 1;
+
+ mmio_start = pci_resource_start(pdev, BAR_0);
+ mmio_len = pci_resource_len(pdev, BAR_0);
+
+ adapter->hw_addr = ioremap(mmio_start, mmio_len);
+ if (!adapter->hw_addr) {
+ GCU_DBG("Unable to map mmio\n");
+ gcu_probe_err(err_ioremap, pdev, adapter);
+ spin_unlock(&global_adapter_spinlock);
+ return -EIO;
+ }
+
+ strncpy(adapter->name, pci_name(pdev), sizeof(adapter->name) - 1);
+ adapter->mem_start = mmio_start;
+ adapter->mem_end = mmio_start + mmio_len;
+
+ adapter->vendor_id = pdev->vendor;
+ adapter->device_id = pdev->device;
+ adapter->subsystem_vendor_id = pdev->subsystem_vendor;
+ adapter->subsystem_id = pdev->subsystem_device;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->revision_id);
+
+ pci_read_config_word(pdev, PCI_COMMAND, &adapter->pci_cmd_word);
+
+ global_adapter = adapter;
+ spin_unlock(&global_adapter_spinlock);
+
+ DPRINTK(PROBE, INFO, "Intel(R) GCU Initialized\n");
+
+ return 0;
+}
+
+/**
+ * gcu_probe_err - gcu_probe error handler
+ * @err: gcu_err_type
+ *
+ * encapsulated error handling for gcu_probe
+ **/
+static void
+gcu_probe_err(enum gcu_err_type err, struct pci_dev *pdev,
+ struct gcu_adapter *adapter)
+{
+
+ switch (err) {
+ case err_ioremap:
+ iounmap(adapter->hw_addr);
+ pci_release_regions(pdev);
+ case err_alloc_gcu_adapter:
+ default:
+ free_gcu_adapter(adapter);
+ break;
+ }
+}
+
+/**
+ * gcu_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * gcu_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit gcu_remove(struct pci_dev *pdev)
+{
+ struct gcu_adapter *adapter = pci_get_drvdata(pdev);
+
+ GCU_DBG("%s\n", __func__);
+
+ iounmap(adapter->hw_addr);
+ pci_release_regions(pdev);
+ free_gcu_adapter(adapter);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static int
+gcu_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
+{
+ struct pci_dev *pdev = NULL;
+
+ GCU_DBG("%s\n", __func__);
+
+ switch (event) {
+ case SYS_DOWN:
+ case SYS_HALT:
+ case SYS_POWER_OFF:
+ while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)))
+ if (pci_dev_driver(pdev) == &gcu_driver)
+ gcu_suspend(pdev, 0x3);
+ }
+ return NOTIFY_DONE;
+}
+
+/**
+ * gcu_suspend - device sleep function
+ * @pdev: PCI device information struct
+ *
+ * gcu_supend is generally called to place a device in sleep mode,
+ * however the GCU doesn't support power mangement. For this case,
+ * it is part of the gcu_notify_reboot() call chain to quiese the
+ * device before a reboot.
+ **/
+static int gcu_suspend(struct pci_dev *pdev, uint32_t state)
+{
+ /*struct gcu_adapter *adapter = pci_get_drvdata(pdev); */
+ GCU_DBG("%s\n", __func__);
+
+ pci_save_state(pdev);
+
+ pci_disable_device(pdev);
+
+ state = (state > 0) ? 0 : 0;
+
+ /*
+ * GCU doesn't support power management, but want to
+ * leave a hook incase that situation changes in the future
+ *
+ * pci_set_power_state(pdev, state);
+ *
+ */
+
+ return state;
+}
+
+/**
+ * alloc_gcu_adapter
+ *
+ * alloc_gcu_adapter is a wrapper for the kmalloc call for the
+ * device specific data block plus inits the global_adapter variable.
+ *
+ * Note that this function assumes that the spinlock for the global
+ * gcu_adapter struct as been acquired.
+ **/
+static struct gcu_adapter *alloc_gcu_adapter()
+{
+ struct gcu_adapter *adapter;
+
+ GCU_DBG("%s\n", __func__);
+
+ adapter = kmalloc(sizeof(*adapter), GFP_KERNEL);
+
+ global_adapter = adapter;
+
+ if (!adapter) {
+ GCU_DBG("Unable to allocate space for global gcu_adapter");
+ return 0;
+ }
+
+ memset(adapter, 0, sizeof(*adapter));
+
+ return adapter;
+}
+
+/**
+ * free_gcu_adapter
+ * @adapter: gcu_adapter struct to be free'd
+ *
+ * free_gcu_adapter is a wrapper for the kfree call for the
+ * device specific data block plus clears the global_adapter variable
+ *
+ * Note that this function assumes that the spinlock for the global
+ * gcu_adapter struct as been acquired.
+ **/
+static void free_gcu_adapter(struct gcu_adapter *adapter)
+{
+ GCU_DBG("%s\n", __func__);
+
+ global_adapter = 0;
+
+ kfree(adapter);
+}
+
+/**
+ * gcu_get_adapter
+ *
+ * gcu_get_adapter is used by the functions exported in gcu_if.c to get
+ * access to the memory addresses needed to access the MMIO registers
+ * of the GCU
+ **/
+const struct gcu_adapter *gcu_get_adapter(void)
+{
+ GCU_DBG("%s\n", __func__);
+
+ if (global_adapter == NULL) {
+ GCU_DBG("global gcu_adapter is not available\n");
+ return NULL;
+ }
+
+ spin_lock_irqsave(&global_adapter_spinlock, g_intflags);
+
+ return global_adapter;
+}
+
+/**
+ * gcu_release_adapter
+ *
+ * gcu_release_adapter is used by the functions exported in gcu_if.c to get
+ * release the adapter spinlock and the handle to the adapter
+ **/
+void gcu_release_adapter(const struct gcu_adapter **adapter)
+{
+ GCU_DBG("%s\n", __func__);
+
+ if (adapter == NULL)
+ GCU_ERR("global gcu_adapter handle is invalid\n");
+ else
+ *adapter = 0;
+
+ spin_unlock_irqrestore(&global_adapter_spinlock, g_intflags);
+
+ return;
+}
+
+/* gcu_main.c */
diff --git a/drivers/net/ethernet/intel/e1000/gcu_reg.h b/drivers/net/ethernet/intel/e1000/gcu_reg.h
new file mode 100644
index 00000000000..cf77303ca5e
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000/gcu_reg.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+
+GPL LICENSE SUMMARY
+
+ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ Intel Corporation
+
+ version: Embedded.Release.Patch.L.1.0.7-5
+
+ Contact Information:
+
+ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+
+******************************************************************************/
+
+/*
+ * gcu_reg.h
+ * Macros and constants related to the registers available on the GCU
+ */
+
+#ifndef GCU_REG_H
+#define GCU_REG_H
+
+/* Register Offsets within memory map register space */
+#define MDIO_STATUS_REG 0x00000010UL
+#define MDIO_COMMAND_REG 0x00000014UL
+
+/* MDIO_STATUS_REG fields */
+#define MDIO_STATUS_STATUS_MASK 0x80000000UL /* bit 31 = 1 on error */
+#define MDIO_STATUS_READ_DATA_MASK 0x0000FFFFUL
+
+/* MDIO_COMMAND_REG fields */
+#define MDIO_COMMAND_GO_MASK 0x80000000UL /* bit 31 = 1 during read
+ * or write, 0 on
+ * completion */
+#define MDIO_COMMAND_OPER_MASK 0x04000000UL /* bit = 1 is a write */
+#define MDIO_COMMAND_PHY_ADDR_MASK 0x03E00000UL
+#define MDIO_COMMAND_PHY_REG_MASK 0x001F0000UL
+#define MDIO_COMMAND_WRITE_DATA_MASK 0x0000FFFFUL
+
+#define MDIO_COMMAND_GO_OFFSET 31
+#define MDIO_COMMAND_OPER_OFFSET 26
+#define MDIO_COMMAND_PHY_ADDR_OFFSET 21
+#define MDIO_COMMAND_PHY_REG_OFFSET 16
+#define MDIO_COMMAND_WRITE_DATA_OFFSET 0
+
+#define MDIO_COMMAND_PHY_ADDR_MAX 2 /* total phys supported by GCU */
+#define MDIO_COMMAND_PHY_REG_MAX 31 /* total registers available on the
+ * M88 Phy used on truxton */
+
+#endif /* ifndef GCU_REG_H */