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
This commit is contained in:
Peter Grehan 2021-07-12 14:50:15 +10:00
parent 0c5a59252c
commit 517904de5c
28 changed files with 12192 additions and 0 deletions

View File

@ -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

167
share/man/man4/igc.4 Normal file
View File

@ -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 .

View File

@ -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

View File

@ -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.

View File

@ -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 \

2984
sys/dev/igc/if_igc.c Normal file

File diff suppressed because it is too large Load Diff

430
sys/dev/igc/if_igc.h Normal file
View File

@ -0,0 +1,430 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2016 Nicole Graziano <nicole@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.
*
* $FreeBSD$
*/
#include "opt_ddb.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_rss.h"
#ifdef HAVE_KERNEL_OPTION_HEADERS
#include "opt_device_polling.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#ifdef DDB
#include <sys/types.h>
#include <ddb/ddb.h>
#endif
#include <sys/buf_ring.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/smp.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
#include <sys/eventhandler.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/iflib.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 "igc_api.h"
#include "igc_i225.h"
#include "ifdi_if.h"
#ifndef _IGC_H_DEFINED_
#define _IGC_H_DEFINED_
/* Tunables */
/*
* IGC_MAX_TXD: Maximum number of Transmit Descriptors
* Valid Range: 128-4096
* Default Value: 1024
* This value is the number of transmit descriptors allocated by the driver.
* Increasing this value allows the driver to queue more transmits. Each
* descriptor is 16 bytes.
* Since TDLEN should be multiple of 128bytes, the number of transmit
* desscriptors should meet the following condition.
* (num_tx_desc * sizeof(struct igc_tx_desc)) % 128 == 0
*/
#define IGC_MIN_TXD 128
#define IGC_MAX_TXD 4096
#define IGC_DEFAULT_TXD 1024
#define IGC_DEFAULT_MULTI_TXD 4096
#define IGC_MAX_TXD 4096
/*
* IGC_MAX_RXD - Maximum number of receive Descriptors
* Valid Range: 128-4096
* Default Value: 1024
* This value is the number of receive descriptors allocated by the driver.
* Increasing this value allows the driver to buffer more incoming packets.
* Each descriptor is 16 bytes. A receive buffer is also allocated for each
* descriptor. The maximum MTU size is 16110.
* Since TDLEN should be multiple of 128bytes, the number of transmit
* desscriptors should meet the following condition.
* (num_tx_desc * sizeof(struct igc_tx_desc)) % 128 == 0
*/
#define IGC_MIN_RXD 128
#define IGC_MAX_RXD 4096
#define IGC_DEFAULT_RXD 1024
#define IGC_DEFAULT_MULTI_RXD 4096
#define IGC_MAX_RXD 4096
/*
* IGC_TIDV_VAL - Transmit Interrupt Delay Value
* Valid Range: 0-65535 (0=off)
* Default Value: 64
* This value delays the generation of transmit interrupts in units of
* 1.024 microseconds. Transmit interrupt reduction can improve CPU
* efficiency if properly tuned for specific network traffic. If the
* system is reporting dropped transmits, this value may be set too high
* causing the driver to run out of available transmit descriptors.
*/
#define IGC_TIDV_VAL 64
/*
* IGC_TADV_VAL - Transmit Absolute Interrupt Delay Value
* Valid Range: 0-65535 (0=off)
* Default Value: 64
* This value, in units of 1.024 microseconds, limits the delay in which a
* transmit interrupt is generated. Useful only if IGC_TIDV is non-zero,
* this value ensures that an interrupt is generated after the initial
* packet is sent on the wire within the set amount of time. Proper tuning,
* along with IGC_TIDV_VAL, may improve traffic throughput in specific
* network conditions.
*/
#define IGC_TADV_VAL 64
/*
* IGC_RDTR_VAL - Receive Interrupt Delay Timer (Packet Timer)
* Valid Range: 0-65535 (0=off)
* Default Value: 0
* This value delays the generation of receive interrupts in units of 1.024
* microseconds. Receive interrupt reduction can improve CPU efficiency if
* properly tuned for specific network traffic. Increasing this value adds
* extra latency to frame reception and can end up decreasing the throughput
* of TCP traffic. If the system is reporting dropped receives, this value
* may be set too high, causing the driver to run out of available receive
* descriptors.
*
* CAUTION: When setting IGC_RDTR to a value other than 0, adapters
* may hang (stop transmitting) under certain network conditions.
* If this occurs a WATCHDOG message is logged in the system
* event log. In addition, the controller is automatically reset,
* restoring the network connection. To eliminate the potential
* for the hang ensure that IGC_RDTR is set to 0.
*/
#define IGC_RDTR_VAL 0
/*
* Receive Interrupt Absolute Delay Timer
* Valid Range: 0-65535 (0=off)
* Default Value: 64
* This value, in units of 1.024 microseconds, limits the delay in which a
* receive interrupt is generated. Useful only if IGC_RDTR is non-zero,
* this value ensures that an interrupt is generated after the initial
* packet is received within the set amount of time. Proper tuning,
* along with IGC_RDTR, may improve traffic throughput in specific network
* conditions.
*/
#define IGC_RADV_VAL 64
/*
* This parameter controls whether or not autonegotation is enabled.
* 0 - Disable autonegotiation
* 1 - Enable autonegotiation
*/
#define DO_AUTO_NEG true
/* Tunables -- End */
#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)
#define AUTO_ALL_MODES 0
/*
* Micellaneous constants
*/
#define MAX_NUM_MULTICAST_ADDRESSES 128
#define IGC_FC_PAUSE_TIME 0x0680
#define IGC_TXPBSIZE 20408
#define IGC_PKTTYPE_MASK 0x0000FFF0
#define IGC_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coalesce Flush */
#define IGC_RX_PTHRESH 8
#define IGC_RX_HTHRESH 8
#define IGC_RX_WTHRESH 4
#define IGC_TX_PTHRESH 8
#define IGC_TX_HTHRESH 1
/*
* TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
* multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary. This will
* also optimize cache line size effect. H/W supports up to cache line size 128.
*/
#define IGC_DBA_ALIGN 128
#define IGC_MSIX_BAR 3
/* Defines for printing debug information */
#define DEBUG_INIT 0
#define DEBUG_IOCTL 0
#define DEBUG_HW 0
#define INIT_DEBUGOUT(S) if (DEBUG_INIT) printf(S "\n")
#define INIT_DEBUGOUT1(S, A) if (DEBUG_INIT) printf(S "\n", A)
#define INIT_DEBUGOUT2(S, A, B) if (DEBUG_INIT) printf(S "\n", A, B)
#define IOCTL_DEBUGOUT(S) if (DEBUG_IOCTL) printf(S "\n")
#define IOCTL_DEBUGOUT1(S, A) if (DEBUG_IOCTL) printf(S "\n", A)
#define IOCTL_DEBUGOUT2(S, A, B) if (DEBUG_IOCTL) printf(S "\n", A, B)
#define HW_DEBUGOUT(S) if (DEBUG_HW) printf(S "\n")
#define HW_DEBUGOUT1(S, A) if (DEBUG_HW) printf(S "\n", A)
#define HW_DEBUGOUT2(S, A, B) if (DEBUG_HW) printf(S "\n", A, B)
#define IGC_MAX_SCATTER 40
#define IGC_VFTA_SIZE 128
#define IGC_TSO_SIZE 65535
#define IGC_TSO_SEG_SIZE 4096 /* Max dma segment size */
#define IGC_CSUM_OFFLOAD (CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP | \
CSUM_IP_SCTP | CSUM_IP6_UDP | CSUM_IP6_TCP | \
CSUM_IP6_SCTP) /* Offload bits in mbuf flag */
struct igc_adapter;
struct igc_int_delay_info {
struct igc_adapter *adapter; /* Back-pointer to the adapter struct */
int offset; /* Register offset to read/write */
int value; /* Current value in usecs */
};
/*
* The transmit ring, one per tx queue
*/
struct tx_ring {
struct igc_adapter *adapter;
struct igc_tx_desc *tx_base;
uint64_t tx_paddr;
qidx_t *tx_rsq;
uint8_t me;
qidx_t tx_rs_cidx;
qidx_t tx_rs_pidx;
qidx_t tx_cidx_processed;
/* Interrupt resources */
void *tag;
struct resource *res;
unsigned long tx_irq;
/* Saved csum offloading context information */
int csum_flags;
int csum_lhlen;
int csum_iphlen;
int csum_thlen;
int csum_mss;
int csum_pktlen;
uint32_t csum_txd_upper;
uint32_t csum_txd_lower; /* last field */
};
/*
* The Receive ring, one per rx queue
*/
struct rx_ring {
struct igc_adapter *adapter;
struct igc_rx_queue *que;
u32 me;
u32 payload;
union igc_rx_desc_extended *rx_base;
uint64_t rx_paddr;
/* Interrupt resources */
void *tag;
struct resource *res;
/* Soft stats */
unsigned long rx_irq;
unsigned long rx_discarded;
unsigned long rx_packets;
unsigned long rx_bytes;
};
struct igc_tx_queue {
struct igc_adapter *adapter;
u32 msix;
u32 eims; /* This queue's EIMS bit */
u32 me;
struct tx_ring txr;
};
struct igc_rx_queue {
struct igc_adapter *adapter;
u32 me;
u32 msix;
u32 eims;
struct rx_ring rxr;
u64 irqs;
struct if_irq que_irq;
};
/* Our adapter structure */
struct igc_adapter {
struct ifnet *ifp;
struct igc_hw hw;
if_softc_ctx_t shared;
if_ctx_t ctx;
#define tx_num_queues shared->isc_ntxqsets
#define rx_num_queues shared->isc_nrxqsets
#define intr_type shared->isc_intr
/* FreeBSD operating-system-specific structures. */
struct igc_osdep osdep;
device_t dev;
struct cdev *led_dev;
struct igc_tx_queue *tx_queues;
struct igc_rx_queue *rx_queues;
struct if_irq irq;
struct resource *memory;
struct resource *flash;
struct resource *ioport;
struct resource *res;
void *tag;
u32 linkvec;
u32 ivars;
struct ifmedia *media;
int msix;
int if_flags;
int igc_insert_vlan_header;
u32 ims;
u32 flags;
/* Task for FAST handling */
struct grouptask link_task;
u16 num_vlans;
u32 txd_cmd;
u32 tx_process_limit;
u32 rx_process_limit;
u32 rx_mbuf_sz;
/* Management and WOL features */
u32 wol;
/* Multicast array memory */
u8 *mta;
/*
** 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.
*/
u32 shadow_vfta[IGC_VFTA_SIZE];
/* Info about the interface */
u16 link_active;
u16 fc;
u16 link_speed;
u16 link_duplex;
u32 smartspeed;
u32 dmac;
int link_mask;
u64 que_mask;
struct igc_int_delay_info tx_int_delay;
struct igc_int_delay_info tx_abs_int_delay;
struct igc_int_delay_info rx_int_delay;
struct igc_int_delay_info rx_abs_int_delay;
struct igc_int_delay_info tx_itr;
/* Misc stats maintained by the driver */
unsigned long dropped_pkts;
unsigned long link_irq;
unsigned long rx_overruns;
unsigned long watchdog_events;
struct igc_hw_stats stats;
u16 vf_ifp;
};
void igc_dump_rs(struct igc_adapter *);
#define IGC_RSSRK_SIZE 4
#define IGC_RSSRK_VAL(key, i) (key[(i) * IGC_RSSRK_SIZE] | \
key[(i) * IGC_RSSRK_SIZE + 1] << 8 | \
key[(i) * IGC_RSSRK_SIZE + 2] << 16 | \
key[(i) * IGC_RSSRK_SIZE + 3] << 24)
#endif /* _IGC_H_DEFINED_ */

735
sys/dev/igc/igc_api.c Normal file
View File

