git: 517904de5cca - main - igc(4): Introduce new driver for the Intel I225 Ethernet controller.

Peter Grehan grehan at FreeBSD.org
Mon Jul 12 00:17:19 UTC 2021


The branch main has been updated by grehan:

URL: https://cgit.FreeBSD.org/src/commit/?id=517904de5ccac643589c71ac0d2751797f89e4f9

commit 517904de5ccac643589c71ac0d2751797f89e4f9
Author:     Peter Grehan <grehan at FreeBSD.org>
AuthorDate: 2021-07-12 04:50:15 +0000
Commit:     Peter Grehan <grehan at FreeBSD.org>
CommitDate: 2021-07-12 04:57:18 +0000

    igc(4): Introduce new driver for the Intel I225 Ethernet controller.
    
    This controller supports 2.5G/1G/100MB/10MB speeds, and allows
    tx/rx checksum offload, TSO, LRO, and multi-queue operation.
    
    The driver was derived from code contributed by Intel, and modified
    by Netgate to fit into the iflib framework.
    
    Thanks to Mike Karels for testing and feedback on the driver.
    
    Reviewed by:    bcr (manpages), kbowling, scottl, erj
    MFC after:      1 month
    Relnotes:       yes
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D30668
---
 share/man/man4/Makefile   |    2 +
 share/man/man4/igc.4      |  167 +++
 sys/amd64/conf/GENERIC    |    1 +
 sys/amd64/conf/NOTES      |    2 +
 sys/conf/files            |    8 +
 sys/dev/igc/if_igc.c      | 2984 +++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/igc/if_igc.h      |  430 +++++++
 sys/dev/igc/igc_api.c     |  735 +++++++++++
 sys/dev/igc/igc_api.h     |   58 +
 sys/dev/igc/igc_base.c    |  188 +++
 sys/dev/igc/igc_base.h    |  131 ++
 sys/dev/igc/igc_defines.h | 1347 ++++++++++++++++++++
 sys/dev/igc/igc_hw.h      |  548 +++++++++
 sys/dev/igc/igc_i225.c    | 1232 +++++++++++++++++++
 sys/dev/igc/igc_i225.h    |  112 ++
 sys/dev/igc/igc_mac.c     | 1050 ++++++++++++++++
 sys/dev/igc/igc_mac.h     |   48 +
 sys/dev/igc/igc_nvm.c     |  721 +++++++++++
 sys/dev/igc/igc_nvm.h     |   32 +
 sys/dev/igc/igc_osdep.h   |  133 ++
 sys/dev/igc/igc_phy.c     | 1109 +++++++++++++++++
 sys/dev/igc/igc_phy.h     |  134 ++
 sys/dev/igc/igc_regs.h    |  424 +++++++
 sys/dev/igc/igc_txrx.c    |  580 +++++++++
 sys/i386/conf/GENERIC     |    1 +
 sys/i386/conf/NOTES       |    2 +
 sys/modules/Makefile      |    2 +
 sys/modules/igc/Makefile  |   11 +
 28 files changed, 12192 insertions(+)

diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 9027fe7df841..71a0d37631c5 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -224,6 +224,7 @@ MAN=	aac.4 \
 	iicmux.4 \
 	iicsmb.4 \
 	iir.4 \
+	${_igc.4} \
 	${_imcsmb.4} \
 	inet.4 \
 	inet6.4 \
@@ -814,6 +815,7 @@ _if_nfe.4=	if_nfe.4
 _if_urtw.4=	if_urtw.4
 _if_vmx.4=	if_vmx.4
 _if_wpi.4=	if_wpi.4
+_igc.4=		igc.4
 _imcsmb.4=	imcsmb.4
 _ipmi.4=	ipmi.4
 _io.4=		io.4
