svn commit: r208108 - stable/7/sys/dev/e1000

Jack F Vogel jfv at FreeBSD.org
Sat May 15 07:01:42 UTC 2010


Author: jfv
Date: Sat May 15 07:01:41 2010
New Revision: 208108
URL: http://svn.freebsd.org/changeset/base/208108

Log:
  Add missing lem files to the MFC

Added:
  stable/7/sys/dev/e1000/if_lem.c   (contents, props changed)
  stable/7/sys/dev/e1000/if_lem.h   (contents, props changed)

Added: stable/7/sys/dev/e1000/if_lem.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/7/sys/dev/e1000/if_lem.c	Sat May 15 07:01:41 2010	(r208108)
@@ -0,0 +1,4552 @@
+/******************************************************************************
+
+  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.
+
+******************************************************************************/
+/*$FreeBSD$*/
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_device_polling.h"
+#include "opt_inet.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+#if __FreeBSD_version >= 700029
+#include <sys/eventhandler.h>
+#endif
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include <machine/in_cksum.h>
+#include <dev/led/led.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include "e1000_api.h"
+#include "if_lem.h"
+
+/*********************************************************************
+ *  Set this to one to display debug statistics
+ *********************************************************************/
+int	lem_display_debug_stats = 0;
+
+/*********************************************************************
+ *  Legacy Em Driver version:
+ *********************************************************************/
+char lem_driver_version[] = "1.0.1";
+
+
+/*********************************************************************
+ *  PCI Device ID Table
+ *
+ *  Used by probe to select devices to load on
+ *  Last field stores an index into e1000_strings
+ *  Last entry must be all 0s
+ *
+ *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
+ *********************************************************************/
+
+static em_vendor_info_t lem_vendor_info_array[] =
+{
+	/* Intel(R) PRO/1000 Network Connection */
+	{ 0x8086, E1000_DEV_ID_82540EM,		PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82540EM_LOM,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82540EP,		PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82540EP_LOM,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82540EP_LP,	PCI_ANY_ID, PCI_ANY_ID, 0},
+
+	{ 0x8086, E1000_DEV_ID_82541EI,		PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82541ER,		PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82541ER_LOM,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82541EI_MOBILE,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82541GI,		PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82541GI_LF,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82541GI_MOBILE,	PCI_ANY_ID, PCI_ANY_ID, 0},
+
+	{ 0x8086, E1000_DEV_ID_82542,		PCI_ANY_ID, PCI_ANY_ID, 0},
+
+	{ 0x8086, E1000_DEV_ID_82543GC_FIBER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82543GC_COPPER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+
+	{ 0x8086, E1000_DEV_ID_82544EI_COPPER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82544EI_FIBER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82544GC_COPPER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82544GC_LOM,	PCI_ANY_ID, PCI_ANY_ID, 0},
+
+	{ 0x8086, E1000_DEV_ID_82545EM_COPPER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82545EM_FIBER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82545GM_COPPER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82545GM_FIBER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82545GM_SERDES,	PCI_ANY_ID, PCI_ANY_ID, 0},
+
+	{ 0x8086, E1000_DEV_ID_82546EB_COPPER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546EB_FIBER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546EB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546GB_COPPER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546GB_FIBER,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546GB_SERDES,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546GB_PCIE,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3,
+						PCI_ANY_ID, PCI_ANY_ID, 0},
+
+	{ 0x8086, E1000_DEV_ID_82547EI,		PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82547EI_MOBILE,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_82547GI,		PCI_ANY_ID, PCI_ANY_ID, 0},
+	/* required last entry */
+	{ 0, 0, 0, 0, 0}
+};
+
+/*********************************************************************
+ *  Table of branding strings for all supported NICs.
+ *********************************************************************/
+
+static char *lem_strings[] = {
+	"Intel(R) PRO/1000 Legacy Network Connection"
+};
+
+/*********************************************************************
+ *  Function prototypes
+ *********************************************************************/
+static int	lem_probe(device_t);
+static int	lem_attach(device_t);
+static int	lem_detach(device_t);
+static int	lem_shutdown(device_t);
+static int	lem_suspend(device_t);
+static int	lem_resume(device_t);
+static void	lem_start(struct ifnet *);
+static void	lem_start_locked(struct ifnet *ifp);
+static int	lem_ioctl(struct ifnet *, u_long, caddr_t);
+static void	lem_init(void *);
+static void	lem_init_locked(struct adapter *);
+static void	lem_stop(void *);
+static void	lem_media_status(struct ifnet *, struct ifmediareq *);
+static int	lem_media_change(struct ifnet *);
+static void	lem_identify_hardware(struct adapter *);
+static int	lem_allocate_pci_resources(struct adapter *);
+static int	lem_allocate_irq(struct adapter *adapter);
+static void	lem_free_pci_resources(struct adapter *);
+static void	lem_local_timer(void *);
+static int	lem_hardware_init(struct adapter *);
+static void	lem_setup_interface(device_t, struct adapter *);
+static void	lem_setup_transmit_structures(struct adapter *);
+static void	lem_initialize_transmit_unit(struct adapter *);
+static int	lem_setup_receive_structures(struct adapter *);
+static void	lem_initialize_receive_unit(struct adapter *);
+static void	lem_enable_intr(struct adapter *);
+static void	lem_disable_intr(struct adapter *);
+static void	lem_free_transmit_structures(struct adapter *);
+static void	lem_free_receive_structures(struct adapter *);
+static void	lem_update_stats_counters(struct adapter *);
+static void	lem_txeof(struct adapter *);
+static void	lem_tx_purge(struct adapter *);
+static int	lem_allocate_receive_structures(struct adapter *);
+static int	lem_allocate_transmit_structures(struct adapter *);
+static int	lem_rxeof(struct adapter *, int);
+#ifndef __NO_STRICT_ALIGNMENT
+static int	lem_fixup_rx(struct adapter *);
+#endif
+static void	lem_receive_checksum(struct adapter *, struct e1000_rx_desc *,
+		    struct mbuf *);
+static void	lem_transmit_checksum_setup(struct adapter *, struct mbuf *,
+		    u32 *, u32 *);
+static void	lem_set_promisc(struct adapter *);
+static void	lem_disable_promisc(struct adapter *);
+static void	lem_set_multi(struct adapter *);
+static void	lem_print_hw_stats(struct adapter *);
+static void	lem_update_link_status(struct adapter *);
+static int	lem_get_buf(struct adapter *, int);
+#if __FreeBSD_version >= 700029
+static void	lem_register_vlan(void *, struct ifnet *, u16);
+static void	lem_unregister_vlan(void *, struct ifnet *, u16);
+static void	lem_setup_vlan_hw_support(struct adapter *);
+#endif
+static int	lem_xmit(struct adapter *, struct mbuf **);
+static void	lem_smartspeed(struct adapter *);
+static int	lem_82547_fifo_workaround(struct adapter *, int);
+static void	lem_82547_update_fifo_head(struct adapter *, int);
+static int	lem_82547_tx_fifo_reset(struct adapter *);
+static void	lem_82547_move_tail(void *);
+static int	lem_dma_malloc(struct adapter *, bus_size_t,
+		    struct em_dma_alloc *, int);
+static void	lem_dma_free(struct adapter *, struct em_dma_alloc *);
+static void	lem_print_debug_info(struct adapter *);
+static void	lem_print_nvm_info(struct adapter *);
+static int 	lem_is_valid_ether_addr(u8 *);
+static int	lem_sysctl_stats(SYSCTL_HANDLER_ARGS);
+static int	lem_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
+static u32	lem_fill_descriptors (bus_addr_t address, u32 length,
+		    PDESC_ARRAY desc_array);
+static int	lem_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
+static void	lem_add_int_delay_sysctl(struct adapter *, const char *,
+		    const char *, struct em_int_delay_info *, int, int);
+/* Management and WOL Support */
+static void	lem_init_manageability(struct adapter *);
+static void	lem_release_manageability(struct adapter *);
+static void     lem_get_hw_control(struct adapter *);
+static void     lem_release_hw_control(struct adapter *);
+static void	lem_get_wakeup(device_t);
+static void     lem_enable_wakeup(device_t);
+static int	lem_enable_phy_wakeup(struct adapter *);
+static void	lem_led_func(void *, int);
+
+#ifdef EM_LEGACY_IRQ
+static void	lem_intr(void *);
+#else /* FAST IRQ */
+#if __FreeBSD_version < 700000
+static void	lem_irq_fast(void *);
+#else
+static int	lem_irq_fast(void *);
+#endif
+static void	lem_handle_rxtx(void *context, int pending);
+static void	lem_handle_link(void *context, int pending);
+static void	lem_add_rx_process_limit(struct adapter *, const char *,
+		    const char *, int *, int);
+#endif /* ~EM_LEGACY_IRQ */
+
+#ifdef DEVICE_POLLING
+static poll_handler_t lem_poll;
+#endif /* POLLING */
+
+/*********************************************************************
+ *  FreeBSD Device Interface Entry Points
+ *********************************************************************/
+
+static device_method_t lem_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, lem_probe),
+	DEVMETHOD(device_attach, lem_attach),
+	DEVMETHOD(device_detach, lem_detach),
+	DEVMETHOD(device_shutdown, lem_shutdown),
+	DEVMETHOD(device_suspend, lem_suspend),
+	DEVMETHOD(device_resume, lem_resume),
+	{0, 0}
+};
+
+static driver_t lem_driver = {
+	"em", lem_methods, sizeof(struct adapter),
+};
+
+extern devclass_t em_devclass;
+DRIVER_MODULE(lem, pci, lem_driver, em_devclass, 0, 0);
+MODULE_DEPEND(lem, pci, 1, 1, 1);
+MODULE_DEPEND(lem, ether, 1, 1, 1);
+
+/*********************************************************************
+ *  Tunable default values.
+ *********************************************************************/
+
+#define EM_TICKS_TO_USECS(ticks)	((1024 * (ticks) + 500) / 1000)
+#define EM_USECS_TO_TICKS(usecs)	((1000 * (usecs) + 512) / 1024)
+
+static int lem_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV);
+static int lem_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR);
+static int lem_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV);
+static int lem_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV);
+static int lem_rxd = EM_DEFAULT_RXD;
+static int lem_txd = EM_DEFAULT_TXD;
+static int lem_smart_pwr_down = FALSE;
+
+/* Controls whether promiscuous also shows bad packets */
+static int lem_debug_sbp = FALSE;
+
+TUNABLE_INT("hw.em.tx_int_delay", &lem_tx_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_int_delay", &lem_rx_int_delay_dflt);
+TUNABLE_INT("hw.em.tx_abs_int_delay", &lem_tx_abs_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_abs_int_delay", &lem_rx_abs_int_delay_dflt);
+TUNABLE_INT("hw.em.rxd", &lem_rxd);
+TUNABLE_INT("hw.em.txd", &lem_txd);
+TUNABLE_INT("hw.em.smart_pwr_down", &lem_smart_pwr_down);
+TUNABLE_INT("hw.em.sbp", &lem_debug_sbp);
+
+#ifndef EM_LEGACY_IRQ
+/* How many packets rxeof tries to clean at a time */
+static int lem_rx_process_limit = 100;
+TUNABLE_INT("hw.em.rx_process_limit", &lem_rx_process_limit);
+#endif
+
+/* Flow control setting - default to FULL */
+static int lem_fc_setting = e1000_fc_full;
+TUNABLE_INT("hw.em.fc_setting", &lem_fc_setting);
+
+/*
+** Shadow VFTA table, this is needed because
+** the real vlan filter table gets cleared during
+** a soft reset and the driver needs to be able
+** to repopulate it.
+*/
+static u32 lem_shadow_vfta[EM_VFTA_SIZE];
+
+/* Global used in WOL setup with multiport cards */
+static int global_quad_port_a = 0;
+
+/*********************************************************************
+ *  Device identification routine
+ *
+ *  em_probe determines if the driver should be loaded on
+ *  adapter based on PCI vendor/device id of the adapter.
+ *
+ *  return BUS_PROBE_DEFAULT on success, positive on failure
+ *********************************************************************/
+
+static int
+lem_probe(device_t dev)
+{
+	char		adapter_name[60];
+	u16		pci_vendor_id = 0;
+	u16		pci_device_id = 0;
+	u16		pci_subvendor_id = 0;
+	u16		pci_subdevice_id = 0;
+	em_vendor_info_t *ent;
+
+	INIT_DEBUGOUT("em_probe: begin");
+
+	pci_vendor_id = pci_get_vendor(dev);
+	if (pci_vendor_id != EM_VENDOR_ID)
+		return (ENXIO);
+
+	pci_device_id = pci_get_device(dev);
+	pci_subvendor_id = pci_get_subvendor(dev);
+	pci_subdevice_id = pci_get_subdevice(dev);
+
+	ent = lem_vendor_info_array;
+	while (ent->vendor_id != 0) {
+		if ((pci_vendor_id == ent->vendor_id) &&
+		    (pci_device_id == ent->device_id) &&
+
+		    ((pci_subvendor_id == ent->subvendor_id) ||
+		    (ent->subvendor_id == PCI_ANY_ID)) &&
+
+		    ((pci_subdevice_id == ent->subdevice_id) ||
+		    (ent->subdevice_id == PCI_ANY_ID))) {
+			sprintf(adapter_name, "%s %s",
+				lem_strings[ent->index],
+				lem_driver_version);
+			device_set_desc_copy(dev, adapter_name);
+			return (BUS_PROBE_DEFAULT);
+		}
+		ent++;
+	}
+
+	return (ENXIO);
+}
+
+/*********************************************************************
+ *  Device initialization routine
+ *
+ *  The attach entry point is called when the driver is being loaded.
+ *  This routine identifies the type of hardware, allocates all resources
+ *  and initializes the hardware.
+ *
+ *  return 0 on success, positive on failure
+ *********************************************************************/
+
+static int
+lem_attach(device_t dev)
+{
+	struct adapter	*adapter;
+	int		tsize, rsize;
+	int		error = 0;
+
+	INIT_DEBUGOUT("lem_attach: begin");
+
+	adapter = device_get_softc(dev);
+	adapter->dev = adapter->osdep.dev = dev;
+	EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
+	EM_TX_LOCK_INIT(adapter, device_get_nameunit(dev));
+	EM_RX_LOCK_INIT(adapter, device_get_nameunit(dev));
+
+	/* SYSCTL stuff */
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
+	    lem_sysctl_debug_info, "I", "Debug Information");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
+	    lem_sysctl_stats, "I", "Statistics");
+
+	callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
+	callout_init_mtx(&adapter->tx_fifo_timer, &adapter->tx_mtx, 0);
+
+	/* Determine hardware and mac info */
+	lem_identify_hardware(adapter);
+
+	/* Setup PCI resources */
+	if (lem_allocate_pci_resources(adapter)) {
+		device_printf(dev, "Allocation of PCI resources failed\n");
+		error = ENXIO;
+		goto err_pci;
+	}
+
+	/* Do Shared Code initialization */
+	if (e1000_setup_init_funcs(&adapter->hw, TRUE)) {
+		device_printf(dev, "Setup of Shared code failed\n");
+		error = ENXIO;
+		goto err_pci;
+	}
+
+	e1000_get_bus_info(&adapter->hw);
+
+	/* Set up some sysctls for the tunable interrupt delays */
+	lem_add_int_delay_sysctl(adapter, "rx_int_delay",
+	    "receive interrupt delay in usecs", &adapter->rx_int_delay,
+	    E1000_REGISTER(&adapter->hw, E1000_RDTR), lem_rx_int_delay_dflt);
+	lem_add_int_delay_sysctl(adapter, "tx_int_delay",
+	    "transmit interrupt delay in usecs", &adapter->tx_int_delay,
+	    E1000_REGISTER(&adapter->hw, E1000_TIDV), lem_tx_int_delay_dflt);
+	if (adapter->hw.mac.type >= e1000_82540) {
+		lem_add_int_delay_sysctl(adapter, "rx_abs_int_delay",
+		    "receive interrupt delay limit in usecs",
+		    &adapter->rx_abs_int_delay,
+		    E1000_REGISTER(&adapter->hw, E1000_RADV),
+		    lem_rx_abs_int_delay_dflt);
+		lem_add_int_delay_sysctl(adapter, "tx_abs_int_delay",
+		    "transmit interrupt delay limit in usecs",
+		    &adapter->tx_abs_int_delay,
+		    E1000_REGISTER(&adapter->hw, E1000_TADV),
+		    lem_tx_abs_int_delay_dflt);
+	}
+
+#ifndef EM_LEGACY_IRQ
+	/* Sysctls for limiting the amount of work done in the taskqueue */
+	lem_add_rx_process_limit(adapter, "rx_processing_limit",
+	    "max number of rx packets to process", &adapter->rx_process_limit,
+	    lem_rx_process_limit);
+#endif
+
+	/*
+	 * Validate number of transmit and receive descriptors. It
+	 * must not exceed hardware maximum, and must be multiple
+	 * of E1000_DBA_ALIGN.
+	 */
+	if (((lem_txd * sizeof(struct e1000_tx_desc)) % EM_DBA_ALIGN) != 0 ||
+	    (adapter->hw.mac.type >= e1000_82544 && lem_txd > EM_MAX_TXD) ||
+	    (adapter->hw.mac.type < e1000_82544 && lem_txd > EM_MAX_TXD_82543) ||
+	    (lem_txd < EM_MIN_TXD)) {
+		device_printf(dev, "Using %d TX descriptors instead of %d!\n",
+		    EM_DEFAULT_TXD, lem_txd);
+		adapter->num_tx_desc = EM_DEFAULT_TXD;
+	} else
+		adapter->num_tx_desc = lem_txd;
+	if (((lem_rxd * sizeof(struct e1000_rx_desc)) % EM_DBA_ALIGN) != 0 ||
+	    (adapter->hw.mac.type >= e1000_82544 && lem_rxd > EM_MAX_RXD) ||
+	    (adapter->hw.mac.type < e1000_82544 && lem_rxd > EM_MAX_RXD_82543) ||
+	    (lem_rxd < EM_MIN_RXD)) {
+		device_printf(dev, "Using %d RX descriptors instead of %d!\n",
+		    EM_DEFAULT_RXD, lem_rxd);
+		adapter->num_rx_desc = EM_DEFAULT_RXD;
+	} else
+		adapter->num_rx_desc = lem_rxd;
+
+	adapter->hw.mac.autoneg = DO_AUTO_NEG;
+	adapter->hw.phy.autoneg_wait_to_complete = FALSE;
+	adapter->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+	adapter->rx_buffer_len = 2048;
+
+	e1000_init_script_state_82541(&adapter->hw, TRUE);
+	e1000_set_tbi_compatibility_82543(&adapter->hw, TRUE);
+
+	/* Copper options */
+	if (adapter->hw.phy.media_type == e1000_media_type_copper) {
+		adapter->hw.phy.mdix = AUTO_ALL_MODES;
+		adapter->hw.phy.disable_polarity_correction = FALSE;
+		adapter->hw.phy.ms_type = EM_MASTER_SLAVE;
+	}
+
+	/*
+	 * Set the frame limits assuming
+	 * standard ethernet sized frames.
+	 */
+	adapter->max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHERNET_FCS_SIZE;
+	adapter->min_frame_size = ETH_ZLEN + ETHERNET_FCS_SIZE;
+
+	/*
+	 * This controls when hardware reports transmit completion
+	 * status.
+	 */
+	adapter->hw.mac.report_tx_early = 1;
+
+	tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc),
+	    EM_DBA_ALIGN);
+
+	/* Allocate Transmit Descriptor ring */
+	if (lem_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) {
+		device_printf(dev, "Unable to allocate tx_desc memory\n");
+		error = ENOMEM;
+		goto err_tx_desc;
+	}
+	adapter->tx_desc_base = 
+	    (struct e1000_tx_desc *)adapter->txdma.dma_vaddr;
+
+	rsize = roundup2(adapter->num_rx_desc * sizeof(struct e1000_rx_desc),
+	    EM_DBA_ALIGN);
+
+	/* Allocate Receive Descriptor ring */
+	if (lem_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) {
+		device_printf(dev, "Unable to allocate rx_desc memory\n");
+		error = ENOMEM;
+		goto err_rx_desc;
+	}
+	adapter->rx_desc_base =
+	    (struct e1000_rx_desc *)adapter->rxdma.dma_vaddr;
+
+	/*
+	** Start from a known state, this is
+	** important in reading the nvm and
+	** mac from that.
+	*/
+	e1000_reset_hw(&adapter->hw);
+
+	/* Make sure we have a good EEPROM before we read from it */
+	if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
+		/*
+		** Some PCI-E parts fail the first check due to
+		** the link being in sleep state, call it again,
+		** if it fails a second time its a real issue.
+		*/
+		if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
+			device_printf(dev,
+			    "The EEPROM Checksum Is Not Valid\n");
+			error = EIO;
+			goto err_hw_init;
+		}
+	}
+
+	/* Copy the permanent MAC address out of the EEPROM */
+	if (e1000_read_mac_addr(&adapter->hw) < 0) {
+		device_printf(dev, "EEPROM read error while reading MAC"
+		    " address\n");
+		error = EIO;
+		goto err_hw_init;
+	}
+
+	if (!lem_is_valid_ether_addr(adapter->hw.mac.addr)) {
+		device_printf(dev, "Invalid MAC address\n");
+		error = EIO;
+		goto err_hw_init;
+	}
+
+	/* Initialize the hardware */
+	if (lem_hardware_init(adapter)) {
+		device_printf(dev, "Unable to initialize the hardware\n");
+		error = EIO;
+		goto err_hw_init;
+	}
+
+	/* Allocate transmit descriptors and buffers */
+	if (lem_allocate_transmit_structures(adapter)) {
+		device_printf(dev, "Could not setup transmit structures\n");
+		error = ENOMEM;
+		goto err_tx_struct;
+	}
+
+	/* Allocate receive descriptors and buffers */
+	if (lem_allocate_receive_structures(adapter)) {
+		device_printf(dev, "Could not setup receive structures\n");
+		error = ENOMEM;
+		goto err_rx_struct;
+	}
+
+	/*
+	**  Do interrupt configuration
+	*/
+	error = lem_allocate_irq(adapter);
+	if (error)
+		goto err_rx_struct;
+
+	/*
+	 * Get Wake-on-Lan and Management info for later use
+	 */
+	lem_get_wakeup(dev);
+
+	/* Setup OS specific network interface */
+	lem_setup_interface(dev, adapter);
+
+	/* Initialize statistics */
+	lem_update_stats_counters(adapter);
+
+	adapter->hw.mac.get_link_status = 1;
+	lem_update_link_status(adapter);
+
+	/* Indicate SOL/IDER usage */
+	if (e1000_check_reset_block(&adapter->hw))
+		device_printf(dev,
+		    "PHY reset is blocked due to SOL/IDER session.\n");
+
+	/* Do we need workaround for 82544 PCI-X adapter? */
+	if (adapter->hw.bus.type == e1000_bus_type_pcix &&
+	    adapter->hw.mac.type == e1000_82544)
+		adapter->pcix_82544 = TRUE;
+	else
+		adapter->pcix_82544 = FALSE;
+
+#if __FreeBSD_version >= 700029
+	/* Register for VLAN events */
+	adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
+	    lem_register_vlan, adapter, EVENTHANDLER_PRI_FIRST);
+	adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
+	    lem_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); 
+#endif
+
+	/* Non-AMT based hardware can now take control from firmware */
+	if (adapter->has_manage && !adapter->has_amt)
+		lem_get_hw_control(adapter);
+
+	/* Tell the stack that the interface is not active */
+	adapter->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+	adapter->led_dev = led_create(lem_led_func, adapter,
+	    device_get_nameunit(dev));
+
+	INIT_DEBUGOUT("lem_attach: end");
+
+	return (0);
+
+err_rx_struct:
+	lem_free_transmit_structures(adapter);
+err_tx_struct:
+err_hw_init:
+	lem_release_hw_control(adapter);
+	lem_dma_free(adapter, &adapter->rxdma);
+err_rx_desc:
+	lem_dma_free(adapter, &adapter->txdma);
+err_tx_desc:
+err_pci:
+	lem_free_pci_resources(adapter);
+	EM_TX_LOCK_DESTROY(adapter);
+	EM_RX_LOCK_DESTROY(adapter);
+	EM_CORE_LOCK_DESTROY(adapter);
+
+	return (error);
+}
+
+/*********************************************************************
+ *  Device removal routine
+ *
+ *  The detach entry point is called when the driver is being removed.
+ *  This routine stops the adapter and deallocates all the resources
+ *  that were allocated for driver operation.
+ *
+ *  return 0 on success, positive on failure
+ *********************************************************************/
+
+static int
+lem_detach(device_t dev)
+{
+	struct adapter	*adapter = device_get_softc(dev);
+	struct ifnet	*ifp = adapter->ifp;
+
+	INIT_DEBUGOUT("em_detach: begin");
+
+	/* Make sure VLANS are not using driver */
+#if __FreeBSD_version >= 700000
+	if (adapter->ifp->if_vlantrunk != NULL) {
+#else
+	if (adapter->ifp->if_nvlans != 0) {
+#endif   
+		device_printf(dev,"Vlan in use, detach first\n");
+		return (EBUSY);
+	}
+
+#ifdef DEVICE_POLLING
+	if (ifp->if_capenable & IFCAP_POLLING)
+		ether_poll_deregister(ifp);
+#endif
+
+	if (adapter->led_dev != NULL)
+		led_destroy(adapter->led_dev);
+
+	EM_CORE_LOCK(adapter);
+	EM_TX_LOCK(adapter);
+	adapter->in_detach = 1;
+	lem_stop(adapter);
+	e1000_phy_hw_reset(&adapter->hw);
+
+	lem_release_manageability(adapter);
+
+	EM_TX_UNLOCK(adapter);
+	EM_CORE_UNLOCK(adapter);
+
+#if __FreeBSD_version >= 700029
+	/* Unregister VLAN events */
+	if (adapter->vlan_attach != NULL)
+		EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach);
+	if (adapter->vlan_detach != NULL)
+		EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); 
+#endif
+
+	ether_ifdetach(adapter->ifp);
+	callout_drain(&adapter->timer);
+	callout_drain(&adapter->tx_fifo_timer);
+
+	lem_free_pci_resources(adapter);
+	bus_generic_detach(dev);
+	if_free(ifp);
+
+	lem_free_transmit_structures(adapter);
+	lem_free_receive_structures(adapter);
+
+	/* Free Transmit Descriptor ring */
+	if (adapter->tx_desc_base) {
+		lem_dma_free(adapter, &adapter->txdma);
+		adapter->tx_desc_base = NULL;
+	}
+
+	/* Free Receive Descriptor ring */
+	if (adapter->rx_desc_base) {
+		lem_dma_free(adapter, &adapter->rxdma);
+		adapter->rx_desc_base = NULL;
+	}
+
+	lem_release_hw_control(adapter);
+	EM_TX_LOCK_DESTROY(adapter);
+	EM_RX_LOCK_DESTROY(adapter);
+	EM_CORE_LOCK_DESTROY(adapter);
+
+	return (0);
+}
+
+/*********************************************************************
+ *
+ *  Shutdown entry point
+ *
+ **********************************************************************/
+
+static int
+lem_shutdown(device_t dev)
+{
+	return lem_suspend(dev);
+}
+
+/*
+ * Suspend/resume device methods.
+ */
+static int
+lem_suspend(device_t dev)
+{
+	struct adapter *adapter = device_get_softc(dev);
+
+	EM_CORE_LOCK(adapter);
+
+	lem_release_manageability(adapter);
+	lem_release_hw_control(adapter);
+	lem_enable_wakeup(dev);
+
+	EM_CORE_UNLOCK(adapter);
+
+	return bus_generic_suspend(dev);
+}
+
+static int
+lem_resume(device_t dev)
+{
+	struct adapter *adapter = device_get_softc(dev);
+	struct ifnet *ifp = adapter->ifp;
+
+	EM_CORE_LOCK(adapter);
+	lem_init_locked(adapter);
+	lem_init_manageability(adapter);
+	EM_CORE_UNLOCK(adapter);
+	lem_start(ifp);
+
+	return bus_generic_resume(dev);
+}
+
+
+static void
+lem_start_locked(struct ifnet *ifp)
+{
+	struct adapter	*adapter = ifp->if_softc;
+	struct mbuf	*m_head;
+
+	EM_TX_LOCK_ASSERT(adapter);
+
+	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
+	    IFF_DRV_RUNNING)
+		return;
+	if (!adapter->link_active)
+		return;
+
+	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
+
+                IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+		if (m_head == NULL)
+			break;
+		/*
+		 *  Encapsulation can modify our pointer, and or make it
+		 *  NULL on failure.  In that event, we can't requeue.
+		 */
+		if (lem_xmit(adapter, &m_head)) {
+			if (m_head == NULL)
+				break;
+			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+			break;
+		}
+
+		/* Send a copy of the frame to the BPF listener */
+		ETHER_BPF_MTAP(ifp, m_head);
+
+		/* Set timeout in case hardware has problems transmitting. */
+		adapter->watchdog_check = TRUE;
+		adapter->watchdog_time = ticks;
+	}
+	if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD)
+		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+
+	return;
+}
+
+static void
+lem_start(struct ifnet *ifp)
+{
+	struct adapter *adapter = ifp->if_softc;
+
+	EM_TX_LOCK(adapter);
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		lem_start_locked(ifp);
+	EM_TX_UNLOCK(adapter);
+}
+
+/*********************************************************************
+ *  Ioctl entry point
+ *
+ *  em_ioctl is called when the user wants to configure the
+ *  interface.
+ *
+ *  return 0 on success, positive on failure
+ **********************************************************************/
+
+static int
+lem_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+	struct adapter	*adapter = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *)data;
+#ifdef INET
+	struct ifaddr *ifa = (struct ifaddr *)data;
+#endif
+	int error = 0;
+
+	if (adapter->in_detach)
+		return (error);
+
+	switch (command) {
+	case SIOCSIFADDR:
+#ifdef INET
+		if (ifa->ifa_addr->sa_family == AF_INET) {
+			/*
+			 * XXX
+			 * Since resetting hardware takes a very long time
+			 * and results in link renegotiation we only
+			 * initialize the hardware only when it is absolutely
+			 * required.
+			 */
+			ifp->if_flags |= IFF_UP;
+			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+				EM_CORE_LOCK(adapter);
+				lem_init_locked(adapter);
+				EM_CORE_UNLOCK(adapter);
+			}
+			arp_ifinit(ifp, ifa);
+		} else
+#endif
+			error = ether_ioctl(ifp, command, data);
+		break;
+	case SIOCSIFMTU:
+	    {
+		int max_frame_size;
+
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
+
+		EM_CORE_LOCK(adapter);
+		switch (adapter->hw.mac.type) {
+		case e1000_82542:
+			max_frame_size = ETHER_MAX_LEN;
+			break;
+		default:
+			max_frame_size = MAX_JUMBO_FRAME_SIZE;
+		}
+		if (ifr->ifr_mtu > max_frame_size - ETHER_HDR_LEN -
+		    ETHER_CRC_LEN) {
+			EM_CORE_UNLOCK(adapter);
+			error = EINVAL;
+			break;
+		}
+
+		ifp->if_mtu = ifr->ifr_mtu;
+		adapter->max_frame_size =
+		    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+		lem_init_locked(adapter);
+		EM_CORE_UNLOCK(adapter);
+		break;
+	    }
+	case SIOCSIFFLAGS:
+		IOCTL_DEBUGOUT("ioctl rcv'd:\
+		    SIOCSIFFLAGS (Set Interface Flags)");
+		EM_CORE_LOCK(adapter);
+		if (ifp->if_flags & IFF_UP) {
+			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+				if ((ifp->if_flags ^ adapter->if_flags) &
+				    (IFF_PROMISC | IFF_ALLMULTI)) {
+					lem_disable_promisc(adapter);
+					lem_set_promisc(adapter);
+				}
+			} else
+				lem_init_locked(adapter);
+		} else
+			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+				EM_TX_LOCK(adapter);
+				lem_stop(adapter);
+				EM_TX_UNLOCK(adapter);
+			}
+		adapter->if_flags = ifp->if_flags;
+		EM_CORE_UNLOCK(adapter);
+		break;
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
+		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+			EM_CORE_LOCK(adapter);
+			lem_disable_intr(adapter);
+			lem_set_multi(adapter);
+			if (adapter->hw.mac.type == e1000_82542 && 
+	    		    adapter->hw.revision_id == E1000_REVISION_2) {
+				lem_initialize_receive_unit(adapter);
+			}
+#ifdef DEVICE_POLLING
+			if (!(ifp->if_capenable & IFCAP_POLLING))
+#endif
+				lem_enable_intr(adapter);
+			EM_CORE_UNLOCK(adapter);
+		}
+		break;
+	case SIOCSIFMEDIA:
+		/* Check SOL/IDER usage */
+		EM_CORE_LOCK(adapter);
+		if (e1000_check_reset_block(&adapter->hw)) {
+			EM_CORE_UNLOCK(adapter);
+			device_printf(adapter->dev, "Media change is"
+			    " blocked due to SOL/IDER session.\n");
+			break;
+		}
+		EM_CORE_UNLOCK(adapter);
+	case SIOCGIFMEDIA:
+		IOCTL_DEBUGOUT("ioctl rcv'd: \
+		    SIOCxIFMEDIA (Get/Set Interface Media)");
+		error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
+		break;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-stable-7 mailing list