@ -0,0 +1,735 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "igc_api.h"
/**
* igc_init_mac_params - Initialize MAC function pointers
* @hw: pointer to the HW structure
*
* This function initializes the function pointers for the MAC
* set of functions. Called by drivers or by igc_setup_init_funcs.
**/
s32 igc_init_mac_params(struct igc_hw *hw)
{
s32 ret_val = IGC_SUCCESS;
if (hw->mac.ops.init_params) {
ret_val = hw->mac.ops.init_params(hw);
if (ret_val) {
DEBUGOUT("MAC Initialization Error\n");
goto out;
}
} else {
DEBUGOUT("mac.init_mac_params was NULL\n");
ret_val = -IGC_ERR_CONFIG;
}
out:
return ret_val;
}
/**
* igc_init_nvm_params - Initialize NVM function pointers
* @hw: pointer to the HW structure
*
* This function initializes the function pointers for the NVM
* set of functions. Called by drivers or by igc_setup_init_funcs.
**/
s32 igc_init_nvm_params(struct igc_hw *hw)
{
s32 ret_val = IGC_SUCCESS;
if (hw->nvm.ops.init_params) {
ret_val = hw->nvm.ops.init_params(hw);
if (ret_val) {
DEBUGOUT("NVM Initialization Error\n");
goto out;
}
} else {
DEBUGOUT("nvm.init_nvm_params was NULL\n");
ret_val = -IGC_ERR_CONFIG;
}
out:
return ret_val;
}
/**
* igc_init_phy_params - Initialize PHY function pointers
* @hw: pointer to the HW structure
*
* This function initializes the function pointers for the PHY
* set of functions. Called by drivers or by igc_setup_init_funcs.
**/
s32 igc_init_phy_params(struct igc_hw *hw)
{
s32 ret_val = IGC_SUCCESS;
if (hw->phy.ops.init_params) {
ret_val = hw->phy.ops.init_params(hw);
if (ret_val) {
DEBUGOUT("PHY Initialization Error\n");
goto out;
}
} else {
DEBUGOUT("phy.init_phy_params was NULL\n");
ret_val = -IGC_ERR_CONFIG;
}
out:
return ret_val;
}
/**
* igc_set_mac_type - Sets MAC type
* @hw: pointer to the HW structure
*
* This function sets the mac type of the adapter based on the
* device ID stored in the hw structure.
* MUST BE FIRST FUNCTION CALLED (explicitly or through
* igc_setup_init_funcs()).
**/
s32 igc_set_mac_type(struct igc_hw *hw)
{
struct igc_mac_info *mac = &hw->mac;
s32 ret_val = IGC_SUCCESS;
DEBUGFUNC("igc_set_mac_type");
switch (hw->device_id) {
case IGC_DEV_ID_I225_LM:
case IGC_DEV_ID_I225_V:
case IGC_DEV_ID_I225_K:
case IGC_DEV_ID_I225_I:
case IGC_DEV_ID_I220_V:
case IGC_DEV_ID_I225_K2:
case IGC_DEV_ID_I225_LMVP:
case IGC_DEV_ID_I225_IT:
case IGC_DEV_ID_I226_LM:
case IGC_DEV_ID_I226_V:
case IGC_DEV_ID_I226_IT:
case IGC_DEV_ID_I221_V:
case IGC_DEV_ID_I226_BLANK_NVM:
case IGC_DEV_ID_I225_BLANK_NVM:
mac->type = igc_i225;
break;
default:
/* Should never have loaded on this device */
ret_val = -IGC_ERR_MAC_INIT;
break;
}
return ret_val;
}
/**
* igc_setup_init_funcs - Initializes function pointers
* @hw: pointer to the HW structure
* @init_device: true will initialize the rest of the function pointers
* getting the device ready for use. FALSE will only set
* MAC type and the function pointers for the other init
* functions. Passing FALSE will not generate any hardware
* reads or writes.
*
* This function must be called by a driver in order to use the rest
* of the 'shared' code files. Called by drivers only.
**/
s32 igc_setup_init_funcs(struct igc_hw *hw, bool init_device)
{
s32 ret_val;
/* Can't do much good without knowing the MAC type. */
ret_val = igc_set_mac_type(hw);
if (ret_val) {
DEBUGOUT("ERROR: MAC type could not be set properly.\n");
goto out;
}
if (!hw->hw_addr) {
DEBUGOUT("ERROR: Registers not mapped\n");
ret_val = -IGC_ERR_CONFIG;
goto out;
}
/*
* Init function pointers to generic implementations. We do this first
* allowing a driver module to override it afterward.
*/
igc_init_mac_ops_generic(hw);
igc_init_phy_ops_generic(hw);
igc_init_nvm_ops_generic(hw);
/*
* Set up the init function pointers. These are functions within the
* adapter family file that sets up function pointers for the rest of
* the functions in that family.
*/
switch (hw->mac.type) {
case igc_i225:
igc_init_function_pointers_i225(hw);
break;
default:
DEBUGOUT("Hardware not supported\n");
ret_val = -IGC_ERR_CONFIG;
break;
}
/*
* Initialize the rest of the function pointers. These require some
* register reads/writes in some cases.
*/
if (!(ret_val) && init_device) {
ret_val = igc_init_mac_params(hw);
if (ret_val)
goto out;
ret_val = igc_init_nvm_params(hw);
if (ret_val)
goto out;
ret_val = igc_init_phy_params(hw);
if (ret_val)
goto out;
}
out:
return ret_val;
}
/**
* igc_get_bus_info - Obtain bus information for adapter
* @hw: pointer to the HW structure
*
* This will obtain information about the HW bus for which the
* adapter is attached and stores it in the hw structure. This is a
* function pointer entry point called by drivers.
**/
s32 igc_get_bus_info(struct igc_hw *hw)
{
if (hw->mac.ops.get_bus_info)
return hw->mac.ops.get_bus_info(hw);
return IGC_SUCCESS;
}
/**
* igc_clear_vfta - Clear VLAN filter table
* @hw: pointer to the HW structure
*
* This clears the VLAN filter table on the adapter. This is a function
* pointer entry point called by drivers.
**/
void igc_clear_vfta(struct igc_hw *hw)
{
if (hw->mac.ops.clear_vfta)
hw->mac.ops.clear_vfta(hw);
}
/**
* igc_write_vfta - Write value to VLAN filter table
* @hw: pointer to the HW structure
* @offset: the 32-bit offset in which to write the value to.
* @value: the 32-bit value to write at location offset.
*
* This writes a 32-bit value to a 32-bit offset in the VLAN filter
* table. This is a function pointer entry point called by drivers.
**/
void igc_write_vfta(struct igc_hw *hw, u32 offset, u32 value)
{
if (hw->mac.ops.write_vfta)
hw->mac.ops.write_vfta(hw, offset, value);
}
/**
* igc_update_mc_addr_list - Update Multicast addresses
* @hw: pointer to the HW structure
* @mc_addr_list: array of multicast addresses to program
* @mc_addr_count: number of multicast addresses to program
*
* Updates the Multicast Table Array.
* The caller must have a packed mc_addr_list of multicast addresses.
**/
void igc_update_mc_addr_list(struct igc_hw *hw, u8 *mc_addr_list,
u32 mc_addr_count)
{
if (hw->mac.ops.update_mc_addr_list)
hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
mc_addr_count);
}
/**
* igc_force_mac_fc - Force MAC flow control
* @hw: pointer to the HW structure
*
* Force the MAC's flow control settings. Currently no func pointer exists
* and all implementations are handled in the generic version of this
* function.
**/
s32 igc_force_mac_fc(struct igc_hw *hw)
{
return igc_force_mac_fc_generic(hw);
}
/**
* igc_check_for_link - Check/Store link connection
* @hw: pointer to the HW structure
*
* This checks the link condition of the adapter and stores the
* results in the hw->mac structure. This is a function pointer entry
* point called by drivers.
**/
s32 igc_check_for_link(struct igc_hw *hw)
{
if (hw->mac.ops.check_for_link)
return hw->mac.ops.check_for_link(hw);
return -IGC_ERR_CONFIG;
}
/**
* igc_reset_hw - Reset hardware
* @hw: pointer to the HW structure
*
* This resets the hardware into a known state. This is a function pointer
* entry point called by drivers.
**/
s32 igc_reset_hw(struct igc_hw *hw)
{
if (hw->mac.ops.reset_hw)
return hw->mac.ops.reset_hw(hw);
return -IGC_ERR_CONFIG;
}
/**
* igc_init_hw - Initialize hardware
* @hw: pointer to the HW structure
*
* This inits the hardware readying it for operation. This is a function
* pointer entry point called by drivers.
**/
s32 igc_init_hw(struct igc_hw *hw)
{
if (hw->mac.ops.init_hw)
return hw->mac.ops.init_hw(hw);
return -IGC_ERR_CONFIG;
}
/**
* igc_setup_link - Configures link and flow control
* @hw: pointer to the HW structure
*
* This configures link and flow control settings for the adapter. This
* is a function pointer entry point called by drivers. While modules can
* also call this, they probably call their own version of this function.
**/
s32 igc_setup_link(struct igc_hw *hw)
{
if (hw->mac.ops.setup_link)
return hw->mac.ops.setup_link(hw);
return -IGC_ERR_CONFIG;
}
/**
* igc_get_speed_and_duplex - Returns current speed and duplex
* @hw: pointer to the HW structure
* @speed: pointer to a 16-bit value to store the speed
* @duplex: pointer to a 16-bit value to store the duplex.
*
* This returns the speed and duplex of the adapter in the two 'out'
* variables passed in. This is a function pointer entry point called
* by drivers.
**/
s32 igc_get_speed_and_duplex(struct igc_hw *hw, u16 *speed, u16 *duplex)
{
if (hw->mac.ops.get_link_up_info)
return hw->mac.ops.get_link_up_info(hw, speed, duplex);
return -IGC_ERR_CONFIG;
}
/**
* igc_disable_pcie_master - Disable PCI-Express master access
* @hw: pointer to the HW structure
*
* Disables PCI-Express master access and verifies there are no pending
* requests. Currently no func pointer exists and all implementations are
* handled in the generic version of this function.
**/
s32 igc_disable_pcie_master(struct igc_hw *hw)
{
return igc_disable_pcie_master_generic(hw);
}
/**
* igc_config_collision_dist - Configure collision distance
* @hw: pointer to the HW structure
*
* Configures the collision distance to the default value and is used
* during link setup.
**/
void igc_config_collision_dist(struct igc_hw *hw)
{
if (hw->mac.ops.config_collision_dist)
hw->mac.ops.config_collision_dist(hw);
}
/**
* igc_rar_set - Sets a receive address register
* @hw: pointer to the HW structure
* @addr: address to set the RAR to
* @index: the RAR to set
*
* Sets a Receive Address Register (RAR) to the specified address.
**/
int igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
{
if (hw->mac.ops.rar_set)
return hw->mac.ops.rar_set(hw, addr, index);
return IGC_SUCCESS;
}
/**
* igc_validate_mdi_setting - Ensures valid MDI/MDIX SW state
* @hw: pointer to the HW structure
*
* Ensures that the MDI/MDIX SW state is valid.
**/
s32 igc_validate_mdi_setting(struct igc_hw *hw)
{
if (hw->mac.ops.validate_mdi_setting)
return hw->mac.ops.validate_mdi_setting(hw);
return IGC_SUCCESS;
}
/**
* igc_hash_mc_addr - Determines address location in multicast table
* @hw: pointer to the HW structure
* @mc_addr: Multicast address to hash.
*
* This hashes an address to determine its location in the multicast
* table. Currently no func pointer exists and all implementations
* are handled in the generic version of this function.
**/
u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)
{
return igc_hash_mc_addr_generic(hw, mc_addr);
}
/**
* igc_check_reset_block - Verifies PHY can be reset
* @hw: pointer to the HW structure
*
* Checks if the PHY is in a state that can be reset or if manageability
* has it tied up. This is a function pointer entry point called by drivers.
**/
s32 igc_check_reset_block(struct igc_hw *hw)
{
if (hw->phy.ops.check_reset_block)
return hw->phy.ops.check_reset_block(hw);
return IGC_SUCCESS;
}
/**
* igc_read_phy_reg - Reads PHY register
* @hw: pointer to the HW structure
* @offset: the register to read
* @data: the buffer to store the 16-bit read.
*
* Reads the PHY register and returns the value in data.
* This is a function pointer entry point called by drivers.
**/
s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data)
{
if (hw->phy.ops.read_reg)
return hw->phy.ops.read_reg(hw, offset, data);
return IGC_SUCCESS;
}
/**
* igc_write_phy_reg - Writes PHY register
* @hw: pointer to the HW structure
* @offset: the register to write
* @data: the value to write.
*
* Writes the PHY register at offset with the value in data.
* This is a function pointer entry point called by drivers.
**/
s32 igc_write_phy_reg(struct igc_hw *hw, u32 offset, u16 data)
{
if (hw->phy.ops.write_reg)
return hw->phy.ops.write_reg(hw, offset, data);
return IGC_SUCCESS;
}
/**
* igc_release_phy - Generic release PHY
* @hw: pointer to the HW structure
*
* Return if silicon family does not require a semaphore when accessing the
* PHY.
**/
void igc_release_phy(struct igc_hw *hw)
{
if (hw->phy.ops.release)
hw->phy.ops.release(hw);
}
/**
* igc_acquire_phy - Generic acquire PHY
* @hw: pointer to the HW structure
*
* Return success if silicon family does not require a semaphore when
* accessing the PHY.
**/
s32 igc_acquire_phy(struct igc_hw *hw)
{
if (hw->phy.ops.acquire)
return hw->phy.ops.acquire(hw);
return IGC_SUCCESS;
}
/**
* igc_get_phy_info - Retrieves PHY information from registers
* @hw: pointer to the HW structure
*
* This function gets some information from various PHY registers and
* populates hw->phy values with it. This is a function pointer entry
* point called by drivers.
**/
s32 igc_get_phy_info(struct igc_hw *hw)
{
if (hw->phy.ops.get_info)
return hw->phy.ops.get_info(hw);
return IGC_SUCCESS;
}
/**
* igc_phy_hw_reset - Hard PHY reset
* @hw: pointer to the HW structure
*
* Performs a hard PHY reset. This is a function pointer entry point called
* by drivers.
**/
s32 igc_phy_hw_reset(struct igc_hw *hw)
{
if (hw->phy.ops.reset)
return hw->phy.ops.reset(hw);
return IGC_SUCCESS;
}
/**
* igc_phy_commit - Soft PHY reset
* @hw: pointer to the HW structure
*
* Performs a soft PHY reset on those that apply. This is a function pointer
* entry point called by drivers.
**/
s32 igc_phy_commit(struct igc_hw *hw)
{
if (hw->phy.ops.commit)
return hw->phy.ops.commit(hw);
return IGC_SUCCESS;
}
/**
* igc_set_d0_lplu_state - Sets low power link up state for D0
* @hw: pointer to the HW structure
* @active: boolean used to enable/disable lplu
*
* Success returns 0, Failure returns 1
*
* The low power link up (lplu) state is set to the power management level D0
* and SmartSpeed is disabled when active is true, else clear lplu for D0
* and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
* is used during Dx states where the power conservation is most important.
* During driver activity, SmartSpeed should be enabled so performance is
* maintained. This is a function pointer entry point called by drivers.
**/
s32 igc_set_d0_lplu_state(struct igc_hw *hw, bool active)
{
if (hw->phy.ops.set_d0_lplu_state)
return hw->phy.ops.set_d0_lplu_state(hw, active);
return IGC_SUCCESS;
}
/**
* igc_set_d3_lplu_state - Sets low power link up state for D3
* @hw: pointer to the HW structure
* @active: boolean used to enable/disable lplu
*
* Success returns 0, Failure returns 1
*
* The low power link up (lplu) state is set to the power management level D3
* and SmartSpeed is disabled when active is true, else clear lplu for D3
* and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
* is used during Dx states where the power conservation is most important.
* During driver activity, SmartSpeed should be enabled so performance is
* maintained. This is a function pointer entry point called by drivers.
**/
s32 igc_set_d3_lplu_state(struct igc_hw *hw, bool active)
{
if (hw->phy.ops.set_d3_lplu_state)
return hw->phy.ops.set_d3_lplu_state(hw, active);
return IGC_SUCCESS;
}
/**
* igc_read_mac_addr - Reads MAC address
* @hw: pointer to the HW structure
*
* Reads the MAC address out of the adapter and stores it in the HW structure.
* Currently no func pointer exists and all implementations are handled in the
* generic version of this function.
**/
s32 igc_read_mac_addr(struct igc_hw *hw)
{
if (hw->mac.ops.read_mac_addr)
return hw->mac.ops.read_mac_addr(hw);
return igc_read_mac_addr_generic(hw);
}
/**
* igc_read_pba_string - Read device part number string
* @hw: pointer to the HW structure
* @pba_num: pointer to device part number
* @pba_num_size: size of part number buffer
*
* Reads the product board assembly (PBA) number from the EEPROM and stores
* the value in pba_num.
* Currently no func pointer exists and all implementations are handled in the
* generic version of this function.
**/
s32 igc_read_pba_string(struct igc_hw *hw, u8 *pba_num, u32 pba_num_size)
{
return igc_read_pba_string_generic(hw, pba_num, pba_num_size);
}
/**
* igc_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
* @hw: pointer to the HW structure
*
* Validates the NVM checksum is correct. This is a function pointer entry
* point called by drivers.
**/
s32 igc_validate_nvm_checksum(struct igc_hw *hw)
{
if (hw->nvm.ops.validate)
return hw->nvm.ops.validate(hw);
return -IGC_ERR_CONFIG;
}
/**
* igc_update_nvm_checksum - Updates NVM (EEPROM) checksum
* @hw: pointer to the HW structure
*
* Updates the NVM checksum. Currently no func pointer exists and all
* implementations are handled in the generic version of this function.
**/
s32 igc_update_nvm_checksum(struct igc_hw *hw)
{
if (hw->nvm.ops.update)
return hw->nvm.ops.update(hw);
return -IGC_ERR_CONFIG;
}
/**
* igc_reload_nvm - Reloads EEPROM
* @hw: pointer to the HW structure
*
* Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
* extended control register.
**/
void igc_reload_nvm(struct igc_hw *hw)
{
if (hw->nvm.ops.reload)
hw->nvm.ops.reload(hw);
}
/**
* igc_read_nvm - Reads NVM (EEPROM)
* @hw: pointer to the HW structure
* @offset: the word offset to read
* @words: number of 16-bit words to read
* @data: pointer to the properly sized buffer for the data.
*
* Reads 16-bit chunks of data from the NVM (EEPROM). This is a function
* pointer entry point called by drivers.
**/
s32 igc_read_nvm(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
{
if (hw->nvm.ops.read)
return hw->nvm.ops.read(hw, offset, words, data);
return -IGC_ERR_CONFIG;
}
/**
* igc_write_nvm - Writes to NVM (EEPROM)
* @hw: pointer to the HW structure
* @offset: the word offset to read
* @words: number of 16-bit words to write
* @data: pointer to the properly sized buffer for the data.
*
* Writes 16-bit chunks of data to the NVM (EEPROM). This is a function
* pointer entry point called by drivers.
**/
s32 igc_write_nvm(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
{
if (hw->nvm.ops.write)
return hw->nvm.ops.write(hw, offset, words, data);
return IGC_SUCCESS;
}
/**
* igc_power_up_phy - Restores link in case of PHY power down
* @hw: pointer to the HW structure
*
* The phy may be powered down to save power, to turn off link when the
* driver is unloaded, or wake on lan is not enabled (among others).
**/
void igc_power_up_phy(struct igc_hw *hw)
{
if (hw->phy.ops.power_up)
hw->phy.ops.power_up(hw);
igc_setup_link(hw);
}
/**
* igc_power_down_phy - Power down PHY
* @hw: pointer to the HW structure
*
* The phy may be powered down to save power, to turn off link when the
* driver is unloaded, or wake on lan is not enabled (among others).
**/
void igc_power_down_phy(struct igc_hw *hw)
{
if (hw->phy.ops.power_down)
hw->phy.ops.power_down(hw);
}

58
sys/dev/igc/igc_api.h Normal file
View File

@ -0,0 +1,58 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_API_H_
#define _IGC_API_H_
#include "igc_hw.h"
extern void igc_init_function_pointers_i225(struct igc_hw *hw);
s32 igc_set_mac_type(struct igc_hw *hw);
s32 igc_setup_init_funcs(struct igc_hw *hw, bool init_device);
s32 igc_init_mac_params(struct igc_hw *hw);
s32 igc_init_nvm_params(struct igc_hw *hw);
s32 igc_init_phy_params(struct igc_hw *hw);
s32 igc_get_bus_info(struct igc_hw *hw);
void igc_clear_vfta(struct igc_hw *hw);
void igc_write_vfta(struct igc_hw *hw, u32 offset, u32 value);
s32 igc_force_mac_fc(struct igc_hw *hw);
s32 igc_check_for_link(struct igc_hw *hw);
s32 igc_reset_hw(struct igc_hw *hw);
s32 igc_init_hw(struct igc_hw *hw);
s32 igc_setup_link(struct igc_hw *hw);
s32 igc_get_speed_and_duplex(struct igc_hw *hw, u16 *speed, u16 *duplex);
s32 igc_disable_pcie_master(struct igc_hw *hw);
void igc_config_collision_dist(struct igc_hw *hw);
int igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index);
u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr);
void igc_update_mc_addr_list(struct igc_hw *hw, u8 *mc_addr_list,
u32 mc_addr_count);
s32 igc_check_reset_block(struct igc_hw *hw);
s32 igc_get_cable_length(struct igc_hw *hw);
s32 igc_validate_mdi_setting(struct igc_hw *hw);
s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data);
s32 igc_write_phy_reg(struct igc_hw *hw, u32 offset, u16 data);
s32 igc_get_phy_info(struct igc_hw *hw);
void igc_release_phy(struct igc_hw *hw);
s32 igc_acquire_phy(struct igc_hw *hw);
s32 igc_phy_hw_reset(struct igc_hw *hw);
s32 igc_phy_commit(struct igc_hw *hw);
void igc_power_up_phy(struct igc_hw *hw);
void igc_power_down_phy(struct igc_hw *hw);
s32 igc_read_mac_addr(struct igc_hw *hw);
s32 igc_read_pba_string(struct igc_hw *hw, u8 *pba_num, u32 pba_num_size);
void igc_reload_nvm(struct igc_hw *hw);
s32 igc_update_nvm_checksum(struct igc_hw *hw);
s32 igc_validate_nvm_checksum(struct igc_hw *hw);
s32 igc_read_nvm(struct igc_hw *hw, u16 offset, u16 words, u16 *data);
s32 igc_write_nvm(struct igc_hw *hw, u16 offset, u16 words, u16 *data);
s32 igc_set_d3_lplu_state(struct igc_hw *hw, bool active);
s32 igc_set_d0_lplu_state(struct igc_hw *hw, bool active);
#endif /* _IGC_API_H_ */

188
sys/dev/igc/igc_base.c Normal file
View File

