summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoe Rubinstein <nrubinstein@avencall.com>2012-04-13 10:53:33 +0200
committerNoe Rubinstein <nrubinstein@avencall.com>2012-04-24 17:49:40 +0200
commit0cb7e3b26bb31178a6ed30e00975c18da22bf9d4 (patch)
treebf7e4ea037ebac2ab4dd74cc4a477dd56a928e36
parentacbbc4bf10a02a99b7075800b41c8f633e84780b (diff)
e1000: add driver for the Intel GCU.
This is used for MDIO on Intel EP80579.
-rw-r--r--src/Makefile1
-rw-r--r--src/drivers/net/e1000/gcu/gcu.h82
-rw-r--r--src/drivers/net/e1000/gcu/gcu_if.c307
-rw-r--r--src/drivers/net/e1000/gcu/gcu_if.h54
-rw-r--r--src/drivers/net/e1000/gcu/gcu_main.c283
-rw-r--r--src/drivers/net/e1000/gcu/gcu_reg.h68
-rw-r--r--src/include/ipxe/errfile.h2
7 files changed, 797 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
index c30dc5c9..efd9f5ce 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -63,6 +63,7 @@ SRCDIRS += image
SRCDIRS += drivers/bus
SRCDIRS += drivers/net
SRCDIRS += drivers/net/e1000
+SRCDIRS += drivers/net/e1000/gcu
SRCDIRS += drivers/net/e1000e
SRCDIRS += drivers/net/igb
SRCDIRS += drivers/net/igbvf
diff --git a/src/drivers/net/e1000/gcu/gcu.h b/src/drivers/net/e1000/gcu/gcu.h
new file mode 100644
index 00000000..a23671cb
--- /dev/null
+++ b/src/drivers/net/e1000/gcu/gcu.h
@@ -0,0 +1,82 @@
+/*****************************************************************************
+
+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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ipxe/linux_compat.h>
+#include <ipxe/timer.h>
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+
+#include "../../wlan_compat.h"
+
+#define BAR_0 0
+
+#define PFX "gcu: "
+#define GCU_DBG(args...) DBG(args)
+#define GCU_ERR(args...) printf(PFX args)
+
+#define pci_dev pci_device
+#define iowrite32 writel
+#define ioread32 readl
+
+struct gcu_adapter {
+ struct pci_dev *pdev;
+ uint32_t mem_start;
+ uint32_t mem_end;
+ uint32_t base_addr;
+ uint8_t *hw_addr;
+ uint32_t pci_state[16];
+ 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;
+};
+
+/*
+ * 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/src/drivers/net/e1000/gcu/gcu_if.c b/src/drivers/net/e1000/gcu/gcu_if.c
new file mode 100644
index 00000000..175b764a
--- /dev/null
+++ b/src/drivers/net/e1000/gcu/gcu_if.c
@@ -0,0 +1,307 @@
+/*****************************************************************************
+
+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"
+
+#if DBG_LOG
+/* 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);
+#endif
+
+/**
+ * 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;
+
+ 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 */
+#if DBG_LOG
+ if (!gcu_write_verify(phy_num, reg_addr, phy_data, adapter))
+ DBG("Write verification failed for PHY=%d and addr=%d\n",
+ phy_num, reg_addr);
+#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;
+
+ 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);
+
+#if DBG_LOG
+/**
+ * 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)
+{
+ u32 data = 0;
+ u32 timeoutCounter = 0;
+ const uint32_t timeoutCounterMax = GCU_MAX_ATTEMPTS;
+ u32 pending = 0;
+ u16 read_data;
+ int success;
+
+ 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;
+ }
+
+ read_data = data & MDIO_STATUS_READ_DATA_MASK;
+ success = written_data == read_data;
+ if (!success)
+ DBG("WARNING: PHY%d reg %x: wrote 0x%04x, read 0x%04x\n",
+ phy_num, reg_addr, written_data, read_data);
+
+ return success;
+}
+#endif
diff --git a/src/drivers/net/e1000/gcu/gcu_if.h b/src/drivers/net/e1000/gcu/gcu_if.h
new file mode 100644
index 00000000..2d5991e8
--- /dev/null
+++ b/src/drivers/net/e1000/gcu/gcu_if.h
@@ -0,0 +1,54 @@
+/*****************************************************************************
+
+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
+
+#include <stdint.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_device *pdev, uint32_t state);
+void gcu_e1000_resume(struct pci_device *pdev);
+#endif /* ifndef GCU_IF_H */
diff --git a/src/drivers/net/e1000/gcu/gcu_main.c b/src/drivers/net/e1000/gcu/gcu_main.c
new file mode 100644
index 00000000..63b2dbc4
--- /dev/null
+++ b/src/drivers/net/e1000/gcu/gcu_main.c
@@ -0,0 +1,283 @@
+/******************************************************************************
+
+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 struct pci_device_id gcu_pci_tbl[] = {
+ PCI_ID(0x8086, 0x503E, "gcu", "Global Configuration Unit", 0),
+};
+
+MODULE_DEVICE_TABLE(pci, gcu_pci_tbl);
+
+enum gcu_err_type { err_ioremap, err_alloc_gcu_adapter };
+
+static int gcu_probe(struct pci_dev *pdev);
+static void gcu_probe_err(enum gcu_err_type err, struct gcu_adapter *adapter);
+static void gcu_remove(struct pci_dev *pdev);
+static struct gcu_adapter *alloc_gcu_adapter(void);
+static void free_gcu_adapter(struct gcu_adapter *adapter);
+
+struct pci_driver gcu_driver __pci_driver = {
+ .ids = gcu_pci_tbl,
+ .id_count = ARRAY_SIZE(gcu_pci_tbl),
+ .probe = gcu_probe,
+ .remove = gcu_remove,
+ .load_order = 1,
+};
+
+static struct gcu_adapter *global_adapter = 0;
+
+/**
+ * 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
+gcu_probe(struct pci_dev *pdev)
+{
+ struct gcu_adapter *adapter = 0;
+ uint32_t mmio_start, mmio_len;
+
+ GCU_DBG("%s\n", __func__);
+
+ /** If we already have an adapter then we must already have been probed. */
+ if (global_adapter != 0)
+ return 0;
+
+ adjust_pci_device(pdev);
+
+ /*
+ * 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, adapter);
+ spin_unlock(&global_adapter_spinlock);
+ return -ENOMEM;
+ }
+
+ pci_set_drvdata(pdev, adapter);
+
+ adapter->pdev = pdev;
+
+ mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+ mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_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, adapter);
+ spin_unlock(&global_adapter_spinlock);
+ return -EIO;
+ }
+
+ adapter->mem_start = mmio_start;
+ adapter->mem_end = mmio_start + mmio_len;
+
+ adapter->vendor_id = pdev->vendor;
+ adapter->device_id = pdev->device;
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID,
+ &adapter->subsystem_vendor_id);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &adapter->subsystem_id);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->revision_id);
+
+ 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);
+
+ DBG("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 gcu_adapter *adapter)
+{
+ switch (err) {
+ case err_ioremap:
+ iounmap(adapter->hw_addr);
+ 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 gcu_remove(struct pci_dev *pdev)
+{
+ struct gcu_adapter *adapter = pci_get_drvdata(pdev);
+
+ GCU_DBG("%s\n", __func__);
+
+ iounmap(adapter->hw_addr);
+ free_gcu_adapter(adapter);
+ pci_set_drvdata(pdev, NULL);
+}
+
+/**
+ * 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 = malloc(sizeof(*adapter));
+
+ 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;
+
+ free(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;
+ }
+
+ 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;
+
+ return;
+}
+
+/* gcu_main.c */
diff --git a/src/drivers/net/e1000/gcu/gcu_reg.h b/src/drivers/net/e1000/gcu/gcu_reg.h
new file mode 100644
index 00000000..cf77303c
--- /dev/null
+++ b/src/drivers/net/e1000/gcu/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 */
diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
index 7c86fdbb..6a334ff0 100644
--- a/src/include/ipxe/errfile.h
+++ b/src/include/ipxe/errfile.h
@@ -140,6 +140,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_ath9k ( ERRFILE_DRIVER | 0x005f0000 )
#define ERRFILE_ath ( ERRFILE_DRIVER | 0x00600000 )
#define ERRFILE_vmxnet3 ( ERRFILE_DRIVER | 0x00610000 )
+#define ERRFILE_gcu_main ( ERRFILE_DRIVER | 0x00620000 )
+#define ERRFILE_gcu_if ( ERRFILE_DRIVER | 0x00630000 )
#define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 )
#define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 )