diff --git a/share/man/man4/igc.4 b/share/man/man4/igc.4
new file mode 100644
index 000000000000..bb79fbe5a8fa
--- /dev/null
+++ b/share/man/man4/igc.4
@@ -0,0 +1,167 @@
+.\"-
+.\" Copyright 2021 Intel Corp
+.\" Copyright 2021 Rubicon Communications, LLC (Netgate)
+.\" SPDX-License-Identifier: BSD-3-Clause
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 10, 2021
+.Dt IGC
+.Os
+.Sh NAME
+.Nm igc
+.Nd "Intel Ethernet Controller I225 driver"
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device iflib"
+.Cd "device igc"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_igc_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for any PCI Express adapter or LOM (LAN
+On Motherboard) based on the Intel I225 Multi Gigabit Controller.
+The driver supports Transmit/Receive checksum offload, Jumbo Frames,
+MSI/MSI-X, TSO, and RSS.
+.Pp
+Support for Jumbo Frames is provided via the interface MTU setting.
+Selecting an MTU larger than 1500 bytes with the
+.Xr ifconfig 8
+utility
+configures the adapter to receive and transmit Jumbo Frames.
+The maximum MTU size for Jumbo Frames is 9216 bytes.
+.Pp
+This driver version supports VLAN hardware insertion / extraction, and
+VLAN checksum offload.
+For information on enabling VLANs, see
+.Xr ifconfig 8 .
+The
+.Nm
+driver supports the following media types:
+.Bl -tag -width ".Cm 10baseT/UTP"
+.It Cm autoselect
+Enables auto-negotiation for speed and duplex.
+.It Cm 10baseT/UTP
+Sets 10Mbps operation.
+Use the
+.Cm mediaopt
+option to select
+.Cm half-duplex
+mode.
+.It Cm 100baseTX
+Sets 100Mbps operation.
+Use the
+.Cm mediaopt
+option to select
+.Cm half-duplex
+mode.
+.It Cm 1000baseT
+Sets 1000Mbps operation.
+Only
+.Cm full-duplex
+mode is supported at this speed.
+.It Cm 2500baseT
+Sets 2500Mbps operation.
+Only
+.Cm full-duplex
+mode is supported at this speed.
+.El
+.Pp
+.Sh HARDWARE
+The
+.Nm
+driver supports the following models:
+.Pp
+.Bl -bullet -compact
+.It
+I225-LM
+.It
+I225-V
+.It
+I225-IT
+.It
+I225-K
+.El
+.Sh LOADER TUNABLES
+Tunables can be set at the
+.Xr loader 8
+prompt before booting the kernel or stored in
+.Xr loader.conf 5 .
+.Bl -tag -width indent
+.It Va hw.igc.igc_disable_crc_stripping
+Disable or enable hardware stripping of CRC field.
+This is mostly useful on BMC/IPMI shared interfaces where stripping the
+CRC causes remote access over IPMI to fail.
+Default 0 (enabled).
+.It Va hw.igc.rx_int_delay
+This value delays the generation of receive interrupts in units
+of 1.024 microseconds.
+The default value is 0, since adapters may hang with this feature being
+enabled.
+.It Va hw.igc.rx_abs_int_delay
+If hw.igc.rx_int_delay is non-zero, this tunable limits the
+maximum delay in which a receive interrupt is generated.
+.It Va hw.igc.tx_int_delay
+This value delays the generation of transmit interrupts in units
+of 1.024 microseconds.
+The default value is 64.
+.It Va hw.igc.tx_abs_int_delay
+If hw.igc.tx_int_delay is non-zero, this tunable limits the
+maximum delay in which a transmit interrupt is generated.
+.It Va hw.igc.sbp
+Show bad packets when in promiscuous mode.
+Default is false.
+.It Va hw.igc.rx_process_limit
+Maximum number of received packets to process at a time.
+Default is 100.
+A value of -1 means unlimited.
+.It Va hw.igc.eee_setting
+Disable or enable Energy Efficient Ethernet.
+Default 1 (disabled).
+.It Va hw.igc.max_interrupt_rate
+Maximum device interrupts per second.
+The default is 8000.
+.El
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "igc%d: Hardware Initialization Failed"
+A fatal initialization error has occurred.
+.It "igc%d: Unable to allocate bus resource: memory"
+A fatal initialization error has occurred.
+.It "igc%d: Invalid MAC address"
+The MAC address programmed into the EEPROM is either empty or a multicast/broadcast
+address.
+.El
+.Sh SEE ALSO
+.Xr altq 4 ,
+.Xr arp 4 ,
+.Xr iflib 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr vlan 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 14.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+was originally written by
+.An Intel Corporation
+and converted to the
+.Xr iflib 4
+framework by
+.An Netgate .
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 2b49dd4726ec..7ea749e28e33 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -249,6 +249,7 @@ device		puc			# Multi I/O cards and multi-channel UARTs
 # PCI/PCI-X/PCIe Ethernet NICs that use iflib infrastructure
 device		iflib
 device		em			# Intel PRO/1000 Gigabit Ethernet Family
+device		igc			# Intel I225 2.5G Ethernet
 device		ix			# Intel PRO/10GbE PCIE PF Ethernet
 device		ixv			# Intel PRO/10GbE PCIE VF Ethernet
 device		ixl			# Intel 700 Series Physical Function
diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES
index 79c92a679414..f5bdf15ebb08 100644
--- a/sys/amd64/conf/NOTES
+++ b/sys/amd64/conf/NOTES
@@ -287,6 +287,7 @@ device		cpufreq
 #       adapters.
 # ice:	Intel 800 Series Physical Function
 #	Requires the ice_ddp module for full functionality
+# igc:	Intel I225 2.5Gb Ethernet adapter
 # ipw:	Intel PRO/Wireless 2100 IEEE 802.11 adapter
 #	Requires the ipw firmware module
 # iwi:	Intel PRO/Wireless 2200BG/2225BG/2915ABG IEEE 802.11 adapters
@@ -309,6 +310,7 @@ device		bxe		# Broadcom NetXtreme II BCM5771X/BCM578XX 10GbE
 options 	ED_3C503
 options 	ED_HPP
 options 	ED_SIC
+device		igc		# Intel I225 2.5G Ethernet
 device		ipw		# Intel 2100 wireless NICs.
 device		iwi		# Intel 2200BG/2225BG/2915ABG wireless NICs.
 device		iwn		# Intel 4965/1000/5000/6000 wireless NICs.
diff --git a/sys/conf/files b/sys/conf/files
index 22cf4db11695..33b57f98e199 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1885,6 +1885,14 @@ dev/iicbus/pmic/fan53555.c	optional fan53555 ext_resources fdt
 dev/iir/iir.c			optional iir
 dev/iir/iir_ctrl.c		optional iir
 dev/iir/iir_pci.c		optional iir pci