@ -0,0 +1,188 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "igc_hw.h"
#include "igc_i225.h"
#include "igc_mac.h"
#include "igc_base.h"
/**
* igc_acquire_phy_base - Acquire rights to access PHY
* @hw: pointer to the HW structure
*
* Acquire access rights to the correct PHY.
**/
s32 igc_acquire_phy_base(struct igc_hw *hw)
{
u16 mask = IGC_SWFW_PHY0_SM;
DEBUGFUNC("igc_acquire_phy_base");
if (hw->bus.func == IGC_FUNC_1)
mask = IGC_SWFW_PHY1_SM;
return hw->mac.ops.acquire_swfw_sync(hw, mask);
}
/**
* igc_release_phy_base - Release rights to access PHY
* @hw: pointer to the HW structure
*
* A wrapper to release access rights to the correct PHY.
**/
void igc_release_phy_base(struct igc_hw *hw)
{
u16 mask = IGC_SWFW_PHY0_SM;
DEBUGFUNC("igc_release_phy_base");
if (hw->bus.func == IGC_FUNC_1)
mask = IGC_SWFW_PHY1_SM;
hw->mac.ops.release_swfw_sync(hw, mask);
}
/**
* igc_init_hw_base - Initialize hardware
* @hw: pointer to the HW structure
*
* This inits the hardware readying it for operation.
**/
s32 igc_init_hw_base(struct igc_hw *hw)
{
struct igc_mac_info *mac = &hw->mac;
s32 ret_val;
u16 i, rar_count = mac->rar_entry_count;
DEBUGFUNC("igc_init_hw_base");
/* Setup the receive address */
igc_init_rx_addrs_generic(hw, rar_count);
/* Zero out the Multicast HASH table */
DEBUGOUT("Zeroing the MTA\n");
for (i = 0; i < mac->mta_reg_count; i++)
IGC_WRITE_REG_ARRAY(hw, IGC_MTA, i, 0);
/* Zero out the Unicast HASH table */
DEBUGOUT("Zeroing the UTA\n");
for (i = 0; i < mac->uta_reg_count; i++)
IGC_WRITE_REG_ARRAY(hw, IGC_UTA, i, 0);
/* Setup link and flow control */
ret_val = mac->ops.setup_link(hw);
/*
* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
* because the symbol error count will increment wildly if there
* is no link.
*/
igc_clear_hw_cntrs_base_generic(hw);
return ret_val;
}
/**
* igc_power_down_phy_copper_base - Remove link during PHY power down
* @hw: pointer to the HW structure
*
* In the case of a PHY power down to save power, or to turn off link during a
* driver unload, or wake on lan is not enabled, remove the link.
**/
void igc_power_down_phy_copper_base(struct igc_hw *hw)
{
struct igc_phy_info *phy = &hw->phy;
if (!(phy->ops.check_reset_block))
return;
/* If the management interface is not enabled, then power down */
if (phy->ops.check_reset_block(hw))
igc_power_down_phy_copper(hw);
return;
}
/**
* igc_rx_fifo_flush_base - Clean Rx FIFO after Rx enable
* @hw: pointer to the HW structure
*
* After Rx enable, if manageability is enabled then there is likely some
* bad data at the start of the FIFO and possibly in the DMA FIFO. This
* function clears the FIFOs and flushes any packets that came in as Rx was
* being enabled.
**/
void igc_rx_fifo_flush_base(struct igc_hw *hw)
{
u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
int i, ms_wait;
DEBUGFUNC("igc_rx_fifo_flush_base");
/* disable IPv6 options as per hardware errata */
rfctl = IGC_READ_REG(hw, IGC_RFCTL);
rfctl |= IGC_RFCTL_IPV6_EX_DIS;
IGC_WRITE_REG(hw, IGC_RFCTL, rfctl);
if (!(IGC_READ_REG(hw, IGC_MANC) & IGC_MANC_RCV_TCO_EN))
return;
/* Disable all Rx queues */
for (i = 0; i < 4; i++) {
rxdctl[i] = IGC_READ_REG(hw, IGC_RXDCTL(i));
IGC_WRITE_REG(hw, IGC_RXDCTL(i),
rxdctl[i] & ~IGC_RXDCTL_QUEUE_ENABLE);
}
/* Poll all queues to verify they have shut down */
for (ms_wait = 0; ms_wait < 10; ms_wait++) {
msec_delay(1);
rx_enabled = 0;
for (i = 0; i < 4; i++)
rx_enabled |= IGC_READ_REG(hw, IGC_RXDCTL(i));
if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
break;
}
if (ms_wait == 10)
DEBUGOUT("Queue disable timed out after 10ms\n");
/* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
* incoming packets are rejected. Set enable and wait 2ms so that
* any packet that was coming in as RCTL.EN was set is flushed
*/
IGC_WRITE_REG(hw, IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
rlpml = IGC_READ_REG(hw, IGC_RLPML);
IGC_WRITE_REG(hw, IGC_RLPML, 0);
rctl = IGC_READ_REG(hw, IGC_RCTL);
temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
temp_rctl |= IGC_RCTL_LPE;
IGC_WRITE_REG(hw, IGC_RCTL, temp_rctl);
IGC_WRITE_REG(hw, IGC_RCTL, temp_rctl | IGC_RCTL_EN);
IGC_WRITE_FLUSH(hw);
msec_delay(2);
/* Enable Rx queues that were previously enabled and restore our
* previous state
*/
for (i = 0; i < 4; i++)
IGC_WRITE_REG(hw, IGC_RXDCTL(i), rxdctl[i]);
IGC_WRITE_REG(hw, IGC_RCTL, rctl);
IGC_WRITE_FLUSH(hw);
IGC_WRITE_REG(hw, IGC_RLPML, rlpml);
IGC_WRITE_REG(hw, IGC_RFCTL, rfctl);
/* Flush receive errors generated by workaround */
IGC_READ_REG(hw, IGC_ROC);
IGC_READ_REG(hw, IGC_RNBC);
IGC_READ_REG(hw, IGC_MPC);
}

131
sys/dev/igc/igc_base.h Normal file
View File

@ -0,0 +1,131 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_BASE_H_
#define _IGC_BASE_H_
/* forward declaration */
s32 igc_init_hw_base(struct igc_hw *hw);
void igc_power_down_phy_copper_base(struct igc_hw *hw);
extern void igc_rx_fifo_flush_base(struct igc_hw *hw);
s32 igc_acquire_phy_base(struct igc_hw *hw);
void igc_release_phy_base(struct igc_hw *hw);
/* Transmit Descriptor - Advanced */
union igc_adv_tx_desc {
struct {
__le64 buffer_addr; /* Address of descriptor's data buf */
__le32 cmd_type_len;
__le32 olinfo_status;
} read;
struct {
__le64 rsvd; /* Reserved */
__le32 nxtseq_seed;
__le32 status;
} wb;
};
/* Context descriptors */
struct igc_adv_tx_context_desc {
__le32 vlan_macip_lens;
union {
__le32 launch_time;
__le32 seqnum_seed;
};
__le32 type_tucmd_mlhl;
__le32 mss_l4len_idx;
};
/* Adv Transmit Descriptor Config Masks */
#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
#define IGC_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
#define IGC_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
#define IGC_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */
#define IGC_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
#define IGC_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
#define IGC_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
#define IGC_ADVTXD_MAC_LINKSEC 0x00040000 /* Apply LinkSec on pkt */
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp pkt */
#define IGC_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED prsnt in WB */
#define IGC_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */
#define IGC_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */
#define IGC_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */
#define IGC_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
/* 1st & Last TSO-full iSCSI PDU*/
#define IGC_ADVTXD_POPTS_ISCO_FULL 0x00001800
#define IGC_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */
#define IGC_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
/* Advanced Transmit Context Descriptor Config */
#define IGC_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
#define IGC_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */
#define IGC_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
#define IGC_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */
#define IGC_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
#define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
#define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */
#define IGC_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */
/* IPSec Encrypt Enable for ESP */
#define IGC_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000
/* Req requires Markers and CRC */
#define IGC_ADVTXD_TUCMD_MKRREQ 0x00002000
#define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
#define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
/* Adv ctxt IPSec SA IDX mask */
#define IGC_ADVTXD_IPSEC_SA_INDEX_MASK 0x000000FF
/* Adv ctxt IPSec ESP len mask */
#define IGC_ADVTXD_IPSEC_ESP_LEN_MASK 0x000000FF
#define IGC_RAR_ENTRIES_BASE 16
/* Receive Descriptor - Advanced */
union igc_adv_rx_desc {
struct {
__le64 pkt_addr; /* Packet buffer address */
__le64 hdr_addr; /* Header buffer address */
} read;
struct {
struct {
union {
__le32 data;
struct {
__le16 pkt_info; /*RSS type, Pkt type*/
/* Split Header, header buffer len */
__le16 hdr_info;
} hs_rss;
} lo_dword;
union {
__le32 rss; /* RSS Hash */
struct {
__le16 ip_id; /* IP id */
__le16 csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
__le32 status_error; /* ext status/error */
__le16 length; /* Packet length */
__le16 vlan; /* VLAN tag */
} upper;
} wb; /* writeback */
};
/* Additional Transmit Descriptor Control definitions */
#define IGC_TXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Tx Queue */
/* Additional Receive Descriptor Control definitions */
#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
/* SRRCTL bit definitions */
#define IGC_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
#define IGC_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
#endif /* _IGC_BASE_H_ */

1347
sys/dev/igc/igc_defines.h Normal file

File diff suppressed because it is too large Load Diff

548
sys/dev/igc/igc_hw.h Normal file
View File

@ -0,0 +1,548 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_HW_H_
#define _IGC_HW_H_
#include "igc_osdep.h"
#include "igc_regs.h"
#include "igc_defines.h"
struct igc_hw;
#define IGC_DEV_ID_I225_LM 0x15F2
#define IGC_DEV_ID_I225_V 0x15F3
#define IGC_DEV_ID_I225_K 0x3100
#define IGC_DEV_ID_I225_I 0x15F8
#define IGC_DEV_ID_I220_V 0x15F7
#define IGC_DEV_ID_I225_K2 0x3101
#define IGC_DEV_ID_I225_LMVP 0x5502
#define IGC_DEV_ID_I226_K 0x5504
#define IGC_DEV_ID_I225_IT 0x0D9F
#define IGC_DEV_ID_I226_LM 0x125B
#define IGC_DEV_ID_I226_V 0x125C
#define IGC_DEV_ID_I226_IT 0x125D
#define IGC_DEV_ID_I221_V 0x125E
#define IGC_DEV_ID_I226_BLANK_NVM 0x125F
#define IGC_DEV_ID_I225_BLANK_NVM 0x15FD
#define IGC_REVISION_0 0
#define IGC_REVISION_1 1
#define IGC_REVISION_2 2
#define IGC_REVISION_3 3
#define IGC_REVISION_4 4
#define IGC_FUNC_1 1
#define IGC_ALT_MAC_ADDRESS_OFFSET_LAN0 0
#define IGC_ALT_MAC_ADDRESS_OFFSET_LAN1 3
enum igc_mac_type {
igc_undefined = 0,
igc_i225,
igc_num_macs /* List is 1-based, so subtract 1 for TRUE count. */
};
enum igc_media_type {
igc_media_type_unknown = 0,
igc_media_type_copper = 1,
igc_num_media_types
};
enum igc_nvm_type {
igc_nvm_unknown = 0,
igc_nvm_eeprom_spi,
igc_nvm_flash_hw,
igc_nvm_invm,
};
enum igc_phy_type {
igc_phy_unknown = 0,
igc_phy_none,
igc_phy_i225,
};
enum igc_bus_type {
igc_bus_type_unknown = 0,
igc_bus_type_pci,
igc_bus_type_pcix,
igc_bus_type_pci_express,
igc_bus_type_reserved
};
enum igc_bus_speed {
igc_bus_speed_unknown = 0,
igc_bus_speed_33,
igc_bus_speed_66,
igc_bus_speed_100,
igc_bus_speed_120,
igc_bus_speed_133,
igc_bus_speed_2500,
igc_bus_speed_5000,
igc_bus_speed_reserved
};
enum igc_bus_width {
igc_bus_width_unknown = 0,
igc_bus_width_pcie_x1,
igc_bus_width_pcie_x2,
igc_bus_width_pcie_x4 = 4,
igc_bus_width_pcie_x8 = 8,
igc_bus_width_32,
igc_bus_width_64,
igc_bus_width_reserved
};
enum igc_fc_mode {
igc_fc_none = 0,
igc_fc_rx_pause,
igc_fc_tx_pause,
igc_fc_full,
igc_fc_default = 0xFF
};
enum igc_ms_type {
igc_ms_hw_default = 0,
igc_ms_force_master,
igc_ms_force_slave,
igc_ms_auto
};
enum igc_smart_speed {
igc_smart_speed_default = 0,
igc_smart_speed_on,
igc_smart_speed_off
};
#define __le16 u16
#define __le32 u32
#define __le64 u64
/* Receive Descriptor */
struct igc_rx_desc {
__le64 buffer_addr; /* Address of the descriptor's data buffer */
__le16 length; /* Length of data DMAed into data buffer */
__le16 csum; /* Packet checksum */
u8 status; /* Descriptor status */
u8 errors; /* Descriptor Errors */
__le16 special;
};
/* Receive Descriptor - Extended */
union igc_rx_desc_extended {
struct {
__le64 buffer_addr;
__le64 reserved;
} read;
struct {
struct {
__le32 mrq; /* Multiple Rx Queues */
union {
__le32 rss; /* RSS Hash */
struct {
__le16 ip_id; /* IP id */
__le16 csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
__le32 status_error; /* ext status/error */
__le16 length;
__le16 vlan; /* VLAN tag */
} upper;
} wb; /* writeback */
};
#define MAX_PS_BUFFERS 4
/* Number of packet split data buffers (not including the header buffer) */
#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1)
/* Receive Descriptor - Packet Split */
union igc_rx_desc_packet_split {
struct {
/* one buffer for protocol header(s), three data buffers */
__le64 buffer_addr[MAX_PS_BUFFERS];
} read;
struct {
struct {
__le32 mrq; /* Multiple Rx Queues */
union {
__le32 rss; /* RSS Hash */
struct {
__le16 ip_id; /* IP id */
__le16 csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
__le32 status_error; /* ext status/error */
__le16 length0; /* length of buffer 0 */
__le16 vlan; /* VLAN tag */
} middle;
struct {
__le16 header_status;
/* length of buffers 1-3 */
__le16 length[PS_PAGE_BUFFERS];
} upper;
__le64 reserved;
} wb; /* writeback */
};
/* Transmit Descriptor */
struct igc_tx_desc {
__le64 buffer_addr; /* Address of the descriptor's data buffer */
union {
__le32 data;
struct {
__le16 length; /* Data buffer length */
u8 cso; /* Checksum offset */
u8 cmd; /* Descriptor control */
} flags;
} lower;
union {
__le32 data;
struct {
u8 status; /* Descriptor status */
u8 css; /* Checksum start */
__le16 special;
} fields;
} upper;
};
/* Offload Context Descriptor */
struct igc_context_desc {
union {
__le32 ip_config;
struct {
u8 ipcss; /* IP checksum start */
u8 ipcso; /* IP checksum offset */
__le16 ipcse; /* IP checksum end */
} ip_fields;
} lower_setup;
union {
__le32 tcp_config;
struct {
u8 tucss; /* TCP checksum start */
u8 tucso; /* TCP checksum offset */
__le16 tucse; /* TCP checksum end */
} tcp_fields;
} upper_setup;
__le32 cmd_and_length;
union {
__le32 data;
struct {
u8 status; /* Descriptor status */
u8 hdr_len; /* Header length */
__le16 mss; /* Maximum segment size */
} fields;
} tcp_seg_setup;
};
/* Offload data descriptor */
struct igc_data_desc {
__le64 buffer_addr; /* Address of the descriptor's buffer address */
union {
__le32 data;
struct {
__le16 length; /* Data buffer length */
u8 typ_len_ext;
u8 cmd;
} flags;
} lower;
union {
__le32 data;
struct {
u8 status; /* Descriptor status */
u8 popts; /* Packet Options */
__le16 special;
} fields;
} upper;
};
/* Statistics counters collected by the MAC */
struct igc_hw_stats {
u64 crcerrs;
u64 algnerrc;
u64 symerrs;
u64 rxerrc;
u64 mpc;
u64 scc;
u64 ecol;
u64 mcc;
u64 latecol;
u64 colc;
u64 dc;
u64 tncrs;
u64 sec;
u64 rlec;
u64 xonrxc;
u64 xontxc;
u64 xoffrxc;
u64 xofftxc;
u64 fcruc;
u64 prc64;
u64 prc127;
u64 prc255;
u64 prc511;
u64 prc1023;
u64 prc1522;
u64 tlpic;
u64 rlpic;
u64 gprc;
u64 bprc;
u64 mprc;
u64 gptc;
u64 gorc;
u64 gotc;
u64 rnbc;
u64 ruc;
u64 rfc;
u64 roc;
u64 rjc;
u64 mgprc;
u64 mgpdc;
u64 mgptc;
u64 tor;
u64 tot;
u64 tpr;
u64 tpt;
u64 ptc64;
u64 ptc127;
u64 ptc255;
u64 ptc511;
u64 ptc1023;
u64 ptc1522;
u64 mptc;
u64 bptc;
u64 tsctc;
u64 iac;
u64 rxdmtc;
u64 htdpmc;
u64 rpthc;
u64 hgptc;
u64 hgorc;
u64 hgotc;
u64 lenerrs;
u64 scvpc;
u64 hrmpc;
u64 doosync;
u64 o2bgptc;
u64 o2bspc;
u64 b2ospc;
u64 b2ogprc;
};
#include "igc_mac.h"
#include "igc_phy.h"
#include "igc_nvm.h"
/* Function pointers for the MAC. */
struct igc_mac_operations {
s32 (*init_params)(struct igc_hw *);
s32 (*check_for_link)(struct igc_hw *);
void (*clear_hw_cntrs)(struct igc_hw *);
void (*clear_vfta)(struct igc_hw *);
s32 (*get_bus_info)(struct igc_hw *);
void (*set_lan_id)(struct igc_hw *);
s32 (*get_link_up_info)(struct igc_hw *, u16 *, u16 *);
void (*update_mc_addr_list)(struct igc_hw *, u8 *, u32);
s32 (*reset_hw)(struct igc_hw *);
s32 (*init_hw)(struct igc_hw *);
s32 (*setup_link)(struct igc_hw *);
s32 (*setup_physical_interface)(struct igc_hw *);
void (*write_vfta)(struct igc_hw *, u32, u32);
void (*config_collision_dist)(struct igc_hw *);
int (*rar_set)(struct igc_hw *, u8*, u32);
s32 (*read_mac_addr)(struct igc_hw *);
s32 (*validate_mdi_setting)(struct igc_hw *);
s32 (*acquire_swfw_sync)(struct igc_hw *, u16);
void (*release_swfw_sync)(struct igc_hw *, u16);
};
/* When to use various PHY register access functions:
*
* Func Caller
* Function Does Does When to use
* ~~~~~~~~~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* X_reg L,P,A n/a for simple PHY reg accesses
* X_reg_locked P,A L for multiple accesses of different regs
* on different pages
* X_reg_page A L,P for multiple accesses of different regs
* on the same page
*
* Where X=[read|write], L=locking, P=sets page, A=register access
*
*/
struct igc_phy_operations {
s32 (*init_params)(struct igc_hw *);
s32 (*acquire)(struct igc_hw *);
s32 (*check_reset_block)(struct igc_hw *);
s32 (*commit)(struct igc_hw *);
s32 (*force_speed_duplex)(struct igc_hw *);
s32 (*get_info)(struct igc_hw *);
s32 (*set_page)(struct igc_hw *, u16);
s32 (*read_reg)(struct igc_hw *, u32, u16 *);
s32 (*read_reg_locked)(struct igc_hw *, u32, u16 *);
s32 (*read_reg_page)(struct igc_hw *, u32, u16 *);
void (*release)(struct igc_hw *);
s32 (*reset)(struct igc_hw *);
s32 (*set_d0_lplu_state)(struct igc_hw *, bool);
s32 (*set_d3_lplu_state)(struct igc_hw *, bool);
s32 (*write_reg)(struct igc_hw *, u32, u16);
s32 (*write_reg_locked)(struct igc_hw *, u32, u16);
s32 (*write_reg_page)(struct igc_hw *, u32, u16);
void (*power_up)(struct igc_hw *);
void (*power_down)(struct igc_hw *);
};
/* Function pointers for the NVM. */
struct igc_nvm_operations {
s32 (*init_params)(struct igc_hw *);
s32 (*acquire)(struct igc_hw *);
s32 (*read)(struct igc_hw *, u16, u16, u16 *);
void (*release)(struct igc_hw *);
void (*reload)(struct igc_hw *);
s32 (*update)(struct igc_hw *);
s32 (*validate)(struct igc_hw *);
s32 (*write)(struct igc_hw *, u16, u16, u16 *);
};
struct igc_info {
s32 (*get_invariants)(struct igc_hw *hw);
struct igc_mac_operations *mac_ops;
const struct igc_phy_operations *phy_ops;
struct igc_nvm_operations *nvm_ops;
};
extern const struct igc_info igc_i225_info;
struct igc_mac_info {
struct igc_mac_operations ops;
u8 addr[ETH_ADDR_LEN];
u8 perm_addr[ETH_ADDR_LEN];
enum igc_mac_type type;
u32 mc_filter_type;
u16 current_ifs_val;
u16 ifs_max_val;
u16 ifs_min_val;
u16 ifs_ratio;
u16 ifs_step_size;
u16 mta_reg_count;
u16 uta_reg_count;
/* Maximum size of the MTA register table in all supported adapters */
#define MAX_MTA_REG 128
u32 mta_shadow[MAX_MTA_REG];
u16 rar_entry_count;
u8 forced_speed_duplex;
bool asf_firmware_present;
bool autoneg;
bool get_link_status;
u32 max_frame_size;
};
struct igc_phy_info {
struct igc_phy_operations ops;
enum igc_phy_type type;
enum igc_smart_speed smart_speed;
u32 addr;
u32 id;
u32 reset_delay_us; /* in usec */
u32 revision;
enum igc_media_type media_type;
u16 autoneg_advertised;
u16 autoneg_mask;
u8 mdix;
bool polarity_correction;
bool speed_downgraded;
bool autoneg_wait_to_complete;
};
struct igc_nvm_info {
struct igc_nvm_operations ops;
enum igc_nvm_type type;
u16 word_size;
u16 delay_usec;
u16 address_bits;
u16 opcode_bits;
u16 page_size;
};
struct igc_bus_info {
enum igc_bus_type type;
enum igc_bus_speed speed;
enum igc_bus_width width;
u16 func;
u16 pci_cmd_word;
};
struct igc_fc_info {
u32 high_water; /* Flow control high-water mark */
u32 low_water; /* Flow control low-water mark */
u16 pause_time; /* Flow control pause timer */
u16 refresh_time; /* Flow control refresh timer */
bool send_xon; /* Flow control send XON */
bool strict_ieee; /* Strict IEEE mode */
enum igc_fc_mode current_mode; /* FC mode in effect */
enum igc_fc_mode requested_mode; /* FC mode requested by caller */
};
struct igc_dev_spec_i225 {
bool eee_disable;
bool clear_semaphore_once;
u32 mtu;
};
struct igc_hw {
void *back;
u8 *hw_addr;
u8 *flash_address;
unsigned long io_base;
struct igc_mac_info mac;
struct igc_fc_info fc;
struct igc_phy_info phy;
struct igc_nvm_info nvm;
struct igc_bus_info bus;
union {
struct igc_dev_spec_i225 _i225;
} dev_spec;
u16 device_id;
u16 subsystem_vendor_id;
u16 subsystem_device_id;
u16 vendor_id;
u8 revision_id;
};
#include "igc_i225.h"
#include "igc_base.h"
/* These functions must be implemented by drivers */
s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value);
s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value);
void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value);
void igc_write_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value);
#endif

1232
sys/dev/igc/igc_i225.c Normal file

File diff suppressed because it is too large Load Diff

112
sys/dev/igc/igc_i225.h Normal file
View File

@ -0,0 +1,112 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_I225_H_
#define _IGC_I225_H_
bool igc_get_flash_presence_i225(struct igc_hw *hw);
s32 igc_update_flash_i225(struct igc_hw *hw);
s32 igc_update_nvm_checksum_i225(struct igc_hw *hw);
s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw);
s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset,
u16 words, u16 *data);
s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset,
u16 words, u16 *data);
s32 igc_set_flsw_flash_burst_counter_i225(struct igc_hw *hw,
u32 burst_counter);
s32 igc_write_erase_flash_command_i225(struct igc_hw *hw, u32 opcode,
u32 address);
s32 igc_check_for_link_i225(struct igc_hw *hw);
s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask);
void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask);
s32 igc_init_hw_i225(struct igc_hw *hw);
s32 igc_setup_copper_link_i225(struct igc_hw *hw);
s32 igc_set_d0_lplu_state_i225(struct igc_hw *hw, bool active);
s32 igc_set_d3_lplu_state_i225(struct igc_hw *hw, bool active);
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
bool adv100M);
#define ID_LED_DEFAULT_I225 ((ID_LED_OFF1_ON2 << 8) | \
(ID_LED_DEF1_DEF2 << 4) | \
(ID_LED_OFF1_OFF2))
#define ID_LED_DEFAULT_I225_SERDES ((ID_LED_DEF1_DEF2 << 8) | \
(ID_LED_DEF1_DEF2 << 4) | \
(ID_LED_OFF1_ON2))
/* NVM offset defaults for I225 devices */
#define NVM_INIT_CTRL_2_DEFAULT_I225 0X7243
#define NVM_INIT_CTRL_4_DEFAULT_I225 0x00C1
#define NVM_LED_1_CFG_DEFAULT_I225 0x0184
#define NVM_LED_0_2_CFG_DEFAULT_I225 0x200C
#define IGC_MRQC_ENABLE_RSS_4Q 0x00000002
#define IGC_MRQC_ENABLE_VMDQ 0x00000003
#define IGC_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005
#define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
#define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
#define IGC_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000
#define IGC_I225_SHADOW_RAM_SIZE 4096
#define IGC_I225_ERASE_CMD_OPCODE 0x02000000
#define IGC_I225_WRITE_CMD_OPCODE 0x01000000
#define IGC_FLSWCTL_DONE 0x40000000
#define IGC_FLSWCTL_CMDV 0x10000000
/* SRRCTL bit definitions */
#define IGC_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
#define IGC_SRRCTL_DESCTYPE_LEGACY 0x00000000
#define IGC_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
#define IGC_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
#define IGC_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000
#define IGC_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
#define IGC_SRRCTL_DESCTYPE_MASK 0x0E000000
#define IGC_SRRCTL_DROP_EN 0x80000000
#define IGC_SRRCTL_BSIZEPKT_MASK 0x0000007F
#define IGC_SRRCTL_BSIZEHDR_MASK 0x00003F00
#define IGC_RXDADV_RSSTYPE_MASK 0x0000000F
#define IGC_RXDADV_RSSTYPE_SHIFT 12
#define IGC_RXDADV_HDRBUFLEN_MASK 0x7FE0
#define IGC_RXDADV_HDRBUFLEN_SHIFT 5
#define IGC_RXDADV_SPLITHEADER_EN 0x00001000
#define IGC_RXDADV_SPH 0x8000
#define IGC_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
#define IGC_RXDADV_ERR_HBO 0x00800000
/* RSS Hash results */
#define IGC_RXDADV_RSSTYPE_NONE 0x00000000
#define IGC_RXDADV_RSSTYPE_IPV4_TCP 0x00000001
#define IGC_RXDADV_RSSTYPE_IPV4 0x00000002
#define IGC_RXDADV_RSSTYPE_IPV6_TCP 0x00000003
#define IGC_RXDADV_RSSTYPE_IPV6_EX 0x00000004
#define IGC_RXDADV_RSSTYPE_IPV6 0x00000005
#define IGC_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
#define IGC_RXDADV_RSSTYPE_IPV4_UDP 0x00000007
#define IGC_RXDADV_RSSTYPE_IPV6_UDP 0x00000008
#define IGC_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
/* RSS Packet Types as indicated in the receive descriptor */
#define IGC_RXDADV_PKTTYPE_ILMASK 0x000000F0
#define IGC_RXDADV_PKTTYPE_TLMASK 0x00000F00
#define IGC_RXDADV_PKTTYPE_NONE 0x00000000
#define IGC_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */
#define IGC_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPV4 hdr + extensions */
#define IGC_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPV6 hdr present */
#define IGC_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPV6 hdr + extensions */
#define IGC_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */
#define IGC_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */
#define IGC_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */
#define IGC_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */
#define IGC_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */
#define IGC_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */
#define IGC_RXDADV_PKTTYPE_LINKSEC 0x00004000 /* LinkSec Encap */
#define IGC_RXDADV_PKTTYPE_ETQF 0x00008000 /* PKTTYPE is ETQF index */
#define IGC_RXDADV_PKTTYPE_ETQF_MASK 0x00000070 /* ETQF has 8 indices */
#define IGC_RXDADV_PKTTYPE_ETQF_SHIFT 4 /* Right-shift 4 bits */
#endif

