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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to