+dev/igc/if_igc.c		optional igc iflib pci
+dev/igc/igc_api.c		optional igc iflib pci
+dev/igc/igc_base.c		optional igc iflib pci
+dev/igc/igc_i225.c		optional igc iflib pci
+dev/igc/igc_mac.c		optional igc iflib pci
+dev/igc/igc_nvm.c		optional igc iflib pci
+dev/igc/igc_phy.c		optional igc iflib pci
+dev/igc/igc_txrx.c		optional igc iflib pci
 dev/intpm/intpm.c		optional intpm pci
 # XXX Work around clang warning, until maintainer approves fix.
 dev/ips/ips.c			optional ips \
diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c
new file mode 100644
index 000000000000..6d94a7c223c7
--- /dev/null
+++ b/sys/dev/igc/if_igc.c
@@ -0,0 +1,2984 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2016 Nicole Graziano <nicole at nextbsd.org>
+ * All rights reserved.
+ * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "if_igc.h"
+#include <sys/sbuf.h>
+#include <machine/_inttypes.h>
+
+#ifdef RSS
+#include <net/rss_config.h>
+#include <netinet/in_rss.h>
+#endif
+
+/*********************************************************************
+ *  PCI Device ID Table
+ *
+ *  Used by probe to select devices to load on
+ *  Last entry must be all 0s
+ *
+ *  { Vendor ID, Device ID, String }
+ *********************************************************************/
+
+static pci_vendor_info_t igc_vendor_info_array[] =
+{
+	/* Intel(R) PRO/1000 Network Connection - igc */
+	PVID(0x8086, IGC_DEV_ID_I225_LM, "Intel(R) Ethernet Controller I225-LM"),
+	PVID(0x8086, IGC_DEV_ID_I225_V, "Intel(R) Ethernet Controller I225-V"),
+	PVID(0x8086, IGC_DEV_ID_I225_K, "Intel(R) Ethernet Controller I225-K"),
+	PVID(0x8086, IGC_DEV_ID_I225_I, "Intel(R) Ethernet Controller I225-I"),
+	PVID(0x8086, IGC_DEV_ID_I220_V, "Intel(R) Ethernet Controller I220-V"),
+	PVID(0x8086, IGC_DEV_ID_I225_K2, "Intel(R) Ethernet Controller I225-K(2)"),
+	PVID(0x8086, IGC_DEV_ID_I225_LMVP, "Intel(R) Ethernet Controller I225-LMvP(2)"),
+	PVID(0x8086, IGC_DEV_ID_I226_K, "Intel(R) Ethernet Controller I226-K"),
+	PVID(0x8086, IGC_DEV_ID_I225_IT, "Intel(R) Ethernet Controller I225-IT(2)"),
+	PVID(0x8086, IGC_DEV_ID_I226_LM, "Intel(R) Ethernet Controller I226-LM"),
+	PVID(0x8086, IGC_DEV_ID_I226_V, "Intel(R) Ethernet Controller I226-V"),
+	PVID(0x8086, IGC_DEV_ID_I226_IT, "Intel(R) Ethernet Controller I226-IT"),
+	PVID(0x8086, IGC_DEV_ID_I221_V, "Intel(R) Ethernet Controller I221-V"),
+	PVID(0x8086, IGC_DEV_ID_I226_BLANK_NVM, "Intel(R) Ethernet Controller I226(blankNVM)"),
+	PVID(0x8086, IGC_DEV_ID_I225_BLANK_NVM, "Intel(R) Ethernet Controller I225(blankNVM)"),
+	/* required last entry */
+	PVID_END
+};
+
+/*********************************************************************
+ *  Function prototypes
+ *********************************************************************/
+static void	*igc_register(device_t dev);
+static int	igc_if_attach_pre(if_ctx_t ctx);
+static int	igc_if_attach_post(if_ctx_t ctx);
+static int	igc_if_detach(if_ctx_t ctx);
+static int	igc_if_shutdown(if_ctx_t ctx);
+static int	igc_if_suspend(if_ctx_t ctx);
+static int	igc_if_resume(if_ctx_t ctx);
+
+static int	igc_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets);
+static int	igc_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets);
+static void	igc_if_queues_free(if_ctx_t ctx);
+
+static uint64_t	igc_if_get_counter(if_ctx_t, ift_counter);
+static void	igc_if_init(if_ctx_t ctx);
+static void	igc_if_stop(if_ctx_t ctx);
+static void	igc_if_media_status(if_ctx_t, struct ifmediareq *);
+static int	igc_if_media_change(if_ctx_t ctx);
+static int	igc_if_mtu_set(if_ctx_t ctx, uint32_t mtu);
+static void	igc_if_timer(if_ctx_t ctx, uint16_t qid);
+static void	igc_if_vlan_register(if_ctx_t ctx, u16 vtag);
+static void	igc_if_vlan_unregister(if_ctx_t ctx, u16 vtag);
+static void	igc_if_watchdog_reset(if_ctx_t ctx);
+static bool	igc_if_needs_restart(if_ctx_t ctx, enum iflib_restart_event event);
+
+static void	igc_identify_hardware(if_ctx_t ctx);
+static int	igc_allocate_pci_resources(if_ctx_t ctx);
+static void	igc_free_pci_resources(if_ctx_t ctx);
+static void	igc_reset(if_ctx_t ctx);
+static int	igc_setup_interface(if_ctx_t ctx);
+static int	igc_setup_msix(if_ctx_t ctx);
+
+static void	igc_initialize_transmit_unit(if_ctx_t ctx);
+static void	igc_initialize_receive_unit(if_ctx_t ctx);
+
+static void	igc_if_intr_enable(if_ctx_t ctx);
+static void	igc_if_intr_disable(if_ctx_t ctx);
+static int	igc_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid);
+static int	igc_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid);
+static void	igc_if_multi_set(if_ctx_t ctx);
+static void	igc_if_update_admin_status(if_ctx_t ctx);
+static void	igc_if_debug(if_ctx_t ctx);
+static void	igc_update_stats_counters(struct igc_adapter *);
+static void	igc_add_hw_stats(struct igc_adapter *adapter);
+static int	igc_if_set_promisc(if_ctx_t ctx, int flags);
+static void	igc_setup_vlan_hw_support(struct igc_adapter *);
+static int	igc_sysctl_nvm_info(SYSCTL_HANDLER_ARGS);
+static void	igc_print_nvm_info(struct igc_adapter *);
+static int	igc_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
+static int	igc_get_rs(SYSCTL_HANDLER_ARGS);
+static void	igc_print_debug_info(struct igc_adapter *);
+static int 	igc_is_valid_ether_addr(u8 *);
+static int	igc_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
+static void	igc_add_int_delay_sysctl(struct igc_adapter *, const char *,
+		    const char *, struct igc_int_delay_info *, int, int);
+/* Management and WOL Support */
+static void	igc_get_hw_control(struct igc_adapter *);
+static void	igc_release_hw_control(struct igc_adapter *);
+static void	igc_get_wakeup(if_ctx_t ctx);
+static void	igc_enable_wakeup(if_ctx_t ctx);
+
+int		igc_intr(void *arg);
+
+/* MSI-X handlers */
+static int	igc_if_msix_intr_assign(if_ctx_t, int);
+static int	igc_msix_link(void *);
+static void	igc_handle_link(void *context);
+
+static int	igc_set_flowcntl(SYSCTL_HANDLER_ARGS);
+static int	igc_sysctl_eee(SYSCTL_HANDLER_ARGS);
+
+static int	igc_get_regs(SYSCTL_HANDLER_ARGS);
+
+static void	igc_configure_queues(struct igc_adapter *adapter);
+
+
+/*********************************************************************
+ *  FreeBSD Device Interface Entry Points
+ *********************************************************************/
+static device_method_t igc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_register, igc_register),
+	DEVMETHOD(device_probe, iflib_device_probe),
+	DEVMETHOD(device_attach, iflib_device_attach),
+	DEVMETHOD(device_detach, iflib_device_detach),
+	DEVMETHOD(device_shutdown, iflib_device_shutdown),
+	DEVMETHOD(device_suspend, iflib_device_suspend),
+	DEVMETHOD(device_resume, iflib_device_resume),
+	DEVMETHOD_END
+};
+
+static driver_t igc_driver = {
+	"igc", igc_methods, sizeof(struct igc_adapter),
+};
+
+static devclass_t igc_devclass;
+DRIVER_MODULE(igc, pci, igc_driver, igc_devclass, 0, 0);
+
+MODULE_DEPEND(igc, pci, 1, 1, 1);
+MODULE_DEPEND(igc, ether, 1, 1, 1);
+MODULE_DEPEND(igc, iflib, 1, 1, 1);
+
+IFLIB_PNP_INFO(pci, igc, igc_vendor_info_array);
+
+static device_method_t igc_if_methods[] = {
+	DEVMETHOD(ifdi_attach_pre, igc_if_attach_pre),
+	DEVMETHOD(ifdi_attach_post, igc_if_attach_post),
+	DEVMETHOD(ifdi_detach, igc_if_detach),
+	DEVMETHOD(ifdi_shutdown, igc_if_shutdown),
+	DEVMETHOD(ifdi_suspend, igc_if_suspend),
+	DEVMETHOD(ifdi_resume, igc_if_resume),
+	DEVMETHOD(ifdi_init, igc_if_init),
+	DEVMETHOD(ifdi_stop, igc_if_stop),
+	DEVMETHOD(ifdi_msix_intr_assign, igc_if_msix_intr_assign),
+	DEVMETHOD(ifdi_intr_enable, igc_if_intr_enable),
+	DEVMETHOD(ifdi_intr_disable, igc_if_intr_disable),
+	DEVMETHOD(ifdi_tx_queues_alloc, igc_if_tx_queues_alloc),
+	DEVMETHOD(ifdi_rx_queues_alloc, igc_if_rx_queues_alloc),
+	DEVMETHOD(ifdi_queues_free, igc_if_queues_free),
+	DEVMETHOD(ifdi_update_admin_status, igc_if_update_admin_status),
+	DEVMETHOD(ifdi_multi_set, igc_if_multi_set),
+	DEVMETHOD(ifdi_media_status, igc_if_media_status),
+	DEVMETHOD(ifdi_media_change, igc_if_media_change),
+	DEVMETHOD(ifdi_mtu_set, igc_if_mtu_set),
+	DEVMETHOD(ifdi_promisc_set, igc_if_set_promisc),
+	DEVMETHOD(ifdi_timer, igc_if_timer),
+	DEVMETHOD(ifdi_watchdog_reset, igc_if_watchdog_reset),
+	DEVMETHOD(ifdi_vlan_register, igc_if_vlan_register),
+	DEVMETHOD(ifdi_vlan_unregister, igc_if_vlan_unregister),
+	DEVMETHOD(ifdi_get_counter, igc_if_get_counter),
+	DEVMETHOD(ifdi_rx_queue_intr_enable, igc_if_rx_queue_intr_enable),
+	DEVMETHOD(ifdi_tx_queue_intr_enable, igc_if_tx_queue_intr_enable),
+	DEVMETHOD(ifdi_debug, igc_if_debug),
+	DEVMETHOD(ifdi_needs_restart, igc_if_needs_restart),
+	DEVMETHOD_END
+};
+
+static driver_t igc_if_driver = {
+	"igc_if", igc_if_methods, sizeof(struct igc_adapter)
+};
+
+/*********************************************************************
+ *  Tunable default values.
+ *********************************************************************/
+
+#define IGC_TICKS_TO_USECS(ticks)	((1024 * (ticks) + 500) / 1000)
+#define IGC_USECS_TO_TICKS(usecs)	((1000 * (usecs) + 512) / 1024)
+
+#define MAX_INTS_PER_SEC	8000
+#define DEFAULT_ITR		(1000000000/(MAX_INTS_PER_SEC * 256))
+
+/* Allow common code without TSO */
+#ifndef CSUM_TSO
+#define CSUM_TSO	0
+#endif
+
+static SYSCTL_NODE(_hw, OID_AUTO, igc, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+    "igc driver parameters");
+
+static int igc_disable_crc_stripping = 0;
+SYSCTL_INT(_hw_igc, OID_AUTO, disable_crc_stripping, CTLFLAG_RDTUN,
+    &igc_disable_crc_stripping, 0, "Disable CRC Stripping");
+
+static int igc_tx_int_delay_dflt = IGC_TICKS_TO_USECS(IGC_TIDV_VAL);
+static int igc_rx_int_delay_dflt = IGC_TICKS_TO_USECS(IGC_RDTR_VAL);
+SYSCTL_INT(_hw_igc, OID_AUTO, tx_int_delay, CTLFLAG_RDTUN, &igc_tx_int_delay_dflt,
+    0, "Default transmit interrupt delay in usecs");
+SYSCTL_INT(_hw_igc, OID_AUTO, rx_int_delay, CTLFLAG_RDTUN, &igc_rx_int_delay_dflt,
+    0, "Default receive interrupt delay in usecs");
+
+static int igc_tx_abs_int_delay_dflt = IGC_TICKS_TO_USECS(IGC_TADV_VAL);
+static int igc_rx_abs_int_delay_dflt = IGC_TICKS_TO_USECS(IGC_RADV_VAL);
+SYSCTL_INT(_hw_igc, OID_AUTO, tx_abs_int_delay, CTLFLAG_RDTUN,
+    &igc_tx_abs_int_delay_dflt, 0,
+    "Default transmit interrupt delay limit in usecs");
+SYSCTL_INT(_hw_igc, OID_AUTO, rx_abs_int_delay, CTLFLAG_RDTUN,
+    &igc_rx_abs_int_delay_dflt, 0,
+    "Default receive interrupt delay limit in usecs");
+
+static int igc_smart_pwr_down = false;
+SYSCTL_INT(_hw_igc, OID_AUTO, smart_pwr_down, CTLFLAG_RDTUN, &igc_smart_pwr_down,
+    0, "Set to true to leave smart power down enabled on newer adapters");
+
+/* Controls whether promiscuous also shows bad packets */
+static int igc_debug_sbp = true;
+SYSCTL_INT(_hw_igc, OID_AUTO, sbp, CTLFLAG_RDTUN, &igc_debug_sbp, 0,
+    "Show bad packets in promiscuous mode");
+
+/* How many packets rxeof tries to clean at a time */
+static int igc_rx_process_limit = 100;
+SYSCTL_INT(_hw_igc, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN,
+    &igc_rx_process_limit, 0,
+    "Maximum number of received packets to process "
+    "at a time, -1 means unlimited");
+
+/* Energy efficient ethernet - default to OFF */
+static int igc_eee_setting = 1;
+SYSCTL_INT(_hw_igc, OID_AUTO, eee_setting, CTLFLAG_RDTUN, &igc_eee_setting, 0,
+    "Enable Energy Efficient Ethernet");
+
+/*
+** Tuneable Interrupt rate
+*/
+static int igc_max_interrupt_rate = 8000;
+SYSCTL_INT(_hw_igc, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
+    &igc_max_interrupt_rate, 0, "Maximum interrupts per second");
+
+extern struct if_txrx igc_txrx;
+
+static struct if_shared_ctx igc_sctx_init = {
+	.isc_magic = IFLIB_MAGIC,
+	.isc_q_align = PAGE_SIZE,
+	.isc_tx_maxsize = IGC_TSO_SIZE + sizeof(struct ether_vlan_header),
+	.isc_tx_maxsegsize = PAGE_SIZE,
+	.isc_tso_maxsize = IGC_TSO_SIZE + sizeof(struct ether_vlan_header),
+	.isc_tso_maxsegsize = IGC_TSO_SEG_SIZE,
+	.isc_rx_maxsize = MAX_JUMBO_FRAME_SIZE,
+	.isc_rx_nsegments = 1,
+	.isc_rx_maxsegsize = MJUM9BYTES,
+	.isc_nfl = 1,
+	.isc_nrxqs = 1,
+	.isc_ntxqs = 1,
+	.isc_admin_intrcnt = 1,
+	.isc_vendor_info = igc_vendor_info_array,
+	.isc_driver_version = "1",
+	.isc_driver = &igc_if_driver,
+	.isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP | IFLIB_NEED_ZERO_CSUM,
+
+	.isc_nrxd_min = {IGC_MIN_RXD},
+	.isc_ntxd_min = {IGC_MIN_TXD},
+	.isc_nrxd_max = {IGC_MAX_RXD},
+	.isc_ntxd_max = {IGC_MAX_TXD},
+	.isc_nrxd_default = {IGC_DEFAULT_RXD},
+	.isc_ntxd_default = {IGC_DEFAULT_TXD},
+};
+
+/*****************************************************************
+ *
+ * Dump Registers
+ *
+ ****************************************************************/
+#define IGC_REGS_LEN 739
+
+static int igc_get_regs(SYSCTL_HANDLER_ARGS)
+{
+	struct igc_adapter *adapter = (struct igc_adapter *)arg1;
+	struct igc_hw *hw = &adapter->hw;
+	struct sbuf *sb;
+	u32 *regs_buff;
+	int rc;
+
+	regs_buff = malloc(sizeof(u32) * IGC_REGS_LEN, M_DEVBUF, M_WAITOK);
+	memset(regs_buff, 0, IGC_REGS_LEN * sizeof(u32));
+
+	rc = sysctl_wire_old_buffer(req, 0);
+	MPASS(rc == 0);
+	if (rc != 0) {
+		free(regs_buff, M_DEVBUF);
+		return (rc);
+	}
+
+	sb = sbuf_new_for_sysctl(NULL, NULL, 32*400, req);
+	MPASS(sb != NULL);
+	if (sb == NULL) {
+		free(regs_buff, M_DEVBUF);
+		return (ENOMEM);
+	}
+
+	/* General Registers */
+	regs_buff[0] = IGC_READ_REG(hw, IGC_CTRL);
+	regs_buff[1] = IGC_READ_REG(hw, IGC_STATUS);
+	regs_buff[2] = IGC_READ_REG(hw, IGC_CTRL_EXT);
+	regs_buff[3] = IGC_READ_REG(hw, IGC_ICR);
+	regs_buff[4] = IGC_READ_REG(hw, IGC_RCTL);
+	regs_buff[5] = IGC_READ_REG(hw, IGC_RDLEN(0));
+	regs_buff[6] = IGC_READ_REG(hw, IGC_RDH(0));
+	regs_buff[7] = IGC_READ_REG(hw, IGC_RDT(0));
+	regs_buff[8] = IGC_READ_REG(hw, IGC_RXDCTL(0));
+	regs_buff[9] = IGC_READ_REG(hw, IGC_RDBAL(0));
+	regs_buff[10] = IGC_READ_REG(hw, IGC_RDBAH(0));
+	regs_buff[11] = IGC_READ_REG(hw, IGC_TCTL);
+	regs_buff[12] = IGC_READ_REG(hw, IGC_TDBAL(0));
+	regs_buff[13] = IGC_READ_REG(hw, IGC_TDBAH(0));
+	regs_buff[14] = IGC_READ_REG(hw, IGC_TDLEN(0));
+	regs_buff[15] = IGC_READ_REG(hw, IGC_TDH(0));
+	regs_buff[16] = IGC_READ_REG(hw, IGC_TDT(0));
+	regs_buff[17] = IGC_READ_REG(hw, IGC_TXDCTL(0));
+
+	sbuf_printf(sb, "General Registers\n");
+	sbuf_printf(sb, "\tCTRL\t %08x\n", regs_buff[0]);
+	sbuf_printf(sb, "\tSTATUS\t %08x\n", regs_buff[1]);
+	sbuf_printf(sb, "\tCTRL_EXIT\t %08x\n\n", regs_buff[2]);
+
+	sbuf_printf(sb, "Interrupt Registers\n");
+	sbuf_printf(sb, "\tICR\t %08x\n\n", regs_buff[3]);
+
+	sbuf_printf(sb, "RX Registers\n");
+	sbuf_printf(sb, "\tRCTL\t %08x\n", regs_buff[4]);
+	sbuf_printf(sb, "\tRDLEN\t %08x\n", regs_buff[5]);
+	sbuf_printf(sb, "\tRDH\t %08x\n", regs_buff[6]);
+	sbuf_printf(sb, "\tRDT\t %08x\n", regs_buff[7]);
+	sbuf_printf(sb, "\tRXDCTL\t %08x\n", regs_buff[8]);
+	sbuf_printf(sb, "\tRDBAL\t %08x\n", regs_buff[9]);
+	sbuf_printf(sb, "\tRDBAH\t %08x\n\n", regs_buff[10]);
+
+	sbuf_printf(sb, "TX Registers\n");
+	sbuf_printf(sb, "\tTCTL\t %08x\n", regs_buff[11]);
+	sbuf_printf(sb, "\tTDBAL\t %08x\n", regs_buff[12]);
+	sbuf_printf(sb, "\tTDBAH\t %08x\n", regs_buff[13]);
+	sbuf_printf(sb, "\tTDLEN\t %08x\n", regs_buff[14]);
+	sbuf_printf(sb, "\tTDH\t %08x\n", regs_buff[15]);
+	sbuf_printf(sb, "\tTDT\t %08x\n", regs_buff[16]);
+	sbuf_printf(sb, "\tTXDCTL\t %08x\n", regs_buff[17]);
+	sbuf_printf(sb, "\tTDFH\t %08x\n", regs_buff[18]);
+	sbuf_printf(sb, "\tTDFT\t %08x\n", regs_buff[19]);
+	sbuf_printf(sb, "\tTDFHS\t %08x\n", regs_buff[20]);
+	sbuf_printf(sb, "\tTDFPC\t %08x\n\n", regs_buff[21]);
+
+	free(regs_buff, M_DEVBUF);
+
+#ifdef DUMP_DESCS
+	{
+		if_softc_ctx_t scctx = adapter->shared;
+		struct rx_ring *rxr = &rx_que->rxr;
+		struct tx_ring *txr = &tx_que->txr;
+		int ntxd = scctx->isc_ntxd[0];
+		int nrxd = scctx->isc_nrxd[0];
+		int j;
+
+	for (j = 0; j < nrxd; j++) {
+		u32 staterr = le32toh(rxr->rx_base[j].wb.upper.status_error);
+		u32 length =  le32toh(rxr->rx_base[j].wb.upper.length);
+		sbuf_printf(sb, "\tReceive Descriptor Address %d: %08" PRIx64 "  Error:%d  Length:%d\n", j, rxr->rx_base[j].read.buffer_addr, staterr, length);
+	}
+
+	for (j = 0; j < min(ntxd, 256); j++) {
+		unsigned int *ptr = (unsigned int *)&txr->tx_base[j];
+
+		sbuf_printf(sb, "\tTXD[%03d] [0]: %08x [1]: %08x [2]: %08x [3]: %08x  eop: %d DD=%d\n",
+			    j, ptr[0], ptr[1], ptr[2], ptr[3], buf->eop,
+			    buf->eop != -1 ? txr->tx_base[buf->eop].upper.fields.status & IGC_TXD_STAT_DD : 0);
+
+	}
+	}
+#endif
+
+	rc = sbuf_finish(sb);
+	sbuf_delete(sb);
+	return(rc);
+}
+
+static void *
+igc_register(device_t dev)
+{
+	return (&igc_sctx_init);
+}
+
+static int
+igc_set_num_queues(if_ctx_t ctx)
+{
+	int maxqueues;
+
+	maxqueues = 4;
+
+	return (maxqueues);
+}
+
+#define	IGC_CAPS							\
+    IFCAP_HWCSUM | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |		\
+    IFCAP_VLAN_HWCSUM | IFCAP_WOL | IFCAP_VLAN_HWFILTER | IFCAP_TSO4 |	\
+    IFCAP_LRO | IFCAP_VLAN_HWTSO | IFCAP_JUMBO_MTU | IFCAP_HWCSUM_IPV6 |\
+    IFCAP_TSO6
+
+/*********************************************************************
+ *  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
+igc_if_attach_pre(if_ctx_t ctx)
+{
+	struct igc_adapter *adapter;
+	if_softc_ctx_t scctx;
+	device_t dev;
+	struct igc_hw *hw;
+	int error = 0;
+
+	INIT_DEBUGOUT("igc_if_attach_pre: begin");
+	dev = iflib_get_dev(ctx);
+	adapter = iflib_get_softc(ctx);
+
+	adapter->ctx = adapter->osdep.ctx = ctx;
+	adapter->dev = adapter->osdep.dev = dev;
+	scctx = adapter->shared = iflib_get_softc_ctx(ctx);
+	adapter->media = iflib_get_media(ctx);
+	hw = &adapter->hw;
+
+	adapter->tx_process_limit = scctx->isc_ntxd[0];
+
+	/* SYSCTL stuff */
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "nvm", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
+	    adapter, 0, igc_sysctl_nvm_info, "I", "NVM Information");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "debug", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
+	    adapter, 0, igc_sysctl_debug_info, "I", "Debug Information");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
+	    adapter, 0, igc_set_flowcntl, "I", "Flow Control");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "reg_dump",
+	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, adapter, 0,
+	    igc_get_regs, "A", "Dump Registers");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "rs_dump",
+	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, adapter, 0,
+	    igc_get_rs, "I", "Dump RS indexes");
+
+	/* Determine hardware and mac info */
+	igc_identify_hardware(ctx);
+
+	scctx->isc_tx_nsegments = IGC_MAX_SCATTER;
+	scctx->isc_nrxqsets_max = scctx->isc_ntxqsets_max = igc_set_num_queues(ctx);
+	if (bootverbose)
+		device_printf(dev, "attach_pre capping queues at %d\n",
+		    scctx->isc_ntxqsets_max);
+
+	scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] * sizeof(union igc_adv_tx_desc), IGC_DBA_ALIGN);
+	scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] * sizeof(union igc_adv_rx_desc), IGC_DBA_ALIGN);
+	scctx->isc_txd_size[0] = sizeof(union igc_adv_tx_desc);
+	scctx->isc_rxd_size[0] = sizeof(union igc_adv_rx_desc);
+	scctx->isc_txrx = &igc_txrx;
+	scctx->isc_tx_tso_segments_max = IGC_MAX_SCATTER;
+	scctx->isc_tx_tso_size_max = IGC_TSO_SIZE;
+	scctx->isc_tx_tso_segsize_max = IGC_TSO_SEG_SIZE;
+	scctx->isc_capabilities = scctx->isc_capenable = IGC_CAPS;
+	scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_TSO |
+		CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_SCTP | CSUM_IP6_SCTP;
+
+	/*
+	** Some new devices, as with ixgbe, now may
+	** use a different BAR, so we need to keep
+	** track of which is used.
+	*/
+	scctx->isc_msix_bar = PCIR_BAR(IGC_MSIX_BAR);
+	if (pci_read_config(dev, scctx->isc_msix_bar, 4) == 0)
+		scctx->isc_msix_bar += 4;
+
+	/* Setup PCI resources */
+	if (igc_allocate_pci_resources(ctx)) {
+		device_printf(dev, "Allocation of PCI resources failed\n");
+		error = ENXIO;
+		goto err_pci;
+	}
+
+	/* Do Shared Code initialization */
+	error = igc_setup_init_funcs(hw, true);
+	if (error) {
+		device_printf(dev, "Setup of Shared code failed, error %d\n",
+		    error);
+		error = ENXIO;
+		goto err_pci;
+	}
+
+	igc_setup_msix(ctx);
+	igc_get_bus_info(hw);
+
+	/* Set up some sysctls for the tunable interrupt delays */
+	igc_add_int_delay_sysctl(adapter, "rx_int_delay",
+	    "receive interrupt delay in usecs", &adapter->rx_int_delay,
+	    IGC_REGISTER(hw, IGC_RDTR), igc_rx_int_delay_dflt);
+	igc_add_int_delay_sysctl(adapter, "tx_int_delay",
+	    "transmit interrupt delay in usecs", &adapter->tx_int_delay,
+	    IGC_REGISTER(hw, IGC_TIDV), igc_tx_int_delay_dflt);
+	igc_add_int_delay_sysctl(adapter, "rx_abs_int_delay",
+	    "receive interrupt delay limit in usecs",
+	    &adapter->rx_abs_int_delay,
+	    IGC_REGISTER(hw, IGC_RADV),
+	    igc_rx_abs_int_delay_dflt);
+	igc_add_int_delay_sysctl(adapter, "tx_abs_int_delay",
+	    "transmit interrupt delay limit in usecs",
+	    &adapter->tx_abs_int_delay,
+	    IGC_REGISTER(hw, IGC_TADV),
+	    igc_tx_abs_int_delay_dflt);
+	igc_add_int_delay_sysctl(adapter, "itr",
+	    "interrupt delay limit in usecs/4",
+	    &adapter->tx_itr,
+	    IGC_REGISTER(hw, IGC_ITR),
+	    DEFAULT_ITR);
+
+	hw->mac.autoneg = DO_AUTO_NEG;
+	hw->phy.autoneg_wait_to_complete = false;
+	hw->phy.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+
+	/* Copper options */
+	if (hw->phy.media_type == igc_media_type_copper) {
+		hw->phy.mdix = AUTO_ALL_MODES;
+	}
+
+	/*
+	 * Set the frame limits assuming
+	 * standard ethernet sized frames.
+	 */
+	scctx->isc_max_frame_size = adapter->hw.mac.max_frame_size =
+	    ETHERMTU + ETHER_HDR_LEN + ETHERNET_FCS_SIZE;
+
+	/* Allocate multicast array memory. */
+	adapter->mta = malloc(sizeof(u8) * ETHER_ADDR_LEN *
+	    MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT);
+	if (adapter->mta == NULL) {
+		device_printf(dev, "Can not allocate multicast setup array\n");
+		error = ENOMEM;
+		goto err_late;
+	}
+
+	/* Check SOL/IDER usage */
+	if (igc_check_reset_block(hw))
+		device_printf(dev, "PHY reset is blocked"
+			      " due to SOL/IDER session.\n");
+
+	/* Sysctl for setting Energy Efficient Ethernet */
+	adapter->hw.dev_spec._i225.eee_disable = igc_eee_setting;
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "eee_control",
+	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
+	    adapter, 0, igc_sysctl_eee, "I",
+	    "Disable Energy Efficient Ethernet");
+
+	/*
+	** Start from a known state, this is
+	** important in reading the nvm and
+	** mac from that.
+	*/
+	igc_reset_hw(hw);
+
+	/* Make sure we have a good EEPROM before we read from it */
+	if (igc_validate_nvm_checksum(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 (igc_validate_nvm_checksum(hw) < 0) {
+			device_printf(dev,
+			    "The EEPROM Checksum Is Not Valid\n");
+			error = EIO;
+			goto err_late;
+		}
+	}
+
+	/* Copy the permanent MAC address out of the EEPROM */
+	if (igc_read_mac_addr(hw) < 0) {
+		device_printf(dev, "EEPROM read error while reading MAC"
+			      " address\n");
+		error = EIO;
+		goto err_late;
+	}
+
+	if (!igc_is_valid_ether_addr(hw->mac.addr)) {
+		device_printf(dev, "Invalid MAC address\n");
+		error = EIO;
+		goto err_late;
+	}
+
+	/*
+	 * Get Wake-on-Lan and Management info for later use
+	 */
+	igc_get_wakeup(ctx);
+
+	/* Enable only WOL MAGIC by default */
+	scctx->isc_capenable &= ~IFCAP_WOL;
+	if (adapter->wol != 0)
+		scctx->isc_capenable |= IFCAP_WOL_MAGIC;
+
+	iflib_set_mac(ctx, hw->mac.addr);
+
+	return (0);
+
+err_late:
+	igc_release_hw_control(adapter);
+err_pci:
+	igc_free_pci_resources(ctx);
+	free(adapter->mta, M_DEVBUF);
+
+	return (error);
+}
+
+static int
+igc_if_attach_post(if_ctx_t ctx)
+{
+	struct igc_adapter *adapter = iflib_get_softc(ctx);
+	struct igc_hw *hw = &adapter->hw;
+	int error = 0;
*** 11492 LINES SKIPPED ***


More information about the dev-commits-src-all mailing list