1050
sys/dev/igc/igc_mac.c Normal file

File diff suppressed because it is too large Load Diff

48
sys/dev/igc/igc_mac.h Normal file
View File

@ -0,0 +1,48 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_MAC_H_
#define _IGC_MAC_H_
void igc_init_mac_ops_generic(struct igc_hw *hw);
void igc_null_mac_generic(struct igc_hw *hw);
s32 igc_null_ops_generic(struct igc_hw *hw);
s32 igc_null_link_info(struct igc_hw *hw, u16 *s, u16 *d);
bool igc_null_mng_mode(struct igc_hw *hw);
void igc_null_update_mc(struct igc_hw *hw, u8 *h, u32 a);
void igc_null_write_vfta(struct igc_hw *hw, u32 a, u32 b);
int igc_null_rar_set(struct igc_hw *hw, u8 *h, u32 a);
s32 igc_check_for_copper_link_generic(struct igc_hw *hw);
s32 igc_config_fc_after_link_up_generic(struct igc_hw *hw);
s32 igc_disable_pcie_master_generic(struct igc_hw *hw);
s32 igc_force_mac_fc_generic(struct igc_hw *hw);
s32 igc_get_auto_rd_done_generic(struct igc_hw *hw);
s32 igc_get_bus_info_pcie_generic(struct igc_hw *hw);
void igc_set_lan_id_single_port(struct igc_hw *hw);
s32 igc_get_hw_semaphore_generic(struct igc_hw *hw);
s32 igc_get_speed_and_duplex_copper_generic(struct igc_hw *hw, u16 *speed,
u16 *duplex);
void igc_update_mc_addr_list_generic(struct igc_hw *hw,
u8 *mc_addr_list, u32 mc_addr_count);
int igc_rar_set_generic(struct igc_hw *hw, u8 *addr, u32 index);
s32 igc_set_fc_watermarks_generic(struct igc_hw *hw);
s32 igc_setup_link_generic(struct igc_hw *hw);
s32 igc_validate_mdi_setting_crossover_generic(struct igc_hw *hw);
u32 igc_hash_mc_addr_generic(struct igc_hw *hw, u8 *mc_addr);
void igc_clear_hw_cntrs_base_generic(struct igc_hw *hw);
void igc_clear_vfta_generic(struct igc_hw *hw);
void igc_init_rx_addrs_generic(struct igc_hw *hw, u16 rar_count);
void igc_pcix_mmrbc_workaround_generic(struct igc_hw *hw);
void igc_put_hw_semaphore_generic(struct igc_hw *hw);
s32 igc_check_alt_mac_addr_generic(struct igc_hw *hw);
void igc_set_pcie_no_snoop_generic(struct igc_hw *hw, u32 no_snoop);
void igc_write_vfta_generic(struct igc_hw *hw, u32 offset, u32 value);
#endif

721
sys/dev/igc/igc_nvm.c Normal file
View File

@ -0,0 +1,721 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "igc_api.h"
static void igc_reload_nvm_generic(struct igc_hw *hw);
/**
* igc_init_nvm_ops_generic - Initialize NVM function pointers
* @hw: pointer to the HW structure
*
* Setups up the function pointers to no-op functions
**/
void igc_init_nvm_ops_generic(struct igc_hw *hw)
{
struct igc_nvm_info *nvm = &hw->nvm;
DEBUGFUNC("igc_init_nvm_ops_generic");
/* Initialize function pointers */
nvm->ops.init_params = igc_null_ops_generic;
nvm->ops.acquire = igc_null_ops_generic;
nvm->ops.read = igc_null_read_nvm;
nvm->ops.release = igc_null_nvm_generic;
nvm->ops.reload = igc_reload_nvm_generic;
nvm->ops.update = igc_null_ops_generic;
nvm->ops.validate = igc_null_ops_generic;
nvm->ops.write = igc_null_write_nvm;
}
/**
* igc_null_nvm_read - No-op function, return 0
* @hw: pointer to the HW structure
* @a: dummy variable
* @b: dummy variable
* @c: dummy variable
**/
s32 igc_null_read_nvm(struct igc_hw IGC_UNUSEDARG *hw,
u16 IGC_UNUSEDARG a, u16 IGC_UNUSEDARG b,
u16 IGC_UNUSEDARG *c)
{
DEBUGFUNC("igc_null_read_nvm");
return IGC_SUCCESS;
}
/**
* igc_null_nvm_generic - No-op function, return void
* @hw: pointer to the HW structure
**/
void igc_null_nvm_generic(struct igc_hw IGC_UNUSEDARG *hw)
{
DEBUGFUNC("igc_null_nvm_generic");
return;
}
/**
* igc_null_write_nvm - No-op function, return 0
* @hw: pointer to the HW structure
* @a: dummy variable
* @b: dummy variable
* @c: dummy variable
**/
s32 igc_null_write_nvm(struct igc_hw IGC_UNUSEDARG *hw,
u16 IGC_UNUSEDARG a, u16 IGC_UNUSEDARG b,
u16 IGC_UNUSEDARG *c)
{
DEBUGFUNC("igc_null_write_nvm");
return IGC_SUCCESS;
}
/**
* igc_raise_eec_clk - Raise EEPROM clock
* @hw: pointer to the HW structure
* @eecd: pointer to the EEPROM
*
* Enable/Raise the EEPROM clock bit.
**/
static void igc_raise_eec_clk(struct igc_hw *hw, u32 *eecd)
{
*eecd = *eecd | IGC_EECD_SK;
IGC_WRITE_REG(hw, IGC_EECD, *eecd);
IGC_WRITE_FLUSH(hw);
usec_delay(hw->nvm.delay_usec);
}
/**
* igc_lower_eec_clk - Lower EEPROM clock
* @hw: pointer to the HW structure
* @eecd: pointer to the EEPROM
*
* Clear/Lower the EEPROM clock bit.
**/
static void igc_lower_eec_clk(struct igc_hw *hw, u32 *eecd)
{
*eecd = *eecd & ~IGC_EECD_SK;
IGC_WRITE_REG(hw, IGC_EECD, *eecd);
IGC_WRITE_FLUSH(hw);
usec_delay(hw->nvm.delay_usec);
}
/**
* igc_shift_out_eec_bits - Shift data bits our to the EEPROM
* @hw: pointer to the HW structure
* @data: data to send to the EEPROM
* @count: number of bits to shift out
*
* We need to shift 'count' bits out to the EEPROM. So, the value in the
* "data" parameter will be shifted out to the EEPROM one bit at a time.
* In order to do this, "data" must be broken down into bits.
**/
static void igc_shift_out_eec_bits(struct igc_hw *hw, u16 data, u16 count)
{
struct igc_nvm_info *nvm = &hw->nvm;
u32 eecd = IGC_READ_REG(hw, IGC_EECD);
u32 mask;
DEBUGFUNC("igc_shift_out_eec_bits");
mask = 0x01 << (count - 1);
if (nvm->type == igc_nvm_eeprom_spi)
eecd |= IGC_EECD_DO;
do {
eecd &= ~IGC_EECD_DI;
if (data & mask)
eecd |= IGC_EECD_DI;
IGC_WRITE_REG(hw, IGC_EECD, eecd);
IGC_WRITE_FLUSH(hw);
usec_delay(nvm->delay_usec);
igc_raise_eec_clk(hw, &eecd);
igc_lower_eec_clk(hw, &eecd);
mask >>= 1;
} while (mask);
eecd &= ~IGC_EECD_DI;
IGC_WRITE_REG(hw, IGC_EECD, eecd);
}
/**
* igc_shift_in_eec_bits - Shift data bits in from the EEPROM
* @hw: pointer to the HW structure
* @count: number of bits to shift in
*
* In order to read a register from the EEPROM, we need to shift 'count' bits
* in from the EEPROM. Bits are "shifted in" by raising the clock input to
* the EEPROM (setting the SK bit), and then reading the value of the data out
* "DO" bit. During this "shifting in" process the data in "DI" bit should
* always be clear.
**/
static u16 igc_shift_in_eec_bits(struct igc_hw *hw, u16 count)
{
u32 eecd;
u32 i;
u16 data;
DEBUGFUNC("igc_shift_in_eec_bits");
eecd = IGC_READ_REG(hw, IGC_EECD);
eecd &= ~(IGC_EECD_DO | IGC_EECD_DI);
data = 0;
for (i = 0; i < count; i++) {
data <<= 1;
igc_raise_eec_clk(hw, &eecd);
eecd = IGC_READ_REG(hw, IGC_EECD);
eecd &= ~IGC_EECD_DI;
if (eecd & IGC_EECD_DO)
data |= 1;
igc_lower_eec_clk(hw, &eecd);
}
return data;
}
/**
* igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion
* @hw: pointer to the HW structure
* @ee_reg: EEPROM flag for polling
*
* Polls the EEPROM status bit for either read or write completion based
* upon the value of 'ee_reg'.
**/
s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
{
u32 attempts = 100000;
u32 i, reg = 0;
DEBUGFUNC("igc_poll_eerd_eewr_done");
for (i = 0; i < attempts; i++) {
if (ee_reg == IGC_NVM_POLL_READ)
reg = IGC_READ_REG(hw, IGC_EERD);
else
reg = IGC_READ_REG(hw, IGC_EEWR);
if (reg & IGC_NVM_RW_REG_DONE)
return IGC_SUCCESS;
usec_delay(5);
}
return -IGC_ERR_NVM;
}
/**
* igc_acquire_nvm_generic - Generic request for access to EEPROM
* @hw: pointer to the HW structure
*
* Set the EEPROM access request bit and wait for EEPROM access grant bit.
* Return successful if access grant bit set, else clear the request for
* EEPROM access and return -IGC_ERR_NVM (-1).
**/
s32 igc_acquire_nvm_generic(struct igc_hw *hw)
{
u32 eecd = IGC_READ_REG(hw, IGC_EECD);
s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
DEBUGFUNC("igc_acquire_nvm_generic");
IGC_WRITE_REG(hw, IGC_EECD, eecd | IGC_EECD_REQ);
eecd = IGC_READ_REG(hw, IGC_EECD);
while (timeout) {
if (eecd & IGC_EECD_GNT)
break;
usec_delay(5);
eecd = IGC_READ_REG(hw, IGC_EECD);
timeout--;
}
if (!timeout) {
eecd &= ~IGC_EECD_REQ;
IGC_WRITE_REG(hw, IGC_EECD, eecd);
DEBUGOUT("Could not acquire NVM grant\n");
return -IGC_ERR_NVM;
}
return IGC_SUCCESS;
}
/**
* igc_standby_nvm - Return EEPROM to standby state
* @hw: pointer to the HW structure
*
* Return the EEPROM to a standby state.
**/
static void igc_standby_nvm(struct igc_hw *hw)
{
struct igc_nvm_info *nvm = &hw->nvm;
u32 eecd = IGC_READ_REG(hw, IGC_EECD);
DEBUGFUNC("igc_standby_nvm");
if (nvm->type == igc_nvm_eeprom_spi) {
/* Toggle CS to flush commands */
eecd |= IGC_EECD_CS;
IGC_WRITE_REG(hw, IGC_EECD, eecd);
IGC_WRITE_FLUSH(hw);
usec_delay(nvm->delay_usec);
eecd &= ~IGC_EECD_CS;
IGC_WRITE_REG(hw, IGC_EECD, eecd);
IGC_WRITE_FLUSH(hw);
usec_delay(nvm->delay_usec);
}
}
/**
* igc_stop_nvm - Terminate EEPROM command
* @hw: pointer to the HW structure
*
* Terminates the current command by inverting the EEPROM's chip select pin.
**/
static void igc_stop_nvm(struct igc_hw *hw)
{
u32 eecd;
DEBUGFUNC("igc_stop_nvm");
eecd = IGC_READ_REG(hw, IGC_EECD);
if (hw->nvm.type == igc_nvm_eeprom_spi) {
/* Pull CS high */
eecd |= IGC_EECD_CS;
igc_lower_eec_clk(hw, &eecd);
}
}
/**
* igc_release_nvm_generic - Release exclusive access to EEPROM
* @hw: pointer to the HW structure
*
* Stop any current commands to the EEPROM and clear the EEPROM request bit.
**/
void igc_release_nvm_generic(struct igc_hw *hw)
{
u32 eecd;
DEBUGFUNC("igc_release_nvm_generic");
igc_stop_nvm(hw);
eecd = IGC_READ_REG(hw, IGC_EECD);
eecd &= ~IGC_EECD_REQ;
IGC_WRITE_REG(hw, IGC_EECD, eecd);
}
/**
* igc_ready_nvm_eeprom - Prepares EEPROM for read/write
* @hw: pointer to the HW structure
*
* Setups the EEPROM for reading and writing.
**/
static s32 igc_ready_nvm_eeprom(struct igc_hw *hw)
{
struct igc_nvm_info *nvm = &hw->nvm;
u32 eecd = IGC_READ_REG(hw, IGC_EECD);
u8 spi_stat_reg;
DEBUGFUNC("igc_ready_nvm_eeprom");
if (nvm->type == igc_nvm_eeprom_spi) {
u16 timeout = NVM_MAX_RETRY_SPI;
/* Clear SK and CS */
eecd &= ~(IGC_EECD_CS | IGC_EECD_SK);
IGC_WRITE_REG(hw, IGC_EECD, eecd);
IGC_WRITE_FLUSH(hw);
usec_delay(1);
/* Read "Status Register" repeatedly until the LSB is cleared.
* The EEPROM will signal that the command has been completed
* by clearing bit 0 of the internal status register. If it's
* not cleared within 'timeout', then error out.
*/
while (timeout) {
igc_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
hw->nvm.opcode_bits);
spi_stat_reg = (u8)igc_shift_in_eec_bits(hw, 8);
if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
break;
usec_delay(5);
igc_standby_nvm(hw);
timeout--;
}
if (!timeout) {
DEBUGOUT("SPI NVM Status error\n");
return -IGC_ERR_NVM;
}
}
return IGC_SUCCESS;
}
/**
* igc_read_nvm_eerd - Reads EEPROM using EERD register
* @hw: pointer to the HW structure
* @offset: offset of word in the EEPROM to read
* @words: number of words to read
* @data: word read from the EEPROM
*
* Reads a 16 bit word from the EEPROM using the EERD register.
**/
s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
{
struct igc_nvm_info *nvm = &hw->nvm;
u32 i, eerd = 0;
s32 ret_val = IGC_SUCCESS;
DEBUGFUNC("igc_read_nvm_eerd");
/* A check for invalid values: offset too large, too many words,
* too many words for the offset, and not enough words.
*/
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
(words == 0)) {
DEBUGOUT("nvm parameter(s) out of bounds\n");
return -IGC_ERR_NVM;
}
for (i = 0; i < words; i++) {
eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
IGC_NVM_RW_REG_START;
IGC_WRITE_REG(hw, IGC_EERD, eerd);
ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
if (ret_val)
break;
data[i] = (IGC_READ_REG(hw, IGC_EERD) >>
IGC_NVM_RW_REG_DATA);
}
if (ret_val)
DEBUGOUT1("NVM read error: %d\n", ret_val);
return ret_val;
}
/**
* igc_write_nvm_spi - Write to EEPROM using SPI
* @hw: pointer to the HW structure
* @offset: offset within the EEPROM to be written to
* @words: number of words to write
* @data: 16 bit word(s) to be written to the EEPROM
*
* Writes data to EEPROM at offset using SPI interface.
*
* If igc_update_nvm_checksum is not called after this function , the
* EEPROM will most likely contain an invalid checksum.
**/
s32 igc_write_nvm_spi(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
{
struct igc_nvm_info *nvm = &hw->nvm;
s32 ret_val = -IGC_ERR_NVM;
u16 widx = 0;
DEBUGFUNC("igc_write_nvm_spi");
/* A check for invalid values: offset too large, too many words,
* and not enough words.
*/
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
(words == 0)) {
DEBUGOUT("nvm parameter(s) out of bounds\n");
return -IGC_ERR_NVM;
}
while (widx < words) {
u8 write_opcode = NVM_WRITE_OPCODE_SPI;
ret_val = nvm->ops.acquire(hw);
if (ret_val)
return ret_val;
ret_val = igc_ready_nvm_eeprom(hw);
if (ret_val) {
nvm->ops.release(hw);
return ret_val;
}
igc_standby_nvm(hw);
/* Send the WRITE ENABLE command (8 bit opcode) */
igc_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
nvm->opcode_bits);
igc_standby_nvm(hw);
/* Some SPI eeproms use the 8th address bit embedded in the
* opcode
*/
if ((nvm->address_bits == 8) && (offset >= 128))
write_opcode |= NVM_A8_OPCODE_SPI;
/* Send the Write command (8-bit opcode + addr) */
igc_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
igc_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
nvm->address_bits);
/* Loop to allow for up to whole page write of eeprom */
while (widx < words) {
u16 word_out = data[widx];
word_out = (word_out >> 8) | (word_out << 8);
igc_shift_out_eec_bits(hw, word_out, 16);
widx++;
if ((((offset + widx) * 2) % nvm->page_size) == 0) {
igc_standby_nvm(hw);
break;
}
}
msec_delay(10);
nvm->ops.release(hw);
}
return ret_val;
}
/**
* igc_read_pba_string_generic - Read device part number
* @hw: pointer to the HW structure
* @pba_num: pointer to device part number
* @pba_num_size: size of part number buffer
*
* Reads the product board assembly (PBA) number from the EEPROM and stores
* the value in pba_num.
**/
s32 igc_read_pba_string_generic(struct igc_hw *hw, u8 *pba_num,
u32 pba_num_size)
{
s32 ret_val;
u16 nvm_data;
u16 pba_ptr;
u16 offset;
u16 length;
DEBUGFUNC("igc_read_pba_string_generic");
if (pba_num == NULL) {
DEBUGOUT("PBA string buffer was null\n");
return -IGC_ERR_INVALID_ARGUMENT;
}
ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
/* if nvm_data is not ptr guard the PBA must be in legacy format which
* means pba_ptr is actually our second data word for the PBA number
* and we can decode it into an ascii string
*/
if (nvm_data != NVM_PBA_PTR_GUARD) {
DEBUGOUT("NVM PBA number is not stored as string\n");
/* make sure callers buffer is big enough to store the PBA */
if (pba_num_size < IGC_PBANUM_LENGTH) {
DEBUGOUT("PBA string buffer too small\n");
return IGC_ERR_NO_SPACE;
}
/* extract hex string from data and pba_ptr */
pba_num[0] = (nvm_data >> 12) & 0xF;
pba_num[1] = (nvm_data >> 8) & 0xF;
pba_num[2] = (nvm_data >> 4) & 0xF;
pba_num[3] = nvm_data & 0xF;
pba_num[4] = (pba_ptr >> 12) & 0xF;
pba_num[5] = (pba_ptr >> 8) & 0xF;
pba_num[6] = '-';
pba_num[7] = 0;
pba_num[8] = (pba_ptr >> 4) & 0xF;
pba_num[9] = pba_ptr & 0xF;
/* put a null character on the end of our string */
pba_num[10] = '\0';
/* switch all the data but the '-' to hex char */
for (offset = 0; offset < 10; offset++) {
if (pba_num[offset] < 0xA)
pba_num[offset] += '0';
else if (pba_num[offset] < 0x10)
pba_num[offset] += 'A' - 0xA;
}
return IGC_SUCCESS;
}
ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
if (length == 0xFFFF || length == 0) {
DEBUGOUT("NVM PBA number section invalid length\n");
return -IGC_ERR_NVM_PBA_SECTION;
}
/* check if pba_num buffer is big enough */
if (pba_num_size < (((u32)length * 2) - 1)) {
DEBUGOUT("PBA string buffer too small\n");
return -IGC_ERR_NO_SPACE;
}
/* trim pba length from start of string */
pba_ptr++;
length--;
for (offset = 0; offset < length; offset++) {
ret_val = hw->nvm.ops.read(hw, pba_ptr + offset, 1, &nvm_data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
pba_num[offset * 2] = (u8)(nvm_data >> 8);
pba_num[(offset * 2) + 1] = (u8)(nvm_data & 0xFF);
}
pba_num[offset * 2] = '\0';
return IGC_SUCCESS;
}
/**
* igc_read_mac_addr_generic - Read device MAC address
* @hw: pointer to the HW structure
*
* Reads the device MAC address from the EEPROM and stores the value.
* Since devices with two ports use the same EEPROM, we increment the
* last bit in the MAC address for the second port.
**/
s32 igc_read_mac_addr_generic(struct igc_hw *hw)
{
u32 rar_high;
u32 rar_low;
u16 i;
rar_high = IGC_READ_REG(hw, IGC_RAH(0));
rar_low = IGC_READ_REG(hw, IGC_RAL(0));
for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++)
hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++)
hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
for (i = 0; i < ETH_ADDR_LEN; i++)
hw->mac.addr[i] = hw->mac.perm_addr[i];
return IGC_SUCCESS;
}
/**
* igc_validate_nvm_checksum_generic - Validate EEPROM checksum
* @hw: pointer to the HW structure
*
* Calculates the EEPROM checksum by reading/adding each word of the EEPROM
* and then verifies that the sum of the EEPROM is equal to 0xBABA.
**/
s32 igc_validate_nvm_checksum_generic(struct igc_hw *hw)
{
s32 ret_val;
u16 checksum = 0;
u16 i, nvm_data;
DEBUGFUNC("igc_validate_nvm_checksum_generic");
for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
checksum += nvm_data;
}
if (checksum != (u16) NVM_SUM) {
DEBUGOUT("NVM Checksum Invalid\n");
return -IGC_ERR_NVM;
}
return IGC_SUCCESS;
}
/**
* igc_update_nvm_checksum_generic - Update EEPROM checksum
* @hw: pointer to the HW structure
*
* Updates the EEPROM checksum by reading/adding each word of the EEPROM
* up to the checksum. Then calculates the EEPROM checksum and writes the
* value to the EEPROM.
**/
s32 igc_update_nvm_checksum_generic(struct igc_hw *hw)
{
s32 ret_val;
u16 checksum = 0;
u16 i, nvm_data;
DEBUGFUNC("igc_update_nvm_checksum");
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
if (ret_val) {
DEBUGOUT("NVM Read Error while updating checksum.\n");
return ret_val;
}
checksum += nvm_data;
}
checksum = (u16) NVM_SUM - checksum;
ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
if (ret_val)
DEBUGOUT("NVM Write Error while updating checksum.\n");
return ret_val;
}
/**
* igc_reload_nvm_generic - Reloads EEPROM
* @hw: pointer to the HW structure
*
* Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
* extended control register.
**/
static void igc_reload_nvm_generic(struct igc_hw *hw)
{
u32 ctrl_ext;
DEBUGFUNC("igc_reload_nvm_generic");
usec_delay(10);
ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT);
ctrl_ext |= IGC_CTRL_EXT_EE_RST;
IGC_WRITE_REG(hw, IGC_CTRL_EXT, ctrl_ext);
IGC_WRITE_FLUSH(hw);
}

32
sys/dev/igc/igc_nvm.h Normal file
View File

@ -0,0 +1,32 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_NVM_H_
#define _IGC_NVM_H_
void igc_init_nvm_ops_generic(struct igc_hw *hw);
s32 igc_null_read_nvm(struct igc_hw *hw, u16 a, u16 b, u16 *c);
void igc_null_nvm_generic(struct igc_hw *hw);
s32 igc_null_led_default(struct igc_hw *hw, u16 *data);
s32 igc_null_write_nvm(struct igc_hw *hw, u16 a, u16 b, u16 *c);
s32 igc_acquire_nvm_generic(struct igc_hw *hw);
s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg);
s32 igc_read_mac_addr_generic(struct igc_hw *hw);
s32 igc_read_pba_string_generic(struct igc_hw *hw, u8 *pba_num,
u32 pba_num_size);
s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words,
u16 *data);
s32 igc_valid_led_default_generic(struct igc_hw *hw, u16 *data);
s32 igc_validate_nvm_checksum_generic(struct igc_hw *hw);
s32 igc_write_nvm_spi(struct igc_hw *hw, u16 offset, u16 words,
u16 *data);
s32 igc_update_nvm_checksum_generic(struct igc_hw *hw);
void igc_release_nvm_generic(struct igc_hw *hw);
#endif

133
sys/dev/igc/igc_osdep.h Normal file
View File

@ -0,0 +1,133 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _FREEBSD_OS_H_
#define _FREEBSD_OS_H_
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/iflib.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/clock.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#define usec_delay(x) DELAY(x)
#define usec_delay_irq(x) usec_delay(x)
#define msec_delay(x) DELAY(1000*(x))
#define msec_delay_irq(x) DELAY(1000*(x))
/* Enable/disable debugging statements in shared code */
#define DBG 0
#define DEBUGOUT(...) \
do { if (DBG) printf(__VA_ARGS__); } while (0)
#define DEBUGOUT1(...) DEBUGOUT(__VA_ARGS__)
#define DEBUGOUT2(...) DEBUGOUT(__VA_ARGS__)
#define DEBUGOUT3(...) DEBUGOUT(__VA_ARGS__)
#define DEBUGOUT7(...) DEBUGOUT(__VA_ARGS__)
#define DEBUGFUNC(F) DEBUGOUT(F "\n")
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef int64_t s64;
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
#define __le16 u16
#define __le32 u32
#define __le64 u64
struct igc_osdep
{
bus_space_tag_t mem_bus_space_tag;
bus_space_handle_t mem_bus_space_handle;
bus_space_tag_t io_bus_space_tag;
bus_space_handle_t io_bus_space_handle;
bus_space_tag_t flash_bus_space_tag;
bus_space_handle_t flash_bus_space_handle;
device_t dev;
if_ctx_t ctx;
};
#define IGC_REGISTER(hw, reg) reg
#define IGC_WRITE_FLUSH(a) IGC_READ_REG(a, IGC_STATUS)
/* Read from an absolute offset in the adapter's memory space */
#define IGC_READ_OFFSET(hw, offset) \
bus_space_read_4(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, offset)
/* Write to an absolute offset in the adapter's memory space */
#define IGC_WRITE_OFFSET(hw, offset, value) \
bus_space_write_4(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, offset, value)
/* Register READ/WRITE macros */
#define IGC_READ_REG(hw, reg) \
bus_space_read_4(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, \
IGC_REGISTER(hw, reg))
#define IGC_WRITE_REG(hw, reg, value) \
bus_space_write_4(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, \
IGC_REGISTER(hw, reg), value)
#define IGC_READ_REG_ARRAY(hw, reg, index) \
bus_space_read_4(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, \
IGC_REGISTER(hw, reg) + ((index)<< 2))
#define IGC_WRITE_REG_ARRAY(hw, reg, index, value) \
bus_space_write_4(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, \
IGC_REGISTER(hw, reg) + ((index)<< 2), value)
#define IGC_READ_REG_ARRAY_DWORD IGC_READ_REG_ARRAY
#define IGC_WRITE_REG_ARRAY_DWORD IGC_WRITE_REG_ARRAY
#define IGC_READ_REG_ARRAY_BYTE(hw, reg, index) \
bus_space_read_1(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, \
IGC_REGISTER(hw, reg) + index)
#define IGC_WRITE_REG_ARRAY_BYTE(hw, reg, index, value) \
bus_space_write_1(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, \
IGC_REGISTER(hw, reg) + index, value)
#define IGC_WRITE_REG_ARRAY_WORD(hw, reg, index, value) \
bus_space_write_2(((struct igc_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct igc_osdep *)(hw)->back)->mem_bus_space_handle, \
IGC_REGISTER(hw, reg) + (index << 1), value)
#endif /* _FREEBSD_OS_H_ */

1109
sys/dev/igc/igc_phy.c Normal file

File diff suppressed because it is too large Load Diff

134
sys/dev/igc/igc_phy.h Normal file
View File

@ -0,0 +1,134 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_PHY_H_
#define _IGC_PHY_H_
void igc_init_phy_ops_generic(struct igc_hw *hw);
s32 igc_null_read_reg(struct igc_hw *hw, u32 offset, u16 *data);
void igc_null_phy_generic(struct igc_hw *hw);
s32 igc_null_lplu_state(struct igc_hw *hw, bool active);
s32 igc_null_write_reg(struct igc_hw *hw, u32 offset, u16 data);
s32 igc_null_set_page(struct igc_hw *hw, u16 data);
s32 igc_check_downshift_generic(struct igc_hw *hw);
s32 igc_check_reset_block_generic(struct igc_hw *hw);
s32 igc_get_phy_id(struct igc_hw *hw);
s32 igc_phy_sw_reset_generic(struct igc_hw *hw);
void igc_phy_force_speed_duplex_setup(struct igc_hw *hw, u16 *phy_ctrl);
s32 igc_phy_hw_reset_generic(struct igc_hw *hw);
s32 igc_phy_reset_dsp_generic(struct igc_hw *hw);
s32 igc_set_d3_lplu_state_generic(struct igc_hw *hw, bool active);
s32 igc_setup_copper_link_generic(struct igc_hw *hw);
s32 igc_phy_has_link_generic(struct igc_hw *hw, u32 iterations,
u32 usec_interval, bool *success);
enum igc_phy_type igc_get_phy_type_from_id(u32 phy_id);
s32 igc_determine_phy_address(struct igc_hw *hw);
s32 igc_enable_phy_wakeup_reg_access_bm(struct igc_hw *hw, u16 *phy_reg);
s32 igc_disable_phy_wakeup_reg_access_bm(struct igc_hw *hw, u16 *phy_reg);
void igc_power_up_phy_copper(struct igc_hw *hw);
void igc_power_down_phy_copper(struct igc_hw *hw);
s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data);
s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data);
s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr, u8 dev_addr,
u16 *data);
s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr, u8 dev_addr,
u16 data);
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data);
#define IGC_MAX_PHY_ADDR 8
/* IGP01IGC Specific Registers */
#define IGP01IGC_PHY_PORT_CONFIG 0x10 /* Port Config */
#define IGP01IGC_PHY_PORT_STATUS 0x11 /* Status */
#define IGP01IGC_PHY_PORT_CTRL 0x12 /* Control */
#define IGP01IGC_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
#define IGP02IGC_PHY_POWER_MGMT 0x19 /* Power Management */
#define IGP01IGC_PHY_PAGE_SELECT 0x1F /* Page Select */
#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */
#define IGP_PAGE_SHIFT 5
#define PHY_REG_MASK 0x1F
#define IGC_I225_PHPM 0x0E14 /* I225 PHY Power Management */
#define IGC_I225_PHPM_DIS_1000_D3 0x0008 /* Disable 1G in D3 */
#define IGC_I225_PHPM_LINK_ENERGY 0x0010 /* Link Energy Detect */
#define IGC_I225_PHPM_GO_LINKD 0x0020 /* Go Link Disconnect */
#define IGC_I225_PHPM_DIS_1000 0x0040 /* Disable 1G globally */
#define IGC_I225_PHPM_SPD_B2B_EN 0x0080 /* Smart Power Down Back2Back */
#define IGC_I225_PHPM_RST_COMPL 0x0100 /* PHY Reset Completed */
#define IGC_I225_PHPM_DIS_100_D3 0x0200 /* Disable 100M in D3 */
#define IGC_I225_PHPM_ULP 0x0400 /* Ultra Low-Power Mode */
#define IGC_I225_PHPM_DIS_2500 0x0800 /* Disable 2.5G globally */
#define IGC_I225_PHPM_DIS_2500_D3 0x1000 /* Disable 2.5G in D3 */
/* GPY211 - I225 defines */
#define GPY_MMD_MASK 0xFFFF0000
#define GPY_MMD_SHIFT 16
#define GPY_REG_MASK 0x0000FFFF
#define IGP01IGC_PHY_PCS_INIT_REG 0x00B4
#define IGP01IGC_PHY_POLARITY_MASK 0x0078
#define IGP01IGC_PSCR_AUTO_MDIX 0x1000
#define IGP01IGC_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
#define IGP01IGC_PSCFR_SMART_SPEED 0x0080
#define IGP02IGC_PM_SPD 0x0001 /* Smart Power Down */
#define IGP02IGC_PM_D0_LPLU 0x0002 /* For D0a states */
#define IGP02IGC_PM_D3_LPLU 0x0004 /* For all other states */
#define IGP01IGC_PLHR_SS_DOWNGRADE 0x8000
#define IGP01IGC_PSSR_POLARITY_REVERSED 0x0002
#define IGP01IGC_PSSR_MDIX 0x0800
#define IGP01IGC_PSSR_SPEED_MASK 0xC000
#define IGP01IGC_PSSR_SPEED_1000MBPS 0xC000
#define IGP02IGC_PHY_CHANNEL_NUM 4
#define IGP02IGC_PHY_AGC_A 0x11B1
#define IGP02IGC_PHY_AGC_B 0x12B1
#define IGP02IGC_PHY_AGC_C 0x14B1
#define IGP02IGC_PHY_AGC_D 0x18B1
#define IGP02IGC_AGC_LENGTH_SHIFT 9 /* Course=15:13, Fine=12:9 */
#define IGP02IGC_AGC_LENGTH_MASK 0x7F
#define IGP02IGC_AGC_RANGE 15
#define IGC_CABLE_LENGTH_UNDEFINED 0xFF
#define IGC_KMRNCTRLSTA_OFFSET 0x001F0000
#define IGC_KMRNCTRLSTA_OFFSET_SHIFT 16
#define IGC_KMRNCTRLSTA_REN 0x00200000
#define IGC_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
#define IGC_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */
#define IGC_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */
#define IGC_KMRNCTRLSTA_IBIST_DISABLE 0x0200 /* Kumeran IBIST Disable */
#define IGC_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Ctrl */
#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Ctrl */
#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
/* IFE PHY Extended Status Control */
#define IFE_PESC_POLARITY_REVERSED 0x0100
/* IFE PHY Special Control */
#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010
#define IFE_PSC_FORCE_POLARITY 0x0020
/* IFE PHY Special Control and LED Control */
#define IFE_PSCL_PROBE_MODE 0x0020
#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
/* IFE PHY MDIX Control */
#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */
#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto, 0=disable */
#endif

424
sys/dev/igc/igc_regs.h Normal file
View File

@ -0,0 +1,424 @@
/*-
* Copyright 2021 Intel Corp
* Copyright 2021 Rubicon Communications, LLC (Netgate)
* SPDX-License-Identifier: BSD-3-Clause
*
* $FreeBSD$
*/
#ifndef _IGC_REGS_H_
#define _IGC_REGS_H_
/* General Register Descriptions */
#define IGC_CTRL 0x00000 /* Device Control - RW */
#define IGC_STATUS 0x00008 /* Device Status - RO */
#define IGC_EECD 0x00010 /* EEPROM/Flash Control - RW */
/* NVM Register Descriptions */
#define IGC_EERD 0x12014 /* EEprom mode read - RW */
#define IGC_EEWR 0x12018 /* EEprom mode write - RW */
#define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define IGC_MDIC 0x00020 /* MDI Control - RW */
#define IGC_MDICNFG 0x00E04 /* MDI Config - RW */
#define IGC_FCAL 0x00028 /* Flow Control Address Low - RW */
#define IGC_FCAH 0x0002C /* Flow Control Address High -RW */
#define IGC_I225_FLSWCTL 0x12048 /* FLASH control register */
#define IGC_I225_FLSWDATA 0x1204C /* FLASH data register */
#define IGC_I225_FLSWCNT 0x12050 /* FLASH Access Counter */
#define IGC_I225_FLSECU 0x12114 /* FLASH Security */
#define IGC_FCT 0x00030 /* Flow Control Type - RW */
#define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
#define IGC_VET 0x00038 /* VLAN Ether Type - RW */
#define IGC_ICR 0x01500 /* Intr Cause Read - RC/W1C */
#define IGC_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
#define IGC_ICS 0x01504 /* Intr Cause Set - WO */
#define IGC_IMS 0x01508 /* Intr Mask Set/Read - RW */
#define IGC_IMC 0x0150C /* Intr Mask Clear - WO */
#define IGC_IAM 0x01510 /* Intr Ack Auto Mask- RW */
#define IGC_RCTL 0x00100 /* Rx Control - RW */
#define IGC_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
#define IGC_TXCW 0x00178 /* Tx Configuration Word - RW */
#define IGC_RXCW 0x00180 /* Rx Configuration Word - RO */
#define IGC_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
#define IGC_EITR(_n) (0x01680 + (0x4 * (_n)))
#define IGC_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
#define IGC_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
#define IGC_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
#define IGC_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
#define IGC_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
#define IGC_GPIE 0x01514 /* General Purpose Interrupt Enable - RW */
#define IGC_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */
#define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
#define IGC_TCTL 0x00400 /* Tx Control - RW */
#define IGC_TCTL_EXT 0x00404 /* Extended Tx Control - RW */
#define IGC_TIPG 0x00410 /* Tx Inter-packet gap -RW */
#define IGC_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
#define IGC_LEDCTL 0x00E00 /* LED Control - RW */
#define IGC_LEDMUX 0x08130 /* LED MUX Control */
#define IGC_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
#define IGC_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
#define IGC_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
#define IGC_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define IGC_PBS 0x01008 /* Packet Buffer Size */
#define IGC_EEMNGCTL 0x01010 /* MNG EEprom Control */
#define IGC_EEMNGCTL_I225 0x01010 /* i225 MNG EEprom Mode Control */
#define IGC_EEARBC_I225 0x12024 /* EEPROM Auto Read Bus Control */
#define IGC_FLOP 0x0103C /* FLASH Opcode Register */
#define IGC_WDSTP 0x01040 /* Watchdog Setup - RW */
#define IGC_SWDSTS 0x01044 /* SW Device Status - RW */
#define IGC_FRTIMER 0x01048 /* Free Running Timer - RW */
#define IGC_TCPTIMER 0x0104C /* TCP Timer - RW */
#define IGC_ERT 0x02008 /* Early Rx Threshold - RW */
#define IGC_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
#define IGC_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
#define IGC_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
#define IGC_RDFH 0x02410 /* Rx Data FIFO Head - RW */
#define IGC_RDFT 0x02418 /* Rx Data FIFO Tail - RW */
#define IGC_RDFHS 0x02420 /* Rx Data FIFO Head Saved - RW */
#define IGC_RDFTS 0x02428 /* Rx Data FIFO Tail Saved - RW */
#define IGC_RDFPC 0x02430 /* Rx Data FIFO Packet Count - RW */
#define IGC_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */
#define IGC_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
/* Split and Replication Rx Control - RW */
#define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
#define IGC_RDTR 0x02820 /* Rx Delay Timer - RW */
#define IGC_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */
/* Shadow Ram Write Register - RW */
#define IGC_SRWR 0x12018
#define IGC_EEC_REG 0x12010
#define IGC_SHADOWINF 0x12068
#define IGC_FLFWUPDATE 0x12108
#define IGC_INVM_DATA_REG(_n) (0x12120 + 4*(_n))
#define IGC_INVM_SIZE 64 /* Number of INVM Data Registers */
#define IGC_MMDAC 13 /* MMD Access Control */
#define IGC_MMDAAD 14 /* MMD Access Address/Data */
/* Convenience macros
*
* Note: "_n" is the queue number of the register to be written to.
*
* Example usage:
* IGC_RDBAL_REG(current_rx_queue)
*/
#define IGC_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
(0x0C000 + ((_n) * 0x40)))
#define IGC_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
(0x0C004 + ((_n) * 0x40)))
#define IGC_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
(0x0C008 + ((_n) * 0x40)))
#define IGC_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
(0x0C00C + ((_n) * 0x40)))
#define IGC_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
(0x0C010 + ((_n) * 0x40)))
#define IGC_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
(0x0C018 + ((_n) * 0x40)))
#define IGC_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
(0x0C028 + ((_n) * 0x40)))
#define IGC_RQDPC(_n) ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \
(0x0C030 + ((_n) * 0x40)))
#define IGC_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
(0x0E000 + ((_n) * 0x40)))
#define IGC_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
(0x0E004 + ((_n) * 0x40)))
#define IGC_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
(0x0E008 + ((_n) * 0x40)))
#define IGC_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
(0x0E010 + ((_n) * 0x40)))
#define IGC_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
(0x0E018 + ((_n) * 0x40)))
#define IGC_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
(0x0E028 + ((_n) * 0x40)))
#define IGC_TARC(_n) (0x03840 + ((_n) * 0x100))
#define IGC_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */
#define IGC_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
#define IGC_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
#define IGC_PSRTYPE(_i) (0x05480 + ((_i) * 4))
#define IGC_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
(0x054E0 + ((_i - 16) * 8)))
#define IGC_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
(0x054E4 + ((_i - 16) * 8)))
#define IGC_VLANPQF 0x055B0 /* VLAN Priority Queue Filter VLAPQF */
#define IGC_SHRAL(_i) (0x05438 + ((_i) * 8))
#define IGC_SHRAH(_i) (0x0543C + ((_i) * 8))
#define IGC_IP4AT_REG(_i) (0x05840 + ((_i) * 8))
#define IGC_IP6AT_REG(_i) (0x05880 + ((_i) * 4))
#define IGC_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
#define IGC_FFMT_REG(_i) (0x09000 + ((_i) * 8))
#define IGC_FFVT_REG(_i) (0x09800 + ((_i) * 8))
#define IGC_FFLT_REG(_i) (0x05F00 + ((_i) * 8))
#define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
#define IGC_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */
#define IGC_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */
/* Statistics Register Descriptions */
#define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */
#define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
#define IGC_MPC 0x04010 /* Missed Packet Count - R/clr */
#define IGC_SCC 0x04014 /* Single Collision Count - R/clr */
#define IGC_ECOL 0x04018 /* Excessive Collision Count - R/clr */
#define IGC_MCC 0x0401C /* Multiple Collision Count - R/clr */
#define IGC_LATECOL 0x04020 /* Late Collision Count - R/clr */
#define IGC_COLC 0x04028 /* Collision Count - R/clr */
#define IGC_RERC 0x0402C /* Receive Error Count - R/clr */
#define IGC_DC 0x04030 /* Defer Count - R/clr */
#define IGC_TNCRS 0x04034 /* Tx-No CRS - R/clr */
#define IGC_HTDPMC 0x0403C /* Host Transmit Discarded by MAC - R/clr */
#define IGC_RLEC 0x04040 /* Receive Length Error Count - R/clr */
#define IGC_XONRXC 0x04048 /* XON Rx Count - R/clr */
#define IGC_XONTXC 0x0404C /* XON Tx Count - R/clr */
#define IGC_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */
#define IGC_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */
#define IGC_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */
#define IGC_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */
#define IGC_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */
#define IGC_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */
#define IGC_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */
#define IGC_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */
#define IGC_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */
#define IGC_GPRC 0x04074 /* Good Packets Rx Count - R/clr */
#define IGC_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */
#define IGC_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */
#define IGC_GPTC 0x04080 /* Good Packets Tx Count - R/clr */
#define IGC_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */
#define IGC_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */
#define IGC_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */
#define IGC_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */
#define IGC_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */
#define IGC_RUC 0x040A4 /* Rx Undersize Count - R/clr */
#define IGC_RFC 0x040A8 /* Rx Fragment Count - R/clr */
#define IGC_ROC 0x040AC /* Rx Oversize Count - R/clr */
#define IGC_RJC 0x040B0 /* Rx Jabber Count - R/clr */
#define IGC_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */
#define IGC_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
#define IGC_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */
#define IGC_TORL 0x040C0 /* Total Octets Rx Low - R/clr */
#define IGC_TORH 0x040C4 /* Total Octets Rx High - R/clr */
#define IGC_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */
#define IGC_TOTH 0x040CC /* Total Octets Tx High - R/clr */
#define IGC_TPR 0x040D0 /* Total Packets Rx - R/clr */
#define IGC_TPT 0x040D4 /* Total Packets Tx - R/clr */
#define IGC_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */
#define IGC_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */
#define IGC_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */
#define IGC_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */
#define IGC_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */
#define IGC_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */
#define IGC_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */
#define IGC_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */
#define IGC_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */
#define IGC_IAC 0x04100 /* Interrupt Assertion Count */
#define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */
#define IGC_VFGPRC 0x00F10
#define IGC_VFGORC 0x00F18
#define IGC_VFMPRC 0x00F3C
#define IGC_VFGPTC 0x00F14
#define IGC_VFGOTC 0x00F34
#define IGC_VFGOTLBC 0x00F50
#define IGC_VFGPTLBC 0x00F44
#define IGC_VFGORLBC 0x00F48
#define IGC_VFGPRLBC 0x00F40
#define IGC_HGORCL 0x04128 /* Host Good Octets Received Count Low */
#define IGC_HGORCH 0x0412C /* Host Good Octets Received Count High */
#define IGC_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */
#define IGC_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */
#define IGC_LENERRS 0x04138 /* Length Errors Count */
#define IGC_PCS_ANADV 0x04218 /* AN advertisement - RW */
#define IGC_PCS_LPAB 0x0421C /* Link Partner Ability - RW */
#define IGC_RXCSUM 0x05000 /* Rx Checksum Control - RW */
#define IGC_RLPML 0x05004 /* Rx Long Packet Max Length */
#define IGC_RFCTL 0x05008 /* Receive Filter Control*/
#define IGC_MTA 0x05200 /* Multicast Table Array - RW Array */
#define IGC_RA 0x05400 /* Receive Address - RW Array */
#define IGC_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
#define IGC_WUC 0x05800 /* Wakeup Control - RW */
#define IGC_WUFC 0x05808 /* Wakeup Filter Control - RW */
#define IGC_WUS 0x05810 /* Wakeup Status - RO */
/* Management registers */
#define IGC_MANC 0x05820 /* Management Control - RW */
#define IGC_IPAV 0x05838 /* IP Address Valid - RW */
#define IGC_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
#define IGC_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
#define IGC_WUPL 0x05900 /* Wakeup Packet Length - RW */
#define IGC_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
#define IGC_WUPM_EXT 0x0B800 /* Wakeup Packet Memory Extended - RO Array */
#define IGC_WUFC_EXT 0x0580C /* Wakeup Filter Control Extended - RW */
#define IGC_WUS_EXT 0x05814 /* Wakeup Status Extended - RW1C */
#define IGC_FHFTSL 0x05804 /* Flex Filter Indirect Table Select - RW */
#define IGC_PROXYFCEX 0x05590 /* Proxy Filter Control Extended - RW1C */
#define IGC_PROXYEXS 0x05594 /* Proxy Extended Status - RO */
#define IGC_WFUTPF 0x05500 /* Wake Flex UDP TCP Port Filter - RW Array */
#define IGC_RFUTPF 0x05580 /* Range Flex UDP TCP Port Filter - RW */
#define IGC_RWPFC 0x05584 /* Range Wake Port Filter Control - RW */
#define IGC_WFUTPS 0x05588 /* Wake Filter UDP TCP Status - RW1C */
#define IGC_WCS 0x0558C /* Wake Control Status - RW1C */
/* MSI-X Table Register Descriptions */
#define IGC_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */
#define IGC_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
#define IGC_HOST_IF 0x08800 /* Host Interface */
/* Flexible Host Filter Table */
#define IGC_FHFT(_n) (0x09000 + ((_n) * 0x100))
/* Ext Flexible Host Filter Table */
#define IGC_FHFT_EXT(_n) (0x09A00 + ((_n) * 0x100))
#define IGC_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
#define IGC_MANC2H 0x05860 /* Management Control To Host - RW */
/* Management Decision Filters */
#define IGC_MDEF(_n) (0x05890 + (4 * (_n)))
/* Semaphore registers */
#define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */
/* Function Active and Power State to MNG */
#define IGC_FACTPS 0x05B30
#define IGC_SWSM 0x05B50 /* SW Semaphore */
#define IGC_FWSM 0x05B54 /* FW Semaphore */
/* Driver-only SW semaphore (not used by BOOT agents) */
#define IGC_SWSM2 0x05B58
#define IGC_FFLT_DBG 0x05F04 /* Debug Register */
#define IGC_HICR 0x08F00 /* Host Interface Control */
#define IGC_FWSTS 0x08F0C /* FW Status */
/* RSS registers */
#define IGC_MRQC 0x05818 /* Multiple Receive Control - RW */
#define IGC_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
#define IGC_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate INTR Ext*/
#define IGC_IMIRVP 0x05AC0 /* Immediate INT Rx VLAN Priority -RW */
#define IGC_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Alloc Reg -RW */
/* Redirection Table - RW Array */
#define IGC_RETA(_i) (0x05C00 + ((_i) * 4))
/* RSS Random Key - RW Array */
#define IGC_RSSRK(_i) (0x05C80 + ((_i) * 4))
#define IGC_RSSIM 0x05864 /* RSS Interrupt Mask */
#define IGC_RSSIR 0x05868 /* RSS Interrupt Request */
#define IGC_UTA 0x0A000 /* Unicast Table Array - RW */
#define IGC_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
#define IGC_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
#define IGC_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
#define IGC_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */
#define IGC_RXSTMPH 0x0B628 /* Rx timestamp High - RO */
#define IGC_RXSATRL 0x0B62C /* Rx timestamp attribute low - RO */
#define IGC_RXSATRH 0x0B630 /* Rx timestamp attribute high - RO */
#define IGC_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
#define IGC_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
#define IGC_SYSTIML 0x0B600 /* System time register Low - RO */
#define IGC_SYSTIMH 0x0B604 /* System time register High - RO */
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
#define IGC_TIMADJL 0x0B60C /* Time sync time adjustment offset Low - RW */
#define IGC_TIMADJH 0x0B610 /* Time sync time adjustment offset High - RW */
#define IGC_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
#define IGC_TSICR 0x0B66C /* Interrupt Cause Register */
#define IGC_TSIM 0x0B674 /* Interrupt Mask Register */
/* Filtering Registers */
#define IGC_SAQF(_n) (0x05980 + (4 * (_n))) /* Source Address Queue Fltr */
#define IGC_DAQF(_n) (0x059A0 + (4 * (_n))) /* Dest Address Queue Fltr */
#define IGC_SPQF(_n) (0x059C0 + (4 * (_n))) /* Source Port Queue Fltr */
#define IGC_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
#define IGC_TTQF(_n) (0x059E0 + (4 * (_n))) /* 2-tuple Queue Fltr */
#define IGC_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
#define IGC_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
/* ETQF register bit definitions */
#define IGC_ETQF_FILTER_ENABLE (1 << 26)
#define IGC_ETQF_IMM_INT (1 << 29)
#define IGC_ETQF_QUEUE_ENABLE (1 << 31)
#define IGC_ETQF_QUEUE_SHIFT 16
#define IGC_ETQF_QUEUE_MASK 0x00070000
#define IGC_ETQF_ETYPE_MASK 0x0000FFFF
#define IGC_RTTDCS 0x3600 /* Reedtown Tx Desc plane control and status */
#define IGC_RTTPCS 0x3474 /* Reedtown Tx Packet Plane control and status */
#define IGC_RTRPCS 0x2474 /* Rx packet plane control and status */
#define IGC_RTRUP2TC 0x05AC4 /* Rx User Priority to Traffic Class */
#define IGC_RTTUP2TC 0x0418 /* Transmit User Priority to Traffic Class */
/* Tx Desc plane TC Rate-scheduler config */
#define IGC_RTTDTCRC(_n) (0x3610 + ((_n) * 4))
/* Tx Packet plane TC Rate-Scheduler Config */
#define IGC_RTTPTCRC(_n) (0x3480 + ((_n) * 4))
/* Rx Packet plane TC Rate-Scheduler Config */
#define IGC_RTRPTCRC(_n) (0x2480 + ((_n) * 4))
/* Tx Desc Plane TC Rate-Scheduler Status */
#define IGC_RTTDTCRS(_n) (0x3630 + ((_n) * 4))
/* Tx Desc Plane TC Rate-Scheduler MMW */
#define IGC_RTTDTCRM(_n) (0x3650 + ((_n) * 4))
/* Tx Packet plane TC Rate-Scheduler Status */
#define IGC_RTTPTCRS(_n) (0x34A0 + ((_n) * 4))
/* Tx Packet plane TC Rate-scheduler MMW */
#define IGC_RTTPTCRM(_n) (0x34C0 + ((_n) * 4))
/* Rx Packet plane TC Rate-Scheduler Status */
#define IGC_RTRPTCRS(_n) (0x24A0 + ((_n) * 4))
/* Rx Packet plane TC Rate-Scheduler MMW */
#define IGC_RTRPTCRM(_n) (0x24C0 + ((_n) * 4))
/* Tx Desc plane VM Rate-Scheduler MMW*/
#define IGC_RTTDVMRM(_n) (0x3670 + ((_n) * 4))
/* Tx BCN Rate-Scheduler MMW */
#define IGC_RTTBCNRM(_n) (0x3690 + ((_n) * 4))
#define IGC_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select */
#define IGC_RTTDVMRC 0x3608 /* Tx Desc Plane VM Rate-Scheduler Config */
#define IGC_RTTDVMRS 0x360C /* Tx Desc Plane VM Rate-Scheduler Status */
#define IGC_RTTBCNRC 0x36B0 /* Tx BCN Rate-Scheduler Config */
#define IGC_RTTBCNRS 0x36B4 /* Tx BCN Rate-Scheduler Status */
#define IGC_RTTBCNCR 0xB200 /* Tx BCN Control Register */
#define IGC_RTTBCNTG 0x35A4 /* Tx BCN Tagging */
#define IGC_RTTBCNCP 0xB208 /* Tx BCN Congestion point */
#define IGC_RTRBCNCR 0xB20C /* Rx BCN Control Register */
#define IGC_RTTBCNRD 0x36B8 /* Tx BCN Rate Drift */
#define IGC_PFCTOP 0x1080 /* Priority Flow Control Type and Opcode */
#define IGC_RTTBCNIDX 0xB204 /* Tx BCN Congestion Point */
#define IGC_RTTBCNACH 0x0B214 /* Tx BCN Control High */
#define IGC_RTTBCNACL 0x0B210 /* Tx BCN Control Low */
/* DMA Coalescing registers */
#define IGC_DMACR 0x02508 /* Control Register */
#define IGC_DMCTXTH 0x03550 /* Transmit Threshold */
#define IGC_DMCTLX 0x02514 /* Time to Lx Request */
#define IGC_DMCRTRH 0x05DD0 /* Receive Packet Rate Threshold */
#define IGC_DMCCNT 0x05DD4 /* Current Rx Count */
#define IGC_FCRTC 0x02170 /* Flow Control Rx high watermark */
#define IGC_PCIEMISC 0x05BB8 /* PCIE misc config register */
/* PCIe Parity Status Register */
#define IGC_PCIEERRSTS 0x05BA8
#define IGC_PROXYS 0x5F64 /* Proxying Status */
#define IGC_PROXYFC 0x5F60 /* Proxying Filter Control */
/* Thermal sensor configuration and status registers */
#define IGC_THMJT 0x08100 /* Junction Temperature */
#define IGC_THLOWTC 0x08104 /* Low Threshold Control */
#define IGC_THMIDTC 0x08108 /* Mid Threshold Control */
#define IGC_THHIGHTC 0x0810C /* High Threshold Control */
#define IGC_THSTAT 0x08110 /* Thermal Sensor Status */
/* Energy Efficient Ethernet "EEE" registers */
#define IGC_IPCNFG 0x0E38 /* Internal PHY Configuration */
#define IGC_LTRC 0x01A0 /* Latency Tolerance Reporting Control */
#define IGC_EEER 0x0E30 /* Energy Efficient Ethernet "EEE"*/
#define IGC_EEE_SU 0x0E34 /* EEE Setup */
#define IGC_EEE_SU_2P5 0x0E3C /* EEE 2.5G Setup */
#define IGC_TLPIC 0x4148 /* EEE Tx LPI Count - TLPIC */
#define IGC_RLPIC 0x414C /* EEE Rx LPI Count - RLPIC */
/* OS2BMC Registers */
#define IGC_B2OSPC 0x08FE0 /* BMC2OS packets sent by BMC */
#define IGC_B2OGPRC 0x04158 /* BMC2OS packets received by host */
#define IGC_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */
#define IGC_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */
#define IGC_LTRMINV 0x5BB0 /* LTR Minimum Value */
#define IGC_LTRMAXV 0x5BB4 /* LTR Maximum Value */
/* IEEE 1588 TIMESYNCH */
#define IGC_TRGTTIML0 0x0B644 /* Target Time Register 0 Low - RW */
#define IGC_TRGTTIMH0 0x0B648 /* Target Time Register 0 High - RW */
#define IGC_TRGTTIML1 0x0B64C /* Target Time Register 1 Low - RW */
#define IGC_TRGTTIMH1 0x0B650 /* Target Time Register 1 High - RW */
#define IGC_FREQOUT0 0x0B654 /* Frequency Out 0 Control Register - RW */
#define IGC_FREQOUT1 0x0B658 /* Frequency Out 1 Control Register - RW */
#define IGC_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
#endif

580
sys/dev/igc/igc_txrx.c Normal file
View File

@ -0,0 +1,580 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2016 Matthew Macy <mmacy@mattmacy.io>
* 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"
#ifdef RSS
#include <net/rss_config.h>
#include <netinet/in_rss.h>
#endif
#ifdef VERBOSE_DEBUG
#define DPRINTF device_printf
#else
#define DPRINTF(...)
#endif
/*********************************************************************
* Local Function prototypes
*********************************************************************/
static int igc_isc_txd_encap(void *arg, if_pkt_info_t pi);
static void igc_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx);
static int igc_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear);
static void igc_isc_rxd_refill(void *arg, if_rxd_update_t iru);
static void igc_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused, qidx_t pidx);
static int igc_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget);
static int igc_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri);
static int igc_tx_ctx_setup(struct tx_ring *txr, if_pkt_info_t pi, u32 *cmd_type_len, u32 *olinfo_status);
static int igc_tso_setup(struct tx_ring *txr, if_pkt_info_t pi, u32 *cmd_type_len, u32 *olinfo_status);
static void igc_rx_checksum(u32 staterr, if_rxd_info_t ri, u32 ptype);
static int igc_determine_rsstype(u16 pkt_info);
extern void igc_if_enable_intr(if_ctx_t ctx);
extern int igc_intr(void *arg);
struct if_txrx igc_txrx = {
.ift_txd_encap = igc_isc_txd_encap,
.ift_txd_flush = igc_isc_txd_flush,
.ift_txd_credits_update = igc_isc_txd_credits_update,
.ift_rxd_available = igc_isc_rxd_available,
.ift_rxd_pkt_get = igc_isc_rxd_pkt_get,
.ift_rxd_refill = igc_isc_rxd_refill,
.ift_rxd_flush = igc_isc_rxd_flush,
.ift_legacy_intr = igc_intr
};
void
igc_dump_rs(struct igc_adapter *adapter)
{
if_softc_ctx_t scctx = adapter->shared;
struct igc_tx_queue *que;
struct tx_ring *txr;
qidx_t i, ntxd, qid, cur;
int16_t rs_cidx;
uint8_t status;
printf("\n");
ntxd = scctx->isc_ntxd[0];
for (qid = 0; qid < adapter->tx_num_queues; qid++) {
que = &adapter->tx_queues[qid];
txr = &que->txr;
rs_cidx = txr->tx_rs_cidx;
if (rs_cidx != txr->tx_rs_pidx) {
cur = txr->tx_rsq[rs_cidx];
status = txr->tx_base[cur].upper.fields.status;
if (!(status & IGC_TXD_STAT_DD))
printf("qid[%d]->tx_rsq[%d]: %d clear ", qid, rs_cidx, cur);
} else {
rs_cidx = (rs_cidx-1)&(ntxd-1);
cur = txr->tx_rsq[rs_cidx];
printf("qid[%d]->tx_rsq[rs_cidx-1=%d]: %d ", qid, rs_cidx, cur);
}
printf("cidx_prev=%d rs_pidx=%d ",txr->tx_cidx_processed, txr->tx_rs_pidx);
for (i = 0; i < ntxd; i++) {
if (txr->tx_base[i].upper.fields.status & IGC_TXD_STAT_DD)
printf("%d set ", i);
}
printf("\n");
}
}
/**********************************************************************
*
* Setup work for hardware segmentation offload (TSO) on
* adapters using advanced tx descriptors
*
**********************************************************************/
static int
igc_tso_setup(struct tx_ring *txr, if_pkt_info_t pi, u32 *cmd_type_len, u32 *olinfo_status)
{
struct igc_adv_tx_context_desc *TXD;
u32 type_tucmd_mlhl = 0, vlan_macip_lens = 0;
u32 mss_l4len_idx = 0;
u32 paylen;
switch(pi->ipi_etype) {
case ETHERTYPE_IPV6:
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV6;
break;
case ETHERTYPE_IP:
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV4;
/* Tell transmit desc to also do IPv4 checksum. */
*olinfo_status |= IGC_TXD_POPTS_IXSM << 8;
break;
default:
panic("%s: CSUM_TSO but no supported IP version (0x%04x)",
__func__, ntohs(pi->ipi_etype));
break;
}
TXD = (struct igc_adv_tx_context_desc *) &txr->tx_base[pi->ipi_pidx];
/* This is used in the transmit desc in encap */
paylen = pi->ipi_len - pi->ipi_ehdrlen - pi->ipi_ip_hlen - pi->ipi_tcp_hlen;
/* VLAN MACLEN IPLEN */
if (pi->ipi_mflags & M_VLANTAG) {
vlan_macip_lens |= (pi->ipi_vtag << IGC_ADVTXD_VLAN_SHIFT);
}
vlan_macip_lens |= pi->ipi_ehdrlen << IGC_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= pi->ipi_ip_hlen;
TXD->vlan_macip_lens = htole32(vlan_macip_lens);
/* ADV DTYPE TUCMD */
type_tucmd_mlhl |= IGC_ADVTXD_DCMD_DEXT | IGC_ADVTXD_DTYP_CTXT;
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_TCP;
TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
/* MSS L4LEN IDX */
mss_l4len_idx |= (pi->ipi_tso_segsz << IGC_ADVTXD_MSS_SHIFT);
mss_l4len_idx |= (pi->ipi_tcp_hlen << IGC_ADVTXD_L4LEN_SHIFT);
TXD->mss_l4len_idx = htole32(mss_l4len_idx);
TXD->seqnum_seed = htole32(0);
*cmd_type_len |= IGC_ADVTXD_DCMD_TSE;
*olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
*olinfo_status |= paylen << IGC_ADVTXD_PAYLEN_SHIFT;
return (1);
}
/*********************************************************************
*
* Advanced Context Descriptor setup for VLAN, CSUM or TSO
*
**********************************************************************/
static int
igc_tx_ctx_setup(struct tx_ring *txr, if_pkt_info_t pi, u32 *cmd_type_len, u32 *olinfo_status)
{
struct igc_adv_tx_context_desc *TXD;
u32 vlan_macip_lens, type_tucmd_mlhl;
u32 mss_l4len_idx;
mss_l4len_idx = vlan_macip_lens = type_tucmd_mlhl = 0;
/* First check if TSO is to be used */
if (pi->ipi_csum_flags & CSUM_TSO)
return (igc_tso_setup(txr, pi, cmd_type_len, olinfo_status));
/* Indicate the whole packet as payload when not doing TSO */
*olinfo_status |= pi->ipi_len << IGC_ADVTXD_PAYLEN_SHIFT;
/* Now ready a context descriptor */
TXD = (struct igc_adv_tx_context_desc *) &txr->tx_base[pi->ipi_pidx];
/*
** In advanced descriptors the vlan tag must
** be placed into the context descriptor. Hence
** we need to make one even if not doing offloads.
*/
if (pi->ipi_mflags & M_VLANTAG) {
vlan_macip_lens |= (pi->ipi_vtag << IGC_ADVTXD_VLAN_SHIFT);
} else if ((pi->ipi_csum_flags & IGC_CSUM_OFFLOAD) == 0) {
return (0);
}
/* Set the ether header length */
vlan_macip_lens |= pi->ipi_ehdrlen << IGC_ADVTXD_MACLEN_SHIFT;
switch(pi->ipi_etype) {
case ETHERTYPE_IP:
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV4;
break;
case ETHERTYPE_IPV6:
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV6;
break;
default:
break;
}
vlan_macip_lens |= pi->ipi_ip_hlen;
type_tucmd_mlhl |= IGC_ADVTXD_DCMD_DEXT | IGC_ADVTXD_DTYP_CTXT;
switch (pi->ipi_ipproto) {
case IPPROTO_TCP:
if (pi->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) {
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_TCP;
*olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
}
break;
case IPPROTO_UDP:
if (pi->ipi_csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP)) {
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_UDP;
*olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
}
break;
case IPPROTO_SCTP:
if (pi->ipi_csum_flags & (CSUM_IP_SCTP | CSUM_IP6_SCTP)) {
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_SCTP;
*olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
}
break;
default:
break;
}
/* Now copy bits into descriptor */
TXD->vlan_macip_lens = htole32(vlan_macip_lens);
TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
TXD->seqnum_seed = htole32(0);
TXD->mss_l4len_idx = htole32(mss_l4len_idx);
return (1);
}
static int
igc_isc_txd_encap(void *arg, if_pkt_info_t pi)
{
struct igc_adapter *sc = arg;
if_softc_ctx_t scctx = sc->shared;
struct igc_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx];
struct tx_ring *txr = &que->txr;
int nsegs = pi->ipi_nsegs;
bus_dma_segment_t *segs = pi->ipi_segs;
union igc_adv_tx_desc *txd = NULL;
int i, j, pidx_last;
u32 olinfo_status, cmd_type_len, txd_flags;
qidx_t ntxd;
pidx_last = olinfo_status = 0;
/* Basic descriptor defines */
cmd_type_len = (IGC_ADVTXD_DTYP_DATA |
IGC_ADVTXD_DCMD_IFCS | IGC_ADVTXD_DCMD_DEXT);
if (pi->ipi_mflags & M_VLANTAG)
cmd_type_len |= IGC_ADVTXD_DCMD_VLE;
i = pi->ipi_pidx;
ntxd = scctx->isc_ntxd[0];
txd_flags = pi->ipi_flags & IPI_TX_INTR ? IGC_ADVTXD_DCMD_RS : 0;
/* Consume the first descriptor */
i += igc_tx_ctx_setup(txr, pi, &cmd_type_len, &olinfo_status);
if (i == scctx->isc_ntxd[0])
i = 0;
for (j = 0; j < nsegs; j++) {
bus_size_t seglen;
bus_addr_t segaddr;
txd = (union igc_adv_tx_desc *)&txr->tx_base[i];
seglen = segs[j].ds_len;
segaddr = htole64(segs[j].ds_addr);
txd->read.buffer_addr = segaddr;
txd->read.cmd_type_len = htole32(IGC_ADVTXD_DCMD_IFCS |
cmd_type_len | seglen);
txd->read.olinfo_status = htole32(olinfo_status);
pidx_last = i;
if (++i == scctx->isc_ntxd[0]) {
i = 0;
}
}
if (txd_flags) {
txr->tx_rsq[txr->tx_rs_pidx] = pidx_last;
txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & (ntxd-1);
MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx);
}
txd->read.cmd_type_len |= htole32(IGC_ADVTXD_DCMD_EOP | txd_flags);
pi->ipi_new_pidx = i;
return (0);
}
static void
igc_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
{
struct igc_adapter *adapter = arg;
struct igc_tx_queue *que = &adapter->tx_queues[txqid];
struct tx_ring *txr = &que->txr;
IGC_WRITE_REG(&adapter->hw, IGC_TDT(txr->me), pidx);
}
static int
igc_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear)
{
struct igc_adapter *adapter = arg;
if_softc_ctx_t scctx = adapter->shared;
struct igc_tx_queue *que = &adapter->tx_queues[txqid];
struct tx_ring *txr = &que->txr;
qidx_t processed = 0;
int updated;
qidx_t cur, prev, ntxd, rs_cidx;
int32_t delta;
uint8_t status;
rs_cidx = txr->tx_rs_cidx;
if (rs_cidx == txr->tx_rs_pidx)
return (0);
cur = txr->tx_rsq[rs_cidx];
status = ((union igc_adv_tx_desc *)&txr->tx_base[cur])->wb.status;
updated = !!(status & IGC_TXD_STAT_DD);
if (!updated)
return (0);
/* If clear is false just let caller know that there
* are descriptors to reclaim */
if (!clear)
return (1);
prev = txr->tx_cidx_processed;
ntxd = scctx->isc_ntxd[0];
do {
MPASS(prev != cur);
delta = (int32_t)cur - (int32_t)prev;
if (delta < 0)
delta += ntxd;
MPASS(delta > 0);
processed += delta;
prev = cur;
rs_cidx = (rs_cidx + 1) & (ntxd-1);
if (rs_cidx == txr->tx_rs_pidx)
break;
cur = txr->tx_rsq[rs_cidx];
status = ((union igc_adv_tx_desc *)&txr->tx_base[cur])->wb.status;
} while ((status & IGC_TXD_STAT_DD));
txr->tx_rs_cidx = rs_cidx;
txr->tx_cidx_processed = prev;
return (processed);
}
static void
igc_isc_rxd_refill(void *arg, if_rxd_update_t iru)
{
struct igc_adapter *sc = arg;
if_softc_ctx_t scctx = sc->shared;
uint16_t rxqid = iru->iru_qsidx;
struct igc_rx_queue *que = &sc->rx_queues[rxqid];
union igc_adv_rx_desc *rxd;
struct rx_ring *rxr = &que->rxr;
uint64_t *paddrs;
uint32_t next_pidx, pidx;
uint16_t count;
int i;
paddrs = iru->iru_paddrs;
pidx = iru->iru_pidx;
count = iru->iru_count;
for (i = 0, next_pidx = pidx; i < count; i++) {
rxd = (union igc_adv_rx_desc *)&rxr->rx_base[next_pidx];
rxd->read.pkt_addr = htole64(paddrs[i]);
if (++next_pidx == scctx->isc_nrxd[0])
next_pidx = 0;
}
}
static void
igc_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused, qidx_t pidx)
{
struct igc_adapter *sc = arg;
struct igc_rx_queue *que = &sc->rx_queues[rxqid];
struct rx_ring *rxr = &que->rxr;
IGC_WRITE_REG(&sc->hw, IGC_RDT(rxr->me), pidx);
}
static int
igc_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
{
struct igc_adapter *sc = arg;
if_softc_ctx_t scctx = sc->shared;
struct igc_rx_queue *que = &sc->rx_queues[rxqid];
struct rx_ring *rxr = &que->rxr;
union igc_adv_rx_desc *rxd;
u32 staterr = 0;
int cnt, i;
for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) {
rxd = (union igc_adv_rx_desc *)&rxr->rx_base[i];
staterr = le32toh(rxd->wb.upper.status_error);
if ((staterr & IGC_RXD_STAT_DD) == 0)
break;
if (++i == scctx->isc_nrxd[0])
i = 0;
if (staterr & IGC_RXD_STAT_EOP)
cnt++;
}
return (cnt);
}
/****************************************************************
* Routine sends data which has been dma'ed into host memory
* to upper layer. Initialize ri structure.
*
* Returns 0 upon success, errno on failure
***************************************************************/
static int
igc_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
{
struct igc_adapter *adapter = arg;
if_softc_ctx_t scctx = adapter->shared;
struct igc_rx_queue *que = &adapter->rx_queues[ri->iri_qsidx];
struct rx_ring *rxr = &que->rxr;
struct ifnet *ifp = iflib_get_ifp(adapter->ctx);
union igc_adv_rx_desc *rxd;
u16 pkt_info, len;
u16 vtag = 0;
u32 ptype;
u32 staterr = 0;
bool eop;
int i = 0;
int cidx = ri->iri_cidx;
do {
rxd = (union igc_adv_rx_desc *)&rxr->rx_base[cidx];
staterr = le32toh(rxd->wb.upper.status_error);
pkt_info = le16toh(rxd->wb.lower.lo_dword.hs_rss.pkt_info);
MPASS ((staterr & IGC_RXD_STAT_DD) != 0);
len = le16toh(rxd->wb.upper.length);
ptype = le32toh(rxd->wb.lower.lo_dword.data) & IGC_PKTTYPE_MASK;
ri->iri_len += len;
rxr->rx_bytes += ri->iri_len;
rxd->wb.upper.status_error = 0;
eop = ((staterr & IGC_RXD_STAT_EOP) == IGC_RXD_STAT_EOP);
vtag = le16toh(rxd->wb.upper.vlan);
/* Make sure bad packets are discarded */
if (eop && ((staterr & IGC_RXDEXT_STATERR_RXE) != 0)) {
adapter->dropped_pkts++;
++rxr->rx_discarded;
return (EBADMSG);
}
ri->iri_frags[i].irf_flid = 0;
ri->iri_frags[i].irf_idx = cidx;
ri->iri_frags[i].irf_len = len;
if (++cidx == scctx->isc_nrxd[0])
cidx = 0;
#ifdef notyet
if (rxr->hdr_split == true) {
ri->iri_frags[i].irf_flid = 1;
ri->iri_frags[i].irf_idx = cidx;
if (++cidx == scctx->isc_nrxd[0])
cidx = 0;
}
#endif
i++;
} while (!eop);
rxr->rx_packets++;
if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
igc_rx_checksum(staterr, ri, ptype);
if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 &&
(staterr & IGC_RXD_STAT_VP) != 0) {
ri->iri_vtag = vtag;
ri->iri_flags |= M_VLANTAG;
}
ri->iri_flowid =
le32toh(rxd->wb.lower.hi_dword.rss);
ri->iri_rsstype = igc_determine_rsstype(pkt_info);
ri->iri_nfrags = i;
return (0);
}
/*********************************************************************
*
* Verify that the hardware indicated that the checksum is valid.
* Inform the stack about the status of checksum so that stack
* doesn't spend time verifying the checksum.
*
*********************************************************************/
static void
igc_rx_checksum(u32 staterr, if_rxd_info_t ri, u32 ptype)
{
u16 status = (u16)staterr;
u8 errors = (u8) (staterr >> 24);
/* Ignore Checksum bit is set */
if (status & IGC_RXD_STAT_IXSM) {
ri->iri_csum_flags = 0;
return;
}
if (status & (IGC_RXD_STAT_TCPCS | IGC_RXD_STAT_UDPCS)) {
u64 type = (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
/* Did it pass? */
if (!(errors & IGC_RXD_ERR_TCPE)) {
ri->iri_csum_flags |= type;
ri->iri_csum_data = htons(0xffff);
}
}
return;
}
/********************************************************************
*
* Parse the packet type to determine the appropriate hash
*
******************************************************************/
static int
igc_determine_rsstype(u16 pkt_info)
{
switch (pkt_info & IGC_RXDADV_RSSTYPE_MASK) {
case IGC_RXDADV_RSSTYPE_IPV4_TCP:
return M_HASHTYPE_RSS_TCP_IPV4;
case IGC_RXDADV_RSSTYPE_IPV4:
return M_HASHTYPE_RSS_IPV4;
case IGC_RXDADV_RSSTYPE_IPV6_TCP:
return M_HASHTYPE_RSS_TCP_IPV6;
case IGC_RXDADV_RSSTYPE_IPV6_EX:
return M_HASHTYPE_RSS_IPV6_EX;
case IGC_RXDADV_RSSTYPE_IPV6:
return M_HASHTYPE_RSS_IPV6;
case IGC_RXDADV_RSSTYPE_IPV6_TCP_EX:
return M_HASHTYPE_RSS_TCP_IPV6_EX;
default:
return M_HASHTYPE_OPAQUE;
}
}

View File

@ -221,6 +221,7 @@ device puc # Multi I/O cards and multi-channel UARTs
# PCI/PCI-X/PCIe Ethernet NICs that use iflib infrastructure
device iflib
device igc # Intel I225 2.5G Ethernet
device em # Intel PRO/1000 Gigabit Ethernet Family
device vmx # VMware VMXNET3 Ethernet

View File

@ -496,6 +496,7 @@ device cpufreq
# V.35/RS-232/RS-530/RS-449/X.21/G.703/E1/E3/T3/STS-1
# serial adaptor (requires sppp (default), or NETGRAPH if
# NETGRAPH_CRONYX is configured)
# igc: Intel I225 2.5G Ethernet adapter
# ipw: Intel PRO/Wireless 2100 IEEE 802.11 adapter
# iwi: Intel PRO/Wireless 2200BG/2225BG/2915ABG IEEE 802.11 adapters
# Requires the iwi firmware module
@ -526,6 +527,7 @@ envvar hint.ed.0.at="isa"
envvar hint.ed.0.port="0x280"
envvar hint.ed.0.irq="5"
envvar hint.ed.0.maddr="0xd8000"
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.

View File

@ -164,6 +164,7 @@ SUBDIR= \
if_vlan \
if_vxlan \
iflib \
${_igc} \
${_iir} \
imgact_binmisc \
${_intelspi} \
@ -634,6 +635,7 @@ _em= em
_et= et
_ftwd= ftwd
_exca= exca
_igc= igc
_io= io
_itwd= itwd
_ix= ix

11
sys/modules/igc/Makefile Normal file
View File

@ -0,0 +1,11 @@
# $FreeBSD$
.PATH: ${SRCTOP}/sys/dev/igc
KMOD = if_igc
SRCS = device_if.h bus_if.h pci_if.h ifdi_if.h
SRCS += opt_ddb.h opt_inet.h opt_inet6.h opt_rss.h
SRCS += if_igc.c igc_api.c igc_base.c igc_i225.c igc_mac.c igc_nvm.c
SRCS += igc_phy.c igc_txrx.c
.include <bsd.kmod.mk>